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  }