gosora/common/forum_perms_store.go
Azareal 25074b58b2 Added a time graph for individual user agents.
We now have an Advanced Forum Permissions Editor providing more granular control over permissions.
Tweaked the button CSS and some other bits and pieces.
Added a details section to the View Count Graph.
Renamed a few template files for the sake of consistency and for an upcoming refactor.
Unknown user agents are now logged in debug mode.
Added GetCopy() to the forum permissions store.
Fixed a crash bug in the forum deletion action.
Refactored the permissions list in the group permissions editor.
2018-01-10 03:32:48 +00:00

221 lines
5.4 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)
GetCopy(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 := Forums.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]")
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 := Forums.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 := Groups.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 := Groups.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
// TODO: Check if the forum exists?
// TODO: Fix the races
func (fps *MemoryForumPermsStore) Get(fid int, gid int) (fperms *ForumPerms, err error) {
group, err := Groups.Get(gid)
if err != nil {
return fperms, ErrNoRows
}
return group.Forums[fid], nil
}
// TODO: Check if the forum exists?
// TODO: Fix the races
func (fps *MemoryForumPermsStore) GetCopy(fid int, gid int) (fperms ForumPerms, err error) {
group, err := Groups.Get(gid)
if err != nil {
return fperms, ErrNoRows
}
return *group.Forums[fid], nil
}