diff --git a/common/common.go b/common/common.go index 18973efe..f920dca2 100644 --- a/common/common.go +++ b/common/common.go @@ -2,6 +2,7 @@ package common import ( "database/sql" + "log" "../query_gen/lib" ) @@ -82,3 +83,27 @@ func (inits dbInits) Run() error { func (inits dbInits) Add(init ...func(acc *qgen.Accumulator) error) { 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...) + } +} diff --git a/common/forum.go b/common/forum.go index 626c23c0..fb660958 100644 --- a/common/forum.go +++ b/common/forum.go @@ -3,6 +3,7 @@ package common //import "fmt" import ( "database/sql" + "errors" "strconv" "strings" @@ -48,7 +49,8 @@ type ForumSimple struct { } type ForumStmts struct { - update *sql.Stmt + update *sql.Stmt + setPreset *sql.Stmt } var forumStmts ForumStmts @@ -56,7 +58,8 @@ var forumStmts ForumStmts func init() { DbInits.Add(func(acc *qgen.Accumulator) error { 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() }) @@ -88,6 +91,39 @@ func (forum *Forum) Update(name string, desc string, active bool, preset string) 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 // ? - Use sort.Slice instead? type SortForum []*Forum diff --git a/common/forum_perms.go b/common/forum_perms.go new file mode 100644 index 00000000..d8ff87b7 --- /dev/null +++ b/common/forum_perms.go @@ -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), + } +} diff --git a/common/forum_perms_store.go b/common/forum_perms_store.go index 262e2764..6c0e933d 100644 --- a/common/forum_perms_store.go +++ b/common/forum_perms_store.go @@ -4,6 +4,7 @@ import ( "database/sql" "encoding/json" "log" + "sync" "../query_gen/lib" ) @@ -12,89 +13,90 @@ var Fpstore ForumPermsStore type ForumPermsStore interface { Init() error - Get(fid int, gid int) (fperms ForumPerms, err 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 + 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(), + 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 } - if Dev.SuperDebug { - log.Print("fids: ", fids) - } + debugDetail("fids: ", fids) rows, err := fps.get.Query() if err != nil { return err } defer rows.Close() - - if Dev.DebugMode { - log.Print("Adding the forum permissions") - if Dev.SuperDebug { - log.Print("forumPerms[gid][fid]") - } - } + 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) + forumPerms = make(map[int]map[int]*ForumPerms) for rows.Next() { var gid, fid int var perms []byte - var pperms ForumPerms err = rows.Scan(&gid, &fid, &perms) if err != nil { return err } - if Dev.SuperDebug { - log.Print("perms: ", string(perms)) - } - err = json.Unmarshal(perms, &pperms) + pperms, err := fps.parseForumPerm(perms) if err != nil { return err } - pperms.ExtData = make(map[string]bool) - pperms.Overrides = true _, ok := forumPerms[gid] if !ok { - forumPerms[gid] = make(map[int]ForumPerms) + forumPerms[gid] = make(map[int]*ForumPerms) } - if Dev.SuperDebug { - log.Print("gid: ", gid) - log.Print("fid: ", fid) - log.Printf("perms: %+v\n", pperms) - } + 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 { - if Dev.DebugMode { - log.Printf("Reloading the forum permissions for forum #%d", fid) - } + 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 @@ -109,38 +111,56 @@ func (fps *MemoryForumPermsStore) Reload(fid int) error { for rows.Next() { var gid int var perms []byte - var pperms ForumPerms err := rows.Scan(&gid, &perms) if err != nil { return err } - err = json.Unmarshal(perms, &pperms) + + pperms, err := fps.parseForumPerm(perms) if err != nil { return err } - pperms.ExtData = make(map[string]bool) - pperms.Overrides = true _, ok := forumPerms[gid] if !ok { - forumPerms[gid] = make(map[int]ForumPerms) + forumPerms[gid] = make(map[int]*ForumPerms) } + forumPerms[gid][fid] = pperms } 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() if err != nil { return err } for _, group := range groups { - if Dev.DebugMode { - log.Printf("Updating the forum permissions for Group #%d", group.ID) - } - group.Forums = []ForumPerms{BlankForumPerms} + debugLogf("Updating the forum permissions for Group #%d", group.ID) + group.Forums = []*ForumPerms{BlankForumPerms()} group.CanSee = []int{} fps.cascadePermSetToGroup(forumPerms, group, fids) @@ -152,18 +172,16 @@ func (fps *MemoryForumPermsStore) cascadePermSetToGroups(forumPerms map[int]map[ 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 { - if Dev.SuperDebug { - log.Printf("Forum #%+v\n", fid) - } + 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 + forumPerm = BlankForumPerms() group.Forums = append(group.Forums, forumPerm) } if forumPerm.Overrides { @@ -174,16 +192,14 @@ func (fps *MemoryForumPermsStore) cascadePermSetToGroup(forumPerms map[int]map[i group.CanSee = append(group.CanSee, fid) } - if Dev.SuperDebug { - log.Print("group.ID: ", group.ID) - log.Printf("forumPerm: %+v\n", forumPerm) - log.Print("group.CanSee: ", group.CanSee) - } + debugDetail("group.ID: ", group.ID) + debugDetailf("forumPerm: %+v\n", forumPerm) + debugDetail("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) if err != nil { return fperms, ErrNoRows diff --git a/common/forum_store.go b/common/forum_store.go index a04bb310..e35e2eea 100644 --- a/common/forum_store.go +++ b/common/forum_store.go @@ -17,9 +17,8 @@ import ( "../query_gen/lib" ) -var ForumUpdateMutex 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 // 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 Dev.DebugMode { - log.Print("Adding a placeholder forum") - } + debugLog("Adding a placeholder forum") } else { 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") } _, err := mfs.delete.Exec(id) - if err != nil { - return err - } mfs.CacheDelete(id) - return nil + return err } func (mfs *MemoryForumStore) AddTopic(tid int, uid int, fid int) error { diff --git a/common/group.go b/common/group.go index a7dbaa9b..4423cafc 100644 --- a/common/group.go +++ b/common/group.go @@ -26,7 +26,7 @@ type Group struct { 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 PluginPermsText []byte - Forums []ForumPerms + Forums []*ForumPerms CanSee []int // The IDs of the forums this group can see } diff --git a/common/group_store.go b/common/group_store.go index 376aab0b..5954f64a 100644 --- a/common/group_store.go +++ b/common/group_store.go @@ -86,9 +86,7 @@ func (mgs *MemoryGroupStore) LoadGroups() error { } mgs.groupCount = i - if Dev.DebugMode { - log.Print("Binding the Not Loggedin Group") - } + debugLog("Binding the Not Loggedin Group") GuestPerms = mgs.dirtyGetUnsafe(6).Perms return nil } @@ -172,9 +170,7 @@ func (mgs *MemoryGroupStore) initGroup(group *Group) error { log.Print("bad group plugin perms: ", group.PluginPermsText) return err } - if Dev.DebugMode { - log.Printf(group.Name+": %+v\n", group.PluginPerms) - } + debugLogf(group.Name+": %+v\n", group.PluginPerms) //group.Perms.ExtData = make(map[string]bool) // 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? +// TODO: Refactor this func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod bool, isBanned bool) (gid int, err error) { var permstr = "{}" tx, err := qgen.Builder.Begin() @@ -224,7 +221,7 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod gid = int(gid64) var perms = BlankPerms - var blankForums []ForumPerms + var blankForums []*ForumPerms var blankIntList []int var pluginPerms = make(map[string]bool) 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 permSet = make(map[int]ForumPerms) - PermUpdateMutex.Lock() - defer PermUpdateMutex.Unlock() + var permSet = make(map[int]*ForumPerms) for _, forum := range fdata { var thePreset string - if isAdmin { + switch { + case isAdmin: thePreset = "admins" - } else if isMod { + case isMod: thePreset = "staff" - } else if isBanned { + case isBanned: thePreset = "banned" - } else { + default: thePreset = "members" } diff --git a/common/permissions.go b/common/permissions.go index 6d9106c1..07d4691b 100644 --- a/common/permissions.go +++ b/common/permissions.go @@ -1,46 +1,20 @@ package common import ( - "database/sql" "encoding/json" "log" - "sync" "../query_gen/lib" ) // TODO: Refactor the perms system - -var PermUpdateMutex sync.Mutex var BlankPerms Perms -var BlankForumPerms ForumPerms var GuestPerms Perms -var ReadForumPerms ForumPerms -var ReadReplyForumPerms ForumPerms -var ReadWriteForumPerms ForumPerms // AllPerms is a set of global permissions with everything set to true 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) -// ? - 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? var GlobalPermList = []string{ "BanUsers", @@ -111,36 +85,11 @@ type Perms struct { //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() { BlankPerms = Perms{ //ExtData: make(map[string]bool), } - BlankForumPerms = ForumPerms{ - ExtData: make(map[string]bool), - } - GuestPerms = Perms{ ViewTopic: true, //ExtData: make(map[string]bool), @@ -183,266 +132,9 @@ func init() { //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 - - if Dev.DebugMode { - 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 + debugLogf("Guest Perms: %+v\n", GuestPerms) + debugLogf("All Perms: %+v\n", AllPerms) } func StripInvalidGroupForumPreset(preset string) string { @@ -457,9 +149,8 @@ func StripInvalidPreset(preset string) string { switch preset { case "all", "announce", "members", "staff", "admins", "archive", "custom": return preset - default: - return "" } + return "" } // TODO: Move this into the phrase system? diff --git a/common/routes_common.go b/common/routes_common.go index 470d2912..e59ae840 100644 --- a/common/routes_common.go +++ b/common/routes_common.go @@ -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? -func cascadeForumPerms(fperms ForumPerms, user *User) { +func cascadeForumPerms(fperms *ForumPerms, user *User) { if fperms.Overrides && !user.IsSuperAdmin { user.Perms.ViewTopic = fperms.ViewTopic user.Perms.LikeItem = fperms.LikeItem diff --git a/gen_mssql.go b/gen_mssql.go index c5ce1a4f..5d3aa854 100644 --- a/gen_mssql.go +++ b/gen_mssql.go @@ -51,7 +51,6 @@ type Stmts struct { updatePlugin *sql.Stmt updatePluginInstall *sql.Stmt updateTheme *sql.Stmt - updateForum *sql.Stmt updateUser *sql.Stmt updateGroupPerms *sql.Stmt updateGroup *sql.Stmt @@ -380,13 +379,6 @@ func _gen_mssql() (err error) { 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.") stmts.updateUser, err = db.Prepare("UPDATE [users] SET [name] = ?,[email] = ?,[group] = ? WHERE [uid] = ?") if err != nil { diff --git a/gen_mysql.go b/gen_mysql.go index 1000bc7c..6936eea5 100644 --- a/gen_mysql.go +++ b/gen_mysql.go @@ -53,7 +53,6 @@ type Stmts struct { updatePlugin *sql.Stmt updatePluginInstall *sql.Stmt updateTheme *sql.Stmt - updateForum *sql.Stmt updateUser *sql.Stmt updateGroupPerms *sql.Stmt updateGroup *sql.Stmt @@ -340,12 +339,6 @@ func _gen_mysql() (err error) { 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.") stmts.updateUser, err = db.Prepare("UPDATE `users` SET `name` = ?,`email` = ?,`group` = ? WHERE `uid` = ?") if err != nil { diff --git a/gen_pgsql.go b/gen_pgsql.go index a61938c3..362d6621 100644 --- a/gen_pgsql.go +++ b/gen_pgsql.go @@ -15,7 +15,6 @@ type Stmts struct { updatePlugin *sql.Stmt updatePluginInstall *sql.Stmt updateTheme *sql.Stmt - updateForum *sql.Stmt updateUser *sql.Stmt updateGroupPerms *sql.Stmt updateGroup *sql.Stmt @@ -80,12 +79,6 @@ func _gen_pgsql() (err error) { 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.") stmts.updateUser, err = db.Prepare("UPDATE `users` SET `name` = ?,`email` = ?,`group` = ? WHERE `uid` = ?") if err != nil { diff --git a/install/install/mysql.go b/install/install/mysql.go index d194581e..0afad84d 100644 --- a/install/install/mysql.go +++ b/install/install/mysql.go @@ -50,6 +50,17 @@ func (ins *MysqlInstaller) DefaultPort() string { 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) { _dbPassword := ins.dbPassword if _dbPassword != "" { @@ -67,13 +78,13 @@ func (ins *MysqlInstaller) InitDatabase() (err error) { } fmt.Println("Successfully connected to the database") - var waste string - err = db.QueryRow("SHOW DATABASES LIKE '" + ins.dbName + "'").Scan(&waste) - if err != nil && err != sql.ErrNoRows { + ins.db = db + ok, err := ins.dbExists(ins.dbName) + if err != nil { return err } - if err == sql.ErrNoRows { + if !ok { fmt.Println("Unable to find the database. Attempting to create it") _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + ins.dbName) if err != nil { @@ -82,7 +93,7 @@ func (ins *MysqlInstaller) InitDatabase() (err error) { 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) if err != nil { return err @@ -90,13 +101,7 @@ func (ins *MysqlInstaller) InitDatabase() (err error) { // Ready the query builder qgen.Builder.SetConn(db) - err = qgen.Builder.SetAdapter("mysql") - if err != nil { - return err - } - - ins.db = db - return nil + return qgen.Builder.SetAdapter("mysql") } func (ins *MysqlInstaller) TableDefs() (err error) { @@ -122,7 +127,7 @@ func (ins *MysqlInstaller) TableDefs() (err error) { return err } - fmt.Println("Creating table '" + table + "'") + fmt.Printf("Creating table '%s'", table) data, err := ioutil.ReadFile("./schema/mysql/" + f.Name()) if err != nil { return err @@ -135,7 +140,6 @@ func (ins *MysqlInstaller) TableDefs() (err error) { return err } } - //fmt.Println("Finished creating the tables") return nil } @@ -163,8 +167,6 @@ func (ins *MysqlInstaller) InitialData() error { return err } } - - //fmt.Println("Finished inserting the database data") return nil } diff --git a/install/install/pgsql.go b/install/install/pgsql.go index ed18e4cf..e9a7de5b 100644 --- a/install/install/pgsql.go +++ b/install/install/pgsql.go @@ -69,14 +69,9 @@ func (ins *PgsqlInstaller) InitDatabase() (err error) { // TODO: Create the database, if it doesn't exist // Ready the query builder - qgen.Builder.SetConn(db) - err = qgen.Builder.SetAdapter("pgsql") - if err != nil { - return err - } ins.db = db - - return nil + qgen.Builder.SetConn(db) + return qgen.Builder.SetAdapter("pgsql") } func (ins *PgsqlInstaller) TableDefs() (err error) { diff --git a/misc_test.go b/misc_test.go index ea951fc3..3cb833ea 100644 --- a/misc_test.go +++ b/misc_test.go @@ -607,8 +607,8 @@ func TestForumPermsStore(t *testing.T) { if !gloinited { gloinit() } - if !pluginsInited { - initPlugins() + if !common.PluginsInited { + common.InitPlugins() } } @@ -617,8 +617,8 @@ func TestGroupStore(t *testing.T) { if !gloinited { gloinit() } - if !pluginsInited { - initPlugins() + if !common.PluginsInited { + common.InitPlugins() } _, err := common.Gstore.Get(-1) @@ -728,8 +728,8 @@ func TestReplyStore(t *testing.T) { if !gloinited { gloinit() } - if !pluginsInited { - initPlugins() + if !common.PluginsInited { + common.InitPlugins() } _, err := common.Rstore.Get(-1) @@ -770,8 +770,8 @@ func TestProfileReplyStore(t *testing.T) { if !gloinited { gloinit() } - if !pluginsInited { - initPlugins() + if !common.PluginsInited { + common.InitPlugins() } _, 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? */ 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") hashedPassword, err = common.BcryptGeneratePasswordNoSalt(realPassword) if err != nil { @@ -853,34 +853,31 @@ func TestAuth(t *testing.T) { } password = realPassword - t.Log("Testing password '" + password + "'") - t.Log("Testing salt '" + salt + "'") + t.Logf("Testing password '%s'", password) + t.Logf("Testing salt '%s'", salt) err = common.CheckPassword(hashedPassword, password, salt) - if err == ErrMismatchedHashAndPassword { + if err == common.ErrMismatchedHashAndPassword { 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") } else if err != nil { t.Error(err) } password = "hahaha" - t.Log("Testing password '" + password + "'") - t.Log("Testing salt '" + salt + "'") + t.Logf("Testing password '%s'", password) + t.Logf("Testing salt '%s'", salt) err = common.CheckPassword(hashedPassword, password, salt) - if err == ErrPasswordTooLong { + if err == common.ErrPasswordTooLong { t.Error("CheckPassword thinks the password is too long") } else if err == nil { t.Error("The two shouldn't match!") } password = "Madame Cassandra's Mystic" - t.Log("Testing password '" + password + "'") - t.Log("Testing salt '" + salt + "'") + t.Logf("Testing password '%s'", password) + t.Logf("Testing salt '%s'", salt) err = common.CheckPassword(hashedPassword, password, salt) - if err == ErrPasswordTooLong { - t.Error("CheckPassword thinks the password is too long") - } else if err == nil { - t.Error("The two shouldn't match!") - } + expect(t, err != common.ErrPasswordTooLong, "CheckPassword thinks the password is too long") + expect(t, err != nil, "The two shouldn't match!") } diff --git a/panel_routes.go b/panel_routes.go index 7d910ca0..209a8e22 100644 --- a/panel_routes.go +++ b/panel_routes.go @@ -425,9 +425,6 @@ func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use 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) if err == ErrNoRows { 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) } - // ! IMPORTANT - // TODO: Refactor this - common.ForumUpdateMutex.Lock() - defer common.ForumUpdateMutex.Unlock() - 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) - } + permPreset := common.StripInvalidGroupForumPreset(r.PostFormValue("perm_preset")) + err = forum.SetPreset(permPreset, gid) + if err != nil { + return common.LocalErrorJSQ(err.Error(), w, r, user, isJs) } if !isJs { diff --git a/query_gen/lib/utils.go b/query_gen/lib/utils.go index 1f5ff85d..4e64664f 100644 --- a/query_gen/lib/utils.go +++ b/query_gen/lib/utils.go @@ -181,15 +181,16 @@ func processWhere(wherestr string) (where []DBWhere) { segment += ")" for i := 0; i < len(segment); i++ { char := segment[i] - if '0' <= char && char <= '9' { + switch { + case '0' <= char && char <= '9': 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) - } else if char == '\'' { + case char == '\'': i = tmpWhere.parseString(segment, i) - } else if isOpByte(char) { + case isOpByte(char): i = tmpWhere.parseOperator(segment, i) - } else if char == '?' { + case char == '?': tmpWhere.Expr = append(tmpWhere.Expr, DBToken{"?", "substitute"}) } } @@ -216,11 +217,12 @@ func (setter *DBSetter) parseColumn(segment string, i int) int { var buffer string for ; i < len(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) - } else if char == '(' { + case char == '(': return setter.parseFunction(segment, buffer, i) - } else { + default: i-- setter.Expr = append(setter.Expr, DBToken{buffer, "column"}) return i @@ -303,15 +305,16 @@ func processSet(setstr string) (setter []DBSetter) { for i := 0; i < len(segment); i++ { char := segment[i] - if '0' <= char && char <= '9' { + switch { + case '0' <= char && char <= '9': 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) - } else if char == '\'' { + case char == '\'': i = tmpSetter.parseString(segment, i) - } else if isOpByte(char) { + case isOpByte(char): i = tmpSetter.parseOperator(segment, i) - } else if char == '?' { + case char == '?': tmpSetter.Expr = append(tmpSetter.Expr, DBToken{"?", "substitute"}) } } diff --git a/query_gen/main.go b/query_gen/main.go index 06606ea1..10d7f2c9 100644 --- a/query_gen/main.go +++ b/query_gen/main.go @@ -352,8 +352,6 @@ func writeUpdates(adapter qgen.Adapter) error { 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("updateGroupPerms").Table("users_groups").Set("permissions = ?").Where("gid = ?").Parse() diff --git a/routes.go b/routes.go index 4603255c..808d1bd2 100644 --- a/routes.go +++ b/routes.go @@ -849,13 +849,12 @@ func routeRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.Use } password := r.PostFormValue("password") - if password == "" { + switch password { + case "": return common.LocalError("You didn't put in a password.", w, r, user) - } - if password == username { + case username: return common.LocalError("You can't use your username as your password.", w, r, user) - } - if password == email { + case email: return common.LocalError("You can't use your email as your password.", w, r, user) } diff --git a/themes/cosora/public/main.css b/themes/cosora/public/main.css index 038fff9e..fec85e7e 100644 --- a/themes/cosora/public/main.css +++ b/themes/cosora/public/main.css @@ -157,7 +157,7 @@ ul { display: none; } -.rowblock { +.rowblock, .colstack_item { margin-bottom: 12px; border: 1px solid var(--header-border-color); border-bottom: 2px solid var(--header-border-color);