Moved the modlog and admin log logic to their own file.

Refactored the code to use the new builder syntax.
Fixed the DbInit logic.
Made sure the prepared statements are cleaned up.
Added the AdminOnly middleware and added it to the routes.
Added the Query method to the selectBuilder.
This commit is contained in:
Azareal 2017-11-11 23:34:27 +00:00
parent 7ac3de8299
commit 6bae378db0
20 changed files with 338 additions and 241 deletions

37
common/audit_logs.go Normal file
View File

@ -0,0 +1,37 @@
package common
import (
"database/sql"
"../query_gen/lib"
)
type LogStmts struct {
addModLogEntry *sql.Stmt
addAdminLogEntry *sql.Stmt
}
var logStmts LogStmts
func init() {
DbInits.Add(func() error {
acc := qgen.Builder.Accumulator()
logStmts = LogStmts{
addModLogEntry: acc.Insert("moderation_logs").Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Fields("?,?,?,?,?,UTC_TIMESTAMP()").Prepare(),
addAdminLogEntry: acc.Insert("administration_logs").Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Fields("?,?,?,?,?,UTC_TIMESTAMP()").Prepare(),
}
return acc.FirstError()
})
}
// TODO: Make a store for this?
func AddModLog(action string, elementID int, elementType string, ipaddress string, actorID int) (err error) {
_, err = logStmts.addModLogEntry.Exec(action, elementID, elementType, ipaddress, actorID)
return err
}
// TODO: Make a store for this?
func AddAdminLog(action string, elementID string, elementType int, ipaddress string, actorID int) (err error) {
_, err = logStmts.addAdminLogEntry.Exec(action, elementID, elementType, ipaddress, actorID)
return err
}

View File

