More refactoring. So much data o.o

Fixed the tests.
Added wrapper functions for the various logging levels.
Added the SetPreset method to *Forum.
Added the ReloadGroup to the ForumPermsStore.
This commit is contained in:
Azareal 2017-11-13 05:22:37 +00:00
parent 0572c3e048
commit b42181c0c6
20 changed files with 523 additions and 512 deletions

View File

@ -2,6 +2,7 @@ package common
import ( import (
"database/sql" "database/sql"
"log"
"../query_gen/lib" "../query_gen/lib"
) )
@ -82,3 +83,27 @@ func (inits dbInits) Run() error {
func (inits dbInits) Add(init ...func(acc *qgen.Accumulator) error) { func (inits dbInits) Add(init ...func(acc *qgen.Accumulator) error) {
DbInits = dbInits(append(DbInits, init...)) DbInits = dbInits(append(DbInits, init...))
} }
func debugDetail(args ...interface{}) {
if Dev.SuperDebug {
log.Print(args...)
}
}
func debugDetailf(str string, args ...interface{}) {
if Dev.SuperDebug {
log.Printf(str, args...)
}
}
func debugLog(args ...interface{}) {
if Dev.DebugMode {
log.Print(args...)
}
}
func debugLogf(str string, args ...interface{}) {
if Dev.DebugMode {
log.Printf(str, args...)
}
}

View File

@ -3,6 +3,7 @@ package common
//import "fmt" //import "fmt"
import ( import (
"database/sql" "database/sql"
"errors"
"strconv" "strconv"
"strings" "strings"
@ -48,7 +49,8 @@ type ForumSimple struct {
} }
type ForumStmts struct { type ForumStmts struct {
update *sql.Stmt update *sql.Stmt
setPreset *sql.Stmt
} }
var forumStmts ForumStmts var forumStmts ForumStmts
@ -56,7 +58,8 @@ var forumStmts ForumStmts
func init() { func init() {
DbInits.Add(func(acc *qgen.Accumulator) error { DbInits.Add(func(acc *qgen.Accumulator) error {
forumStmts = ForumStmts{ forumStmts = ForumStmts{
update: acc.Update("forums").Set("name = ?, desc = ?, active = ?, preset = ?").Where("fid = ?").Prepare(), update: acc.Update("forums").Set("name = ?, desc = ?, active = ?, preset = ?").Where("fid = ?").Prepare(),
setPreset: acc.Update("forums").Set("preset = ?").Where("fid = ?").Prepare(),
} }
return acc.FirstError() return acc.FirstError()
}) })
@ -88,6 +91,39 @@ func (forum *Forum) Update(name string, desc string, active bool, preset string)
return nil return nil
} }
func (forum *Forum) SetPreset(preset string, gid int) error {
fperms, changed := GroupForumPresetToForumPerms(preset)
if changed {
return forum.setPreset(fperms, preset, gid)
}
return nil
}
// TODO: Refactor this
func (forum *Forum) setPreset(fperms *ForumPerms, preset string, gid int) (err error) {
err = ReplaceForumPermsForGroup(gid, map[int]string{forum.ID: preset}, map[int]*ForumPerms{forum.ID: fperms})
if err != nil {
LogError(err)
return errors.New("Unable to update the permissions")
}
// TODO: Add this and replaceForumPermsForGroup into a transaction?
_, err = forumStmts.setPreset.Exec("", forum.ID)
if err != nil {
LogError(err)
return errors.New("Unable to update the forum")
}
err = Fstore.Reload(forum.ID)
if err != nil {
return errors.New("Unable to reload forum")
}
err = Fpstore.ReloadGroup(forum.ID, gid)
if err != nil {
return errors.New("Unable to reload the forum permissions")
}
return nil
}
// TODO: Replace this sorting mechanism with something a lot more efficient // TODO: Replace this sorting mechanism with something a lot more efficient
// ? - Use sort.Slice instead? // ? - Use sort.Slice instead?
type SortForum []*Forum type SortForum []*Forum

307
common/forum_perms.go Normal file
View File

@ -0,0 +1,307 @@
package common
import (
"database/sql"
"encoding/json"
"../query_gen/lib"
)
// ? - Can we avoid duplicating the items in this list in a bunch of places?
var LocalPermList = []string{
"ViewTopic",
"LikeItem",
"CreateTopic",
"EditTopic",
"DeleteTopic",
"CreateReply",
"EditReply",
"DeleteReply",
"PinTopic",
"CloseTopic",
}
/* Inherit from group permissions for ones we don't have */
type ForumPerms struct {
ViewTopic bool
//ViewOwnTopic bool
LikeItem bool
CreateTopic bool
EditTopic bool
DeleteTopic bool
CreateReply bool
//CreateReplyToOwn bool
EditReply bool
//EditOwnReply bool
DeleteReply bool
PinTopic bool
CloseTopic bool
//CloseOwnTopic bool
Overrides bool
ExtData map[string]bool
}
func PresetToPermmap(preset string) (out map[string]*ForumPerms) {
out = make(map[string]*ForumPerms)
switch preset {
case "all":
out["guests"] = ReadForumPerms()
out["members"] = ReadWriteForumPerms()
out["staff"] = AllForumPerms()
out["admins"] = AllForumPerms()
case "announce":
out["guests"] = ReadForumPerms()
out["members"] = ReadReplyForumPerms()
out["staff"] = AllForumPerms()
out["admins"] = AllForumPerms()
case "members":
out["guests"] = BlankForumPerms()
out["members"] = ReadWriteForumPerms()
out["staff"] = AllForumPerms()
out["admins"] = AllForumPerms()
case "staff":
out["guests"] = BlankForumPerms()
out["members"] = BlankForumPerms()
out["staff"] = ReadWriteForumPerms()
out["admins"] = AllForumPerms()
case "admins":
out["guests"] = BlankForumPerms()
out["members"] = BlankForumPerms()
out["staff"] = BlankForumPerms()
out["admins"] = AllForumPerms()
case "archive":
out["guests"] = ReadForumPerms()
out["members"] = ReadForumPerms()
out["staff"] = ReadForumPerms()
out["admins"] = ReadForumPerms() //CurateForumPerms. Delete / Edit but no create?
default:
out["guests"] = BlankForumPerms()
out["members"] = BlankForumPerms()
out["staff"] = BlankForumPerms()
out["admins"] = BlankForumPerms()
}
return out
}
func PermmapToQuery(permmap map[string]*ForumPerms, fid int) error {
tx, err := qgen.Builder.Begin()
if err != nil {
return err
}
defer tx.Rollback()
deleteForumPermsByForumTx, err := qgen.Builder.SimpleDeleteTx(tx, "forums_permissions", "fid = ?")
if err != nil {
return err
}
_, err = deleteForumPermsByForumTx.Exec(fid)
if err != nil {
return err
}
perms, err := json.Marshal(permmap["admins"])
if err != nil {
return err
}
addForumPermsToForumAdminsTx, err := qgen.Builder.SimpleInsertSelectTx(tx,
qgen.DBInsert{"forums_permissions", "gid, fid, preset, permissions", ""},
qgen.DBSelect{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 1", "", ""},
)
if err != nil {
return err
}
_, err = addForumPermsToForumAdminsTx.Exec(fid, "", perms)
if err != nil {
return err
}
perms, err = json.Marshal(permmap["staff"])
if err != nil {
return err
}
addForumPermsToForumStaffTx, err := qgen.Builder.SimpleInsertSelectTx(tx,
qgen.DBInsert{"forums_permissions", "gid, fid, preset, permissions", ""},
qgen.DBSelect{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 1", "", ""},
)
if err != nil {
return err
}
_, err = addForumPermsToForumStaffTx.Exec(fid, "", perms)
if err != nil {
return err
}
perms, err = json.Marshal(permmap["members"])
if err != nil {
return err
}
addForumPermsToForumMembersTx, err := qgen.Builder.SimpleInsertSelectTx(tx,
qgen.DBInsert{"forums_permissions", "gid, fid, preset, permissions", ""},
qgen.DBSelect{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 0 AND is_banned = 0", "", ""},
)
if err != nil {
return err
}
_, err = addForumPermsToForumMembersTx.Exec(fid, "", perms)
if err != nil {
return err
}
// 6 is the ID of the Not Loggedin Group
// TODO: Use a shared variable rather than a literal for the group ID
err = ReplaceForumPermsForGroupTx(tx, 6, map[int]string{fid: ""}, map[int]*ForumPerms{fid: permmap["guests"]})
if err != nil {
return err
}
err = tx.Commit()
if err != nil {
return err
}
return Fpstore.Reload(fid)
}
func ReplaceForumPermsForGroup(gid int, presetSet map[int]string, permSets map[int]*ForumPerms) error {
tx, err := qgen.Builder.Begin()
if err != nil {
return err
}
defer tx.Rollback()
err = ReplaceForumPermsForGroupTx(tx, gid, presetSet, permSets)
if err != nil {
return err
}
return tx.Commit()
}
func ReplaceForumPermsForGroupTx(tx *sql.Tx, gid int, presetSets map[int]string, permSets map[int]*ForumPerms) error {
deleteForumPermsForGroupTx, err := qgen.Builder.SimpleDeleteTx(tx, "forums_permissions", "gid = ? AND fid = ?")
if err != nil {
return err
}
addForumPermsToGroupTx, err := qgen.Builder.SimpleInsertTx(tx, "forums_permissions", "gid, fid, preset, permissions", "?,?,?,?")
if err != nil {
return err
}
for fid, permSet := range permSets {
permstr, err := json.Marshal(permSet)
if err != nil {
return err
}
_, err = deleteForumPermsForGroupTx.Exec(gid, fid)
if err != nil {
return err
}
_, err = addForumPermsToGroupTx.Exec(gid, fid, presetSets[fid], string(permstr))
if err != nil {
return err
}
}
return nil
}
// TODO: Refactor this and write tests for it
func ForumPermsToGroupForumPreset(fperms *ForumPerms) string {
if !fperms.Overrides {
return "default"
}
if !fperms.ViewTopic {
return "no_access"
}
var canPost = (fperms.LikeItem && fperms.CreateTopic && fperms.CreateReply)
var canModerate = (canPost && fperms.EditTopic && fperms.DeleteTopic && fperms.EditReply && fperms.DeleteReply && fperms.PinTopic && fperms.CloseTopic)
if canModerate {
return "can_moderate"
}
if fperms.EditTopic || fperms.DeleteTopic || fperms.EditReply || fperms.DeleteReply || fperms.PinTopic || fperms.CloseTopic {
if !canPost {
return "custom"
}
return "quasi_mod"
}
if canPost {
return "can_post"
}
if fperms.ViewTopic && !fperms.LikeItem && !fperms.CreateTopic && !fperms.CreateReply {
return "read_only"
}
return "custom"
}
func GroupForumPresetToForumPerms(preset string) (fperms *ForumPerms, changed bool) {
switch preset {
case "read_only":
return ReadForumPerms(), true
case "can_post":
return ReadWriteForumPerms(), true
case "can_moderate":
return AllForumPerms(), true
case "no_access":
return &ForumPerms{Overrides: true, ExtData: make(map[string]bool)}, true
case "default":
return BlankForumPerms(), true
}
return fperms, false
}
func BlankForumPerms() *ForumPerms {
return &ForumPerms{ViewTopic: false}
}
func ReadWriteForumPerms() *ForumPerms {
return &ForumPerms{
ViewTopic: true,
LikeItem: true,
CreateTopic: true,
CreateReply: true,
Overrides: true,
ExtData: make(map[string]bool),
}
}
func ReadReplyForumPerms() *ForumPerms {
return &ForumPerms{
ViewTopic: true,
LikeItem: true,
CreateReply: true,
Overrides: true,
ExtData: make(map[string]bool),
}
}
func ReadForumPerms() *ForumPerms {
return &ForumPerms{
ViewTopic: true,
Overrides: true,
ExtData: make(map[string]bool),
}
}
// AllForumPerms is a set of forum local permissions with everything set to true
func AllForumPerms() *ForumPerms {
return &ForumPerms{
ViewTopic: true,
LikeItem: true,
CreateTopic: true,
EditTopic: true,
DeleteTopic: true,
CreateReply: true,
EditReply: true,
DeleteReply: true,
PinTopic: true,
CloseTopic: true,
Overrides: true,
ExtData: make(map[string]bool),
}
}

View File

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

View File

@ -17,9 +17,8 @@ import (
"../query_gen/lib" "../query_gen/lib"
) )
var ForumUpdateMutex sync.Mutex
var forumCreateMutex sync.Mutex var forumCreateMutex sync.Mutex
var forumPerms map[int]map[int]ForumPerms // [gid][fid]Perms // TODO: Add an abstraction around this and make it more thread-safe var forumPerms map[int]map[int]*ForumPerms // [gid][fid]*ForumPerms // TODO: Add an abstraction around this and make it more thread-safe
var Fstore ForumStore var Fstore ForumStore
// ForumStore is an interface for accessing the forums and the metadata stored on them // ForumStore is an interface for accessing the forums and the metadata stored on them
@ -110,9 +109,7 @@ func (mfs *MemoryForumStore) LoadForums() error {
} }
if forum.Name == "" { if forum.Name == "" {
if Dev.DebugMode { debugLog("Adding a placeholder forum")
log.Print("Adding a placeholder forum")
}
} else { } else {
log.Printf("Adding the '%s' forum", forum.Name) log.Printf("Adding the '%s' forum", forum.Name)
} }
@ -272,11 +269,8 @@ func (mfs *MemoryForumStore) Delete(id int) error {
return errors.New("You cannot delete the Reports forum") return errors.New("You cannot delete the Reports forum")
} }
_, err := mfs.delete.Exec(id) _, err := mfs.delete.Exec(id)
if err != nil {
return err
}
mfs.CacheDelete(id) mfs.CacheDelete(id)
return nil return err
} }
func (mfs *MemoryForumStore) AddTopic(tid int, uid int, fid int) error { func (mfs *MemoryForumStore) AddTopic(tid int, uid int, fid int) error {

View File

@ -26,7 +26,7 @@ type Group struct {
PermissionsText []byte PermissionsText []byte
PluginPerms map[string]bool // Custom permissions defined by plugins. What if two plugins declare the same permission, but they handle them in incompatible ways? Very unlikely, we probably don't need to worry about this, the plugin authors should be aware of each other to some extent PluginPerms map[string]bool // Custom permissions defined by plugins. What if two plugins declare the same permission, but they handle them in incompatible ways? Very unlikely, we probably don't need to worry about this, the plugin authors should be aware of each other to some extent
PluginPermsText []byte PluginPermsText []byte
Forums []ForumPerms Forums []*ForumPerms
CanSee []int // The IDs of the forums this group can see CanSee []int // The IDs of the forums this group can see
} }

View File

@ -86,9 +86,7 @@ func (mgs *MemoryGroupStore) LoadGroups() error {
} }
mgs.groupCount = i mgs.groupCount = i
if Dev.DebugMode { debugLog("Binding the Not Loggedin Group")
log.Print("Binding the Not Loggedin Group")
}
GuestPerms = mgs.dirtyGetUnsafe(6).Perms GuestPerms = mgs.dirtyGetUnsafe(6).Perms
return nil return nil
} }
@ -172,9 +170,7 @@ func (mgs *MemoryGroupStore) initGroup(group *Group) error {
log.Print("bad group plugin perms: ", group.PluginPermsText) log.Print("bad group plugin perms: ", group.PluginPermsText)
return err return err
} }
if Dev.DebugMode { debugLogf(group.Name+": %+v\n", group.PluginPerms)
log.Printf(group.Name+": %+v\n", group.PluginPerms)
}
//group.Perms.ExtData = make(map[string]bool) //group.Perms.ExtData = make(map[string]bool)
// TODO: Can we optimise the bit where this cascades down to the user now? // TODO: Can we optimise the bit where this cascades down to the user now?
@ -200,6 +196,7 @@ func (mgs *MemoryGroupStore) Exists(gid int) bool {
} }
// ? Allow two groups with the same name? // ? Allow two groups with the same name?
// TODO: Refactor this
func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod bool, isBanned bool) (gid int, err error) { func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod bool, isBanned bool) (gid int, err error) {
var permstr = "{}" var permstr = "{}"
tx, err := qgen.Builder.Begin() tx, err := qgen.Builder.Begin()
@ -224,7 +221,7 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod
gid = int(gid64) gid = int(gid64)
var perms = BlankPerms var perms = BlankPerms
var blankForums []ForumPerms var blankForums []*ForumPerms
var blankIntList []int var blankIntList []int
var pluginPerms = make(map[string]bool) var pluginPerms = make(map[string]bool)
var pluginPermsBytes = []byte("{}") var pluginPermsBytes = []byte("{}")
@ -239,18 +236,17 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod
} }
var presetSet = make(map[int]string) var presetSet = make(map[int]string)
var permSet = make(map[int]ForumPerms) var permSet = make(map[int]*ForumPerms)
PermUpdateMutex.Lock()
defer PermUpdateMutex.Unlock()
for _, forum := range fdata { for _, forum := range fdata {
var thePreset string var thePreset string
if isAdmin { switch {
case isAdmin:
thePreset = "admins" thePreset = "admins"
} else if isMod { case isMod:
thePreset = "staff" thePreset = "staff"
} else if isBanned { case isBanned:
thePreset = "banned" thePreset = "banned"
} else { default:
thePreset = "members" thePreset = "members"
} }

View File

@ -1,46 +1,20 @@
package common package common
import ( import (
"database/sql"
"encoding/json" "encoding/json"
"log" "log"
"sync"
"../query_gen/lib" "../query_gen/lib"
) )
// TODO: Refactor the perms system // TODO: Refactor the perms system
var PermUpdateMutex sync.Mutex
var BlankPerms Perms var BlankPerms Perms
var BlankForumPerms ForumPerms
var GuestPerms Perms var GuestPerms Perms
var ReadForumPerms ForumPerms
var ReadReplyForumPerms ForumPerms
var ReadWriteForumPerms ForumPerms
// AllPerms is a set of global permissions with everything set to true // AllPerms is a set of global permissions with everything set to true
var AllPerms Perms var AllPerms Perms
// AllForumPerms is a set of forum local permissions with everything set to true
var AllForumPerms ForumPerms
var AllPluginPerms = make(map[string]bool) var AllPluginPerms = make(map[string]bool)
// ? - Can we avoid duplicating the items in this list in a bunch of places?
var LocalPermList = []string{
"ViewTopic",
"LikeItem",
"CreateTopic",
"EditTopic",
"DeleteTopic",
"CreateReply",
"EditReply",
"DeleteReply",
"PinTopic",
"CloseTopic",
}
// ? - Can we avoid duplicating the items in this list in a bunch of places? // ? - Can we avoid duplicating the items in this list in a bunch of places?
var GlobalPermList = []string{ var GlobalPermList = []string{
"BanUsers", "BanUsers",
@ -111,36 +85,11 @@ type Perms struct {
//ExtData map[string]bool //ExtData map[string]bool
} }
/* Inherit from group permissions for ones we don't have */
type ForumPerms struct {
ViewTopic bool
//ViewOwnTopic bool
LikeItem bool
CreateTopic bool
EditTopic bool
DeleteTopic bool
CreateReply bool
//CreateReplyToOwn bool
EditReply bool
//EditOwnReply bool
DeleteReply bool
PinTopic bool
CloseTopic bool
//CloseOwnTopic bool
Overrides bool
ExtData map[string]bool
}
func init() { func init() {
BlankPerms = Perms{ BlankPerms = Perms{
//ExtData: make(map[string]bool), //ExtData: make(map[string]bool),
} }
BlankForumPerms = ForumPerms{
ExtData: make(map[string]bool),
}
GuestPerms = Perms{ GuestPerms = Perms{
ViewTopic: true, ViewTopic: true,
//ExtData: make(map[string]bool), //ExtData: make(map[string]bool),
@ -183,266 +132,9 @@ func init() {
//ExtData: make(map[string]bool), //ExtData: make(map[string]bool),
} }
AllForumPerms = ForumPerms{
ViewTopic: true,
LikeItem: true,
CreateTopic: true,
EditTopic: true,
DeleteTopic: true,
CreateReply: true,
EditReply: true,
DeleteReply: true,
PinTopic: true,
CloseTopic: true,
Overrides: true,
ExtData: make(map[string]bool),
}
ReadWriteForumPerms = ForumPerms{
ViewTopic: true,
LikeItem: true,
CreateTopic: true,
CreateReply: true,
Overrides: true,
ExtData: make(map[string]bool),
}
ReadReplyForumPerms = ForumPerms{
ViewTopic: true,
LikeItem: true,
CreateReply: true,
Overrides: true,
ExtData: make(map[string]bool),
}
ReadForumPerms = ForumPerms{
ViewTopic: true,
Overrides: true,
ExtData: make(map[string]bool),
}
GuestUser.Perms = GuestPerms GuestUser.Perms = GuestPerms
debugLogf("Guest Perms: %+v\n", GuestPerms)
if Dev.DebugMode { debugLogf("All Perms: %+v\n", AllPerms)
log.Printf("Guest Perms: %+v\n", GuestPerms)
log.Printf("All Perms: %+v\n", AllPerms)
}
}
func PresetToPermmap(preset string) (out map[string]ForumPerms) {
out = make(map[string]ForumPerms)
switch preset {
case "all":
out["guests"] = ReadForumPerms
out["members"] = ReadWriteForumPerms
out["staff"] = AllForumPerms
out["admins"] = AllForumPerms
case "announce":
out["guests"] = ReadForumPerms
out["members"] = ReadReplyForumPerms
out["staff"] = AllForumPerms
out["admins"] = AllForumPerms
case "members":
out["guests"] = BlankForumPerms
out["members"] = ReadWriteForumPerms
out["staff"] = AllForumPerms
out["admins"] = AllForumPerms
case "staff":
out["guests"] = BlankForumPerms
out["members"] = BlankForumPerms
out["staff"] = ReadWriteForumPerms
out["admins"] = AllForumPerms
case "admins":
out["guests"] = BlankForumPerms
out["members"] = BlankForumPerms
out["staff"] = BlankForumPerms
out["admins"] = AllForumPerms
case "archive":
out["guests"] = ReadForumPerms
out["members"] = ReadForumPerms
out["staff"] = ReadForumPerms
out["admins"] = ReadForumPerms //CurateForumPerms. Delete / Edit but no create?
default:
out["guests"] = BlankForumPerms
out["members"] = BlankForumPerms
out["staff"] = BlankForumPerms
out["admins"] = BlankForumPerms
}
return out
}
func PermmapToQuery(permmap map[string]ForumPerms, fid int) error {
tx, err := qgen.Builder.Begin()
if err != nil {
return err
}
defer tx.Rollback()
deleteForumPermsByForumTx, err := qgen.Builder.SimpleDeleteTx(tx, "forums_permissions", "fid = ?")
if err != nil {
return err
}
_, err = deleteForumPermsByForumTx.Exec(fid)
if err != nil {
return err
}
perms, err := json.Marshal(permmap["admins"])
if err != nil {
return err
}
addForumPermsToForumAdminsTx, err := qgen.Builder.SimpleInsertSelectTx(tx,
qgen.DBInsert{"forums_permissions", "gid, fid, preset, permissions", ""},
qgen.DBSelect{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 1", "", ""},
)
if err != nil {
return err
}
_, err = addForumPermsToForumAdminsTx.Exec(fid, "", perms)
if err != nil {
return err
}
perms, err = json.Marshal(permmap["staff"])
if err != nil {
return err
}
addForumPermsToForumStaffTx, err := qgen.Builder.SimpleInsertSelectTx(tx,
qgen.DBInsert{"forums_permissions", "gid, fid, preset, permissions", ""},
qgen.DBSelect{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 1", "", ""},
)
if err != nil {
return err
}
_, err = addForumPermsToForumStaffTx.Exec(fid, "", perms)
if err != nil {
return err
}
perms, err = json.Marshal(permmap["members"])
if err != nil {
return err
}
addForumPermsToForumMembersTx, err := qgen.Builder.SimpleInsertSelectTx(tx,
qgen.DBInsert{"forums_permissions", "gid, fid, preset, permissions", ""},
qgen.DBSelect{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 0 AND is_banned = 0", "", ""},
)
if err != nil {
return err
}
_, err = addForumPermsToForumMembersTx.Exec(fid, "", perms)
if err != nil {
return err
}
// 6 is the ID of the Not Loggedin Group
// TODO: Use a shared variable rather than a literal for the group ID
err = ReplaceForumPermsForGroupTx(tx, 6, map[int]string{fid: ""}, map[int]ForumPerms{fid: permmap["guests"]})
if err != nil {
return err
}
err = tx.Commit()
if err != nil {
return err
}
PermUpdateMutex.Lock()
defer PermUpdateMutex.Unlock()
return Fpstore.Reload(fid)
}
func ReplaceForumPermsForGroup(gid int, presetSet map[int]string, permSets map[int]ForumPerms) error {
tx, err := qgen.Builder.Begin()
if err != nil {
return err
}
defer tx.Rollback()
err = ReplaceForumPermsForGroupTx(tx, gid, presetSet, permSets)
if err != nil {
return err
}
return tx.Commit()
}
func ReplaceForumPermsForGroupTx(tx *sql.Tx, gid int, presetSets map[int]string, permSets map[int]ForumPerms) error {
deleteForumPermsForGroupTx, err := qgen.Builder.SimpleDeleteTx(tx, "forums_permissions", "gid = ? AND fid = ?")
if err != nil {
return err
}
addForumPermsToGroupTx, err := qgen.Builder.SimpleInsertTx(tx, "forums_permissions", "gid, fid, preset, permissions", "?,?,?,?")
if err != nil {
return err
}
for fid, permSet := range permSets {
permstr, err := json.Marshal(permSet)
if err != nil {
return err
}
_, err = deleteForumPermsForGroupTx.Exec(gid, fid)
if err != nil {
return err
}
_, err = addForumPermsToGroupTx.Exec(gid, fid, presetSets[fid], string(permstr))
if err != nil {
return err
}
}
return nil
}
// TODO: Refactor this and write tests for it
func ForumPermsToGroupForumPreset(fperms ForumPerms) string {
if !fperms.Overrides {
return "default"
}
if !fperms.ViewTopic {
return "no_access"
}
var canPost = (fperms.LikeItem && fperms.CreateTopic && fperms.CreateReply)
var canModerate = (canPost && fperms.EditTopic && fperms.DeleteTopic && fperms.EditReply && fperms.DeleteReply && fperms.PinTopic && fperms.CloseTopic)
if canModerate {
return "can_moderate"
}
if fperms.EditTopic || fperms.DeleteTopic || fperms.EditReply || fperms.DeleteReply || fperms.PinTopic || fperms.CloseTopic {
if !canPost {
return "custom"
}
return "quasi_mod"
}
if canPost {
return "can_post"
}
if fperms.ViewTopic && !fperms.LikeItem && !fperms.CreateTopic && !fperms.CreateReply {
return "read_only"
}
return "custom"
}
func GroupForumPresetToForumPerms(preset string) (fperms ForumPerms, changed bool) {
switch preset {
case "read_only":
return ReadForumPerms, true
case "can_post":
return ReadWriteForumPerms, true
case "can_moderate":
return AllForumPerms, true
case "no_access":
return ForumPerms{Overrides: true, ExtData: make(map[string]bool)}, true
case "default":
return BlankForumPerms, true
//case "custom": return fperms, false
}
return fperms, false
} }
func StripInvalidGroupForumPreset(preset string) string { func StripInvalidGroupForumPreset(preset string) string {
@ -457,9 +149,8 @@ func StripInvalidPreset(preset string) string {
switch preset { switch preset {
case "all", "announce", "members", "staff", "admins", "archive", "custom": case "all", "announce", "members", "staff", "admins", "archive", "custom":
return preset return preset
default:
return ""
} }
return ""
} }
// TODO: Move this into the phrase system? // TODO: Move this into the phrase system?

View File

@ -101,7 +101,7 @@ func forumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fid int)
} }
// TODO: Put this on the user instance? Do we really want forum specific logic in there? Maybe, a method which spits a new pointer with the same contents as user? // TODO: Put this on the user instance? Do we really want forum specific logic in there? Maybe, a method which spits a new pointer with the same contents as user?
func cascadeForumPerms(fperms ForumPerms, user *User) { func cascadeForumPerms(fperms *ForumPerms, user *User) {
if fperms.Overrides && !user.IsSuperAdmin { if fperms.Overrides && !user.IsSuperAdmin {
user.Perms.ViewTopic = fperms.ViewTopic user.Perms.ViewTopic = fperms.ViewTopic
user.Perms.LikeItem = fperms.LikeItem user.Perms.LikeItem = fperms.LikeItem

View File

@ -51,7 +51,6 @@ type Stmts struct {
updatePlugin *sql.Stmt updatePlugin *sql.Stmt
updatePluginInstall *sql.Stmt updatePluginInstall *sql.Stmt
updateTheme *sql.Stmt updateTheme *sql.Stmt
updateForum *sql.Stmt
updateUser *sql.Stmt updateUser *sql.Stmt
updateGroupPerms *sql.Stmt updateGroupPerms *sql.Stmt
updateGroup *sql.Stmt updateGroup *sql.Stmt
@ -380,13 +379,6 @@ func _gen_mssql() (err error) {
return err return err
} }
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE [forums] SET [name] = ?,[desc] = ?,[active] = ?,[preset] = ? WHERE [fid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [forums] SET [name] = ?,[desc] = ?,[active] = ?,[preset] = ? WHERE [fid] = ?")
return err
}
log.Print("Preparing updateUser statement.") log.Print("Preparing updateUser statement.")
stmts.updateUser, err = db.Prepare("UPDATE [users] SET [name] = ?,[email] = ?,[group] = ? WHERE [uid] = ?") stmts.updateUser, err = db.Prepare("UPDATE [users] SET [name] = ?,[email] = ?,[group] = ? WHERE [uid] = ?")
if err != nil { if err != nil {

View File

@ -53,7 +53,6 @@ type Stmts struct {
updatePlugin *sql.Stmt updatePlugin *sql.Stmt
updatePluginInstall *sql.Stmt updatePluginInstall *sql.Stmt
updateTheme *sql.Stmt updateTheme *sql.Stmt
updateForum *sql.Stmt
updateUser *sql.Stmt updateUser *sql.Stmt
updateGroupPerms *sql.Stmt updateGroupPerms *sql.Stmt
updateGroup *sql.Stmt updateGroup *sql.Stmt
@ -340,12 +339,6 @@ func _gen_mysql() (err error) {
return err return err
} }
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE `forums` SET `name` = ?,`desc` = ?,`active` = ?,`preset` = ? WHERE `fid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateUser statement.") log.Print("Preparing updateUser statement.")
stmts.updateUser, err = db.Prepare("UPDATE `users` SET `name` = ?,`email` = ?,`group` = ? WHERE `uid` = ?") stmts.updateUser, err = db.Prepare("UPDATE `users` SET `name` = ?,`email` = ?,`group` = ? WHERE `uid` = ?")
if err != nil { if err != nil {

View File

@ -15,7 +15,6 @@ type Stmts struct {
updatePlugin *sql.Stmt updatePlugin *sql.Stmt
updatePluginInstall *sql.Stmt updatePluginInstall *sql.Stmt
updateTheme *sql.Stmt updateTheme *sql.Stmt
updateForum *sql.Stmt
updateUser *sql.Stmt updateUser *sql.Stmt
updateGroupPerms *sql.Stmt updateGroupPerms *sql.Stmt
updateGroup *sql.Stmt updateGroup *sql.Stmt
@ -80,12 +79,6 @@ func _gen_pgsql() (err error) {
return err return err
} }
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE `forums` SET `name` = ?,`desc` = ?,`active` = ?,`preset` = ? WHERE `fid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateUser statement.") log.Print("Preparing updateUser statement.")
stmts.updateUser, err = db.Prepare("UPDATE `users` SET `name` = ?,`email` = ?,`group` = ? WHERE `uid` = ?") stmts.updateUser, err = db.Prepare("UPDATE `users` SET `name` = ?,`email` = ?,`group` = ? WHERE `uid` = ?")
if err != nil { if err != nil {

View File

@ -50,6 +50,17 @@ func (ins *MysqlInstaller) DefaultPort() string {
return "3306" return "3306"
} }
func (ins *MysqlInstaller) dbExists(dbName string) (bool, error) {
var waste string
err := ins.db.QueryRow("SHOW DATABASES LIKE '" + dbName + "'").Scan(&waste)
if err != nil && err != sql.ErrNoRows {
return false, err
} else if err == sql.ErrNoRows {
return false, nil
}
return true, nil
}
func (ins *MysqlInstaller) InitDatabase() (err error) { func (ins *MysqlInstaller) InitDatabase() (err error) {
_dbPassword := ins.dbPassword _dbPassword := ins.dbPassword
if _dbPassword != "" { if _dbPassword != "" {
@ -67,13 +78,13 @@ func (ins *MysqlInstaller) InitDatabase() (err error) {
} }
fmt.Println("Successfully connected to the database") fmt.Println("Successfully connected to the database")
var waste string ins.db = db
err = db.QueryRow("SHOW DATABASES LIKE '" + ins.dbName + "'").Scan(&waste) ok, err := ins.dbExists(ins.dbName)
if err != nil && err != sql.ErrNoRows { if err != nil {
return err return err
} }
if err == sql.ErrNoRows { if !ok {
fmt.Println("Unable to find the database. Attempting to create it") fmt.Println("Unable to find the database. Attempting to create it")
_, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + ins.dbName) _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + ins.dbName)
if err != nil { if err != nil {
@ -82,7 +93,7 @@ func (ins *MysqlInstaller) InitDatabase() (err error) {
fmt.Println("The database was successfully created") fmt.Println("The database was successfully created")
} }
fmt.Println("Switching to database " + ins.dbName) fmt.Println("Switching to database ", ins.dbName)
_, err = db.Exec("USE " + ins.dbName) _, err = db.Exec("USE " + ins.dbName)
if err != nil { if err != nil {
return err return err
@ -90,13 +101,7 @@ func (ins *MysqlInstaller) InitDatabase() (err error) {
// Ready the query builder // Ready the query builder
qgen.Builder.SetConn(db) qgen.Builder.SetConn(db)
err = qgen.Builder.SetAdapter("mysql") return qgen.Builder.SetAdapter("mysql")
if err != nil {
return err
}
ins.db = db
return nil
} }
func (ins *MysqlInstaller) TableDefs() (err error) { func (ins *MysqlInstaller) TableDefs() (err error) {
@ -122,7 +127,7 @@ func (ins *MysqlInstaller) TableDefs() (err error) {
return err return err
} }
fmt.Println("Creating table '" + table + "'") fmt.Printf("Creating table '%s'", table)
data, err := ioutil.ReadFile("./schema/mysql/" + f.Name()) data, err := ioutil.ReadFile("./schema/mysql/" + f.Name())
if err != nil { if err != nil {
return err return err
@ -135,7 +140,6 @@ func (ins *MysqlInstaller) TableDefs() (err error) {
return err return err
} }
} }
//fmt.Println("Finished creating the tables")
return nil return nil
} }
@ -163,8 +167,6 @@ func (ins *MysqlInstaller) InitialData() error {
return err return err
} }
} }
//fmt.Println("Finished inserting the database data")
return nil return nil
} }

View File

@ -69,14 +69,9 @@ func (ins *PgsqlInstaller) InitDatabase() (err error) {
// TODO: Create the database, if it doesn't exist // TODO: Create the database, if it doesn't exist
// Ready the query builder // Ready the query builder
qgen.Builder.SetConn(db)
err = qgen.Builder.SetAdapter("pgsql")
if err != nil {
return err
}
ins.db = db ins.db = db
qgen.Builder.SetConn(db)
return nil return qgen.Builder.SetAdapter("pgsql")
} }
func (ins *PgsqlInstaller) TableDefs() (err error) { func (ins *PgsqlInstaller) TableDefs() (err error) {

View File

@ -607,8 +607,8 @@ func TestForumPermsStore(t *testing.T) {
if !gloinited { if !gloinited {
gloinit() gloinit()
} }
if !pluginsInited { if !common.PluginsInited {
initPlugins() common.InitPlugins()
} }
} }
@ -617,8 +617,8 @@ func TestGroupStore(t *testing.T) {
if !gloinited { if !gloinited {
gloinit() gloinit()
} }
if !pluginsInited { if !common.PluginsInited {
initPlugins() common.InitPlugins()
} }
_, err := common.Gstore.Get(-1) _, err := common.Gstore.Get(-1)
@ -728,8 +728,8 @@ func TestReplyStore(t *testing.T) {
if !gloinited { if !gloinited {
gloinit() gloinit()
} }
if !pluginsInited { if !common.PluginsInited {
initPlugins() common.InitPlugins()
} }
_, err := common.Rstore.Get(-1) _, err := common.Rstore.Get(-1)
@ -770,8 +770,8 @@ func TestProfileReplyStore(t *testing.T) {
if !gloinited { if !gloinited {
gloinit() gloinit()
} }
if !pluginsInited { if !common.PluginsInited {
initPlugins() common.InitPlugins()
} }
_, err := common.Prstore.Get(-1) _, err := common.Prstore.Get(-1)
@ -845,7 +845,7 @@ func TestAuth(t *testing.T) {
/* No extra salt tests, we might not need this extra salt, as bcrypt has it's own? */ /* No extra salt tests, we might not need this extra salt, as bcrypt has it's own? */
realPassword = "Madame Cassandra's Mystic Orb" realPassword = "Madame Cassandra's Mystic Orb"
t.Log("Set realPassword to '" + realPassword + "'") t.Logf("Set realPassword to '%s'", realPassword)
t.Log("Hashing the real password") t.Log("Hashing the real password")
hashedPassword, err = common.BcryptGeneratePasswordNoSalt(realPassword) hashedPassword, err = common.BcryptGeneratePasswordNoSalt(realPassword)
if err != nil { if err != nil {
@ -853,34 +853,31 @@ func TestAuth(t *testing.T) {
} }
password = realPassword password = realPassword
t.Log("Testing password '" + password + "'") t.Logf("Testing password '%s'", password)
t.Log("Testing salt '" + salt + "'") t.Logf("Testing salt '%s'", salt)
err = common.CheckPassword(hashedPassword, password, salt) err = common.CheckPassword(hashedPassword, password, salt)
if err == ErrMismatchedHashAndPassword { if err == common.ErrMismatchedHashAndPassword {
t.Error("The two don't match") t.Error("The two don't match")
} else if err == ErrPasswordTooLong { } else if err == common.ErrPasswordTooLong {
t.Error("CheckPassword thinks the password is too long") t.Error("CheckPassword thinks the password is too long")
} else if err != nil { } else if err != nil {
t.Error(err) t.Error(err)
} }
password = "hahaha" password = "hahaha"
t.Log("Testing password '" + password + "'") t.Logf("Testing password '%s'", password)
t.Log("Testing salt '" + salt + "'") t.Logf("Testing salt '%s'", salt)
err = common.CheckPassword(hashedPassword, password, salt) err = common.CheckPassword(hashedPassword, password, salt)
if err == ErrPasswordTooLong { if err == common.ErrPasswordTooLong {
t.Error("CheckPassword thinks the password is too long") t.Error("CheckPassword thinks the password is too long")
} else if err == nil { } else if err == nil {
t.Error("The two shouldn't match!") t.Error("The two shouldn't match!")
} }
password = "Madame Cassandra's Mystic" password = "Madame Cassandra's Mystic"
t.Log("Testing password '" + password + "'") t.Logf("Testing password '%s'", password)
t.Log("Testing salt '" + salt + "'") t.Logf("Testing salt '%s'", salt)
err = common.CheckPassword(hashedPassword, password, salt) err = common.CheckPassword(hashedPassword, password, salt)
if err == ErrPasswordTooLong { expect(t, err != common.ErrPasswordTooLong, "CheckPassword thinks the password is too long")
t.Error("CheckPassword thinks the password is too long") expect(t, err != nil, "The two shouldn't match!")
} else if err == nil {
t.Error("The two shouldn't match!")
}
} }

View File

@ -425,9 +425,6 @@ func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use
return common.LocalErrorJSQ("Invalid Group ID", w, r, user, isJs) return common.LocalErrorJSQ("Invalid Group ID", w, r, user, isJs)
} }
permPreset := common.StripInvalidGroupForumPreset(r.PostFormValue("perm_preset"))
fperms, changed := common.GroupForumPresetToForumPerms(permPreset)
forum, err := common.Fstore.Get(fid) forum, err := common.Fstore.Get(fid)
if err == ErrNoRows { if err == ErrNoRows {
return common.LocalErrorJSQ("This forum doesn't exist", w, r, user, isJs) return common.LocalErrorJSQ("This forum doesn't exist", w, r, user, isJs)
@ -435,33 +432,10 @@ func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use
return common.InternalErrorJSQ(err, w, r, isJs) return common.InternalErrorJSQ(err, w, r, isJs)
} }
// ! IMPORTANT permPreset := common.StripInvalidGroupForumPreset(r.PostFormValue("perm_preset"))
// TODO: Refactor this err = forum.SetPreset(permPreset, gid)
common.ForumUpdateMutex.Lock() if err != nil {
defer common.ForumUpdateMutex.Unlock() return common.LocalErrorJSQ(err.Error(), w, r, user, isJs)
if changed {
common.PermUpdateMutex.Lock()
defer common.PermUpdateMutex.Unlock()
group, err := common.Gstore.Get(gid)
if err != nil {
return common.LocalError("The group whose permissions you're updating doesn't exist.", w, r, user)
}
group.Forums[fid] = fperms
err = common.ReplaceForumPermsForGroup(gid, map[int]string{fid: permPreset}, map[int]common.ForumPerms{fid: fperms})
if err != nil {
return common.InternalErrorJSQ(err, w, r, isJs)
}
// TODO: Add this and replaceForumPermsForGroup into a transaction?
_, err = stmts.updateForum.Exec(forum.Name, forum.Desc, forum.Active, "", fid)
if err != nil {
return common.InternalErrorJSQ(err, w, r, isJs)
}
err = common.Fstore.Reload(fid)
if err != nil {
return common.LocalErrorJSQ("Unable to reload forum", w, r, user, isJs)
}
} }
if !isJs { if !isJs {

View File

@ -181,15 +181,16 @@ func processWhere(wherestr string) (where []DBWhere) {
segment += ")" segment += ")"
for i := 0; i < len(segment); i++ { for i := 0; i < len(segment); i++ {
char := segment[i] char := segment[i]
if '0' <= char && char <= '9' { switch {
case '0' <= char && char <= '9':
i = tmpWhere.parseNumber(segment, i) i = tmpWhere.parseNumber(segment, i)
} else if ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_' { case ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_':
i = tmpWhere.parseColumn(segment, i) i = tmpWhere.parseColumn(segment, i)
} else if char == '\'' { case char == '\'':
i = tmpWhere.parseString(segment, i) i = tmpWhere.parseString(segment, i)
} else if isOpByte(char) { case isOpByte(char):
i = tmpWhere.parseOperator(segment, i) i = tmpWhere.parseOperator(segment, i)
} else if char == '?' { case char == '?':
tmpWhere.Expr = append(tmpWhere.Expr, DBToken{"?", "substitute"}) tmpWhere.Expr = append(tmpWhere.Expr, DBToken{"?", "substitute"})
} }
} }
@ -216,11 +217,12 @@ func (setter *DBSetter) parseColumn(segment string, i int) int {
var buffer string var buffer string
for ; i < len(segment); i++ { for ; i < len(segment); i++ {
char := segment[i] char := segment[i]
if ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_' { switch {
case ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_':
buffer += string(char) buffer += string(char)
} else if char == '(' { case char == '(':
return setter.parseFunction(segment, buffer, i) return setter.parseFunction(segment, buffer, i)
} else { default:
i-- i--
setter.Expr = append(setter.Expr, DBToken{buffer, "column"}) setter.Expr = append(setter.Expr, DBToken{buffer, "column"})
return i return i
@ -303,15 +305,16 @@ func processSet(setstr string) (setter []DBSetter) {
for i := 0; i < len(segment); i++ { for i := 0; i < len(segment); i++ {
char := segment[i] char := segment[i]
if '0' <= char && char <= '9' { switch {
case '0' <= char && char <= '9':
i = tmpSetter.parseNumber(segment, i) i = tmpSetter.parseNumber(segment, i)
} else if ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_' { case ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_':
i = tmpSetter.parseColumn(segment, i) i = tmpSetter.parseColumn(segment, i)
} else if char == '\'' { case char == '\'':
i = tmpSetter.parseString(segment, i) i = tmpSetter.parseString(segment, i)
} else if isOpByte(char) { case isOpByte(char):
i = tmpSetter.parseOperator(segment, i) i = tmpSetter.parseOperator(segment, i)
} else if char == '?' { case char == '?':
tmpSetter.Expr = append(tmpSetter.Expr, DBToken{"?", "substitute"}) tmpSetter.Expr = append(tmpSetter.Expr, DBToken{"?", "substitute"})
} }
} }

View File

@ -352,8 +352,6 @@ func writeUpdates(adapter qgen.Adapter) error {
build.Update("updateTheme").Table("themes").Set("default = ?").Where("uname = ?").Parse() build.Update("updateTheme").Table("themes").Set("default = ?").Where("uname = ?").Parse()
build.Update("updateForum").Table("forums").Set("name = ?, desc = ?, active = ?, preset = ?").Where("fid = ?").Parse()
build.Update("updateUser").Table("users").Set("name = ?, email = ?, group = ?").Where("uid = ?").Parse() build.Update("updateUser").Table("users").Set("name = ?, email = ?, group = ?").Where("uid = ?").Parse()
build.Update("updateGroupPerms").Table("users_groups").Set("permissions = ?").Where("gid = ?").Parse() build.Update("updateGroupPerms").Table("users_groups").Set("permissions = ?").Where("gid = ?").Parse()

View File

@ -849,13 +849,12 @@ func routeRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.Use
} }
password := r.PostFormValue("password") password := r.PostFormValue("password")
if password == "" { switch password {
case "":
return common.LocalError("You didn't put in a password.", w, r, user) return common.LocalError("You didn't put in a password.", w, r, user)
} case username:
if password == username {
return common.LocalError("You can't use your username as your password.", w, r, user) return common.LocalError("You can't use your username as your password.", w, r, user)
} case email:
if password == email {
return common.LocalError("You can't use your email as your password.", w, r, user) return common.LocalError("You can't use your email as your password.", w, r, user)
} }

View File

@ -157,7 +157,7 @@ ul {
display: none; display: none;
} }
.rowblock { .rowblock, .colstack_item {
margin-bottom: 12px; margin-bottom: 12px;
border: 1px solid var(--header-border-color); border: 1px solid var(--header-border-color);
border-bottom: 2px solid var(--header-border-color); border-bottom: 2px solid var(--header-border-color);