gosora/common/page_store.go

177 lines
5.0 KiB
Go

package common
import (
"database/sql"
"strconv"
"strings"
qgen "git.tuxpa.in/a/gosora/query_gen"
)
type CustomPageStmts struct {
update *sql.Stmt
create *sql.Stmt
}
var customPageStmts CustomPageStmts
func init() {
DbInits.Add(func(acc *qgen.Accumulator) error {
customPageStmts = CustomPageStmts{
update: acc.Update("pages").Set("name=?,title=?,body=?,allowedGroups=?,menuID=?").Where("pid=?").Prepare(),
create: acc.Insert("pages").Columns("name,title,body,allowedGroups,menuID").Fields("?,?,?,?,?").Prepare(),
}
return acc.FirstError()
})
}
type CustomPage struct {
ID int
Name string // TODO: Let admins put pages in "virtual subdirectories"
Title string
Body string
AllowedGroups []int
MenuID int
}
func BlankCustomPage() *CustomPage {
return new(CustomPage)
}
func (p *CustomPage) AddAllowedGroup(gid int) {
p.AllowedGroups = append(p.AllowedGroups, gid)
}
func (p *CustomPage) getRawAllowedGroups() (rawAllowedGroups string) {
for _, group := range p.AllowedGroups {
rawAllowedGroups += strconv.Itoa(group) + ","
}
if len(rawAllowedGroups) > 0 {
rawAllowedGroups = rawAllowedGroups[:len(rawAllowedGroups)-1]
}
return rawAllowedGroups
}
func (p *CustomPage) Commit() error {
_, err := customPageStmts.update.Exec(p.Name, p.Title, p.Body, p.getRawAllowedGroups(), p.MenuID, p.ID)
Pages.Reload(p.ID)
return err
}
func (p *CustomPage) Create() (int, error) {
res, err := customPageStmts.create.Exec(p.Name, p.Title, p.Body, p.getRawAllowedGroups(), p.MenuID)
if err != nil {
return 0, err
}
pid64, err := res.LastInsertId()
return int(pid64), err
}
var Pages PageStore
// 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
type PageStore interface {
Count() (count int)
Get(id int) (*CustomPage, error)
GetByName(name string) (*CustomPage, error)
GetOffset(offset, perPage int) (pages []*CustomPage, err error)
Reload(id int) error
Delete(id int) error
}
// TODO: Add a cache to this to save on the queries
type DefaultPageStore struct {
get *sql.Stmt
getByName *sql.Stmt
getOffset *sql.Stmt
count *sql.Stmt
delete *sql.Stmt
}
func NewDefaultPageStore(acc *qgen.Accumulator) (*DefaultPageStore, error) {
pa := "pages"
allCols := "pid, name, title, body, allowedGroups, menuID"
return &DefaultPageStore{
get: acc.Select(pa).Columns("name, title, body, allowedGroups, menuID").Where("pid=?").Prepare(),
getByName: acc.Select(pa).Columns(allCols).Where("name=?").Prepare(),
getOffset: acc.Select(pa).Columns(allCols).Orderby("pid DESC").Limit("?,?").Prepare(),
count: acc.Count(pa).Prepare(),
delete: acc.Delete(pa).Where("pid=?").Prepare(),
}, acc.FirstError()
}
func (s *DefaultPageStore) Count() (count int) {
err := s.count.QueryRow().Scan(&count)
if err != nil {
LogError(err)
}
return count
}
func (s *DefaultPageStore) parseAllowedGroups(raw string, page *CustomPage) error {
if raw == "" {
return nil
}
for _, sgroup := range strings.Split(raw, ",") {
group, err := strconv.Atoi(sgroup)
if err != nil {
return err
}
page.AddAllowedGroup(group)
}
return nil
}
func (s *DefaultPageStore) Get(id int) (*CustomPage, error) {
p := &CustomPage{ID: id}
rawAllowedGroups := ""
err := s.get.QueryRow(id).Scan(&p.Name, &p.Title, &p.Body, &rawAllowedGroups, &p.MenuID)
if err != nil {
return nil, err
}
return p, s.parseAllowedGroups(rawAllowedGroups, p)
}
func (s *DefaultPageStore) GetByName(name string) (*CustomPage, error) {
p := BlankCustomPage()
rawAllowedGroups := ""
err := s.getByName.QueryRow(name).Scan(&p.ID, &p.Name, &p.Title, &p.Body, &rawAllowedGroups, &p.MenuID)
if err != nil {
return nil, err
}
return p, s.parseAllowedGroups(rawAllowedGroups, p)
}
func (s *DefaultPageStore) GetOffset(offset, perPage int) (pages []*CustomPage, err error) {
rows, err := s.getOffset.Query(offset, perPage)
if err != nil {
return pages, err
}
defer rows.Close()
for rows.Next() {
p := &CustomPage{ID: 0}
rawAllowedGroups := ""
err := rows.Scan(&p.ID, &p.Name, &p.Title, &p.Body, &rawAllowedGroups, &p.MenuID)
if err != nil {
return pages, err
}
err = s.parseAllowedGroups(rawAllowedGroups, p)
if err != nil {
return pages, err
}
pages = append(pages, p)
}
return pages, rows.Err()
}
// Always returns nil as there's currently no cache
func (s *DefaultPageStore) Reload(id int) error {
return nil
}
func (s *DefaultPageStore) Delete(id int) error {
_, err := s.delete.Exec(id)
return err
}