gosora/common/forum_perms_store.go

209 lines
5.1 KiB
Go

package common
import (
"database/sql"
"encoding/json"
"log"
"sync"
"../query_gen/lib"
)
var Fpstore ForumPermsStore
type ForumPermsStore interface {
Init() error
Get(fid int, gid int) (fperms *ForumPerms, err error)
Reload(id int) error
ReloadGroup(fid int, gid int) error
}
type ForumPermsCache interface {
}
type MemoryForumPermsStore struct {
get *sql.Stmt
getByForum *sql.Stmt
getByForumGroup *sql.Stmt
updateMutex sync.Mutex
}
func NewMemoryForumPermsStore() (*MemoryForumPermsStore, error) {
acc := qgen.Builder.Accumulator()
return &MemoryForumPermsStore{
get: acc.Select("forums_permissions").Columns("gid, fid, permissions").Orderby("gid ASC, fid ASC").Prepare(),
getByForum: acc.Select("forums_permissions").Columns("gid, permissions").Where("fid = ?").Orderby("gid ASC").Prepare(),
getByForumGroup: acc.Select("forums_permissions").Columns("permissions").Where("fid = ? AND gid = ?").Prepare(),
}, acc.FirstError()
}
func (fps *MemoryForumPermsStore) Init() error {
fps.updateMutex.Lock()
defer fps.updateMutex.Unlock()
fids, err := Fstore.GetAllIDs()
if err != nil {
return err
}
debugDetail("fids: ", fids)
rows, err := fps.get.Query()
if err != nil {
return err
}
defer rows.Close()
debugLog("Adding the forum permissions")
debugDetail("forumPerms[gid][fid]")
// Temporarily store the forum perms in a map before transferring it to a much faster and thread-safe slice
forumPerms = make(map[int]map[int]*ForumPerms)
for rows.Next() {
var gid, fid int
var perms []byte
err = rows.Scan(&gid, &fid, &perms)
if err != nil {
return err
}
pperms, err := fps.parseForumPerm(perms)
if err != nil {
return err
}
_, ok := forumPerms[gid]
if !ok {
forumPerms[gid] = make(map[int]*ForumPerms)
}
debugDetail("gid: ", gid)
debugDetail("fid: ", fid)
debugDetailf("perms: %+v\n", pperms)
forumPerms[gid][fid] = pperms
}
return fps.cascadePermSetToGroups(forumPerms, fids)
}
func (fps *MemoryForumPermsStore) parseForumPerm(perms []byte) (pperms *ForumPerms, err error) {
debugDetail("perms: ", string(perms))
pperms = BlankForumPerms()
err = json.Unmarshal(perms, &pperms)
pperms.ExtData = make(map[string]bool)
pperms.Overrides = true
return pperms, err
}
// TODO: Need a more thread-safe way of doing this. Possibly with sync.Map?
func (fps *MemoryForumPermsStore) Reload(fid int) error {
fps.updateMutex.Lock()
defer fps.updateMutex.Unlock()
debugLogf("Reloading the forum permissions for forum #%d", fid)
fids, err := Fstore.GetAllIDs()
if err != nil {
return err
}
rows, err := fps.getByForum.Query(fid)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var gid int
var perms []byte
err := rows.Scan(&gid, &perms)
if err != nil {
return err
}
pperms, err := fps.parseForumPerm(perms)
if err != nil {
return err
}
_, ok := forumPerms[gid]
if !ok {
forumPerms[gid] = make(map[int]*ForumPerms)
}
forumPerms[gid][fid] = pperms
}
return fps.cascadePermSetToGroups(forumPerms, fids)
}
func (fps *MemoryForumPermsStore) ReloadGroup(fid int, gid int) (err error) {
fps.updateMutex.Lock()
defer fps.updateMutex.Unlock()
var perms []byte
err = fps.getByForumGroup.QueryRow(fid, gid).Scan(&perms)
if err != nil {
return err
}
fperms, err := fps.parseForumPerm(perms)
if err != nil {
return err
}
group, err := Gstore.Get(gid)
if err != nil {
return err
}
// TODO: Refactor this
group.Forums[fid] = fperms
return nil
}
func (fps *MemoryForumPermsStore) cascadePermSetToGroups(forumPerms map[int]map[int]*ForumPerms, fids []int) error {
groups, err := Gstore.GetAll()
if err != nil {
return err
}
for _, group := range groups {
debugLogf("Updating the forum permissions for Group #%d", group.ID)
group.Forums = []*ForumPerms{BlankForumPerms()}
group.CanSee = []int{}
fps.cascadePermSetToGroup(forumPerms, group, fids)
if Dev.SuperDebug {
log.Printf("group.CanSee (length %d): %+v \n", len(group.CanSee), group.CanSee)
log.Printf("group.Forums (length %d): %+v\n", len(group.Forums), group.Forums)
}
}
return nil
}
func (fps *MemoryForumPermsStore) cascadePermSetToGroup(forumPerms map[int]map[int]*ForumPerms, group *Group, fids []int) {
for _, fid := range fids {
debugDetailf("Forum #%+v\n", fid)
forumPerm, ok := forumPerms[group.ID][fid]
if ok {
//log.Printf("Overriding permissions for forum #%d",fid)
group.Forums = append(group.Forums, forumPerm)
} else {
//log.Printf("Inheriting from group defaults for forum #%d",fid)
forumPerm = BlankForumPerms()
group.Forums = append(group.Forums, forumPerm)
}
if forumPerm.Overrides {
if forumPerm.ViewTopic {
group.CanSee = append(group.CanSee, fid)
}
} else if group.Perms.ViewTopic {
group.CanSee = append(group.CanSee, fid)
}
debugDetail("group.ID: ", group.ID)
debugDetailf("forumPerm: %+v\n", forumPerm)
debugDetail("group.CanSee: ", group.CanSee)
}
}
// TODO: Add a hook here and have plugin_guilds use it
func (fps *MemoryForumPermsStore) Get(fid int, gid int) (fperms *ForumPerms, err error) {
group, err := Gstore.Get(gid)
if err != nil {
return fperms, ErrNoRows
}
return group.Forums[fid], nil
}