github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/common/page_store.go (about) 1 package common 2 3 import ( 4 "database/sql" 5 "strconv" 6 "strings" 7 8 qgen "github.com/Azareal/Gosora/query_gen" 9 ) 10 11 type CustomPageStmts struct { 12 update *sql.Stmt 13 create *sql.Stmt 14 } 15 16 var customPageStmts CustomPageStmts 17 18 func init() { 19 DbInits.Add(func(acc *qgen.Accumulator) error { 20 customPageStmts = CustomPageStmts{ 21 update: acc.Update("pages").Set("name=?,title=?,body=?,allowedGroups=?,menuID=?").Where("pid=?").Prepare(), 22 create: acc.Insert("pages").Columns("name,title,body,allowedGroups,menuID").Fields("?,?,?,?,?").Prepare(), 23 } 24 return acc.FirstError() 25 }) 26 } 27 28 type CustomPage struct { 29 ID int 30 Name string // TODO: Let admins put pages in "virtual subdirectories" 31 Title string 32 Body string 33 AllowedGroups []int 34 MenuID int 35 } 36 37 func BlankCustomPage() *CustomPage { 38 return new(CustomPage) 39 } 40 41 func (p *CustomPage) AddAllowedGroup(gid int) { 42 p.AllowedGroups = append(p.AllowedGroups, gid) 43 } 44 45 func (p *CustomPage) getRawAllowedGroups() (rawAllowedGroups string) { 46 for _, group := range p.AllowedGroups { 47 rawAllowedGroups += strconv.Itoa(group) + "," 48 } 49 if len(rawAllowedGroups) > 0 { 50 rawAllowedGroups = rawAllowedGroups[:len(rawAllowedGroups)-1] 51 } 52 return rawAllowedGroups 53 } 54 55 func (p *CustomPage) Commit() error { 56 _, err := customPageStmts.update.Exec(p.Name, p.Title, p.Body, p.getRawAllowedGroups(), p.MenuID, p.ID) 57 Pages.Reload(p.ID) 58 return err 59 } 60 61 func (p *CustomPage) Create() (int, error) { 62 res, err := customPageStmts.create.Exec(p.Name, p.Title, p.Body, p.getRawAllowedGroups(), p.MenuID) 63 if err != nil { 64 return 0, err 65 } 66 pid64, err := res.LastInsertId() 67 return int(pid64), err 68 } 69 70 var Pages PageStore 71 72 // Holds the custom pages, but doesn't include the template pages in /pages/ which are a lot more flexible yet harder to use and which are too risky security-wise to make editable in the Control Panel 73 type PageStore interface { 74 Count() (count int) 75 Get(id int) (*CustomPage, error) 76 GetByName(name string) (*CustomPage, error) 77 GetOffset(offset, perPage int) (pages []*CustomPage, err error) 78 Reload(id int) error 79 Delete(id int) error 80 } 81 82 // TODO: Add a cache to this to save on the queries 83 type DefaultPageStore struct { 84 get *sql.Stmt 85 getByName *sql.Stmt 86 getOffset *sql.Stmt 87 count *sql.Stmt 88 delete *sql.Stmt 89 } 90 91 func NewDefaultPageStore(acc *qgen.Accumulator) (*DefaultPageStore, error) { 92 pa := "pages" 93 allCols := "pid, name, title, body, allowedGroups, menuID" 94 return &DefaultPageStore{ 95 get: acc.Select(pa).Columns("name, title, body, allowedGroups, menuID").Where("pid=?").Prepare(), 96 getByName: acc.Select(pa).Columns(allCols).Where("name=?").Prepare(), 97 getOffset: acc.Select(pa).Columns(allCols).Orderby("pid DESC").Limit("?,?").Prepare(), 98 count: acc.Count(pa).Prepare(), 99 delete: acc.Delete(pa).Where("pid=?").Prepare(), 100 }, acc.FirstError() 101 } 102 103 func (s *DefaultPageStore) Count() (count int) { 104 err := s.count.QueryRow().Scan(&count) 105 if err != nil { 106 LogError(err) 107 } 108 return count 109 } 110 111 func (s *DefaultPageStore) parseAllowedGroups(raw string, page *CustomPage) error { 112 if raw == "" { 113 return nil 114 } 115 for _, sgroup := range strings.Split(raw, ",") { 116 group, err := strconv.Atoi(sgroup) 117 if err != nil { 118 return err 119 } 120 page.AddAllowedGroup(group) 121 } 122 return nil 123 } 124 125 func (s *DefaultPageStore) Get(id int) (*CustomPage, error) { 126 p := &CustomPage{ID: id} 127 rawAllowedGroups := "" 128 err := s.get.QueryRow(id).Scan(&p.Name, &p.Title, &p.Body, &rawAllowedGroups, &p.MenuID) 129 if err != nil { 130 return nil, err 131 } 132 return p, s.parseAllowedGroups(rawAllowedGroups, p) 133 } 134 135 func (s *DefaultPageStore) GetByName(name string) (*CustomPage, error) { 136 p := BlankCustomPage() 137 rawAllowedGroups := "" 138 err := s.getByName.QueryRow(name).Scan(&p.ID, &p.Name, &p.Title, &p.Body, &rawAllowedGroups, &p.MenuID) 139 if err != nil { 140 return nil, err 141 } 142 return p, s.parseAllowedGroups(rawAllowedGroups, p) 143 } 144 145 func (s *DefaultPageStore) GetOffset(offset, perPage int) (pages []*CustomPage, err error) { 146 rows, err := s.getOffset.Query(offset, perPage) 147 if err != nil { 148 return pages, err 149 } 150 defer rows.Close() 151 152 for rows.Next() { 153 p := &CustomPage{ID: 0} 154 rawAllowedGroups := "" 155 err := rows.Scan(&p.ID, &p.Name, &p.Title, &p.Body, &rawAllowedGroups, &p.MenuID) 156 if err != nil { 157 return pages, err 158 } 159 err = s.parseAllowedGroups(rawAllowedGroups, p) 160 if err != nil { 161 return pages, err 162 } 163 pages = append(pages, p) 164 } 165 return pages, rows.Err() 166 } 167 168 // Always returns nil as there's currently no cache 169 func (s *DefaultPageStore) Reload(id int) error { 170 return nil 171 } 172 173 func (s *DefaultPageStore) Delete(id int) error { 174 _, err := s.delete.Exec(id) 175 return err 176 }