@ -1,6 +1,8 @@
package common package common
import "database/sql" import (
"database/sql"
)
// nolint I don't want to write comments for each of these o.o // nolint I don't want to write comments for each of these o.o
const Hour int = 60 * 60 const Hour int = 60 * 60
@ -60,11 +62,11 @@ func (slice StringList) Contains(needle string) bool {
return false return false
} }
type DBInits []func() error type dbInits []func() error
var DbInits DBInits var DbInits dbInits
func (inits DBInits) Run() error { func (inits dbInits) Run() error {
for _, init := range inits { for _, init := range inits {
err := init() err := init()
if err != nil { if err != nil {
@ -74,6 +76,6 @@ func (inits DBInits) Run() error {
return nil return nil
} }
func (inits DBInits) Add(init ...func() error) { func (inits dbInits) Add(init ...func() error) {
inits = append(inits, init...) DbInits = dbInits(append(DbInits, init...))
} }

View File

@ -7,6 +7,7 @@
package common package common
import ( import (
"database/sql"
"log" "log"
"net/http" "net/http"
@ -137,6 +138,22 @@ type Plugin struct {
Data interface{} // Usually used for hosting the VMs / reusable elements of non-native plugins Data interface{} // Usually used for hosting the VMs / reusable elements of non-native plugins
} }
type ExtendStmts struct {
getPlugins *sql.Stmt
}
var extendStmts ExtendStmts
func init() {
DbInits.Add(func() error {
acc := qgen.Builder.Accumulator()
extendStmts = ExtendStmts{
getPlugins: acc.Select("plugins").Columns("uname, active, installed").Prepare(),
}
return acc.FirstError()
})
}
func InitExtend() (err error) { func InitExtend() (err error) {
err = InitPluginLangs() err = InitPluginLangs()
if err != nil { if err != nil {
@ -147,11 +164,7 @@ func InitExtend() (err error) {
// Load polls the database to see which plugins have been activated and which have been installed // Load polls the database to see which plugins have been activated and which have been installed
func (plugins PluginList) Load() error { func (plugins PluginList) Load() error {
getPlugins, err := qgen.Builder.SimpleSelect("plugins", "uname, active, installed", "", "", "") rows, err := extendStmts.getPlugins.Query()
if err != nil {
return err
}
rows, err := getPlugins.Query()
if err != nil { if err != nil {
return err return err
} }
@ -283,24 +296,24 @@ func (plugin *Plugin) RemoveHook(name string, handler interface{}) {
delete(plugin.Hooks, name) delete(plugin.Hooks, name)
} }
var pluginsInited = false var PluginsInited = false
func InitPlugins() { func InitPlugins() {
for name, body := range Plugins { for name, body := range Plugins {
log.Printf("Added plugin %s", name) log.Printf("Added plugin '%s'", name)
if body.Active { if body.Active {
log.Printf("Initialised plugin %s", name) log.Printf("Initialised plugin '%s'", name)
if Plugins[name].Init != nil { if Plugins[name].Init != nil {
err := Plugins[name].Init() err := Plugins[name].Init()
if err != nil { if err != nil {
log.Print(err) log.Print(err)
} }
} else { } else {
log.Printf("Plugin %s doesn't have an initialiser.", name) log.Printf("Plugin '%s' doesn't have an initialiser.", name)
} }
} }
} }
pluginsInited = true PluginsInited = true
} }
// ? - Are the following functions racey? // ? - Are the following functions racey?

View File

@ -25,18 +25,11 @@ type MemoryForumPermsStore struct {
} }
func NewMemoryForumPermsStore() (*MemoryForumPermsStore, error) { func NewMemoryForumPermsStore() (*MemoryForumPermsStore, error) {
getPermsStmt, err := qgen.Builder.SimpleSelect("forums_permissions", "gid, fid, permissions", "", "gid ASC, fid ASC", "") acc := qgen.Builder.Accumulator()
if err != nil {
return nil, err
}
getPermsByForumStmt, err := qgen.Builder.SimpleSelect("forums_permissions", "gid, permissions", "fid = ?", "gid ASC", "")
if err != nil {
return nil, err
}
return &MemoryForumPermsStore{ return &MemoryForumPermsStore{
get: getPermsStmt, get: acc.Select("forums_permissions").Columns("gid, fid, permissions").Orderby("gid ASC, fid ASC").Prepare(),
getByForum: getPermsByForumStmt, getByForum: acc.Select("forums_permissions").Columns("gid, permissions").Where("fid = ?").Orderby("gid ASC").Prepare(),
}, nil }, acc.FirstError()
} }
func (fps *MemoryForumPermsStore) Init() error { func (fps *MemoryForumPermsStore) Init() error {

View File

@ -483,6 +483,7 @@ func RebuildGroupPermissions(gid int) error {
if err != nil { if err != nil {
return err return err
} }
defer getGroupPerms.Close()
err = getGroupPerms.QueryRow(gid).Scan(&permstr) err = getGroupPerms.QueryRow(gid).Scan(&permstr)
if err != nil { if err != nil {

View File

@ -294,6 +294,14 @@ func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) {
return *usercpy, true return *usercpy, true
} }
// AdminOnly makes sure that only admins can access certain panel routes
func AdminOnly(w http.ResponseWriter, r *http.Request, user User) RouteError {
if !user.IsAdmin {
return NoPermissions(w, r, user)
}
return nil
}
// SuperModeOnly makes sure that only super mods or higher can access the panel routes // SuperModeOnly makes sure that only super mods or higher can access the panel routes
func SuperModOnly(w http.ResponseWriter, r *http.Request, user User) RouteError { func SuperModOnly(w http.ResponseWriter, r *http.Request, user User) RouteError {
if !user.IsSuperMod { if !user.IsSuperMod {

View File

@ -1,9 +1,13 @@
package common package common
import "strconv" import (
import "strings" "database/sql"
import "sync/atomic" "strconv"
import "../query_gen/lib" "strings"
"sync/atomic"
"../query_gen/lib"
)
// SettingMap is a map type specifically for holding the various settings admins set to toggle features on and off or to otherwise alter Gosora's behaviour from the Control Panel // SettingMap is a map type specifically for holding the various settings admins set to toggle features on and off or to otherwise alter Gosora's behaviour from the Control Panel
type SettingMap map[string]interface{} type SettingMap map[string]interface{}
@ -23,17 +27,25 @@ type Setting struct {
Constraint string Constraint string
} }
type SettingStmts struct {
getFull *sql.Stmt
}
var settingStmts SettingStmts
func init() { func init() {
SettingBox.Store(SettingMap(make(map[string]interface{}))) SettingBox.Store(SettingMap(make(map[string]interface{})))
DbInits.Add(func() error {
acc := qgen.Builder.Accumulator()
settingStmts = SettingStmts{
getFull: acc.Select("settings").Columns("name, content, type, constraints").Prepare(),
}
return acc.FirstError()
})
} }
func LoadSettings() error { func LoadSettings() error {
// TODO: Stop doing this inline rows, err := settingStmts.getFull.Query()
getFullSettings, err := qgen.Builder.SimpleSelect("settings", "name, content, type, constraints", "", "", "")
if err != nil {
return err
}
rows, err := getFullSettings.Query()
if err != nil { if err != nil {
return err return err
} }

View File

@ -7,24 +7,35 @@
package common package common
import ( import (
"database/sql"
"log" "log"
"time" "time"
"../query_gen/lib" "../query_gen/lib"
) )
type TaskStmts struct {
getExpiredScheduledGroups *sql.Stmt
getSync *sql.Stmt
}
var taskStmts TaskStmts
var lastSync time.Time var lastSync time.Time
func init() { func init() {
lastSync = time.Now() lastSync = time.Now()
DbInits.Add(func() error {
acc := qgen.Builder.Accumulator()
taskStmts = TaskStmts{
getExpiredScheduledGroups: acc.SimpleSelect("users_groups_scheduler", "uid", "UTC_TIMESTAMP() > revert_at AND temporary = 1", "", ""),
getSync: acc.SimpleSelect("sync", "last_update", "", "", ""),
}
return acc.FirstError()
})
} }
func HandleExpiredScheduledGroups() error { func HandleExpiredScheduledGroups() error {
getExpiredScheduledGroups, err := qgen.Builder.SimpleSelect("users_groups_scheduler", "uid", "UTC_TIMESTAMP() > revert_at AND temporary = 1", "", "") rows, err := taskStmts.getExpiredScheduledGroups.Query()
if err != nil {
return err
}
rows, err := getExpiredScheduledGroups.Query()
if err != nil { if err != nil {
return err return err
} }
@ -50,11 +61,7 @@ func HandleExpiredScheduledGroups() error {
func HandleServerSync() error { func HandleServerSync() error {
var lastUpdate time.Time var lastUpdate time.Time
getSync, err := qgen.Builder.SimpleSelect("sync", "last_update", "", "", "") err := taskStmts.getSync.QueryRow().Scan(&lastUpdate)
if err != nil {
return err
}
err = getSync.QueryRow().Scan(&lastUpdate)
if err != nil { if err != nil {
return err return err
} }

View File

@ -4,6 +4,7 @@ package common
import ( import (
//"fmt" //"fmt"
"bytes" "bytes"
"database/sql"
"encoding/json" "encoding/json"
"errors" "errors"
"io/ioutil" "io/ioutil"
@ -74,20 +75,28 @@ type ThemeResource struct {
Location string Location string
} }
type ThemeStmts struct {
getThemes *sql.Stmt
}
var themeStmts ThemeStmts
func init() { func init() {
DefaultThemeBox.Store(fallbackTheme) DefaultThemeBox.Store(fallbackTheme)
DbInits.Add(func() error {
acc := qgen.Builder.Accumulator()
themeStmts = ThemeStmts{
getThemes: acc.Select("themes").Columns("uname, default").Prepare(),
}
return acc.FirstError()
})
} }
// TODO: Make the initThemes and LoadThemes functions less confusing // TODO: Make the initThemes and LoadThemes functions less confusing
// ? - Delete themes which no longer exist in the themes folder from the database? // ? - Delete themes which no longer exist in the themes folder from the database?
func (themes ThemeList) LoadActiveStatus() error { func (themes ThemeList) LoadActiveStatus() error {
getThemes, err := qgen.Builder.SimpleSelect("themes", "uname, default", "", "", "")
if err != nil {
return err
}
ChangeDefaultThemeMutex.Lock() ChangeDefaultThemeMutex.Lock()
rows, err := getThemes.Query() rows, err := themeStmts.getThemes.Query()
if err != nil { if err != nil {
return err return err
} }

View File

@ -170,12 +170,8 @@ func (mus *MemoryUserStore) BulkGetMap(ids []int) (list map[int]*User, err error
} }
qlist = qlist[0 : len(qlist)-1] qlist = qlist[0 : len(qlist)-1]
stmt, err := qgen.Builder.SimpleSelect("users", "uid, name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip, temp_group", "uid IN("+qlist+")", "", "") acc := qgen.Builder.Accumulator()
if err != nil { rows, err := acc.Select("users").Columns("uid, name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip, temp_group").Where("uid IN(" + qlist + ")").Query(uidList...)
return nil, err
}
rows, err := stmt.Query(uidList...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -187,13 +183,8 @@ func (mus *MemoryUserStore) BulkGetMap(ids []int) (list map[int]*User, err error
return nil, err return nil, err
} }
// Initialise the user
user.Init() user.Init()
mus.CacheSet(user)
// Add it to the cache...
_ = mus.CacheSet(user)
// Add it to the list to be returned
list[user.ID] = user list[user.ID] = user
} }
@ -219,10 +210,10 @@ func (mus *MemoryUserStore) BulkGetMap(ids []int) (list map[int]*User, err error
} }
sidList = sidList[0 : len(sidList)-1] sidList = sidList[0 : len(sidList)-1]
return list, errors.New("Unable to find the users with the following IDs: " + sidList) err = errors.New("Unable to find the users with the following IDs: " + sidList)
} }
return list, nil return list, err
} }
func (mus *MemoryUserStore) BypassGet(id int) (*User, error) { func (mus *MemoryUserStore) BypassGet(id int) (*User, error) {
@ -420,12 +411,8 @@ func (mus *SQLUserStore) BulkGetMap(ids []int) (list map[int]*User, err error) {
} }
qlist = qlist[0 : len(qlist)-1] qlist = qlist[0 : len(qlist)-1]
stmt, err := qgen.Builder.SimpleSelect("users", "uid, name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip, temp_group", "uid IN("+qlist+")", "", "") acc := qgen.Builder.Accumulator()
if err != nil { rows, err := acc.Select("users").Columns("uid, name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip, temp_group").Where("uid IN(" + qlist + ")").Query(uidList...)
return nil, err
}
rows, err := stmt.Query(uidList...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -438,10 +425,7 @@ func (mus *SQLUserStore) BulkGetMap(ids []int) (list map[int]*User, err error) {
return nil, err return nil, err
} }
// Initialise the user
user.Init() user.Init()
// Add it to the list to be returned
list[user.ID] = user list[user.ID] = user
} }

View File

@ -17,8 +17,6 @@ import (
"strings" "strings"
"time" "time"
"unicode" "unicode"
"../query_gen/lib"
) )
// Version stores a Gosora version // Version stores a Gosora version
@ -374,23 +372,3 @@ func BuildSlug(slug string, id int) string {
} }
return slug + "." + strconv.Itoa(id) return slug + "." + strconv.Itoa(id)
} }
// TODO: Make a store for this?
func AddModLog(action string, elementID int, elementType string, ipaddress string, actorID int) (err error) {
addModLogEntry, err := qgen.Builder.SimpleInsert("moderation_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "?,?,?,?,?,UTC_TIMESTAMP()")
if err != nil {
return err
}
_, err = addModLogEntry.Exec(action, elementID, elementType, ipaddress, actorID)
return err
}
// TODO: Make a store for this?
func AddAdminLog(action string, elementID string, elementType int, ipaddress string, actorID int) (err error) {
addAdminLogEntry, err := qgen.Builder.SimpleInsert("administration_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "?,?,?,?,?,UTC_TIMESTAMP()")
if err != nil {
return err
}
_, err = addAdminLogEntry.Exec(action, elementID, elementType, ipaddress, actorID)
return err
}

View File

@ -1,11 +1,15 @@
/* Copyright Azareal 2017 - 2018 */ /* Copyright Azareal 2017 - 2018 */
package common package common
import "log" import (
import "bytes" "bytes"
import "sync" "database/sql"
import "encoding/json" "encoding/json"
import "../query_gen/lib" "log"
"sync"
"../query_gen/lib"
)
var Docks WidgetDocks var Docks WidgetDocks
var widgetUpdateMutex sync.RWMutex var widgetUpdateMutex sync.RWMutex
@ -39,13 +43,25 @@ type NameTextPair struct {
Text string Text string
} }
type WidgetStmts struct {
getWidgets *sql.Stmt
}
var widgetStmts WidgetStmts
func init() {
DbInits.Add(func() error {
acc := qgen.Builder.Accumulator()
widgetStmts = WidgetStmts{
getWidgets: acc.Select("widgets").Columns("position, side, type, active, location, data").Orderby("position ASC").Prepare(),
}
return acc.FirstError()
})
}
// TODO: Make a store for this? // TODO: Make a store for this?
func InitWidgets() error { func InitWidgets() error {
getWidgets, err := qgen.Builder.SimpleSelect("widgets", "position, side, type, active, location, data", "", "position ASC", "") rows, err := widgetStmts.getWidgets.Query()
if err != nil {
return err
}
rows, err := getWidgets.Query()
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,7 +1,11 @@
package common package common
import "sync/atomic" import (
import "../query_gen/lib" "database/sql"
"sync/atomic"
"../query_gen/lib"
)
type WordFilter struct { type WordFilter struct {
ID int ID int
@ -12,16 +16,25 @@ type WordFilterMap map[int]WordFilter
var WordFilterBox atomic.Value // An atomic value holding a WordFilterBox var WordFilterBox atomic.Value // An atomic value holding a WordFilterBox
type FilterStmts struct {
getWordFilters *sql.Stmt
}
var filterStmts FilterStmts
func init() { func init() {
WordFilterBox.Store(WordFilterMap(make(map[int]WordFilter))) WordFilterBox.Store(WordFilterMap(make(map[int]WordFilter)))
DbInits.Add(func() error {
acc := qgen.Builder.Accumulator()
filterStmts = FilterStmts{
getWordFilters: acc.Select("word_filters").Columns("wfid, find, replacement").Prepare(),
}
return acc.FirstError()
})
} }
func LoadWordFilters() error { func LoadWordFilters() error {
getWordFilters, err := qgen.Builder.SimpleSelect("word_filters", "wfid, find, replacement", "", "", "") rows, err := filterStmts.getWordFilters.Query()
if err != nil {
return err
}
rows, err := getWordFilters.Query()
if err != nil { if err != nil {
return err return err
} }

View File

@ -28,6 +28,7 @@ func InitDatabase() (err error) {
} }
globs = &Globs{stmts} globs = &Globs{stmts}
log.Print("Running the db handlers.")
err = common.DbInits.Run() err = common.DbInits.Run()
if err != nil { if err != nil {
return err return err

View File

@ -192,50 +192,134 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
case "/panel/forums/": case "/panel/forums/":
err = routePanelForums(w,req,user) err = routePanelForums(w,req,user)
case "/panel/forums/create/": case "/panel/forums/create/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelForumsCreateSubmit(w,req,user) err = routePanelForumsCreateSubmit(w,req,user)
case "/panel/forums/delete/": case "/panel/forums/delete/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelForumsDelete(w,req,user,extra_data) err = routePanelForumsDelete(w,req,user,extra_data)
case "/panel/forums/delete/submit/": case "/panel/forums/delete/submit/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelForumsDeleteSubmit(w,req,user,extra_data) err = routePanelForumsDeleteSubmit(w,req,user,extra_data)
case "/panel/forums/edit/": case "/panel/forums/edit/":
err = routePanelForumsEdit(w,req,user,extra_data) err = routePanelForumsEdit(w,req,user,extra_data)
case "/panel/forums/edit/submit/": case "/panel/forums/edit/submit/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelForumsEditSubmit(w,req,user,extra_data) err = routePanelForumsEditSubmit(w,req,user,extra_data)
case "/panel/forums/edit/perms/submit/": case "/panel/forums/edit/perms/submit/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelForumsEditPermsSubmit(w,req,user,extra_data) err = routePanelForumsEditPermsSubmit(w,req,user,extra_data)
case "/panel/settings/": case "/panel/settings/":
err = routePanelSettings(w,req,user) err = routePanelSettings(w,req,user)
case "/panel/settings/edit/": case "/panel/settings/edit/":
err = routePanelSetting(w,req,user,extra_data) err = routePanelSetting(w,req,user,extra_data)
case "/panel/settings/edit/submit/": case "/panel/settings/edit/submit/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelSettingEdit(w,req,user,extra_data) err = routePanelSettingEdit(w,req,user,extra_data)
case "/panel/settings/word-filters/": case "/panel/settings/word-filters/":
err = routePanelWordFilters(w,req,user) err = routePanelWordFilters(w,req,user)
case "/panel/settings/word-filters/create/": case "/panel/settings/word-filters/create/":
err = common.ParseForm(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelWordFiltersCreate(w,req,user) err = routePanelWordFiltersCreate(w,req,user)
case "/panel/settings/word-filters/edit/": case "/panel/settings/word-filters/edit/":
err = routePanelWordFiltersEdit(w,req,user,extra_data) err = routePanelWordFiltersEdit(w,req,user,extra_data)
case "/panel/settings/word-filters/edit/submit/": case "/panel/settings/word-filters/edit/submit/":
err = common.ParseForm(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelWordFiltersEditSubmit(w,req,user,extra_data) err = routePanelWordFiltersEditSubmit(w,req,user,extra_data)
case "/panel/settings/word-filters/delete/submit/": case "/panel/settings/word-filters/delete/submit/":
err = common.ParseForm(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelWordFiltersDeleteSubmit(w,req,user,extra_data) err = routePanelWordFiltersDeleteSubmit(w,req,user,extra_data)
case "/panel/themes/": case "/panel/themes/":
err = routePanelThemes(w,req,user) err = routePanelThemes(w,req,user)
case "/panel/themes/default/": case "/panel/themes/default/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelThemesSetDefault(w,req,user,extra_data) err = routePanelThemesSetDefault(w,req,user,extra_data)
case "/panel/plugins/": case "/panel/plugins/":
err = routePanelPlugins(w,req,user) err = routePanelPlugins(w,req,user)
case "/panel/plugins/activate/": case "/panel/plugins/activate/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelPluginsActivate(w,req,user,extra_data) err = routePanelPluginsActivate(w,req,user,extra_data)
case "/panel/plugins/deactivate/": case "/panel/plugins/deactivate/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelPluginsDeactivate(w,req,user,extra_data) err = routePanelPluginsDeactivate(w,req,user,extra_data)
case "/panel/plugins/install/": case "/panel/plugins/install/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelPluginsInstall(w,req,user,extra_data) err = routePanelPluginsInstall(w,req,user,extra_data)
case "/panel/users/": case "/panel/users/":
err = routePanelUsers(w,req,user) err = routePanelUsers(w,req,user)
case "/panel/users/edit/": case "/panel/users/edit/":
err = routePanelUsersEdit(w,req,user,extra_data) err = routePanelUsersEdit(w,req,user,extra_data)
case "/panel/users/edit/submit/": case "/panel/users/edit/submit/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelUsersEditSubmit(w,req,user,extra_data) err = routePanelUsersEditSubmit(w,req,user,extra_data)
case "/panel/groups/": case "/panel/groups/":
err = routePanelGroups(w,req,user) err = routePanelGroups(w,req,user)
@ -244,16 +328,40 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
case "/panel/groups/edit/perms/": case "/panel/groups/edit/perms/":
err = routePanelGroupsEditPerms(w,req,user,extra_data) err = routePanelGroupsEditPerms(w,req,user,extra_data)
case "/panel/groups/edit/submit/": case "/panel/groups/edit/submit/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelGroupsEditSubmit(w,req,user,extra_data) err = routePanelGroupsEditSubmit(w,req,user,extra_data)
case "/panel/groups/edit/perms/submit/": case "/panel/groups/edit/perms/submit/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelGroupsEditPermsSubmit(w,req,user,extra_data) err = routePanelGroupsEditPermsSubmit(w,req,user,extra_data)
case "/panel/groups/create/": case "/panel/groups/create/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelGroupsCreateSubmit(w,req,user) err = routePanelGroupsCreateSubmit(w,req,user)
case "/panel/backups/": case "/panel/backups/":
err = routePanelBackups(w,req,user,extra_data) err = routePanelBackups(w,req,user,extra_data)
case "/panel/logs/mod/": case "/panel/logs/mod/":
err = routePanelLogsMod(w,req,user) err = routePanelLogsMod(w,req,user)
case "/panel/debug/": case "/panel/debug/":
err = common.AdminOnly(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
err = routePanelDebug(w,req,user) err = routePanelDebug(w,req,user)
default: default:
err = routePanel(w,req,user) err = routePanel(w,req,user)

View File

@ -553,6 +553,7 @@ func BenchmarkQueryPreparedTopicParallel(b *testing.B) {
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
defer getTopicUser.Close()
for pb.Next() { for pb.Next() {
err := getTopicUser.QueryRow(1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level) err := getTopicUser.QueryRow(1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)

View File

@ -229,21 +229,13 @@ func routePanelForumsCreateSubmit(w http.ResponseWriter, r *http.Request, user c
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
err := r.ParseForm()
if err != nil {
return common.LocalError("Bad Form", w, r, user)
}
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
fname := r.PostFormValue("forum-name") fname := r.PostFormValue("forum-name")
fdesc := r.PostFormValue("forum-desc") fdesc := r.PostFormValue("forum-desc")
fpreset := common.StripInvalidPreset(r.PostFormValue("forum-preset")) fpreset := common.StripInvalidPreset(r.PostFormValue("forum-preset"))
factive := r.PostFormValue("forum-name") factive := r.PostFormValue("forum-name")
active := (factive == "on" || factive == "1") active := (factive == "on" || factive == "1")
_, err = common.Fstore.Create(fname, fdesc, active, fpreset) _, err := common.Fstore.Create(fname, fdesc, active, fpreset)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return common.InternalError(err, w, r)
} }
@ -261,9 +253,6 @@ func routePanelForumsDelete(w http.ResponseWriter, r *http.Request, user common.
if !user.Perms.ManageForums { if !user.Perms.ManageForums {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
fid, err := strconv.Atoi(sfid) fid, err := strconv.Atoi(sfid)
if err != nil { if err != nil {
@ -301,9 +290,6 @@ func routePanelForumsDeleteSubmit(w http.ResponseWriter, r *http.Request, user c
if !user.Perms.ManageForums { if !user.Perms.ManageForums {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
fid, err := strconv.Atoi(sfid) fid, err := strconv.Atoi(sfid)
if err != nil { if err != nil {
@ -380,14 +366,6 @@ func routePanelForumsEditSubmit(w http.ResponseWriter, r *http.Request, user com
if !user.Perms.ManageForums { if !user.Perms.ManageForums {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
err := r.ParseForm()
if err != nil {
return common.LocalError("Bad Form", w, r, user)
}
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
fid, err := strconv.Atoi(sfid) fid, err := strconv.Atoi(sfid)
@ -435,14 +413,6 @@ func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use
if !user.Perms.ManageForums { if !user.Perms.ManageForums {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
err := r.ParseForm()
if err != nil {
return common.LocalError("Bad Form", w, r, user)
}
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
fid, err := strconv.Atoi(sfid) fid, err := strconv.Atoi(sfid)
@ -620,18 +590,10 @@ func routePanelSettingEdit(w http.ResponseWriter, r *http.Request, user common.U
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
err := r.ParseForm()
if err != nil {
return common.LocalError("Bad Form", w, r, user)
}
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
var stype, sconstraints string var stype, sconstraints string
scontent := r.PostFormValue("setting-value") scontent := r.PostFormValue("setting-value")
err = stmts.getFullSetting.QueryRow(sname).Scan(&sname, &stype, &sconstraints) err := stmts.getFullSetting.QueryRow(sname).Scan(&sname, &stype, &sconstraints)
if err == ErrNoRows { if err == ErrNoRows {
return common.LocalError("The setting you want to edit doesn't exist.", w, r, user) return common.LocalError("The setting you want to edit doesn't exist.", w, r, user)
} else if err != nil { } else if err != nil {
@ -665,7 +627,7 @@ func routePanelSettingEdit(w http.ResponseWriter, r *http.Request, user common.U
func routePanelWordFilters(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { func routePanelWordFilters(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return nil return ferr
} }
if !user.Perms.EditSettings { if !user.Perms.EditSettings {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
@ -693,11 +655,6 @@ func routePanelWordFiltersCreate(w http.ResponseWriter, r *http.Request, user co
if !user.Perms.EditSettings { if !user.Perms.EditSettings {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
err := r.ParseForm()
if err != nil {
return common.PreError("Bad Form", w, r)
}
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
find := strings.TrimSpace(r.PostFormValue("find")) find := strings.TrimSpace(r.PostFormValue("find"))
@ -755,11 +712,6 @@ func routePanelWordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, use
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
err := r.ParseForm()
if err != nil {
return common.PreError("Bad Form", w, r)
}
// TODO: Either call it isJs or js rather than flip-flopping back and forth across the routes x.x // TODO: Either call it isJs or js rather than flip-flopping back and forth across the routes x.x
isJs := (r.PostFormValue("isJs") == "1") isJs := (r.PostFormValue("isJs") == "1")
if !user.Perms.EditSettings { if !user.Perms.EditSettings {
@ -798,10 +750,6 @@ func routePanelWordFiltersDeleteSubmit(w http.ResponseWriter, r *http.Request, u
return ferr return ferr
} }
err := r.ParseForm()
if err != nil {
return common.PreError("Bad Form", w, r)
}
isJs := (r.PostFormValue("isJs") == "1") isJs := (r.PostFormValue("isJs") == "1")
if !user.Perms.EditSettings { if !user.Perms.EditSettings {
return common.NoPermissionsJSQ(w, r, user, isJs) return common.NoPermissionsJSQ(w, r, user, isJs)
@ -860,16 +808,11 @@ func routePanelPluginsActivate(w http.ResponseWriter, r *http.Request, user comm
if !user.Perms.ManagePlugins { if !user.Perms.ManagePlugins {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
//log.Print("uname","'"+uname+"'")
plugin, ok := common.Plugins[uname] plugin, ok := common.Plugins[uname]
if !ok { if !ok {
return common.LocalError("The plugin isn't registered in the system", w, r, user) return common.LocalError("The plugin isn't registered in the system", w, r, user)
} }
if plugin.Installable && !plugin.Installed { if plugin.Installable && !plugin.Installed {
return common.LocalError("You can't activate this plugin without installing it first", w, r, user) return common.LocalError("You can't activate this plugin without installing it first", w, r, user)
} }
@ -888,26 +831,19 @@ func routePanelPluginsActivate(w http.ResponseWriter, r *http.Request, user comm
} }
} }
//log.Print("err", err)
//log.Print("active", active)
if hasPlugin { if hasPlugin {
if active { if active {
return common.LocalError("The plugin is already active", w, r, user) return common.LocalError("The plugin is already active", w, r, user)
} }
//log.Print("updatePlugin")
_, err = stmts.updatePlugin.Exec(1, uname) _, err = stmts.updatePlugin.Exec(1, uname)
if err != nil {
return common.InternalError(err, w, r)
}
} else { } else {
//log.Print("addPlugin") _, err = stmts.addPlugin.Exec(uname, 1, 0)
_, err := stmts.addPlugin.Exec(uname, 1, 0) }
if err != nil { if err != nil {
return common.InternalError(err, w, r) return common.InternalError(err, w, r)
}
} }
log.Print("Activating plugin '" + plugin.Name + "'") log.Printf("Activating plugin '%s'", plugin.Name)
plugin.Active = true plugin.Active = true
common.Plugins[uname] = plugin common.Plugins[uname] = plugin
err = common.Plugins[uname].Init() err = common.Plugins[uname].Init()
@ -927,9 +863,6 @@ func routePanelPluginsDeactivate(w http.ResponseWriter, r *http.Request, user co
if !user.Perms.ManagePlugins { if !user.Perms.ManagePlugins {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
plugin, ok := common.Plugins[uname] plugin, ok := common.Plugins[uname]
if !ok { if !ok {
@ -968,9 +901,6 @@ func routePanelPluginsInstall(w http.ResponseWriter, r *http.Request, user commo
if !user.Perms.ManagePlugins { if !user.Perms.ManagePlugins {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
plugin, ok := common.Plugins[uname] plugin, ok := common.Plugins[uname]
if !ok { if !ok {
@ -1096,7 +1026,6 @@ func routePanelUsersEdit(w http.ResponseWriter, r *http.Request, user common.Use
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.EditUser { if !user.Perms.EditUser {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
@ -1155,9 +1084,6 @@ func routePanelUsersEditSubmit(w http.ResponseWriter, r *http.Request, user comm
if !user.Perms.EditUser { if !user.Perms.EditUser {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
uid, err := strconv.Atoi(suid) uid, err := strconv.Atoi(suid)
if err != nil { if err != nil {
@ -1434,9 +1360,6 @@ func routePanelGroupsEditSubmit(w http.ResponseWriter, r *http.Request, user com
if !user.Perms.EditGroup { if !user.Perms.EditGroup {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
gid, err := strconv.Atoi(sgid) gid, err := strconv.Atoi(sgid)
if err != nil { if err != nil {
@ -1527,9 +1450,6 @@ func routePanelGroupsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use
if !user.Perms.EditGroup { if !user.Perms.EditGroup {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
gid, err := strconv.Atoi(sgid) gid, err := strconv.Atoi(sgid)
if err != nil { if err != nil {
@ -1551,7 +1471,6 @@ func routePanelGroupsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use
return common.LocalError("You need the EditGroupSuperMod permission to edit a super-mod group.", w, r, user) return common.LocalError("You need the EditGroupSuperMod permission to edit a super-mod group.", w, r, user)
} }
////var lpmap map[string]bool = make(map[string]bool)
var pmap = make(map[string]bool) var pmap = make(map[string]bool)
if user.Perms.EditGroupLocalPerms { if user.Perms.EditGroupLocalPerms {
for _, perm := range common.LocalPermList { for _, perm := range common.LocalPermList {
@ -1560,7 +1479,6 @@ func routePanelGroupsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use
} }
} }
////var gpmap map[string]bool = make(map[string]bool)
if user.Perms.EditGroupGlobalPerms { if user.Perms.EditGroupGlobalPerms {
for _, perm := range common.GlobalPermList { for _, perm := range common.GlobalPermList {
pvalue := r.PostFormValue("group-perm-" + perm) pvalue := r.PostFormValue("group-perm-" + perm)
@ -1593,9 +1511,6 @@ func routePanelGroupsCreateSubmit(w http.ResponseWriter, r *http.Request, user c
if !user.Perms.EditGroup { if !user.Perms.EditGroup {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
groupName := r.PostFormValue("group-name") groupName := r.PostFormValue("group-name")
if groupName == "" { if groupName == "" {
@ -1673,9 +1588,6 @@ func routePanelThemesSetDefault(w http.ResponseWriter, r *http.Request, user com
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return common.NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
if r.FormValue("session") != user.Session {
return common.SecurityError(w, r, user)
}
theme, ok := common.Themes[uname] theme, ok := common.Themes[uname]
if !ok { if !ok {
@ -1686,7 +1598,6 @@ func routePanelThemesSetDefault(w http.ResponseWriter, r *http.Request, user com
} }
var isDefault bool var isDefault bool
log.Print("uname", uname) // TODO: Do we need to log this?
err := stmts.isThemeDefault.QueryRow(uname).Scan(&isDefault) err := stmts.isThemeDefault.QueryRow(uname).Scan(&isDefault)
if err != nil && err != ErrNoRows { if err != nil && err != ErrNoRows {
return common.InternalError(err, w, r) return common.InternalError(err, w, r)
@ -1694,19 +1605,15 @@ func routePanelThemesSetDefault(w http.ResponseWriter, r *http.Request, user com
hasTheme := err != ErrNoRows hasTheme := err != ErrNoRows
if hasTheme { if hasTheme {
log.Print("isDefault", isDefault) // TODO: Do we need to log this?
if isDefault { if isDefault {
return common.LocalError("The theme is already active", w, r, user) return common.LocalError("The theme is already active", w, r, user)
} }
_, err = stmts.updateTheme.Exec(1, uname) _, err = stmts.updateTheme.Exec(1, uname)
if err != nil {
return common.InternalError(err, w, r)
}
} else { } else {
_, err := stmts.addTheme.Exec(uname, 1) _, err = stmts.addTheme.Exec(uname, 1)
if err != nil { }
return common.InternalError(err, w, r) if err != nil {
} return common.InternalError(err, w, r)
} }
// TODO: Make this less racey // TODO: Make this less racey
@ -1908,9 +1815,6 @@ func routePanelDebug(w http.ResponseWriter, r *http.Request, user common.User) c
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.IsAdmin {
return common.NoPermissions(w, r, user)
}
uptime := "..." uptime := "..."
dbStats := db.Stats() dbStats := db.Stats()

View File

@ -271,6 +271,14 @@ func (selectItem *selectBuilder) Prepare() *sql.Stmt {
return selectItem.build.SimpleSelect(selectItem.table, selectItem.columns, selectItem.where, selectItem.orderby, selectItem.limit) return selectItem.build.SimpleSelect(selectItem.table, selectItem.columns, selectItem.where, selectItem.orderby, selectItem.limit)
} }
func (selectItem *selectBuilder) Query(args ...interface{}) (*sql.Rows, error) {
stmt := selectItem.Prepare()
if stmt != nil {
return stmt.Query(args...)
}
return nil, selectItem.FirstError()
}
func (build *accBuilder) Insert(table string) *insertBuilder { func (build *accBuilder) Insert(table string) *insertBuilder {
return &insertBuilder{table, "", "", build} return &insertBuilder{table, "", "", build}
} }

View File

@ -62,45 +62,45 @@ func buildPanelRoutes() {
panelGroup.Routes( panelGroup.Routes(
Route("routePanel", "/panel/"), Route("routePanel", "/panel/"),
Route("routePanelForums", "/panel/forums/"), Route("routePanelForums", "/panel/forums/"),
Route("routePanelForumsCreateSubmit", "/panel/forums/create/"), Route("routePanelForumsCreateSubmit", "/panel/forums/create/").Before("NoSessionMismatch"),
Route("routePanelForumsDelete", "/panel/forums/delete/", "extra_data"), Route("routePanelForumsDelete", "/panel/forums/delete/", "extra_data").Before("NoSessionMismatch"),
Route("routePanelForumsDeleteSubmit", "/panel/forums/delete/submit/", "extra_data"), Route("routePanelForumsDeleteSubmit", "/panel/forums/delete/submit/", "extra_data").Before("NoSessionMismatch"),
Route("routePanelForumsEdit", "/panel/forums/edit/", "extra_data"), Route("routePanelForumsEdit", "/panel/forums/edit/", "extra_data"),
Route("routePanelForumsEditSubmit", "/panel/forums/edit/submit/", "extra_data"), Route("routePanelForumsEditSubmit", "/panel/forums/edit/submit/", "extra_data").Before("NoSessionMismatch"),
Route("routePanelForumsEditPermsSubmit", "/panel/forums/edit/perms/submit/", "extra_data"), Route("routePanelForumsEditPermsSubmit", "/panel/forums/edit/perms/submit/", "extra_data").Before("NoSessionMismatch"),
Route("routePanelSettings", "/panel/settings/"), Route("routePanelSettings", "/panel/settings/"),
Route("routePanelSetting", "/panel/settings/edit/", "extra_data"), Route("routePanelSetting", "/panel/settings/edit/", "extra_data"),
Route("routePanelSettingEdit", "/panel/settings/edit/submit/", "extra_data"), Route("routePanelSettingEdit", "/panel/settings/edit/submit/", "extra_data").Before("NoSessionMismatch"),
Route("routePanelWordFilters", "/panel/settings/word-filters/"), Route("routePanelWordFilters", "/panel/settings/word-filters/"),
Route("routePanelWordFiltersCreate", "/panel/settings/word-filters/create/"), Route("routePanelWordFiltersCreate", "/panel/settings/word-filters/create/").Before("ParseForm"),
Route("routePanelWordFiltersEdit", "/panel/settings/word-filters/edit/", "extra_data"), Route("routePanelWordFiltersEdit", "/panel/settings/word-filters/edit/", "extra_data"),
Route("routePanelWordFiltersEditSubmit", "/panel/settings/word-filters/edit/submit/", "extra_data"), Route("routePanelWordFiltersEditSubmit", "/panel/settings/word-filters/edit/submit/", "extra_data").Before("ParseForm"),
Route("routePanelWordFiltersDeleteSubmit", "/panel/settings/word-filters/delete/submit/", "extra_data"), Route("routePanelWordFiltersDeleteSubmit", "/panel/settings/word-filters/delete/submit/", "extra_data").Before("ParseForm"),
Route("routePanelThemes", "/panel/themes/"), Route("routePanelThemes", "/panel/themes/"),
Route("routePanelThemesSetDefault", "/panel/themes/default/", "extra_data"), Route("routePanelThemesSetDefault", "/panel/themes/default/", "extra_data").Before("NoSessionMismatch"),
Route("routePanelPlugins", "/panel/plugins/"), Route("routePanelPlugins", "/panel/plugins/"),
Route("routePanelPluginsActivate", "/panel/plugins/activate/", "extra_data"), Route("routePanelPluginsActivate", "/panel/plugins/activate/", "extra_data").Before("NoSessionMismatch"),
Route("routePanelPluginsDeactivate", "/panel/plugins/deactivate/", "extra_data"), Route("routePanelPluginsDeactivate", "/panel/plugins/deactivate/", "extra_data").Before("NoSessionMismatch"),
Route("routePanelPluginsInstall", "/panel/plugins/install/", "extra_data"), Route("routePanelPluginsInstall", "/panel/plugins/install/", "extra_data").Before("NoSessionMismatch"),
Route("routePanelUsers", "/panel/users/"), Route("routePanelUsers", "/panel/users/"),
Route("routePanelUsersEdit", "/panel/users/edit/", "extra_data"), Route("routePanelUsersEdit", "/panel/users/edit/", "extra_data"),
Route("routePanelUsersEditSubmit", "/panel/users/edit/submit/", "extra_data"), Route("routePanelUsersEditSubmit", "/panel/users/edit/submit/", "extra_data").Before("NoSessionMismatch"),
Route("routePanelGroups", "/panel/groups/"), Route("routePanelGroups", "/panel/groups/"),
Route("routePanelGroupsEdit", "/panel/groups/edit/", "extra_data"), Route("routePanelGroupsEdit", "/panel/groups/edit/", "extra_data"),
Route("routePanelGroupsEditPerms", "/panel/groups/edit/perms/", "extra_data"), Route("routePanelGroupsEditPerms", "/panel/groups/edit/perms/", "extra_data"),
Route("routePanelGroupsEditSubmit", "/panel/groups/edit/submit/", "extra_data"), Route("routePanelGroupsEditSubmit", "/panel/groups/edit/submit/", "extra_data").Before("NoSessionMismatch"),
Route("routePanelGroupsEditPermsSubmit", "/panel/groups/edit/perms/submit/", "extra_data"), Route("routePanelGroupsEditPermsSubmit", "/panel/groups/edit/perms/submit/", "extra_data").Before("NoSessionMismatch"),
Route("routePanelGroupsCreateSubmit", "/panel/groups/create/"), Route("routePanelGroupsCreateSubmit", "/panel/groups/create/").Before("NoSessionMismatch"),
Route("routePanelBackups", "/panel/backups/", "extra_data"), Route("routePanelBackups", "/panel/backups/", "extra_data"),
Route("routePanelLogsMod", "/panel/logs/mod/"), Route("routePanelLogsMod", "/panel/logs/mod/"),
Route("routePanelDebug", "/panel/debug/"), Route("routePanelDebug", "/panel/debug/").Before("AdminOnly"),
) )
addRouteGroup(panelGroup) addRouteGroup(panelGroup)
} }

View File

@ -202,6 +202,7 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user common.User) commo
if err != nil { if err != nil {
return common.InternalError(err, w, r) return common.InternalError(err, w, r)
} }
defer topicCountStmt.Close()
var topicCount int var topicCount int
err = topicCountStmt.QueryRow(argList...).Scan(&topicCount) err = topicCountStmt.QueryRow(argList...).Scan(&topicCount)
@ -229,6 +230,7 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user common.User) commo
if err != nil { if err != nil {
return common.InternalError(err, w, r) return common.InternalError(err, w, r)
} }
defer stmt.Close()
argList = append(argList, offset) argList = append(argList, offset)
argList = append(argList, common.Config.ItemsPerPage) argList = append(argList, common.Config.ItemsPerPage)