diff --git a/alerts.go b/alerts.go index 2b3d596c..137dba58 100644 --- a/alerts.go +++ b/alerts.go @@ -6,10 +6,14 @@ */ package main -import "log" -import "strings" -import "strconv" -import "errors" +import ( + "errors" + "log" + "strconv" + "strings" + + "./common" +) // These notes are for me, don't worry about it too much ^_^ /* @@ -26,10 +30,10 @@ import "errors" "{x}{created a new topic}{topic}" */ -func buildAlert(asid int, event string, elementType string, actorID int, targetUserID int, elementID int, user User /* The current user */) (string, error) { - var targetUser *User +func buildAlert(asid int, event string, elementType string, actorID int, targetUserID int, elementID int, user common.User /* The current user */) (string, error) { + var targetUser *common.User - actor, err := users.Get(actorID) + actor, err := common.Users.Get(actorID) if err != nil { return "", errors.New("Unable to find the actor") } @@ -52,7 +56,7 @@ func buildAlert(asid int, event string, elementType string, actorID int, targetU case "forum": if event == "reply" { act = "created a new topic" - topic, err := topics.Get(elementID) + topic, err := common.Topics.Get(elementID) if err != nil { return "", errors.New("Unable to find the linked topic") } @@ -64,7 +68,7 @@ func buildAlert(asid int, event string, elementType string, actorID int, targetU act = "did something in a forum" } case "topic": - topic, err := topics.Get(elementID) + topic, err := common.Topics.Get(elementID) if err != nil { return "", errors.New("Unable to find the linked topic") } @@ -75,7 +79,7 @@ func buildAlert(asid int, event string, elementType string, actorID int, targetU postAct = " your topic" } case "user": - targetUser, err = users.Get(elementID) + targetUser, err = common.Users.Get(elementID) if err != nil { return "", errors.New("Unable to find the target user") } @@ -83,7 +87,9 @@ func buildAlert(asid int, event string, elementType string, actorID int, targetU endFrag = "'s profile" url = targetUser.Link case "post": - topic, err := getTopicByReply(elementID) + reply := common.BlankReply() + reply.ID = elementID + topic, err := reply.Topic() if err != nil { return "", errors.New("Unable to find the linked reply or parent topic") } diff --git a/auth.go b/common/auth.go similarity index 83% rename from auth.go rename to common/auth.go index 306a6591..72f63c6c 100644 --- a/auth.go +++ b/common/auth.go @@ -4,18 +4,17 @@ * Copyright Azareal 2017 - 2018 * */ -package main +package common -import "log" import "errors" import "strconv" import "net/http" import "database/sql" -import "./query_gen/lib" import "golang.org/x/crypto/bcrypt" +import "../query_gen/lib" -var auth Auth +var Auth AuthInt // ErrMismatchedHashAndPassword is thrown whenever a hash doesn't match it's unhashed password var ErrMismatchedHashAndPassword = bcrypt.ErrMismatchedHashAndPassword @@ -27,8 +26,8 @@ var ErrWrongPassword = errors.New("That's not the correct password.") var ErrSecretError = errors.New("There was a glitch in the system. Please contact your local administrator.") var ErrNoUserByName = errors.New("We couldn't find an account with that username.") -// Auth is the main authentication interface. -type Auth interface { +// AuthInt is the main authentication interface. +type AuthInt interface { Authenticate(username string, password string) (uid int, err error) Logout(w http.ResponseWriter, uid int) ForceLogout(uid int) error @@ -40,24 +39,19 @@ type Auth interface { // DefaultAuth is the default authenticator used by Gosora, may be swapped with an alternate authenticator in some situations. E.g. To support LDAP. type DefaultAuth struct { - login *sql.Stmt - logout *sql.Stmt + login *sql.Stmt + logout *sql.Stmt + updateSession *sql.Stmt } // NewDefaultAuth is a factory for spitting out DefaultAuths -func NewDefaultAuth() *DefaultAuth { - loginStmt, err := qgen.Builder.SimpleSelect("users", "uid, password, salt", "name = ?", "", "") - if err != nil { - log.Fatal(err) - } - logoutStmt, err := qgen.Builder.SimpleUpdate("users", "session = ''", "uid = ?") - if err != nil { - log.Fatal(err) - } +func NewDefaultAuth() (*DefaultAuth, error) { + acc := qgen.Builder.Accumulator() return &DefaultAuth{ - login: loginStmt, - logout: logoutStmt, - } + login: acc.SimpleSelect("users", "uid, password, salt", "name = ?", "", ""), + logout: acc.SimpleUpdate("users", "session = ''", "uid = ?"), + updateSession: acc.SimpleUpdate("users", "session = ?", "uid = ?"), + }, acc.FirstError() } // Authenticate checks if a specific username and password is valid and returns the UID for the corresponding user, if so. Otherwise, a user safe error. @@ -97,7 +91,7 @@ func (auth *DefaultAuth) ForceLogout(uid int) error { } // Flush the user out of the cache - ucache, ok := users.(UserCache) + ucache, ok := Users.(UserCache) if ok { ucache.CacheRemove(uid) } @@ -107,18 +101,18 @@ func (auth *DefaultAuth) ForceLogout(uid int) error { // Logout logs you out of the computer you requested the logout for, but not the other computers you're logged in with func (auth *DefaultAuth) Logout(w http.ResponseWriter, _ int) { - cookie := http.Cookie{Name: "uid", Value: "", Path: "/", MaxAge: year} + cookie := http.Cookie{Name: "uid", Value: "", Path: "/", MaxAge: Year} http.SetCookie(w, &cookie) - cookie = http.Cookie{Name: "session", Value: "", Path: "/", MaxAge: year} + cookie = http.Cookie{Name: "session", Value: "", Path: "/", MaxAge: Year} http.SetCookie(w, &cookie) } // TODO: Set the cookie domain // SetCookies sets the two cookies required for the current user to be recognised as a specific user in future requests func (auth *DefaultAuth) SetCookies(w http.ResponseWriter, uid int, session string) { - cookie := http.Cookie{Name: "uid", Value: strconv.Itoa(uid), Path: "/", MaxAge: year} + cookie := http.Cookie{Name: "uid", Value: strconv.Itoa(uid), Path: "/", MaxAge: Year} http.SetCookie(w, &cookie) - cookie = http.Cookie{Name: "session", Value: session, Path: "/", MaxAge: year} + cookie = http.Cookie{Name: "session", Value: session, Path: "/", MaxAge: Year} http.SetCookie(w, &cookie) } @@ -144,20 +138,20 @@ func (auth *DefaultAuth) GetCookies(r *http.Request) (uid int, session string, e func (auth *DefaultAuth) SessionCheck(w http.ResponseWriter, r *http.Request) (user *User, halt bool) { uid, session, err := auth.GetCookies(r) if err != nil { - return &guestUser, false + return &GuestUser, false } // Is this session valid..? - user, err = users.Get(uid) + user, err = Users.Get(uid) if err == ErrNoRows { - return &guestUser, false + return &GuestUser, false } else if err != nil { InternalError(err, w, r) - return &guestUser, true + return &GuestUser, true } if user.Session == "" || session != user.Session { - return &guestUser, false + return &GuestUser, false } return user, false @@ -165,18 +159,18 @@ func (auth *DefaultAuth) SessionCheck(w http.ResponseWriter, r *http.Request) (u // CreateSession generates a new session to allow a remote client to stay logged in as a specific user func (auth *DefaultAuth) CreateSession(uid int) (session string, err error) { - session, err = GenerateSafeString(sessionLength) + session, err = GenerateSafeString(SessionLength) if err != nil { return "", err } - _, err = stmts.updateSession.Exec(session, uid) + _, err = auth.updateSession.Exec(session, uid) if err != nil { return "", err } // Flush the user data from the cache - ucache, ok := users.(UserCache) + ucache, ok := Users.(UserCache) if ok { ucache.CacheRemove(uid) } diff --git a/cache.go b/common/cache.go similarity index 89% rename from cache.go rename to common/cache.go index 2ea4bc71..849fd925 100644 --- a/cache.go +++ b/common/cache.go @@ -1,4 +1,4 @@ -package main +package common import "errors" @@ -17,10 +17,10 @@ var ErrStoreCapacityOverflow = errors.New("This datastore has reached it's maxim // nolint type DataStore interface { - Load(id int) error + DirtyGet(id int) interface{} Get(id int) (interface{}, error) BypassGet(id int) (interface{}, error) - //GetGlobalCount() + //GlobalCount() } // nolint @@ -32,6 +32,9 @@ type DataCache interface { CacheAddUnsafe(item interface{}) error CacheRemove(id int) error CacheRemoveUnsafe(id int) error - GetLength() int + Reload(id int) error + Flush() + Length() int + SetCapacity(capacity int) GetCapacity() int } diff --git a/common/common.go b/common/common.go index 5fa8e013..288796b1 100644 --- a/common/common.go +++ b/common/common.go @@ -2,5 +2,78 @@ package common import "database/sql" +// nolint I don't want to write comments for each of these o.o +const Hour int = 60 * 60 +const Day int = Hour * 24 +const Week int = Day * 7 +const Month int = Day * 30 +const Year int = Day * 365 +const Kilobyte int = 1024 +const Megabyte int = Kilobyte * 1024 +const Gigabyte int = Megabyte * 1024 +const Terabyte int = Gigabyte * 1024 +const Petabyte int = Terabyte * 1024 + +const SaltLength int = 32 +const SessionLength int = 80 + +var TmplPtrMap = make(map[string]interface{}) + // ErrNoRows is an alias of sql.ErrNoRows, just in case we end up with non-database/sql datastores var ErrNoRows = sql.ErrNoRows + +// ? - Make this more customisable? +var ExternalSites = map[string]string{ + "YT": "https://www.youtube.com/", +} + +type StringList []string + +// ? - Should we allow users to upload .php or .go files? It could cause security issues. We could store them with a mangled extension to render them inert +// TODO: Let admins manage this from the Control Panel +var AllowedFileExts = StringList{ + "png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp", "apng", // images + + "txt", "xml", "json", "yaml", "toml", "ini", "md", "html", "rtf", "js", "py", "rb", "css", "scss", "less", "eqcss", "pcss", "java", "ts", "cs", "c", "cc", "cpp", "cxx", "C", "c++", "h", "hh", "hpp", "hxx", "h++", "rs", "rlib", "htaccess", "gitignore", // text + + "mp3", "mp4", "avi", "wmv", "webm", // video + + "otf", "woff2", "woff", "ttf", "eot", // fonts +} +var ImageFileExts = StringList{ + "png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp", "apng", +} +var ArchiveFileExts = StringList{ + "bz2", "zip", "gz", "7z", "tar", "cab", +} +var ExecutableFileExts = StringList{ + "exe", "jar", "phar", "shar", "iso", +} + +// TODO: Write a test for this +func (slice StringList) Contains(needle string) bool { + for _, item := range slice { + if item == needle { + return true + } + } + return false +} + +type DBInits []func() error + +var DbInits DBInits + +func (inits DBInits) Run() error { + for _, init := range inits { + err := init() + if err != nil { + return err + } + } + return nil +} + +func (inits DBInits) Add(init ...func() error) { + inits = append(inits, init...) +} diff --git a/common/email.go b/common/email.go new file mode 100644 index 00000000..38ba2207 --- /dev/null +++ b/common/email.go @@ -0,0 +1,73 @@ +package common + +import ( + "fmt" + "net/smtp" +) + +type Email struct { + UserID int + Email string + Validated bool + Primary bool + Token string +} + +func SendValidationEmail(username string, email string, token string) bool { + var schema = "http" + if Site.EnableSsl { + schema += "s" + } + + // TODO: Move these to the phrase system + subject := "Validate Your Email @ " + Site.Name + msg := "Dear " + username + ", following your registration on our forums, we ask you to validate your email, so that we can confirm that this email actually belongs to you.\n\nClick on the following link to do so. " + schema + "://" + Site.URL + "/user/edit/token/" + token + "\n\nIf you haven't created an account here, then please feel free to ignore this email.\nWe're sorry for the inconvenience this may have caused." + return SendEmail(email, subject, msg) +} + +// TODO: Refactor this +func SendEmail(email string, subject string, msg string) bool { + // This hook is useful for plugin_sendmail or for testing tools. Possibly to hook it into some sort of mail server? + if Vhooks["email_send_intercept"] != nil { + return Vhooks["email_send_intercept"](email, subject, msg).(bool) + } + body := "Subject: " + subject + "\n\n" + msg + "\n" + + con, err := smtp.Dial(Config.SMTPServer + ":" + Config.SMTPPort) + if err != nil { + return false + } + + if Config.SMTPUsername != "" { + auth := smtp.PlainAuth("", Config.SMTPUsername, Config.SMTPPassword, Config.SMTPServer) + err = con.Auth(auth) + if err != nil { + return false + } + } + + err = con.Mail(Site.Email) + if err != nil { + return false + } + err = con.Rcpt(email) + if err != nil { + return false + } + + emailData, err := con.Data() + if err != nil { + return false + } + _, err = fmt.Fprintf(emailData, body) + if err != nil { + return false + } + + err = emailData.Close() + if err != nil { + return false + } + err = con.Quit() + return err == nil +} diff --git a/common/errors.go b/common/errors.go index c29744a1..7b5efec5 100644 --- a/common/errors.go +++ b/common/errors.go @@ -21,7 +21,7 @@ var tList []interface{} type RouteError interface { Type() string Error() string - Json() bool + JSON() bool Handled() bool } @@ -49,7 +49,7 @@ func (err *RouteErrorImpl) Error() string { } // Respond with JSON? -func (err *RouteErrorImpl) Json() bool { +func (err *RouteErrorImpl) JSON() bool { return err.json } @@ -86,7 +86,7 @@ func InternalError(err error, w http.ResponseWriter, r *http.Request) RouteError // TODO: Centralise the user struct somewhere else user := User{0, "guest", "Guest", "", 0, false, false, false, false, false, false, GuestPerms, nil, "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0} pi := Page{"Internal Server Error", user, DefaultHeaderVar(), tList, "A problem has occurred in the system."} - err = templates.ExecuteTemplate(w, "error.html", pi) + err = Templates.ExecuteTemplate(w, "error.html", pi) if err != nil { log.Print(err) } @@ -119,33 +119,16 @@ func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) RouteErr return HandledRouteError() } -// ? - Where is this used? Should we use it more? -// LoginRequired is an error shown to the end-user when they try to access an area which requires them to login -func LoginRequired(w http.ResponseWriter, r *http.Request, user User) RouteError { - w.WriteHeader(401) - pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You need to login to do that."} - if preRenderHooks["pre_render_error"] != nil { - if runPreRenderHook("pre_render_error", w, r, &user, &pi) { - return nil - } - } - err := templates.ExecuteTemplate(w, "error.html", pi) - if err != nil { - LogError(err) - } - return HandledRouteError() -} - func PreError(errmsg string, w http.ResponseWriter, r *http.Request) RouteError { w.WriteHeader(500) user := User{ID: 0, Group: 6, Perms: GuestPerms} pi := Page{"Error", user, DefaultHeaderVar(), tList, errmsg} - if preRenderHooks["pre_render_error"] != nil { - if runPreRenderHook("pre_render_error", w, r, &user, &pi) { + if PreRenderHooks["pre_render_error"] != nil { + if RunPreRenderHook("pre_render_error", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "error.html", pi) + err := Templates.ExecuteTemplate(w, "error.html", pi) if err != nil { LogError(err) } @@ -169,12 +152,12 @@ func PreErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, isJs boo func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User) RouteError { w.WriteHeader(500) pi := Page{"Local Error", user, DefaultHeaderVar(), tList, errmsg} - if preRenderHooks["pre_render_error"] != nil { - if runPreRenderHook("pre_render_error", w, r, &user, &pi) { + if PreRenderHooks["pre_render_error"] != nil { + if RunPreRenderHook("pre_render_error", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "error.html", pi) + err := Templates.ExecuteTemplate(w, "error.html", pi) if err != nil { LogError(err) } @@ -200,12 +183,12 @@ func NoPermissions(w http.ResponseWriter, r *http.Request, user User) RouteError w.WriteHeader(403) pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You don't have permission to do that."} // TODO: What to do about this hook? - if preRenderHooks["pre_render_error"] != nil { - if runPreRenderHook("pre_render_error", w, r, &user, &pi) { + if PreRenderHooks["pre_render_error"] != nil { + if RunPreRenderHook("pre_render_error", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "error.html", pi) + err := Templates.ExecuteTemplate(w, "error.html", pi) if err != nil { LogError(err) } @@ -229,12 +212,12 @@ func NoPermissionsJS(w http.ResponseWriter, r *http.Request, user User) RouteErr func Banned(w http.ResponseWriter, r *http.Request, user User) RouteError { w.WriteHeader(403) pi := Page{"Banned", user, DefaultHeaderVar(), tList, "You have been banned from this site."} - if preRenderHooks["pre_render_error"] != nil { - if runPreRenderHook("pre_render_error", w, r, &user, &pi) { + if PreRenderHooks["pre_render_error"] != nil { + if RunPreRenderHook("pre_render_error", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "error.html", pi) + err := Templates.ExecuteTemplate(w, "error.html", pi) if err != nil { LogError(err) } @@ -258,21 +241,33 @@ func BannedJS(w http.ResponseWriter, r *http.Request, user User) RouteError { // nolint func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) RouteError { - w.WriteHeader(401) if !isJs { - pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You need to login to do that."} - if preRenderHooks["pre_render_error"] != nil { - if runPreRenderHook("pre_render_error", w, r, &user, &pi) { - return nil - } - } - err := templates.ExecuteTemplate(w, "error.html", pi) - if err != nil { - LogError(err) - } - } else { - _, _ = w.Write([]byte(`{"errmsg":"You need to login to do that."}`)) + return LoginRequired(w, r, user) } + return LoginRequiredJS(w, r, user) +} + +// ? - Where is this used? Should we use it more? +// LoginRequired is an error shown to the end-user when they try to access an area which requires them to login +func LoginRequired(w http.ResponseWriter, r *http.Request, user User) RouteError { + w.WriteHeader(401) + pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You need to login to do that."} + if PreRenderHooks["pre_render_error"] != nil { + if RunPreRenderHook("pre_render_error", w, r, &user, &pi) { + return nil + } + } + err := Templates.ExecuteTemplate(w, "error.html", pi) + if err != nil { + LogError(err) + } + return HandledRouteError() +} + +// nolint +func LoginRequiredJS(w http.ResponseWriter, r *http.Request, user User) RouteError { + w.WriteHeader(401) + _, _ = w.Write([]byte(`{"errmsg":"You need to login to do that."}`)) return HandledRouteError() } @@ -281,12 +276,12 @@ func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bo func SecurityError(w http.ResponseWriter, r *http.Request, user User) RouteError { w.WriteHeader(403) pi := Page{"Security Error", user, DefaultHeaderVar(), tList, "There was a security issue with your request."} - if preRenderHooks["pre_render_security_error"] != nil { - if runPreRenderHook("pre_render_security_error", w, r, &user, &pi) { + if PreRenderHooks["pre_render_security_error"] != nil { + if RunPreRenderHook("pre_render_security_error", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "error.html", pi) + err := Templates.ExecuteTemplate(w, "error.html", pi) if err != nil { LogError(err) } @@ -301,7 +296,7 @@ func NotFound(w http.ResponseWriter, r *http.Request) RouteError { // TODO: Centralise the user struct somewhere else user := User{0, "guest", "Guest", "", 0, false, false, false, false, false, false, GuestPerms, nil, "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0} pi := Page{"Not Found", user, DefaultHeaderVar(), tList, "The requested page doesn't exist."} - err := templates.ExecuteTemplate(w, "error.html", pi) + err := Templates.ExecuteTemplate(w, "error.html", pi) if err != nil { LogError(err) } @@ -312,12 +307,12 @@ func NotFound(w http.ResponseWriter, r *http.Request) RouteError { func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) RouteError { w.WriteHeader(errcode) pi := Page{errtitle, user, DefaultHeaderVar(), tList, errmsg} - if preRenderHooks["pre_render_error"] != nil { - if runPreRenderHook("pre_render_error", w, r, &user, &pi) { + if PreRenderHooks["pre_render_error"] != nil { + if RunPreRenderHook("pre_render_error", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "error.html", pi) + err := Templates.ExecuteTemplate(w, "error.html", pi) if err != nil { LogError(err) } diff --git a/common/extend.go b/common/extend.go index 3016631e..c6a06f94 100644 --- a/common/extend.go +++ b/common/extend.go @@ -18,13 +18,13 @@ type PluginList map[string]*Plugin var Plugins PluginList = make(map[string]*Plugin) // Hooks with a single argument. Is this redundant? Might be useful for inlining, as variadics aren't inlined? Are closures even inlined to begin with? -var hooks = map[string][]func(interface{}) interface{}{ +var Hooks = map[string][]func(interface{}) interface{}{ "forums_frow_assign": nil, "topic_create_frow_assign": nil, } // Hooks with a variable number of arguments -var vhooks = map[string]func(...interface{}) interface{}{ +var Vhooks = map[string]func(...interface{}) interface{}{ "intercept_build_widgets": nil, "forum_trow_assign": nil, "topics_topic_row_assign": nil, @@ -35,7 +35,7 @@ var vhooks = map[string]func(...interface{}) interface{}{ } // Hooks with a variable number of arguments and return values for skipping the parent function and propagating an error upwards -var vhookSkippable = map[string]func(...interface{}) (bool, RouteError){ +var VhookSkippable = map[string]func(...interface{}) (bool, RouteError){ "simple_forum_check_pre_perms": nil, "forum_check_pre_perms": nil, } @@ -65,13 +65,13 @@ var messageHooks = map[string][]func(Message, PageInt, ...interface{}) interface } // Hooks which take in and spit out a string. This is usually used for parser components -var sshooks = map[string][]func(string) string{ +var Sshooks = map[string][]func(string) string{ "preparse_preassign": nil, "parse_assign": nil, } // The hooks which run before the template is rendered for a route -var preRenderHooks = map[string][]func(http.ResponseWriter, *http.Request, *User, interface{}) bool{ +var PreRenderHooks = map[string][]func(http.ResponseWriter, *http.Request, *User, interface{}) bool{ "pre_render": nil, "pre_render_forum_list": nil, @@ -137,7 +137,7 @@ type Plugin struct { Data interface{} // Usually used for hosting the VMs / reusable elements of non-native plugins } -func initExtend() (err error) { +func InitExtend() (err error) { err = InitPluginLangs() if err != nil { return err @@ -145,7 +145,7 @@ func initExtend() (err error) { return Plugins.Load() } -// LoadPlugins 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 { getPlugins, err := qgen.Builder.SimpleSelect("plugins", "uname, active, installed", "", "", "") if err != nil { @@ -206,37 +206,37 @@ func NewPlugin(uname string, name string, author string, url string, settings st func (plugin *Plugin) AddHook(name string, handler interface{}) { switch h := handler.(type) { case func(interface{}) interface{}: - if len(hooks[name]) == 0 { + if len(Hooks[name]) == 0 { var hookSlice []func(interface{}) interface{} hookSlice = append(hookSlice, h) - hooks[name] = hookSlice + Hooks[name] = hookSlice } else { - hooks[name] = append(hooks[name], h) + Hooks[name] = append(Hooks[name], h) } - plugin.Hooks[name] = len(hooks[name]) + plugin.Hooks[name] = len(Hooks[name]) case func(string) string: - if len(sshooks[name]) == 0 { + if len(Sshooks[name]) == 0 { var hookSlice []func(string) string hookSlice = append(hookSlice, h) - sshooks[name] = hookSlice + Sshooks[name] = hookSlice } else { - sshooks[name] = append(sshooks[name], h) + Sshooks[name] = append(Sshooks[name], h) } - plugin.Hooks[name] = len(sshooks[name]) + plugin.Hooks[name] = len(Sshooks[name]) case func(http.ResponseWriter, *http.Request, *User, interface{}) bool: - if len(preRenderHooks[name]) == 0 { + if len(PreRenderHooks[name]) == 0 { var hookSlice []func(http.ResponseWriter, *http.Request, *User, interface{}) bool hookSlice = append(hookSlice, h) - preRenderHooks[name] = hookSlice + PreRenderHooks[name] = hookSlice } else { - preRenderHooks[name] = append(preRenderHooks[name], h) + PreRenderHooks[name] = append(PreRenderHooks[name], h) } - plugin.Hooks[name] = len(preRenderHooks[name]) + plugin.Hooks[name] = len(PreRenderHooks[name]) case func(...interface{}) interface{}: - vhooks[name] = h + Vhooks[name] = h plugin.Hooks[name] = 0 case func(...interface{}) (bool, RouteError): - vhookSkippable[name] = h + VhookSkippable[name] = h plugin.Hooks[name] = 0 default: panic("I don't recognise this kind of handler!") // Should this be an error for the plugin instead of a panic()? @@ -248,35 +248,35 @@ func (plugin *Plugin) RemoveHook(name string, handler interface{}) { switch handler.(type) { case func(interface{}) interface{}: key := plugin.Hooks[name] - hook := hooks[name] + hook := Hooks[name] if len(hook) == 1 { hook = []func(interface{}) interface{}{} } else { hook = append(hook[:key], hook[key+1:]...) } - hooks[name] = hook + Hooks[name] = hook case func(string) string: key := plugin.Hooks[name] - hook := sshooks[name] + hook := Sshooks[name] if len(hook) == 1 { hook = []func(string) string{} } else { hook = append(hook[:key], hook[key+1:]...) } - sshooks[name] = hook + Sshooks[name] = hook case func(http.ResponseWriter, *http.Request, *User, interface{}) bool: key := plugin.Hooks[name] - hook := preRenderHooks[name] + hook := PreRenderHooks[name] if len(hook) == 1 { hook = []func(http.ResponseWriter, *http.Request, *User, interface{}) bool{} } else { hook = append(hook[:key], hook[key+1:]...) } - preRenderHooks[name] = hook + PreRenderHooks[name] = hook case func(...interface{}) interface{}: - delete(vhooks, name) + delete(Vhooks, name) case func(...interface{}) (bool, RouteError): - delete(vhookSkippable, name) + delete(VhookSkippable, name) default: panic("I don't recognise this kind of handler!") // Should this be an error for the plugin instead of a panic()? } @@ -285,18 +285,18 @@ func (plugin *Plugin) RemoveHook(name string, handler interface{}) { var pluginsInited = false -func initPlugins() { +func InitPlugins() { for name, body := range Plugins { - log.Print("Added plugin " + name) + log.Printf("Added plugin %s", name) if body.Active { - log.Print("Initialised plugin " + name) + log.Printf("Initialised plugin %s", name) if Plugins[name].Init != nil { err := Plugins[name].Init() if err != nil { log.Print(err) } } else { - log.Print("Plugin " + name + " doesn't have an initialiser.") + log.Printf("Plugin %s doesn't have an initialiser.", name) } } } @@ -304,49 +304,49 @@ func initPlugins() { } // ? - Are the following functions racey? -func runHook(name string, data interface{}) interface{} { - for _, hook := range hooks[name] { +func RunHook(name string, data interface{}) interface{} { + for _, hook := range Hooks[name] { data = hook(data) } return data } -func runHookNoreturn(name string, data interface{}) { - for _, hook := range hooks[name] { +func RunHookNoreturn(name string, data interface{}) { + for _, hook := range Hooks[name] { _ = hook(data) } } -func runVhook(name string, data ...interface{}) interface{} { - return vhooks[name](data...) +func RunVhook(name string, data ...interface{}) interface{} { + return Vhooks[name](data...) } -func runVhookSkippable(name string, data ...interface{}) (bool, RouteError) { - return vhookSkippable[name](data...) +func RunVhookSkippable(name string, data ...interface{}) (bool, RouteError) { + return VhookSkippable[name](data...) } -func runVhookNoreturn(name string, data ...interface{}) { - _ = vhooks[name](data...) +func RunVhookNoreturn(name string, data ...interface{}) { + _ = Vhooks[name](data...) } // Trying to get a teeny bit of type-safety where-ever possible, especially for such a critical set of hooks -func runSshook(name string, data string) string { - for _, hook := range sshooks[name] { +func RunSshook(name string, data string) string { + for _, hook := range Sshooks[name] { data = hook(data) } return data } -func runPreRenderHook(name string, w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) { +func RunPreRenderHook(name string, w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) { // This hook runs on ALL pre_render hooks - for _, hook := range preRenderHooks["pre_render"] { + for _, hook := range PreRenderHooks["pre_render"] { if hook(w, r, user, data) { return true } } // The actual pre_render hook - for _, hook := range preRenderHooks[name] { + for _, hook := range PreRenderHooks[name] { if hook(w, r, user, data) { return true } diff --git a/files.go b/common/files.go similarity index 69% rename from files.go rename to common/files.go index 3093320a..569f592e 100644 --- a/files.go +++ b/common/files.go @@ -1,4 +1,4 @@ -package main +package common import ( "bytes" @@ -13,6 +13,10 @@ import ( "path/filepath" ) +type SFileList map[string]SFile + +var StaticFiles SFileList = make(map[string]SFile) + type SFile struct { Data []byte GzipData []byte @@ -28,7 +32,7 @@ type CSSData struct { ComingSoon string } -func initStaticFiles() error { +func (list SFileList) Init() error { return filepath.Walk("./public", func(path string, f os.FileInfo, err error) error { if f.IsDir() { return nil @@ -44,16 +48,16 @@ func initStaticFiles() error { var ext = filepath.Ext("/public/" + path) gzipData := compressBytesGzip(data) - staticFiles["/static/"+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)} + list["/static/"+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)} - if dev.DebugMode { + if Dev.DebugMode { log.Print("Added the '" + path + "' static file.") } return nil }) } -func addStaticFile(path string, prefix string) error { +func (list SFileList) Add(path string, prefix string) error { data, err := ioutil.ReadFile(path) if err != nil { return err @@ -71,10 +75,10 @@ func addStaticFile(path string, prefix string) error { path = strings.TrimPrefix(path, prefix) gzipData := compressBytesGzip(data) - staticFiles["/static"+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)} + list["/static"+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)} - if dev.DebugMode { - log.Print("Added the '" + path + "' static file") + if Dev.DebugMode { + log.Printf("Added the '%s' static file", path) } return nil } diff --git a/common/forum.go b/common/forum.go index 83aa340a..a643bb13 100644 --- a/common/forum.go +++ b/common/forum.go @@ -2,12 +2,15 @@ package common //import "fmt" import ( + "database/sql" "strconv" "strings" + "../query_gen/lib" _ "github.com/go-sql-driver/mysql" ) +// TODO: Do we really need this? type ForumAdmin struct { ID int Name string @@ -44,11 +47,25 @@ type ForumSimple struct { Preset string } +type ForumStmts struct { + update *sql.Stmt +} + +var forumStmts ForumStmts + +func init() { + DbInits.Add(func() error { + acc := qgen.Builder.Accumulator() + forumStmts = ForumStmts{ + update: acc.SimpleUpdate("forums", "name = ?, desc = ?, active = ?, preset = ?", "fid = ?"), + } + return acc.FirstError() + }) +} + // Copy gives you a non-pointer concurrency safe copy of the forum func (forum *Forum) Copy() (fcopy Forum) { - //forum.LastLock.RLock() fcopy = *forum - //forum.LastLock.RUnlock() return fcopy } @@ -58,17 +75,17 @@ func (forum *Forum) Update(name string, desc string, active bool, preset string) name = forum.Name } preset = strings.TrimSpace(preset) - _, err := stmts.updateForum.Exec(name, desc, active, preset, forum.ID) + _, err := forumStmts.update.Exec(name, desc, active, preset, forum.ID) if err != nil { return err } if forum.Preset != preset || preset == "custom" || preset == "" { - err = permmapToQuery(presetToPermmap(preset), forum.ID) + err = PermmapToQuery(PresetToPermmap(preset), forum.ID) if err != nil { return err } } - _ = fstore.Reload(forum.ID) + _ = Fstore.Reload(forum.ID) return nil } @@ -91,13 +108,13 @@ func makeDummyForum(fid int, link string, name string, desc string, active bool, return &Forum{ID: fid, Link: link, Name: name, Desc: desc, Active: active, Preset: preset, ParentID: parentID, ParentType: parentType, TopicCount: topicCount} } -func buildForumURL(slug string, fid int) string { +func BuildForumURL(slug string, fid int) string { if slug == "" { return "/forum/" + strconv.Itoa(fid) } return "/forum/" + slug + "." + strconv.Itoa(fid) } -func getForumURLPrefix() string { +func GetForumURLPrefix() string { return "/forum/" } diff --git a/common/forum_perms_store.go b/common/forum_perms_store.go index 81f81372..fa954fad 100644 --- a/common/forum_perms_store.go +++ b/common/forum_perms_store.go @@ -8,7 +8,7 @@ import ( "../query_gen/lib" ) -var fpstore ForumPermsStore +var Fpstore ForumPermsStore type ForumPermsStore interface { Init() error @@ -40,11 +40,11 @@ func NewMemoryForumPermsStore() (*MemoryForumPermsStore, error) { } func (fps *MemoryForumPermsStore) Init() error { - fids, err := fstore.GetAllIDs() + fids, err := Fstore.GetAllIDs() if err != nil { return err } - if dev.SuperDebug { + if Dev.SuperDebug { log.Print("fids: ", fids) } @@ -54,9 +54,9 @@ func (fps *MemoryForumPermsStore) Init() error { } defer rows.Close() - if dev.DebugMode { + if Dev.DebugMode { log.Print("Adding the forum permissions") - if dev.SuperDebug { + if Dev.SuperDebug { log.Print("forumPerms[gid][fid]") } } @@ -72,7 +72,7 @@ func (fps *MemoryForumPermsStore) Init() error { return err } - if dev.SuperDebug { + if Dev.SuperDebug { log.Print("perms: ", string(perms)) } err = json.Unmarshal(perms, &pperms) @@ -86,7 +86,7 @@ func (fps *MemoryForumPermsStore) Init() error { forumPerms[gid] = make(map[int]ForumPerms) } - if dev.SuperDebug { + if Dev.SuperDebug { log.Print("gid: ", gid) log.Print("fid: ", fid) log.Printf("perms: %+v\n", pperms) @@ -99,10 +99,10 @@ func (fps *MemoryForumPermsStore) Init() error { // TODO: Need a more thread-safe way of doing this. Possibly with sync.Map? func (fps *MemoryForumPermsStore) Reload(fid int) error { - if dev.DebugMode { + if Dev.DebugMode { log.Printf("Reloading the forum permissions for forum #%d", fid) } - fids, err := fstore.GetAllIDs() + fids, err := Fstore.GetAllIDs() if err != nil { return err } @@ -138,20 +138,20 @@ func (fps *MemoryForumPermsStore) Reload(fid int) error { } func (fps *MemoryForumPermsStore) cascadePermSetToGroups(forumPerms map[int]map[int]ForumPerms, fids []int) error { - groups, err := gstore.GetAll() + groups, err := Gstore.GetAll() if err != nil { return err } for _, group := range groups { - if dev.DebugMode { + if Dev.DebugMode { log.Printf("Updating the forum permissions for Group #%d", group.ID) } group.Forums = []ForumPerms{BlankForumPerms} group.CanSee = []int{} fps.cascadePermSetToGroup(forumPerms, group, fids) - if dev.SuperDebug { + if Dev.SuperDebug { log.Printf("group.CanSee (length %d): %+v \n", len(group.CanSee), group.CanSee) log.Printf("group.Forums (length %d): %+v\n", len(group.Forums), group.Forums) } @@ -161,12 +161,12 @@ func (fps *MemoryForumPermsStore) cascadePermSetToGroups(forumPerms map[int]map[ func (fps *MemoryForumPermsStore) cascadePermSetToGroup(forumPerms map[int]map[int]ForumPerms, group *Group, fids []int) { for _, fid := range fids { - if dev.SuperDebug { + if Dev.SuperDebug { log.Printf("Forum #%+v\n", fid) } forumPerm, ok := forumPerms[group.ID][fid] if ok { - //log.Print("Overriding permissions for forum #%d",fid) + //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) @@ -181,7 +181,7 @@ func (fps *MemoryForumPermsStore) cascadePermSetToGroup(forumPerms map[int]map[i group.CanSee = append(group.CanSee, fid) } - if dev.SuperDebug { + if Dev.SuperDebug { log.Print("group.ID: ", group.ID) log.Printf("forumPerm: %+v\n", forumPerm) log.Print("group.CanSee: ", group.CanSee) @@ -191,7 +191,7 @@ func (fps *MemoryForumPermsStore) cascadePermSetToGroup(forumPerms map[int]map[i func (fps *MemoryForumPermsStore) Get(fid int, gid int) (fperms ForumPerms, err error) { // TODO: Add a hook here and have plugin_guilds use it - group, err := gstore.Get(gid) + group, err := Gstore.Get(gid) if err != nil { return fperms, ErrNoRows } diff --git a/common/forum_store.go b/common/forum_store.go index 105376bf..4cfbe9bf 100644 --- a/common/forum_store.go +++ b/common/forum_store.go @@ -17,10 +17,10 @@ import ( "../query_gen/lib" ) -var forumUpdateMutex sync.Mutex +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 fstore ForumStore +var Fstore ForumStore // ForumStore is an interface for accessing the forums and the metadata stored on them type ForumStore interface { @@ -110,26 +110,16 @@ func (mfs *MemoryForumStore) LoadForums() error { } if forum.Name == "" { - if dev.DebugMode { + if Dev.DebugMode { log.Print("Adding a placeholder forum") } } else { - log.Printf("Adding the %s forum", forum.Name) + log.Printf("Adding the '%s' forum", forum.Name) } - forum.Link = buildForumURL(nameToSlug(forum.Name), forum.ID) - - topic, err := topics.Get(forum.LastTopicID) - if err != nil { - topic = getDummyTopic() - } - user, err := users.Get(forum.LastReplyerID) - if err != nil { - user = getDummyUser() - } - forum.LastTopic = topic - forum.LastReplyer = user - //forum.SetLast(topic, user) + forum.Link = BuildForumURL(NameToSlug(forum.Name), forum.ID) + forum.LastTopic = Topics.DirtyGet(forum.LastTopicID) + forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID) addForum(forum) } @@ -178,19 +168,9 @@ func (mfs *MemoryForumStore) Get(id int) (*Forum, error) { return forum, err } - forum.Link = buildForumURL(nameToSlug(forum.Name), forum.ID) - - topic, err := topics.Get(forum.LastTopicID) - if err != nil { - topic = getDummyTopic() - } - user, err := users.Get(forum.LastReplyerID) - if err != nil { - user = getDummyUser() - } - forum.LastTopic = topic - forum.LastReplyer = user - //forum.SetLast(topic, user) + forum.Link = BuildForumURL(NameToSlug(forum.Name), forum.ID) + forum.LastTopic = Topics.DirtyGet(forum.LastTopicID) + forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID) mfs.CacheSet(forum) return forum, err @@ -205,19 +185,9 @@ func (mfs *MemoryForumStore) BypassGet(id int) (*Forum, error) { return nil, err } - forum.Link = buildForumURL(nameToSlug(forum.Name), forum.ID) - - topic, err := topics.Get(forum.LastTopicID) - if err != nil { - topic = getDummyTopic() - } - user, err := users.Get(forum.LastReplyerID) - if err != nil { - user = getDummyUser() - } - forum.LastTopic = topic - forum.LastReplyer = user - //forum.SetLast(topic, user) + forum.Link = BuildForumURL(NameToSlug(forum.Name), forum.ID) + forum.LastTopic = Topics.DirtyGet(forum.LastTopicID) + forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID) return forum, err } @@ -228,19 +198,9 @@ func (mfs *MemoryForumStore) Reload(id int) error { if err != nil { return err } - forum.Link = buildForumURL(nameToSlug(forum.Name), forum.ID) - - topic, err := topics.Get(forum.LastTopicID) - if err != nil { - topic = getDummyTopic() - } - user, err := users.Get(forum.LastReplyerID) - if err != nil { - user = getDummyUser() - } - forum.LastTopic = topic - forum.LastReplyer = user - //forum.SetLast(topic, user) + forum.Link = BuildForumURL(NameToSlug(forum.Name), forum.ID) + forum.LastTopic = Topics.DirtyGet(forum.LastTopicID) + forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID) mfs.CacheSet(forum) return nil @@ -372,7 +332,7 @@ func (mfs *MemoryForumStore) Create(forumName string, forumDesc string, active b return 0, err } - permmapToQuery(presetToPermmap(preset), fid) + PermmapToQuery(PresetToPermmap(preset), fid) forumCreateMutex.Unlock() return fid, nil } diff --git a/common/group.go b/common/group.go index b6c91366..99e1f9c0 100644 --- a/common/group.go +++ b/common/group.go @@ -1,5 +1,8 @@ package common +import "database/sql" +import "../query_gen/lib" + var blankGroup = Group{ID: 0, Name: ""} type GroupAdmin struct { @@ -27,13 +30,29 @@ type Group struct { CanSee []int // The IDs of the forums this group can see } +type GroupStmts struct { + updateGroupRank *sql.Stmt +} + +var groupStmts GroupStmts + +func init() { + DbInits.Add(func() error { + acc := qgen.Builder.Accumulator() + groupStmts = GroupStmts{ + updateGroupRank: acc.SimpleUpdate("users_groups", "is_admin = ?, is_mod = ?, is_banned = ?", "gid = ?"), + } + return acc.FirstError() + }) +} + func (group *Group) ChangeRank(isAdmin bool, isMod bool, isBanned bool) (err error) { - _, err = stmts.updateGroupRank.Exec(isAdmin, isMod, isBanned, group.ID) + _, err = groupStmts.updateGroupRank.Exec(isAdmin, isMod, isBanned, group.ID) if err != nil { return err } - gstore.Reload(group.ID) + Gstore.Reload(group.ID) return nil } diff --git a/common/group_store.go b/common/group_store.go index 18d2ce16..f8340e02 100644 --- a/common/group_store.go +++ b/common/group_store.go @@ -12,7 +12,7 @@ import ( "../query_gen/lib" ) -var gstore GroupStore +var Gstore GroupStore // ? - We could fallback onto the database when an item can't be found in the cache? type GroupStore interface { @@ -38,6 +38,7 @@ type MemoryGroupStore struct { groupCount int getAll *sql.Stmt get *sql.Stmt + count *sql.Stmt sync.RWMutex } @@ -49,6 +50,7 @@ func NewMemoryGroupStore() (*MemoryGroupStore, error) { groupCount: 0, getAll: acc.SimpleSelect("users_groups", "gid, name, permissions, plugin_perms, is_mod, is_admin, is_banned, tag", "", "", ""), get: acc.SimpleSelect("users_groups", "name, permissions, plugin_perms, is_mod, is_admin, is_banned, tag", "gid = ?", "", ""), + count: acc.SimpleCount("users_groups", "", ""), }, acc.FirstError() } @@ -84,7 +86,7 @@ func (mgs *MemoryGroupStore) LoadGroups() error { } mgs.groupCount = i - if dev.DebugMode { + if Dev.DebugMode { log.Print("Binding the Not Loggedin Group") } GuestPerms = mgs.dirtyGetUnsafe(6).Perms @@ -146,7 +148,7 @@ func (mgs *MemoryGroupStore) Reload(id int) error { } mgs.CacheSet(group) - err = rebuildGroupPermissions(id) + err = RebuildGroupPermissions(id) if err != nil { LogError(err) } @@ -160,7 +162,7 @@ func (mgs *MemoryGroupStore) initGroup(group *Group) error { log.Print("bad group perms: ", group.PermissionsText) return err } - if dev.DebugMode { + if Dev.DebugMode { log.Printf(group.Name+": %+v\n", group.Perms) } @@ -170,7 +172,7 @@ func (mgs *MemoryGroupStore) initGroup(group *Group) error { log.Print("bad group plugin perms: ", group.PluginPermsText) return err } - if dev.DebugMode { + if Dev.DebugMode { log.Printf(group.Name+": %+v\n", group.PluginPerms) } @@ -200,7 +202,7 @@ func (mgs *MemoryGroupStore) Exists(gid int) bool { // ? Allow two groups with the same name? func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod bool, isBanned bool) (gid int, err error) { var permstr = "{}" - tx, err := db.Begin() + tx, err := qgen.Builder.Begin() if err != nil { return 0, err } @@ -226,20 +228,20 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod var blankIntList []int var pluginPerms = make(map[string]bool) var pluginPermsBytes = []byte("{}") - if vhooks["create_group_preappend"] != nil { - runVhook("create_group_preappend", &pluginPerms, &pluginPermsBytes) + if Vhooks["create_group_preappend"] != nil { + RunVhook("create_group_preappend", &pluginPerms, &pluginPermsBytes) } // Generate the forum permissions based on the presets... - fdata, err := fstore.GetAll() + fdata, err := Fstore.GetAll() if err != nil { return 0, err } var presetSet = make(map[int]string) var permSet = make(map[int]ForumPerms) - permUpdateMutex.Lock() - defer permUpdateMutex.Unlock() + PermUpdateMutex.Lock() + defer PermUpdateMutex.Unlock() for _, forum := range fdata { var thePreset string if isAdmin { @@ -252,7 +254,7 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod thePreset = "members" } - permmap := presetToPermmap(forum.Preset) + permmap := PresetToPermmap(forum.Preset) permItem := permmap[thePreset] permItem.Overrides = true @@ -260,7 +262,7 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod presetSet[forum.ID] = forum.Preset } - err = replaceForumPermsForGroupTx(tx, gid, presetSet, permSet) + err = ReplaceForumPermsForGroupTx(tx, gid, presetSet, permSet) if err != nil { return 0, err } @@ -281,7 +283,7 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod mgs.Unlock() for _, forum := range fdata { - err = fpstore.Reload(forum.ID) + err = Fpstore.Reload(forum.ID) if err != nil { return gid, err } @@ -344,8 +346,10 @@ func (mgs *MemoryGroupStore) Length() int { return mgs.groupCount } -func (mgs *MemoryGroupStore) GlobalCount() int { - mgs.RLock() - defer mgs.RUnlock() - return mgs.groupCount +func (mgs *MemoryGroupStore) GlobalCount() (count int) { + err := mgs.count.QueryRow().Scan(&count) + if err != nil { + LogError(err) + } + return count } diff --git a/module_ottojs.go b/common/module_ottojs.go similarity index 99% rename from module_ottojs.go rename to common/module_ottojs.go index 80e69fef..fe2167cb 100644 --- a/module_ottojs.go +++ b/common/module_ottojs.go @@ -4,7 +4,7 @@ * Copyright Azareal 2016 - 2018 * */ -package main +package common import ( "errors" diff --git a/common/pages.go b/common/pages.go index cbac4a63..62413d08 100644 --- a/common/pages.go +++ b/common/pages.go @@ -11,7 +11,7 @@ type HeaderVars struct { Scripts []string Stylesheets []string Widgets PageWidgets - Site *Site + Site *site Settings map[string]interface{} Themes map[string]Theme // TODO: Use a slice containing every theme instead of the main map for speed ThemeName string @@ -21,7 +21,7 @@ type HeaderVars struct { // TODO: Add this to routes which don't use templates. E.g. Json APIs. type HeaderLite struct { - Site *Site + Site *site Settings SettingMap ExtData ExtData } @@ -34,7 +34,7 @@ type PageWidgets struct { // TODO: Add a ExtDataHolder interface with methods for manipulating the contents? // ? - Could we use a sync.Map instead? type ExtData struct { - items map[string]interface{} // Key: pluginname + Items map[string]interface{} // Key: pluginname sync.RWMutex } @@ -226,7 +226,7 @@ type PanelEditGroupPermsPage struct { GlobalPerms []NameLangToggle } -type backupItem struct { +type BackupItem struct { SQLURL string // TODO: Add an easier to parse format here for Gosora to be able to more easily reimport portions of the dump and to strip unnecessary data (e.g. table defs and parsed post data) @@ -239,10 +239,10 @@ type PanelBackupPage struct { CurrentUser User Header *HeaderVars Stats PanelStats - Backups []backupItem + Backups []BackupItem } -type logItem struct { +type LogItem struct { Action template.HTML IPAddress string DoneAt string @@ -253,7 +253,7 @@ type PanelLogsPage struct { CurrentUser User Header *HeaderVars Stats PanelStats - Logs []logItem + Logs []LogItem PageList []int Page int LastPage int @@ -282,5 +282,5 @@ type AreYouSure struct { // This is mostly for errors.go, please create *HeaderVars on the spot instead of relying on this or the atomic store underlying it, if possible // TODO: Write a test for this func DefaultHeaderVar() *HeaderVars { - return &HeaderVars{Site: site, ThemeName: fallbackTheme} + return &HeaderVars{Site: Site, ThemeName: fallbackTheme} } diff --git a/pages.go b/common/parser.go similarity index 87% rename from pages.go rename to common/parser.go index 481db7f4..b0c77104 100644 --- a/pages.go +++ b/common/parser.go @@ -1,4 +1,4 @@ -package main +package common import ( //"fmt" @@ -9,19 +9,19 @@ import ( "strings" ) -var spaceGap = []byte(" ") +var SpaceGap = []byte(" ") var httpProtBytes = []byte("http://") -var invalidURL = []byte("[Invalid URL]") -var invalidTopic = []byte("[Invalid Topic]") -var invalidProfile = []byte("[Invalid Profile]") -var invalidForum = []byte("[Invalid Forum]") +var InvalidURL = []byte("[Invalid URL]") +var InvalidTopic = []byte("[Invalid Topic]") +var InvalidProfile = []byte("[Invalid Profile]") +var InvalidForum = []byte("[Invalid Forum]") var unknownMedia = []byte("[Unknown Media]") -var urlOpen = []byte("") +var UrlOpen = []byte("") var bytesSinglequote = []byte("'") var bytesGreaterthan = []byte(">") var urlMention = []byte(" class='mention'") -var urlClose = []byte("") +var UrlClose = []byte("") var imageOpen = []byte("") @@ -164,16 +164,16 @@ func shortcodeToUnicode(msg string) string { return msg } -func preparseMessage(msg string) string { - if sshooks["preparse_preassign"] != nil { - msg = runSshook("preparse_preassign", msg) +func PreparseMessage(msg string) string { + if Sshooks["preparse_preassign"] != nil { + msg = RunSshook("preparse_preassign", msg) } return shortcodeToUnicode(msg) } // TODO: Write a test for this // TODO: We need a lot more hooks here. E.g. To add custom media types and handlers. -func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) string { +func ParseMessage(msg string, sectionID int, sectionType string /*, user User*/) string { msg = strings.Replace(msg, ":)", "😀", -1) msg = strings.Replace(msg, ":(", "😞", -1) msg = strings.Replace(msg, ":D", "😃", -1) @@ -185,7 +185,7 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) //msg = url_reg.ReplaceAllString(msg,"$2$3//$4") // Word filter list. E.g. Swear words and other things the admins don't like - wordFilters := wordFilterBox.Load().(WordFilterBox) + wordFilters := WordFilterBox.Load().(WordFilterMap) for _, filter := range wordFilters { msg = strings.Replace(msg, filter.Find, filter.Replacement, -1) } @@ -194,7 +194,7 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) //log.Print("Parser Loop!") var msgbytes = []byte(msg) var outbytes []byte - msgbytes = append(msgbytes, spaceGap...) + msgbytes = append(msgbytes, SpaceGap...) //log.Printf("string(msgbytes) %+v\n", `"`+string(msgbytes)+`"`) var lastItem = 0 var i = 0 @@ -215,23 +215,23 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) outbytes = append(outbytes, msgbytes[lastItem:i]...) i += 5 start := i - tid, intLen := coerceIntBytes(msgbytes[start:]) + tid, intLen := CoerceIntBytes(msgbytes[start:]) i += intLen - topic, err := topics.Get(tid) - if err != nil || !fstore.Exists(topic.ParentID) { - outbytes = append(outbytes, invalidTopic...) + topic, err := Topics.Get(tid) + if err != nil || !Fstore.Exists(topic.ParentID) { + outbytes = append(outbytes, InvalidTopic...) lastItem = i continue } - outbytes = append(outbytes, urlOpen...) - var urlBit = []byte(buildTopicURL("", tid)) + outbytes = append(outbytes, UrlOpen...) + var urlBit = []byte(BuildTopicURL("", tid)) outbytes = append(outbytes, urlBit...) - outbytes = append(outbytes, urlOpen2...) + outbytes = append(outbytes, UrlOpen2...) var tidBit = []byte("#tid-" + strconv.Itoa(tid)) outbytes = append(outbytes, tidBit...) - outbytes = append(outbytes, urlClose...) + outbytes = append(outbytes, UrlClose...) lastItem = i //log.Print("string(msgbytes): ",string(msgbytes)) @@ -244,44 +244,46 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) outbytes = append(outbytes, msgbytes[lastItem:i]...) i += 5 start := i - rid, intLen := coerceIntBytes(msgbytes[start:]) + rid, intLen := CoerceIntBytes(msgbytes[start:]) i += intLen - topic, err := getTopicByReply(rid) - if err != nil || !fstore.Exists(topic.ParentID) { - outbytes = append(outbytes, invalidTopic...) + reply := BlankReply() + reply.ID = rid + topic, err := reply.Topic() + if err != nil || !Fstore.Exists(topic.ParentID) { + outbytes = append(outbytes, InvalidTopic...) lastItem = i continue } - outbytes = append(outbytes, urlOpen...) - var urlBit = []byte(buildTopicURL("", topic.ID)) + outbytes = append(outbytes, UrlOpen...) + var urlBit = []byte(BuildTopicURL("", topic.ID)) outbytes = append(outbytes, urlBit...) - outbytes = append(outbytes, urlOpen2...) + outbytes = append(outbytes, UrlOpen2...) var ridBit = []byte("#rid-" + strconv.Itoa(rid)) outbytes = append(outbytes, ridBit...) - outbytes = append(outbytes, urlClose...) + outbytes = append(outbytes, UrlClose...) lastItem = i } else if bytes.Equal(msgbytes[i+1:i+5], []byte("fid-")) { outbytes = append(outbytes, msgbytes[lastItem:i]...) i += 5 start := i - fid, intLen := coerceIntBytes(msgbytes[start:]) + fid, intLen := CoerceIntBytes(msgbytes[start:]) i += intLen - if !fstore.Exists(fid) { - outbytes = append(outbytes, invalidForum...) + if !Fstore.Exists(fid) { + outbytes = append(outbytes, InvalidForum...) lastItem = i continue } - outbytes = append(outbytes, urlOpen...) - var urlBit = []byte(buildForumURL("", fid)) + outbytes = append(outbytes, UrlOpen...) + var urlBit = []byte(BuildForumURL("", fid)) outbytes = append(outbytes, urlBit...) - outbytes = append(outbytes, urlOpen2...) + outbytes = append(outbytes, UrlOpen2...) var fidBit = []byte("#fid-" + strconv.Itoa(fid)) outbytes = append(outbytes, fidBit...) - outbytes = append(outbytes, urlClose...) + outbytes = append(outbytes, UrlClose...) lastItem = i } else { // TODO: Forum Shortcode Link @@ -291,17 +293,17 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) outbytes = append(outbytes, msgbytes[lastItem:i]...) i++ start := i - uid, intLen := coerceIntBytes(msgbytes[start:]) + uid, intLen := CoerceIntBytes(msgbytes[start:]) i += intLen - menUser, err := users.Get(uid) + menUser, err := Users.Get(uid) if err != nil { - outbytes = append(outbytes, invalidProfile...) + outbytes = append(outbytes, InvalidProfile...) lastItem = i continue } - outbytes = append(outbytes, urlOpen...) + outbytes = append(outbytes, UrlOpen...) var urlBit = []byte(menUser.Link) outbytes = append(outbytes, urlBit...) outbytes = append(outbytes, bytesSinglequote...) @@ -309,7 +311,7 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) outbytes = append(outbytes, bytesGreaterthan...) var uidBit = []byte("@" + menUser.Name) outbytes = append(outbytes, uidBit...) - outbytes = append(outbytes, urlClose...) + outbytes = append(outbytes, UrlClose...) lastItem = i //log.Print(string(msgbytes)) @@ -338,21 +340,21 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) //log.Print("Normal URL") outbytes = append(outbytes, msgbytes[lastItem:i]...) - urlLen := partialURLBytesLen(msgbytes[i:]) + urlLen := PartialURLBytesLen(msgbytes[i:]) if msgbytes[i+urlLen] > 32 { // space and invisibles //log.Print("INVALID URL") //log.Print("msgbytes[i+urlLen]: ", msgbytes[i+urlLen]) //log.Print("string(msgbytes[i+urlLen]): ", string(msgbytes[i+urlLen])) //log.Print("msgbytes[i:i+urlLen]: ", msgbytes[i:i+urlLen]) //log.Print("string(msgbytes[i:i+urlLen]): ", string(msgbytes[i:i+urlLen])) - outbytes = append(outbytes, invalidURL...) + outbytes = append(outbytes, InvalidURL...) i += urlLen continue } media, ok := parseMediaBytes(msgbytes[i : i+urlLen]) if !ok { - outbytes = append(outbytes, invalidURL...) + outbytes = append(outbytes, InvalidURL...) i += urlLen continue } @@ -386,23 +388,23 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) continue } - outbytes = append(outbytes, urlOpen...) + outbytes = append(outbytes, UrlOpen...) outbytes = append(outbytes, msgbytes[i:i+urlLen]...) - outbytes = append(outbytes, urlOpen2...) + outbytes = append(outbytes, UrlOpen2...) outbytes = append(outbytes, msgbytes[i:i+urlLen]...) - outbytes = append(outbytes, urlClose...) + outbytes = append(outbytes, UrlClose...) i += urlLen lastItem = i } else if msgbytes[i] == '/' && msgbytes[i+1] == '/' { outbytes = append(outbytes, msgbytes[lastItem:i]...) - urlLen := partialURLBytesLen(msgbytes[i:]) + urlLen := PartialURLBytesLen(msgbytes[i:]) if msgbytes[i+urlLen] > 32 { // space and invisibles //log.Print("INVALID URL") //log.Print("msgbytes[i+urlLen]: ", msgbytes[i+urlLen]) //log.Print("string(msgbytes[i+urlLen]): ", string(msgbytes[i+urlLen])) //log.Print("msgbytes[i:i+urlLen]: ", msgbytes[i:i+urlLen]) //log.Print("string(msgbytes[i:i+urlLen]): ", string(msgbytes[i:i+urlLen])) - outbytes = append(outbytes, invalidURL...) + outbytes = append(outbytes, InvalidURL...) i += urlLen continue } @@ -412,7 +414,7 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) //log.Print("string(msgbytes[i:i+urlLen]): ", string(msgbytes[i:i+urlLen])) media, ok := parseMediaBytes(msgbytes[i : i+urlLen]) if !ok { - outbytes = append(outbytes, invalidURL...) + outbytes = append(outbytes, InvalidURL...) i += urlLen continue } @@ -446,11 +448,11 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) continue } - outbytes = append(outbytes, urlOpen...) + outbytes = append(outbytes, UrlOpen...) outbytes = append(outbytes, msgbytes[i:i+urlLen]...) - outbytes = append(outbytes, urlOpen2...) + outbytes = append(outbytes, UrlOpen2...) outbytes = append(outbytes, msgbytes[i:i+urlLen]...) - outbytes = append(outbytes, urlClose...) + outbytes = append(outbytes, UrlClose...) i += urlLen lastItem = i } @@ -474,25 +476,12 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) //log.Print("msg",`"`+msg+`"`) msg = strings.Replace(msg, "\n", "
", -1) - if sshooks["parse_assign"] != nil { - msg = runSshook("parse_assign", msg) + if Sshooks["parse_assign"] != nil { + msg = RunSshook("parse_assign", msg) } return msg } -// TODO: Write a test for this -/*func regexParseMessage(msg string) string { - msg = strings.Replace(msg, ":)", "😀", -1) - msg = strings.Replace(msg, ":D", "😃", -1) - msg = strings.Replace(msg, ":P", "😛", -1) - msg = urlReg.ReplaceAllString(msg, "$2$3//$4") - msg = strings.Replace(msg, "\n", "
", -1) - if sshooks["parse_assign"] != nil { - msg = runSshook("parse_assign", msg) - } - return msg -}*/ - // 6, 7, 8, 6, 2, 7 // ftp://, http://, https:// git://, //, mailto: (not a URL, just here for length comparison purposes) // TODO: Write a test for this @@ -541,7 +530,7 @@ func validatedURLBytes(data []byte) (url []byte) { // ? - There should only be one : and that's only if the URL is on a non-standard port. Same for ?s. for ; datalen > i; i++ { if data[i] != '\\' && data[i] != '_' && data[i] != ':' && data[i] != '?' && data[i] != '&' && data[i] != '=' && data[i] != ';' && data[i] != '@' && !(data[i] > 44 && data[i] < 58) && !(data[i] > 64 && data[i] < 91) && !(data[i] > 96 && data[i] < 123) { - return invalidURL + return InvalidURL } } @@ -550,7 +539,7 @@ func validatedURLBytes(data []byte) (url []byte) { } // TODO: Write a test for this -func partialURLBytes(data []byte) (url []byte) { +func PartialURLBytes(data []byte) (url []byte) { datalen := len(data) i := 0 end := datalen - 1 @@ -579,7 +568,7 @@ func partialURLBytes(data []byte) (url []byte) { } // TODO: Write a test for this -func partialURLBytesLen(data []byte) int { +func PartialURLBytesLen(data []byte) int { datalen := len(data) i := 0 @@ -632,13 +621,12 @@ func parseMediaBytes(data []byte) (media MediaEmbed, ok bool) { query := url.Query() //log.Printf("query %+v\n", query) - var samesite = hostname == "localhost" || hostname == site.URL + var samesite = hostname == "localhost" || hostname == Site.URL if samesite { - //log.Print("samesite") - hostname = strings.Split(site.URL, ":")[0] + hostname = strings.Split(Site.URL, ":")[0] // ?- Test this as I'm not sure it'll do what it should. If someone's running SSL on port 80 or non-SSL on port 443 then... Well... They're in far worse trouble than this... - port = site.Port - if scheme == "" && site.EnableSsl { + port = Site.Port + if scheme == "" && Site.EnableSsl { scheme = "https" } } @@ -684,7 +672,7 @@ func parseMediaBytes(data []byte) (media MediaEmbed, ok bool) { extarr := strings.Split(lastFrag, ".") if len(extarr) >= 2 { ext := extarr[len(extarr)-1] - if imageFileExts.Contains(ext) { + if ImageFileExts.Contains(ext) { media.Type = "image" var sport string if port != "443" && port != "80" { @@ -704,7 +692,7 @@ func parseURL(data []byte) (*url.URL, error) { } // TODO: Write a test for this -func coerceIntBytes(data []byte) (res int, length int) { +func CoerceIntBytes(data []byte) (res int, length int) { if !(data[0] > 47 && data[0] < 58) { return 0, 1 } @@ -728,7 +716,7 @@ func coerceIntBytes(data []byte) (res int, length int) { } // TODO: Write tests for this -func paginate(count int, perPage int, maxPages int) []int { +func Paginate(count int, perPage int, maxPages int) []int { if count < perPage { return []int{1} } @@ -745,7 +733,7 @@ func paginate(count int, perPage int, maxPages int) []int { } // TODO: Write tests for this -func pageOffset(count int, page int, perPage int) (int, int, int) { +func PageOffset(count int, page int, perPage int) (int, int, int) { var offset int lastPage := (count / perPage) + 1 if page > 1 { diff --git a/common/permissions.go b/common/permissions.go index a2132439..d2ca6d59 100644 --- a/common/permissions.go +++ b/common/permissions.go @@ -5,18 +5,24 @@ import ( "encoding/json" "log" "sync" + + "../query_gen/lib" ) // TODO: Refactor the perms system -var permUpdateMutex sync.Mutex +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) @@ -216,15 +222,15 @@ func init() { ExtData: make(map[string]bool), } - guestUser.Perms = GuestPerms + GuestUser.Perms = GuestPerms - if dev.DebugMode { + 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) { +func PresetToPermmap(preset string) (out map[string]ForumPerms) { out = make(map[string]ForumPerms) switch preset { case "all": @@ -266,8 +272,8 @@ func presetToPermmap(preset string) (out map[string]ForumPerms) { return out } -func permmapToQuery(permmap map[string]ForumPerms, fid int) error { - tx, err := db.Begin() +func PermmapToQuery(permmap map[string]ForumPerms, fid int) error { + tx, err := qgen.Builder.Begin() if err != nil { return err } @@ -337,7 +343,7 @@ func permmapToQuery(permmap map[string]ForumPerms, fid int) error { // 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"]}) + err = ReplaceForumPermsForGroupTx(tx, 6, map[int]string{fid: ""}, map[int]ForumPerms{fid: permmap["guests"]}) if err != nil { return err } @@ -347,25 +353,25 @@ func permmapToQuery(permmap map[string]ForumPerms, fid int) error { return err } - permUpdateMutex.Lock() - defer permUpdateMutex.Unlock() - return fpstore.Reload(fid) + PermUpdateMutex.Lock() + defer PermUpdateMutex.Unlock() + return Fpstore.Reload(fid) } -func replaceForumPermsForGroup(gid int, presetSet map[int]string, permSets map[int]ForumPerms) error { - tx, err := db.Begin() +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) + 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 { +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 @@ -394,7 +400,7 @@ func replaceForumPermsForGroupTx(tx *sql.Tx, gid int, presetSets map[int]string, } // TODO: Refactor this and write tests for it -func forumPermsToGroupForumPreset(fperms ForumPerms) string { +func ForumPermsToGroupForumPreset(fperms ForumPerms) string { if !fperms.Overrides { return "default" } @@ -422,7 +428,7 @@ func forumPermsToGroupForumPreset(fperms ForumPerms) string { return "custom" } -func groupForumPresetToForumPerms(preset string) (fperms ForumPerms, changed bool) { +func GroupForumPresetToForumPerms(preset string) (fperms ForumPerms, changed bool) { switch preset { case "read_only": return ReadForumPerms, true @@ -439,7 +445,7 @@ func groupForumPresetToForumPerms(preset string) (fperms ForumPerms, changed boo return fperms, false } -func stripInvalidGroupForumPreset(preset string) string { +func StripInvalidGroupForumPreset(preset string) string { switch preset { case "read_only", "can_post", "can_moderate", "no_access", "default", "custom": return preset @@ -447,7 +453,7 @@ func stripInvalidGroupForumPreset(preset string) string { return "" } -func stripInvalidPreset(preset string) string { +func StripInvalidPreset(preset string) string { switch preset { case "all", "announce", "members", "staff", "admins", "archive", "custom": return preset @@ -457,7 +463,7 @@ func stripInvalidPreset(preset string) string { } // TODO: Move this into the phrase system? -func presetToLang(preset string) string { +func PresetToLang(preset string) string { phrases := GetAllPermPresets() phrase, ok := phrases[preset] if !ok { @@ -467,10 +473,18 @@ func presetToLang(preset string) string { } // TODO: Is this racey? -func rebuildGroupPermissions(gid int) error { +// TODO: Test this along with the rest of the perms system +func RebuildGroupPermissions(gid int) error { var permstr []byte log.Print("Reloading a group") - err := db.QueryRow("select permissions from users_groups where gid = ?", gid).Scan(&permstr) + + // TODO: Avoid re-initting this all the time + getGroupPerms, err := qgen.Builder.SimpleSelect("users_groups", "permissions", "gid = ?", "", "") + if err != nil { + return err + } + + err = getGroupPerms.QueryRow(gid).Scan(&permstr) if err != nil { return err } @@ -483,7 +497,7 @@ func rebuildGroupPermissions(gid int) error { return err } - group, err := gstore.Get(gid) + group, err := Gstore.Get(gid) if err != nil { return err } @@ -491,7 +505,7 @@ func rebuildGroupPermissions(gid int) error { return nil } -func overridePerms(perms *Perms, status bool) { +func OverridePerms(perms *Perms, status bool) { if status { *perms = AllPerms } else { @@ -500,7 +514,7 @@ func overridePerms(perms *Perms, status bool) { } // TODO: We need a better way of overriding forum perms rather than setting them one by one -func overrideForumPerms(perms *Perms, status bool) { +func OverrideForumPerms(perms *Perms, status bool) { perms.ViewTopic = status perms.LikeItem = status perms.CreateTopic = status @@ -513,10 +527,10 @@ func overrideForumPerms(perms *Perms, status bool) { perms.CloseTopic = status } -func registerPluginPerm(name string) { +func RegisterPluginPerm(name string) { AllPluginPerms[name] = true } -func deregisterPluginPerm(name string) { +func DeregisterPluginPerm(name string) { delete(AllPluginPerms, name) } diff --git a/phrases.go b/common/phrases.go similarity index 88% rename from phrases.go rename to common/phrases.go index b18d9214..5fb32b0d 100644 --- a/phrases.go +++ b/common/phrases.go @@ -4,7 +4,7 @@ * Copyright Azareal 2017 - 2018 * */ -package main +package common import ( "encoding/json" @@ -20,7 +20,7 @@ import ( // TODO: Let the admin edit phrases from inside the Control Panel? How should we persist these? Should we create a copy of the langpack or edit the primaries? Use the changeLangpack mutex for this? // nolint Be quiet megacheck, this *is* used var currentLangPack atomic.Value -var langpackCount int // TODO: Use atomics for this +var langPackCount int // TODO: Use atomics for this // TODO: We'll be implementing the level phrases in the software proper very very soon! type LevelPhrases struct { @@ -44,10 +44,9 @@ type LanguagePack struct { } // TODO: Add the ability to edit language JSON files from the Control Panel and automatically scan the files for changes -////var langpacks = map[string]*LanguagePack -var langpacks sync.Map // nolint it is used +var langPacks sync.Map // nolint it is used -func initPhrases() error { +func InitPhrases() error { log.Print("Loading the language packs") err := filepath.Walk("./langs", func(path string, f os.FileInfo, err error) error { if f.IsDir() { @@ -61,8 +60,8 @@ func initPhrases() error { var ext = filepath.Ext("/langs/" + path) if ext != ".json" { - if dev.DebugMode { - log.Print("Found a " + ext + "in /langs/") + if Dev.DebugMode { + log.Printf("Found a '%s' in /langs/", ext) } return nil } @@ -74,8 +73,8 @@ func initPhrases() error { } log.Print("Adding the '" + langPack.Name + "' language pack") - langpacks.Store(langPack.Name, &langPack) - langpackCount++ + langPacks.Store(langPack.Name, &langPack) + langPackCount++ return nil }) @@ -83,13 +82,13 @@ func initPhrases() error { if err != nil { return err } - if langpackCount == 0 { + if langPackCount == 0 { return errors.New("You don't have any language packs") } - langPack, ok := langpacks.Load(site.Language) + langPack, ok := langPacks.Load(Site.Language) if !ok { - return errors.New("Couldn't find the " + site.Language + " language pack") + return errors.New("Couldn't find the " + Site.Language + " language pack") } currentLangPack.Store(langPack) return nil @@ -167,7 +166,7 @@ func DeletePhrase() { // TODO: Use atomics to store the pointer of the current active langpack? // nolint func ChangeLanguagePack(name string) (exists bool) { - pack, ok := langpacks.Load(name) + pack, ok := langPacks.Load(name) if !ok { return false } diff --git a/common/pluginlangs.go b/common/pluginlangs.go index 58ef5422..f9915817 100644 --- a/common/pluginlangs.go +++ b/common/pluginlangs.go @@ -89,7 +89,7 @@ func InitPluginLangs() error { if err != nil { return err } - plugins[plugin.UName] = pplugin + Plugins[plugin.UName] = pplugin } return nil } diff --git a/common/profile_reply_store.go b/common/profile_reply_store.go index 382accc3..2b745ff8 100644 --- a/common/profile_reply_store.go +++ b/common/profile_reply_store.go @@ -2,9 +2,11 @@ package common import ( "database/sql" + + "../query_gen/lib" ) -var prstore ProfileReplyStore +var Prstore ProfileReplyStore type ProfileReplyStore interface { Get(id int) (*Reply, error) @@ -33,7 +35,7 @@ func (store *SQLProfileReplyStore) Get(id int) (*Reply, error) { } func (store *SQLProfileReplyStore) Create(profileID int, content string, createdBy int, ipaddress string) (id int, err error) { - res, err := store.create.Exec(profileID, content, parseMessage(content, 0, ""), createdBy, ipaddress) + res, err := store.create.Exec(profileID, content, ParseMessage(content, 0, ""), createdBy, ipaddress) if err != nil { return 0, err } diff --git a/common/reply.go b/common/reply.go index 00b76e23..2f851f33 100644 --- a/common/reply.go +++ b/common/reply.go @@ -7,8 +7,11 @@ package common import ( + "database/sql" "errors" "time" + + "../query_gen/lib" ) type ReplyUser struct { @@ -56,12 +59,37 @@ type Reply struct { } var ErrAlreadyLiked = errors.New("You already liked this!") +var replyStmts ReplyStmts + +type ReplyStmts struct { + isLiked *sql.Stmt + createLike *sql.Stmt + delete *sql.Stmt + addLikesToReply *sql.Stmt + removeRepliesFromTopic *sql.Stmt + getParent *sql.Stmt +} + +func init() { + DbInits.Add(func() error { + acc := qgen.Builder.Accumulator() + replyStmts = ReplyStmts{ + isLiked: acc.SimpleSelect("likes", "targetItem", "sentBy = ? and targetItem = ? and targetType = 'replies'", "", ""), + createLike: acc.SimpleInsert("likes", "weight, targetItem, targetType, sentBy", "?,?,?,?"), + delete: acc.SimpleDelete("replies", "rid = ?"), + addLikesToReply: acc.SimpleUpdate("replies", "likeCount = likeCount + ?", "rid = ?"), + removeRepliesFromTopic: acc.SimpleUpdate("topics", "postCount = postCount - ?", "tid = ?"), + getParent: acc.SimpleLeftJoin("replies", "topics", "topics.tid, topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, topics.data", "replies.tid = topics.tid", "rid = ?", "", ""), + } + return acc.FirstError() + }) +} // TODO: Write tests for this // TODO: Wrap these queries in a transaction to make sure the state is consistent func (reply *Reply) Like(uid int) (err error) { var rid int // unused, just here to avoid mutating reply.ID - err = stmts.hasLikedReply.QueryRow(uid, reply.ID).Scan(&rid) + err = replyStmts.isLiked.QueryRow(uid, reply.ID).Scan(&rid) if err != nil && err != ErrNoRows { return err } else if err != ErrNoRows { @@ -69,29 +97,41 @@ func (reply *Reply) Like(uid int) (err error) { } score := 1 - _, err = stmts.createLike.Exec(score, reply.ID, "replies", uid) + _, err = replyStmts.createLike.Exec(score, reply.ID, "replies", uid) if err != nil { return err } - _, err = stmts.addLikesToReply.Exec(1, reply.ID) + _, err = replyStmts.addLikesToReply.Exec(1, reply.ID) return err } // TODO: Write tests for this func (reply *Reply) Delete() error { - _, err := stmts.deleteReply.Exec(reply.ID) + _, err := replyStmts.delete.Exec(reply.ID) if err != nil { return err } - _, err = stmts.removeRepliesFromTopic.Exec(1, reply.ParentID) - tcache, ok := topics.(TopicCache) + // TODO: Move this bit to *Topic + _, err = replyStmts.removeRepliesFromTopic.Exec(1, reply.ParentID) + tcache, ok := Topics.(TopicCache) if ok { tcache.CacheRemove(reply.ParentID) } return err } +func (reply *Reply) Topic() (*Topic, error) { + topic := Topic{ID: 0} + err := replyStmts.getParent.QueryRow(reply.ID).Scan(&topic.ID, &topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data) + topic.Link = BuildTopicURL(NameToSlug(topic.Title), topic.ID) + return &topic, err +} + // Copy gives you a non-pointer concurrency safe copy of the reply func (reply *Reply) Copy() Reply { return *reply } + +func BlankReply() *Reply { + return &Reply{ID: 0} +} diff --git a/common/reply_store.go b/common/reply_store.go index bc3692c0..a823c582 100644 --- a/common/reply_store.go +++ b/common/reply_store.go @@ -3,7 +3,7 @@ package common import "database/sql" import "../query_gen/lib" -var rstore ReplyStore +var Rstore ReplyStore type ReplyStore interface { Get(id int) (*Reply, error) @@ -31,8 +31,8 @@ func (store *SQLReplyStore) Get(id int) (*Reply, error) { // TODO: Write a test for this func (store *SQLReplyStore) Create(topic *Topic, content string, ipaddress string, uid int) (id int, err error) { - wcount := wordCount(content) - res, err := store.create.Exec(topic.ID, content, parseMessage(content, topic.ParentID, "forums"), ipaddress, wcount, uid) + wcount := WordCount(content) + res, err := store.create.Exec(topic.ID, content, ParseMessage(content, topic.ParentID, "forums"), ipaddress, wcount, uid) if err != nil { return 0, err } diff --git a/routes_common.go b/common/routes_common.go similarity index 72% rename from routes_common.go rename to common/routes_common.go index 16ee30c1..effbbb9f 100644 --- a/routes_common.go +++ b/common/routes_common.go @@ -1,4 +1,4 @@ -package main +package common import ( "html" @@ -7,8 +7,6 @@ import ( "net" "net/http" "strings" - - "./common" ) // nolint @@ -16,28 +14,28 @@ var PreRoute func(http.ResponseWriter, *http.Request) (User, bool) = preRoute // TODO: Come up with a better middleware solution // nolint We need these types so people can tell what they are without scrolling to the bottom of the file -var PanelUserCheck func(http.ResponseWriter, *http.Request, *User) (*common.HeaderVars, common.PanelStats, RouteError) = panelUserCheck -var SimplePanelUserCheck func(http.ResponseWriter, *http.Request, *User) (*common.HeaderLite, RouteError) = simplePanelUserCheck -var SimpleForumUserCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *common.HeaderLite, err RouteError) = simpleForumUserCheck -var ForumUserCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *common.HeaderVars, err RouteError) = forumUserCheck -var MemberCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, err RouteError) = memberCheck -var UserCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, err RouteError) = userCheck -var UserCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, err RouteError) = userCheck +var PanelUserCheck func(http.ResponseWriter, *http.Request, *User) (*HeaderVars, PanelStats, RouteError) = panelUserCheck +var SimplePanelUserCheck func(http.ResponseWriter, *http.Request, *User) (*HeaderLite, RouteError) = simplePanelUserCheck +var SimpleForumUserCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *HeaderLite, err RouteError) = simpleForumUserCheck +var ForumUserCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *HeaderVars, err RouteError) = forumUserCheck +var MemberCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, err RouteError) = memberCheck +var SimpleUserCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, err RouteError) = simpleUserCheck +var UserCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, err RouteError) = userCheck // TODO: Support for left sidebars and sidebars on both sides // http.Request is for context.Context middleware. Mostly for plugin_guilds right now -func BuildWidgets(zone string, data interface{}, headerVars *common.HeaderVars, r *http.Request) { - if vhooks["intercept_build_widgets"] != nil { - if runVhook("intercept_build_widgets", zone, data, headerVars, r).(bool) { +func BuildWidgets(zone string, data interface{}, headerVars *HeaderVars, r *http.Request) { + if Vhooks["intercept_build_widgets"] != nil { + if RunVhook("intercept_build_widgets", zone, data, headerVars, r).(bool) { return } } - //log.Print("themes[headerVars.ThemeName].Sidebars",themes[headerVars.ThemeName].Sidebars) - if themes[headerVars.ThemeName].Sidebars == "right" { - if len(docks.RightSidebar) != 0 { + //log.Print("Themes[headerVars.ThemeName].Sidebars", Themes[headerVars.ThemeName].Sidebars) + if Themes[headerVars.ThemeName].Sidebars == "right" { + if len(Docks.RightSidebar) != 0 { var sbody string - for _, widget := range docks.RightSidebar { + for _, widget := range Docks.RightSidebar { if widget.Enabled { if widget.Location == "global" || widget.Location == zone { sbody += widget.Body @@ -49,21 +47,21 @@ func BuildWidgets(zone string, data interface{}, headerVars *common.HeaderVars, } } -func simpleForumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *common.HeaderLite, rerr RouteError) { - if !fstore.Exists(fid) { +func simpleForumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *HeaderLite, rerr RouteError) { + if !Fstore.Exists(fid) { return nil, PreError("The target forum doesn't exist.", w, r) } // Is there a better way of doing the skip AND the success flag on this hook like multiple returns? - if vhookSkippable["simple_forum_check_pre_perms"] != nil { + if VhookSkippable["simple_forum_check_pre_perms"] != nil { var skip bool - skip, rerr = runVhookSkippable("simple_forum_check_pre_perms", w, r, user, &fid, &headerLite) + skip, rerr = RunVhookSkippable("simple_forum_check_pre_perms", w, r, user, &fid, &headerLite) if skip || rerr != nil { return headerLite, rerr } } - fperms, err := fpstore.Get(fid, user.Group) + fperms, err := Fpstore.Get(fid, user.Group) if err != nil { // TODO: Refactor this log.Printf("Unable to get the forum perms for Group #%d for User #%d", user.Group, user.ID) @@ -73,24 +71,24 @@ func simpleForumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fi return headerLite, nil } -func forumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *common.HeaderVars, rerr RouteError) { +func forumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *HeaderVars, rerr RouteError) { headerVars, rerr = UserCheck(w, r, user) if rerr != nil { return headerVars, rerr } - if !fstore.Exists(fid) { + if !Fstore.Exists(fid) { return headerVars, NotFound(w, r) } - if vhookSkippable["forum_check_pre_perms"] != nil { + if VhookSkippable["forum_check_pre_perms"] != nil { var skip bool - skip, rerr = runVhookSkippable("forum_check_pre_perms", w, r, user, &fid, &headerVars) + skip, rerr = RunVhookSkippable("forum_check_pre_perms", w, r, user, &fid, &headerVars) if skip || rerr != nil { return headerVars, rerr } } - fperms, err := fpstore.Get(fid, user.Group) + fperms, err := Fpstore.Get(fid, user.Group) if err != nil { // TODO: Refactor this log.Printf("Unable to get the forum perms for Group #%d for User #%d", user.Group, user.ID) @@ -126,29 +124,29 @@ func cascadeForumPerms(fperms ForumPerms, user *User) { // Even if they have the right permissions, the control panel is only open to supermods+. There are many areas without subpermissions which assume that the current user is a supermod+ and admins are extremely unlikely to give these permissions to someone who isn't at-least a supermod to begin with // TODO: Do a panel specific theme? -func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, stats common.PanelStats, rerr RouteError) { - var themeName = defaultThemeBox.Load().(string) +func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, stats PanelStats, rerr RouteError) { + var themeName = DefaultThemeBox.Load().(string) cookie, err := r.Cookie("current_theme") if err == nil { cookie := html.EscapeString(cookie.Value) - theme, ok := themes[cookie] + theme, ok := Themes[cookie] if ok && !theme.HideFromThemes { themeName = cookie } } headerVars = &HeaderVars{ - Site: site, - Settings: settingBox.Load().(SettingBox), - Themes: themes, + Site: Site, + Settings: SettingBox.Load().(SettingMap), + Themes: Themes, ThemeName: themeName, } // TODO: We should probably initialise headerVars.ExtData headerVars.Stylesheets = append(headerVars.Stylesheets, headerVars.ThemeName+"/panel.css") - if len(themes[headerVars.ThemeName].Resources) > 0 { - rlist := themes[headerVars.ThemeName].Resources + if len(Themes[headerVars.ThemeName].Resources) > 0 { + rlist := Themes[headerVars.ThemeName].Resources for _, resource := range rlist { if resource.Location == "global" || resource.Location == "panel" { extarr := strings.Split(resource.Name, ".") @@ -162,16 +160,12 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerV } } - err = stmts.groupCount.QueryRow().Scan(&stats.Groups) - if err != nil { - return headerVars, stats, InternalError(err, w, r) - } - - stats.Users = users.GlobalCount() - stats.Forums = fstore.GlobalCount() // TODO: Stop it from showing the blanked forums + stats.Users = Users.GlobalCount() + stats.Groups = Gstore.GlobalCount() + stats.Forums = Fstore.GlobalCount() // TODO: Stop it from showing the blanked forums stats.Settings = len(headerVars.Settings) - stats.WordFilters = len(wordFilterBox.Load().(WordFilterBox)) - stats.Themes = len(themes) + stats.WordFilters = len(WordFilterBox.Load().(WordFilterMap)) + stats.Themes = len(Themes) stats.Reports = 0 // TODO: Do the report count. Only show open threads? pusher, ok := w.(http.Pusher) @@ -188,15 +182,15 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerV return headerVars, stats, nil } -func simplePanelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerLite *common.HeaderLite, rerr RouteError) { +func simplePanelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, rerr RouteError) { return &HeaderLite{ - Site: site, - Settings: settingBox.Load().(SettingBox), + Site: Site, + Settings: SettingBox.Load().(SettingMap), }, nil } // TODO: Add this to the member routes -func memberCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, rerr RouteError) { +func memberCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, rerr RouteError) { headerVars, rerr = UserCheck(w, r, user) if !user.Loggedin { return headerVars, NoPermissions(w, r, *user) @@ -205,31 +199,31 @@ func memberCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars } // SimpleUserCheck is back from the grave, yay :D -func simpleUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerLite *common.HeaderLite, rerr RouteError) { +func simpleUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, rerr RouteError) { headerLite = &HeaderLite{ - Site: site, - Settings: settingBox.Load().(SettingBox), + Site: Site, + Settings: SettingBox.Load().(SettingMap), } return headerLite, nil } // TODO: Add the ability for admins to restrict certain themes to certain groups? -func userCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, rerr RouteError) { - var themeName = defaultThemeBox.Load().(string) +func userCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, rerr RouteError) { + var themeName = DefaultThemeBox.Load().(string) cookie, err := r.Cookie("current_theme") if err == nil { cookie := html.EscapeString(cookie.Value) - theme, ok := themes[cookie] + theme, ok := Themes[cookie] if ok && !theme.HideFromThemes { themeName = cookie } } headerVars = &HeaderVars{ - Site: site, - Settings: settingBox.Load().(SettingBox), - Themes: themes, + Site: Site, + Settings: SettingBox.Load().(SettingMap), + Themes: Themes, ThemeName: themeName, } @@ -237,8 +231,8 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars * headerVars.NoticeList = append(headerVars.NoticeList, "Your account has been suspended. Some of your permissions may have been revoked.") } - if len(themes[headerVars.ThemeName].Resources) > 0 { - rlist := themes[headerVars.ThemeName].Resources + if len(Themes[headerVars.ThemeName].Resources) > 0 { + rlist := Themes[headerVars.ThemeName].Resources for _, resource := range rlist { if resource.Location == "global" || resource.Location == "frontend" { extarr := strings.Split(resource.Name, ".") @@ -266,27 +260,28 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars * } func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) { - user, halt := auth.SessionCheck(w, r) + user, halt := Auth.SessionCheck(w, r) if halt { return *user, false } - if user == &guestUser { + if user == &GuestUser { return *user, true } - var usercpy = *user + var usercpy *User + *usercpy = *user // TODO: WIP. Refactor this to eliminate the unnecessary query host, _, err := net.SplitHostPort(r.RemoteAddr) if err != nil { PreError("Bad IP", w, r) - return usercpy, false + return *usercpy, false } if host != usercpy.LastIP { - _, err = stmts.updateLastIP.Exec(host, usercpy.ID) + err = usercpy.UpdateIP(host) if err != nil { InternalError(err, w, r) - return usercpy, false + return *usercpy, false } usercpy.LastIP = host } @@ -296,7 +291,7 @@ func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) { //h.Set("X-XSS-Protection", "1") // TODO: Set the content policy header - return usercpy, true + return *usercpy, true } // SuperModeOnly makes sure that only super mods or higher can access the panel routes diff --git a/common/setting.go b/common/setting.go index 8f061425..4dcce5f9 100644 --- a/common/setting.go +++ b/common/setting.go @@ -3,6 +3,7 @@ package common import "strconv" import "strings" import "sync/atomic" +import "../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 type SettingMap map[string]interface{} @@ -27,7 +28,12 @@ func init() { } func LoadSettings() error { - rows, err := stmts.getFullSettings.Query() + // TODO: Stop doing this inline + getFullSettings, err := qgen.Builder.SimpleSelect("settings", "name, content, type, constraints", "", "", "") + if err != nil { + return err + } + rows, err := getFullSettings.Query() if err != nil { return err } diff --git a/common/site.go b/common/site.go index 9d176011..f6354f31 100644 --- a/common/site.go +++ b/common/site.go @@ -6,24 +6,31 @@ import ( "strings" ) -var site = &Site{Name: "Magical Fairy Land", Language: "english"} -var dbConfig = DBConfig{Host: "localhost"} -var config Config -var dev DevConfig +// Site holds the basic settings which should be tweaked when setting up a site, we might move them to the settings table at some point +var Site = &site{Name: "Magical Fairy Land", Language: "english"} -type Site struct { +// DbConfig holds the database configuration +var DbConfig = dbConfig{Host: "localhost"} + +// Config holds the more technical settings +var Config config + +// Dev holds build flags and other things which should only be modified during developers or to gather additional test data +var Dev devConfig + +type site struct { ShortName string - Name string // ? - Move this into the settings table? Should we make a second version of this for the abbreviation shown in the navbar? - Email string // ? - Move this into the settings table? + Name string + Email string URL string Port string EnableSsl bool EnableEmails bool HasProxy bool - Language string // ? - Move this into the settings table? + Language string } -type DBConfig struct { +type dbConfig struct { // Production database Host string Username string @@ -39,7 +46,7 @@ type DBConfig struct { TestPort string } -type Config struct { +type config struct { SslPrivkey string SslFullchain string @@ -65,7 +72,7 @@ type Config struct { ItemsPerPage int // ? - Move this into the settings table? } -type DevConfig struct { +type devConfig struct { DebugMode bool SuperDebug bool TemplateDebug bool @@ -73,35 +80,35 @@ type DevConfig struct { TestDB bool } -func processConfig() error { - config.Noavatar = strings.Replace(config.Noavatar, "{site_url}", site.URL, -1) - if site.Port != "80" && site.Port != "443" { - site.URL = strings.TrimSuffix(site.URL, "/") - site.URL = strings.TrimSuffix(site.URL, "\\") - site.URL = strings.TrimSuffix(site.URL, ":") - site.URL = site.URL + ":" + site.Port +func ProcessConfig() error { + Config.Noavatar = strings.Replace(Config.Noavatar, "{site_url}", Site.URL, -1) + if Site.Port != "80" && Site.Port != "443" { + Site.URL = strings.TrimSuffix(Site.URL, "/") + Site.URL = strings.TrimSuffix(Site.URL, "\\") + Site.URL = strings.TrimSuffix(Site.URL, ":") + Site.URL = Site.URL + ":" + Site.Port } // We need this in here rather than verifyConfig as switchToTestDB() currently overwrites the values it verifies - if dbConfig.TestDbname == dbConfig.Dbname { + if DbConfig.TestDbname == DbConfig.Dbname { return errors.New("Your test database can't have the same name as your production database") } - if dev.TestDB { - switchToTestDB() + if Dev.TestDB { + SwitchToTestDB() } return nil } -func verifyConfig() error { - if !fstore.Exists(config.DefaultForum) { +func VerifyConfig() error { + if !Fstore.Exists(Config.DefaultForum) { return errors.New("Invalid default forum") } return nil } -func switchToTestDB() { - dbConfig.Host = dbConfig.TestHost - dbConfig.Username = dbConfig.TestUsername - dbConfig.Password = dbConfig.TestPassword - dbConfig.Dbname = dbConfig.TestDbname - dbConfig.Port = dbConfig.TestPort +func SwitchToTestDB() { + DbConfig.Host = DbConfig.TestHost + DbConfig.Username = DbConfig.TestUsername + DbConfig.Password = DbConfig.TestPassword + DbConfig.Dbname = DbConfig.TestDbname + DbConfig.Port = DbConfig.TestPort } diff --git a/tasks.go b/common/tasks.go similarity index 64% rename from tasks.go rename to common/tasks.go index f5b95bb4..c5fb7d42 100644 --- a/tasks.go +++ b/common/tasks.go @@ -4,11 +4,13 @@ * Copyright Azareal 2017 - 2018 * */ -package main +package common import ( "log" "time" + + "../query_gen/lib" ) var lastSync time.Time @@ -17,8 +19,12 @@ func init() { lastSync = time.Now() } -func handleExpiredScheduledGroups() error { - rows, err := stmts.getExpiredScheduledGroups.Query() +func HandleExpiredScheduledGroups() error { + getExpiredScheduledGroups, err := qgen.Builder.SimpleSelect("users_groups_scheduler", "uid", "UTC_TIMESTAMP() > revert_at AND temporary = 1", "", "") + if err != nil { + return err + } + rows, err := getExpiredScheduledGroups.Query() if err != nil { return err } @@ -32,7 +38,7 @@ func handleExpiredScheduledGroups() error { } // Sneaky way of initialising a *User, please use the methods on the UserStore instead - user := getDummyUser() + user := BlankUser() user.ID = uid err = user.RevertGroupUpdate() if err != nil { @@ -42,16 +48,20 @@ func handleExpiredScheduledGroups() error { return rows.Err() } -func handleServerSync() error { +func HandleServerSync() error { var lastUpdate time.Time - err := stmts.getSync.QueryRow().Scan(&lastUpdate) + getSync, err := qgen.Builder.SimpleSelect("sync", "last_update", "", "", "") + if err != nil { + return err + } + err = getSync.QueryRow().Scan(&lastUpdate) if err != nil { return err } if lastUpdate.After(lastSync) { // TODO: A more granular sync - err = fstore.LoadForums() + err = Fstore.LoadForums() if err != nil { log.Print("Unable to reload the forums") return err diff --git a/common/template_init.go b/common/template_init.go index ea272d94..248aa370 100644 --- a/common/template_init.go +++ b/common/template_init.go @@ -5,10 +5,12 @@ import ( "log" "net/http" "time" + + "./templates" ) -var templates = template.New("") -var prebuildTmplList []func(*User, *HeaderVars) CTmpl +var Templates = template.New("") +var PrebuildTmplList []func(User, *HeaderVars) CTmpl type CTmpl struct { Name string @@ -20,11 +22,11 @@ type CTmpl struct { // nolint func interpreted_topic_template(pi TopicPage, w http.ResponseWriter) error { - mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap["topic"] + mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["topic"] if !ok { mapping = "topic" } - return templates.ExecuteTemplate(w, mapping+".html", pi) + return Templates.ExecuteTemplate(w, mapping+".html", pi) } // nolint @@ -33,64 +35,66 @@ var template_topic_alt_handle func(TopicPage, http.ResponseWriter) error = inter // nolint var template_topics_handle func(TopicsPage, http.ResponseWriter) error = func(pi TopicsPage, w http.ResponseWriter) error { - mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap["topics"] + mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["topics"] if !ok { mapping = "topics" } - return templates.ExecuteTemplate(w, mapping+".html", pi) + return Templates.ExecuteTemplate(w, mapping+".html", pi) } // nolint var template_forum_handle func(ForumPage, http.ResponseWriter) error = func(pi ForumPage, w http.ResponseWriter) error { - mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap["forum"] + mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["forum"] if !ok { mapping = "forum" } - return templates.ExecuteTemplate(w, mapping+".html", pi) + return Templates.ExecuteTemplate(w, mapping+".html", pi) } // nolint var template_forums_handle func(ForumsPage, http.ResponseWriter) error = func(pi ForumsPage, w http.ResponseWriter) error { - mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap["forums"] + mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["forums"] if !ok { mapping = "forums" } - return templates.ExecuteTemplate(w, mapping+".html", pi) + return Templates.ExecuteTemplate(w, mapping+".html", pi) } // nolint var template_profile_handle func(ProfilePage, http.ResponseWriter) error = func(pi ProfilePage, w http.ResponseWriter) error { - mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap["profile"] + mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["profile"] if !ok { mapping = "profile" } - return templates.ExecuteTemplate(w, mapping+".html", pi) + return Templates.ExecuteTemplate(w, mapping+".html", pi) } // nolint var template_create_topic_handle func(CreateTopicPage, http.ResponseWriter) error = func(pi CreateTopicPage, w http.ResponseWriter) error { - mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap["create-topic"] + mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["create-topic"] if !ok { mapping = "create-topic" } - return templates.ExecuteTemplate(w, mapping+".html", pi) + return Templates.ExecuteTemplate(w, mapping+".html", pi) } // ? - Add template hooks? func compileTemplates() error { - var c CTemplateSet + var c tmpl.CTemplateSet + c.Minify(Config.MinifyTemplates) + c.SuperDebug(Dev.TemplateDebug) // Schemas to train the template compiler on what to expect // TODO: Add support for interface{}s - user := User{62, buildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0} + user := User{62, BuildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0} // TODO: Do a more accurate level calculation for this? - user2 := User{1, buildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", "", "", "", "", 58, 1000, "127.0.0.1", 0} - user3 := User{2, buildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", "", "", "", "", 42, 900, "::1", 0} + user2 := User{1, BuildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", "", "", "", "", 58, 1000, "127.0.0.1", 0} + user3 := User{2, BuildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", "", "", "", "", 42, 900, "::1", 0} headerVars := &HeaderVars{ - Site: site, - Settings: settingBox.Load().(SettingBox), - Themes: themes, - ThemeName: defaultThemeBox.Load().(string), + Site: Site, + Settings: SettingBox.Load().(SettingMap), + Themes: Themes, + ThemeName: DefaultThemeBox.Load().(string), NoticeList: []string{"test"}, Stylesheets: []string{"panel"}, Scripts: []string{"whatever"}, @@ -102,31 +106,31 @@ func compileTemplates() error { log.Print("Compiling the templates") var now = time.Now() - topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, now, relativeTime(now), now, relativeTime(now), 0, "", "127.0.0.1", 0, 1, "classname", "weird-data", buildProfileURL("fake-user", 62), "Fake User", config.DefaultGroup, "", 0, "", "", "", "", "", 58, false} + topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, now, RelativeTime(now), now, RelativeTime(now), 0, "", "127.0.0.1", 0, 1, "classname", "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, "", 0, "", "", "", "", "", 58, false} var replyList []ReplyUser - replyList = append(replyList, ReplyUser{0, 0, "Yo!", "Yo!", 0, "alice", "Alice", config.DefaultGroup, now, relativeTime(now), 0, 0, "", "", 0, "", "", "", "", 0, "127.0.0.1", false, 1, "", ""}) + replyList = append(replyList, ReplyUser{0, 0, "Yo!", "Yo!", 0, "alice", "Alice", Config.DefaultGroup, now, RelativeTime(now), 0, 0, "", "", 0, "", "", "", "", 0, "127.0.0.1", false, 1, "", ""}) - var varList = make(map[string]VarItem) + var varList = make(map[string]tmpl.VarItem) tpage := TopicPage{"Title", user, headerVars, replyList, topic, 1, 1} - topicIDTmpl, err := c.compileTemplate("topic.html", "templates/", "TopicPage", tpage, varList) + topicIDTmpl, err := c.Compile("topic.html", "templates/", "TopicPage", tpage, varList) if err != nil { return err } - topicIDAltTmpl, err := c.compileTemplate("topic_alt.html", "templates/", "TopicPage", tpage, varList) + topicIDAltTmpl, err := c.Compile("topic_alt.html", "templates/", "TopicPage", tpage, varList) if err != nil { return err } - varList = make(map[string]VarItem) + varList = make(map[string]tmpl.VarItem) ppage := ProfilePage{"User 526", user, headerVars, replyList, user} - profileTmpl, err := c.compileTemplate("profile.html", "templates/", "ProfilePage", ppage, varList) + profileTmpl, err := c.Compile("profile.html", "templates/", "ProfilePage", ppage, varList) if err != nil { return err } // TODO: Use a dummy forum list to avoid o(n) problems var forumList []Forum - forums, err := fstore.GetAll() + forums, err := Fstore.GetAll() if err != nil { return err } @@ -135,17 +139,17 @@ func compileTemplates() error { //log.Printf("*forum %+v\n", *forum) forumList = append(forumList, *forum) } - varList = make(map[string]VarItem) + varList = make(map[string]tmpl.VarItem) forumsPage := ForumsPage{"Forum List", user, headerVars, forumList} - forumsTmpl, err := c.compileTemplate("forums.html", "templates/", "ForumsPage", forumsPage, varList) + forumsTmpl, err := c.Compile("forums.html", "templates/", "ForumsPage", forumsPage, varList) if err != nil { return err } var topicsList []*TopicsRow topicsList = append(topicsList, &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, "Date", time.Now(), "Date", user3.ID, 1, "", "127.0.0.1", 0, 1, "classname", "", &user2, "", 0, &user3, "General", "/forum/general.2"}) - topicsPage := TopicsPage{"Topic List", user, headerVars, topicsList, forumList, config.DefaultForum} - topicsTmpl, err := c.compileTemplate("topics.html", "templates/", "TopicsPage", topicsPage, varList) + topicsPage := TopicsPage{"Topic List", user, headerVars, topicsList, forumList, Config.DefaultForum} + topicsTmpl, err := c.Compile("topics.html", "templates/", "TopicsPage", topicsPage, varList) if err != nil { return err } @@ -154,20 +158,20 @@ func compileTemplates() error { //topicList = append(topicList,TopicUser{1,"topic-title","Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"classname","","admin-fred","Admin Fred",config.DefaultGroup,"",0,"","","","",58,false}) forumItem := makeDummyForum(1, "general-forum.1", "General Forum", "Where the general stuff happens", true, "all", 0, "", 0) forumPage := ForumPage{"General Forum", user, headerVars, topicsList, forumItem, 1, 1} - forumTmpl, err := c.compileTemplate("forum.html", "templates/", "ForumPage", forumPage, varList) + forumTmpl, err := c.Compile("forum.html", "templates/", "ForumPage", forumPage, varList) if err != nil { return err } // Let plugins register their own templates - for _, tmplfunc := range prebuildTmplList { - tmpl := tmplfunc(user, headerVars) - varList = make(map[string]VarItem) - compiledTmpl, err := c.compileTemplate(tmpl.Filename, tmpl.Path, tmpl.StructName, tmpl.Data, varList) + for _, tmplfunc := range PrebuildTmplList { + tmplItem := tmplfunc(user, headerVars) + varList = make(map[string]tmpl.VarItem) + compiledTmpl, err := c.Compile(tmplItem.Filename, tmplItem.Path, tmplItem.StructName, tmplItem.Data, varList) if err != nil { return err } - go writeTemplate(tmpl.Name, compiledTmpl) + go writeTemplate(tmplItem.Name, compiledTmpl) } log.Print("Writing the templates") @@ -194,8 +198,8 @@ func writeTemplate(name string, content string) { } } -func initTemplates() { - if dev.DebugMode { +func InitTemplates() { + if Dev.DebugMode { log.Print("Initialising the template system") } compileTemplates() @@ -259,10 +263,10 @@ func initTemplates() { } // The interpreted templates... - if dev.DebugMode { + if Dev.DebugMode { log.Print("Loading the template files...") } - templates.Funcs(fmap) - template.Must(templates.ParseGlob("templates/*")) - template.Must(templates.ParseGlob("pages/*")) + Templates.Funcs(fmap) + template.Must(Templates.ParseGlob("templates/*")) + template.Must(Templates.ParseGlob("pages/*")) } diff --git a/templates.go b/common/templates/templates.go similarity index 96% rename from templates.go rename to common/templates/templates.go index 0eec8584..7f28c7bd 100644 --- a/templates.go +++ b/common/templates/templates.go @@ -1,4 +1,4 @@ -package main +package tmpl import ( "bytes" @@ -14,8 +14,7 @@ import ( ) // TODO: Turn this file into a library -var ctemplates []string -var tmplPtrMap = make(map[string]interface{}) +var cTemplates []string var textOverlapList = make(map[string]int) // nolint @@ -47,11 +46,26 @@ type CTemplateSet struct { nextNode parse.NodeType //tempVars map[string]string doImports bool + minify bool + debug bool + superDebug bool expectsInt interface{} } -func (c *CTemplateSet) compileTemplate(name string, dir string, expects string, expectsInt interface{}, varList map[string]VarItem) (out string, err error) { - if dev.DebugMode { +func (c *CTemplateSet) Minify(on bool) { + c.minify = on +} + +func (c *CTemplateSet) Debug(on bool) { + c.debug = on +} + +func (c *CTemplateSet) SuperDebug(on bool) { + c.superDebug = on +} + +func (c *CTemplateSet) Compile(name string, dir string, expects string, expectsInt interface{}, varList map[string]VarItem) (out string, err error) { + if c.debug { fmt.Println("Compiling template '" + name + "'") } @@ -75,6 +89,7 @@ func (c *CTemplateSet) compileTemplate(name string, dir string, expects string, c.importMap = map[string]string{ "net/http": "net/http", + "./common": "./common", } c.varList = varList //c.pVarList = "" @@ -89,7 +104,7 @@ func (c *CTemplateSet) compileTemplate(name string, dir string, expects string, } content := string(res) - if config.MinifyTemplates { + if c.minify { content = minify(content) } @@ -133,7 +148,7 @@ func (c *CTemplateSet) compileTemplate(name string, dir string, expects string, fout := "// +build !no_templategen\n\n// Code generated by Gosora. More below:\n/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */\n" fout += "package main\n" + importList + c.pVarList + "\n" - fout += "// nolint\nfunc init() {\n\ttemplate_" + fname + "_handle = template_" + fname + "\n\t//o_template_" + fname + "_handle = template_" + fname + "\n\tctemplates = append(ctemplates,\"" + fname + "\")\n\ttmplPtrMap[\"" + fname + "\"] = &template_" + fname + "_handle\n\ttmplPtrMap[\"o_" + fname + "\"] = template_" + fname + "\n}\n\n" + fout += "// nolint\nfunc init() {\n\ttemplate_" + fname + "_handle = template_" + fname + "\n\t//o_template_" + fname + "_handle = template_" + fname + "\n\tctemplates = append(ctemplates,\"" + fname + "\")\n\tTmplPtrMap[\"" + fname + "\"] = &template_" + fname + "_handle\n\tcommon.TmplPtrMap[\"o_" + fname + "\"] = template_" + fname + "\n}\n\n" fout += "// nolint\nfunc template_" + fname + "(tmpl_" + fname + "_vars " + expects + ", w http.ResponseWriter) error {\n" + varString + out + "\treturn nil\n}\n" fout = strings.Replace(fout, `)) @@ -143,7 +158,7 @@ w.Write([]byte(`, " + ", -1) //whitespaceWrites := regexp.MustCompile(`(?s)w.Write\(\[\]byte\(`+spstr+`\)\)`) //fout = whitespaceWrites.ReplaceAllString(fout,"") - if dev.DebugMode { + if c.debug { for index, count := range c.stats { fmt.Println(index+": ", strconv.Itoa(count)) } @@ -160,9 +175,7 @@ func (c *CTemplateSet) rootIterate(tree *parse.Tree, varholder string, holdrefle c.log(tree.Root) treeLength := len(tree.Root.Nodes) for index, node := range tree.Root.Nodes { - if dev.TemplateDebug { - fmt.Println("Node:", node.String()) - } + c.log("Node:", node.String()) c.previousNode = c.currentNode c.currentNode = node.Type() if treeLength != (index + 1) { @@ -245,9 +258,7 @@ func (c *CTemplateSet) compileRangeNode(varholder string, holdreflect reflect.Va var outVal reflect.Value for _, cmd := range node.Pipe.Cmds { - if dev.TemplateDebug { - fmt.Println("Range Bit:", cmd) - } + c.log("Range Bit:", cmd) out, outVal = c.compileReflectSwitch(varholder, holdreflect, templateName, cmd) } c.log("Returned:", out) @@ -259,7 +270,7 @@ func (c *CTemplateSet) compileRangeNode(varholder string, holdreflect reflect.Va for _, key := range outVal.MapKeys() { item = outVal.MapIndex(key) } - if dev.DebugMode { + if c.debug { fmt.Println("Range item:", item) } if !item.IsValid() { @@ -317,11 +328,11 @@ func (c *CTemplateSet) compileSubswitch(varholder string, holdreflect reflect.Va } if !cur.IsValid() { - if dev.DebugMode { + if c.debug { fmt.Println("Debug Data:") fmt.Println("Holdreflect:", holdreflect) fmt.Println("Holdreflect.Kind():", holdreflect.Kind()) - if !dev.TemplateDebug { + if !c.superDebug { fmt.Println("cur.Kind():", cur.Kind().String()) } fmt.Println("") @@ -382,7 +393,7 @@ func (c *CTemplateSet) compileVarswitch(varholder string, holdreflect reflect.Va firstWord := node.Args[0] switch n := firstWord.(type) { case *parse.FieldNode: - if dev.TemplateDebug { + if c.superDebug { fmt.Println("Field Node:", n.Ident) for _, id := range n.Ident { fmt.Println("Field Bit:", id) @@ -564,7 +575,7 @@ func (c *CTemplateSet) compileReflectSwitch(varholder string, holdreflect reflec firstWord := node.Args[0] switch n := firstWord.(type) { case *parse.FieldNode: - if dev.TemplateDebug { + if c.superDebug { fmt.Println("Field Node:", n.Ident) for _, id := range n.Ident { fmt.Println("Field Bit:", id) @@ -771,7 +782,7 @@ func (c *CTemplateSet) compileSubtemplate(pvarholder string, pholdreflect reflec } content := string(res) - if config.MinifyTemplates { + if c.minify { content = minify(content) } @@ -795,7 +806,7 @@ func (c *CTemplateSet) compileSubtemplate(pvarholder string, pholdreflect reflec } func (c *CTemplateSet) log(args ...interface{}) { - if dev.TemplateDebug { + if c.superDebug { fmt.Println(args...) } } diff --git a/common/themes.go b/common/themes.go index fbe7b744..41cfd0f1 100644 --- a/common/themes.go +++ b/common/themes.go @@ -17,13 +17,15 @@ import ( "sync" "sync/atomic" "text/template" + + "../query_gen/lib" ) type ThemeList map[string]Theme -//var themes ThemeList = make(map[string]Theme) +var Themes ThemeList = make(map[string]Theme) var DefaultThemeBox atomic.Value -var changeDefaultThemeMutex sync.Mutex +var ChangeDefaultThemeMutex sync.Mutex // TODO: Use this when the default theme doesn't exist var fallbackTheme = "shadow" @@ -73,14 +75,19 @@ type ThemeResource struct { } func init() { - defaultThemeBox.Store(fallbackTheme) + DefaultThemeBox.Store(fallbackTheme) } // TODO: Make the initThemes and LoadThemes functions less confusing // ? - Delete themes which no longer exist in the themes folder from the database? -func LoadThemeActiveStatus() error { - changeDefaultThemeMutex.Lock() - rows, err := stmts.getThemes.Query() +func (themes ThemeList) LoadActiveStatus() error { + getThemes, err := qgen.Builder.SimpleSelect("themes", "uname, default", "", "", "") + if err != nil { + return err + } + + ChangeDefaultThemeMutex.Lock() + rows, err := getThemes.Query() if err != nil { return err } @@ -103,8 +110,8 @@ func LoadThemeActiveStatus() error { if defaultThemeSwitch { log.Print("Loading the default theme '" + theme.Name + "'") theme.Active = true - defaultThemeBox.Store(theme.Name) - mapThemeTemplates(theme) + DefaultThemeBox.Store(theme.Name) + MapThemeTemplates(theme) } else { log.Print("Loading the theme '" + theme.Name + "'") theme.Active = false @@ -112,11 +119,11 @@ func LoadThemeActiveStatus() error { themes[uname] = theme } - changeDefaultThemeMutex.Unlock() + ChangeDefaultThemeMutex.Unlock() return rows.Err() } -func initThemes() error { +func InitThemes() error { themeFiles, err := ioutil.ReadDir("./themes") if err != nil { return err @@ -156,10 +163,10 @@ func initThemes() error { } if theme.FullImage != "" { - if dev.DebugMode { + if Dev.DebugMode { log.Print("Adding theme image") } - err = addStaticFile("./themes/"+themeName+"/"+theme.FullImage, "./themes/"+themeName) + err = StaticFiles.Add("./themes/"+themeName+"/"+theme.FullImage, "./themes/"+themeName) if err != nil { return err } @@ -170,7 +177,7 @@ func initThemes() error { if theme.Templates != nil { for _, themeTmpl := range theme.Templates { theme.TemplatesMap[themeTmpl.Name] = themeTmpl.Source - theme.TmplPtr[themeTmpl.Name] = tmplPtrMap["o_"+themeTmpl.Source] + theme.TmplPtr[themeTmpl.Name] = TmplPtrMap["o_"+themeTmpl.Source] } } @@ -178,20 +185,20 @@ func initThemes() error { template.Must(theme.ResourceTemplates.ParseGlob("./themes/" + theme.Name + "/public/*.css")) // It should be safe for us to load the files for all the themes in memory, as-long as the admin hasn't setup a ridiculous number of themes - err = addThemeStaticFiles(theme) + err = AddThemeStaticFiles(theme) if err != nil { return err } - themes[theme.Name] = theme + Themes[theme.Name] = theme } return nil } -func addThemeStaticFiles(theme Theme) error { +func AddThemeStaticFiles(theme Theme) error { // TODO: Use a function instead of a closure to make this more testable? What about a function call inside the closure to take the theme variable into account? return filepath.Walk("./themes/"+theme.Name+"/public", func(path string, f os.FileInfo, err error) error { - if dev.DebugMode { + if Dev.DebugMode { log.Print("Attempting to add static file '" + path + "' for default theme '" + theme.Name + "'") } if err != nil { @@ -224,16 +231,16 @@ func addThemeStaticFiles(theme Theme) error { path = strings.TrimPrefix(path, "themes/"+theme.Name+"/public") gzipData := compressBytesGzip(data) - staticFiles["/static/"+theme.Name+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)} + StaticFiles["/static/"+theme.Name+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)} - if dev.DebugMode { + if Dev.DebugMode { log.Print("Added the '/" + theme.Name + path + "' static file for theme " + theme.Name + ".") } return nil }) } -func mapThemeTemplates(theme Theme) { +func MapThemeTemplates(theme Theme) { if theme.Templates != nil { for _, themeTmpl := range theme.Templates { if themeTmpl.Name == "" { @@ -245,11 +252,11 @@ func mapThemeTemplates(theme Theme) { // `go generate` is one possibility for letting plugins inject custom page structs, but it would simply add another step of compilation. It might be simpler than the current build process from the perspective of the administrator? - destTmplPtr, ok := tmplPtrMap[themeTmpl.Name] + destTmplPtr, ok := TmplPtrMap[themeTmpl.Name] if !ok { return } - sourceTmplPtr, ok := tmplPtrMap[themeTmpl.Source] + sourceTmplPtr, ok := TmplPtrMap[themeTmpl.Source] if !ok { log.Fatal("The source template doesn't exist!") } @@ -325,20 +332,20 @@ func mapThemeTemplates(theme Theme) { } } -func resetTemplateOverrides() { +func ResetTemplateOverrides() { log.Print("Resetting the template overrides") for name := range overridenTemplates { log.Print("Resetting '" + name + "' template override") - originPointer, ok := tmplPtrMap["o_"+name] + originPointer, ok := TmplPtrMap["o_"+name] if !ok { //log.Fatal("The origin template doesn't exist!") log.Print("The origin template doesn't exist!") return } - destTmplPtr, ok := tmplPtrMap[name] + destTmplPtr, ok := TmplPtrMap[name] if !ok { //log.Fatal("The destination template doesn't exist!") log.Print("The destination template doesn't exist!") @@ -447,11 +454,11 @@ func RunThemeTemplate(theme string, template string, pi interface{}, w http.Resp case func(Page, http.ResponseWriter) error: return tmplO(pi.(Page), w) case string: - mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap[template] + mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap[template] if !ok { mapping = template } - return templates.ExecuteTemplate(w, mapping+".html", pi) + return Templates.ExecuteTemplate(w, mapping+".html", pi) default: log.Print("theme ", theme) log.Print("template ", template) @@ -474,11 +481,11 @@ func RunThemeTemplate(theme string, template string, pi interface{}, w http.Resp // GetThemeTemplate attempts to get the template for a specific theme, otherwise it falls back on the default template pointer, which if absent will fallback onto the template interpreter func GetThemeTemplate(theme string, template string) interface{} { - tmpl, ok := themes[theme].TmplPtr[template] + tmpl, ok := Themes[theme].TmplPtr[template] if ok { return tmpl } - tmpl, ok = tmplPtrMap[template] + tmpl, ok = TmplPtrMap[template] if ok { return tmpl } @@ -487,19 +494,19 @@ func GetThemeTemplate(theme string, template string) interface{} { // CreateThemeTemplate creates a theme template on the current default theme func CreateThemeTemplate(theme string, name string) { - themes[theme].TmplPtr[name] = func(pi Page, w http.ResponseWriter) error { - mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap[name] + Themes[theme].TmplPtr[name] = func(pi Page, w http.ResponseWriter) error { + mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap[name] if !ok { mapping = name } - return templates.ExecuteTemplate(w, mapping+".html", pi) + return Templates.ExecuteTemplate(w, mapping+".html", pi) } } func GetDefaultThemeName() string { - return defaultThemeBox.Load().(string) + return DefaultThemeBox.Load().(string) } func SetDefaultThemeName(name string) { - defaultThemeBox.Store(name) + DefaultThemeBox.Store(name) } diff --git a/common/topic.go b/common/topic.go index b8df45d6..dc06faf0 100644 --- a/common/topic.go +++ b/common/topic.go @@ -6,12 +6,14 @@ */ package common -//import "fmt" import ( + "database/sql" "html" "html/template" "strconv" "time" + + "../query_gen/lib" ) // This is also in reply.go @@ -105,10 +107,49 @@ type TopicsRow struct { ForumLink string } +type TopicStmts struct { + addRepliesToTopic *sql.Stmt + lock *sql.Stmt + unlock *sql.Stmt + stick *sql.Stmt + unstick *sql.Stmt + hasLikedTopic *sql.Stmt + createLike *sql.Stmt + addLikesToTopic *sql.Stmt + delete *sql.Stmt + edit *sql.Stmt + createActionReply *sql.Stmt + + getTopicUser *sql.Stmt // TODO: Can we get rid of this? +} + +var topicStmts TopicStmts + +func init() { + DbInits.Add(func() error { + acc := qgen.Builder.Accumulator() + topicStmts = TopicStmts{ + addRepliesToTopic: acc.SimpleUpdate("topics", "postCount = postCount + ?, lastReplyBy = ?, lastReplyAt = UTC_TIMESTAMP()", "tid = ?"), + lock: acc.SimpleUpdate("topics", "is_closed = 1", "tid = ?"), + unlock: acc.SimpleUpdate("topics", "is_closed = 0", "tid = ?"), + stick: acc.SimpleUpdate("topics", "sticky = 1", "tid = ?"), + unstick: acc.SimpleUpdate("topics", "sticky = 0", "tid = ?"), + hasLikedTopic: acc.SimpleSelect("likes", "targetItem", "sentBy = ? and targetItem = ? and targetType = 'topics'", "", ""), + createLike: acc.SimpleInsert("likes", "weight, targetItem, targetType, sentBy", "?,?,?,?"), + addLikesToTopic: acc.SimpleUpdate("topics", "likeCount = likeCount + ?", "tid = ?"), + delete: acc.SimpleDelete("topics", "tid = ?"), + edit: acc.SimpleUpdate("topics", "title = ?, content = ?, parsed_content = ?", "tid = ?"), + createActionReply: acc.SimpleInsert("replies", "tid, actionType, ipaddress, createdBy, createdAt, lastUpdated, content, parsed_content", "?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'',''"), + getTopicUser: acc.SimpleLeftJoin("topics", "users", "topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level", "topics.createdBy = users.uid", "tid = ?", "", ""), + } + return acc.FirstError() + }) +} + // Flush the topic out of the cache // ? - We do a CacheRemove() here instead of mutating the pointer to avoid creating a race condition func (topic *Topic) cacheRemove() { - tcache, ok := topics.(TopicCache) + tcache, ok := Topics.(TopicCache) if ok { tcache.CacheRemove(topic.ID) } @@ -116,32 +157,32 @@ func (topic *Topic) cacheRemove() { // TODO: Write a test for this func (topic *Topic) AddReply(uid int) (err error) { - _, err = stmts.addRepliesToTopic.Exec(1, uid, topic.ID) + _, err = topicStmts.addRepliesToTopic.Exec(1, uid, topic.ID) topic.cacheRemove() return err } func (topic *Topic) Lock() (err error) { - _, err = stmts.lockTopic.Exec(topic.ID) + _, err = topicStmts.lock.Exec(topic.ID) topic.cacheRemove() return err } func (topic *Topic) Unlock() (err error) { - _, err = stmts.unlockTopic.Exec(topic.ID) + _, err = topicStmts.unlock.Exec(topic.ID) topic.cacheRemove() return err } // TODO: We might want more consistent terminology rather than using stick in some places and pin in others. If you don't understand the difference, there is none, they are one and the same. func (topic *Topic) Stick() (err error) { - _, err = stmts.stickTopic.Exec(topic.ID) + _, err = topicStmts.stick.Exec(topic.ID) topic.cacheRemove() return err } func (topic *Topic) Unstick() (err error) { - _, err = stmts.unstickTopic.Exec(topic.ID) + _, err = topicStmts.unstick.Exec(topic.ID) topic.cacheRemove() return err } @@ -150,19 +191,19 @@ func (topic *Topic) Unstick() (err error) { // TODO: Use a transaction for this func (topic *Topic) Like(score int, uid int) (err error) { var tid int // Unused - err = stmts.hasLikedTopic.QueryRow(uid, topic.ID).Scan(&tid) + err = topicStmts.hasLikedTopic.QueryRow(uid, topic.ID).Scan(&tid) if err != nil && err != ErrNoRows { return err } else if err != ErrNoRows { return ErrAlreadyLiked } - _, err = stmts.createLike.Exec(score, tid, "topics", uid) + _, err = topicStmts.createLike.Exec(score, tid, "topics", uid) if err != nil { return err } - _, err = stmts.addLikesToTopic.Exec(1, tid) + _, err = topicStmts.addLikesToTopic.Exec(1, tid) topic.cacheRemove() return err } @@ -174,10 +215,10 @@ func (topic *Topic) Unlike(uid int) error { // TODO: Use a transaction here func (topic *Topic) Delete() error { - topicCreator, err := users.Get(topic.CreatedBy) + topicCreator, err := Users.Get(topic.CreatedBy) if err == nil { - wcount := wordCount(topic.Content) - err = topicCreator.decreasePostStats(wcount, true) + wcount := WordCount(topic.Content) + err = topicCreator.DecreasePostStats(wcount, true) if err != nil { return err } @@ -185,31 +226,31 @@ func (topic *Topic) Delete() error { return err } - err = fstore.RemoveTopic(topic.ParentID) + err = Fstore.RemoveTopic(topic.ParentID) if err != nil && err != ErrNoRows { return err } - _, err = stmts.deleteTopic.Exec(topic.ID) + _, err = topicStmts.delete.Exec(topic.ID) topic.cacheRemove() return err } func (topic *Topic) Update(name string, content string) error { - content = preparseMessage(content) - parsed_content := parseMessage(html.EscapeString(content), topic.ParentID, "forums") - - _, err := stmts.editTopic.Exec(name, content, parsed_content, topic.ID) + content = PreparseMessage(content) + parsedContent := ParseMessage(html.EscapeString(content), topic.ParentID, "forums") + _, err := topicStmts.edit.Exec(name, content, parsedContent, topic.ID) topic.cacheRemove() return err } +// TODO: Have this go through the ReplyStore? func (topic *Topic) CreateActionReply(action string, ipaddress string, user User) (err error) { - _, err = stmts.createActionReply.Exec(topic.ID, action, ipaddress, user.ID) + _, err = topicStmts.createActionReply.Exec(topic.ID, action, ipaddress, user.ID) if err != nil { return err } - _, err = stmts.addRepliesToTopic.Exec(1, user.ID, topic.ID) + _, err = topicStmts.addRepliesToTopic.Exec(1, user.ID, topic.ID) topic.cacheRemove() // ? - Update the last topic cache for the parent forum? return err @@ -221,13 +262,13 @@ func (topic *Topic) Copy() Topic { } // TODO: Refactor the caller to take a Topic and a User rather than a combined TopicUser -func getTopicUser(tid int) (TopicUser, error) { - tcache, tok := topics.(TopicCache) - ucache, uok := users.(UserCache) +func GetTopicUser(tid int) (TopicUser, error) { + tcache, tok := Topics.(TopicCache) + ucache, uok := Users.(UserCache) if tok && uok { topic, err := tcache.CacheGet(tid) if err == nil { - user, err := users.Get(topic.CreatedBy) + user, err := Users.Get(topic.CreatedBy) if err != nil { return TopicUser{ID: tid}, err } @@ -235,11 +276,11 @@ func getTopicUser(tid int) (TopicUser, error) { // We might be better off just passing separate topic and user structs to the caller? return copyTopicToTopicUser(topic, user), nil } else if ucache.Length() < ucache.GetCapacity() { - topic, err = topics.Get(tid) + topic, err = Topics.Get(tid) if err != nil { return TopicUser{ID: tid}, err } - user, err := users.Get(topic.CreatedBy) + user, err := Users.Get(topic.CreatedBy) if err != nil { return TopicUser{ID: tid}, err } @@ -248,14 +289,14 @@ func getTopicUser(tid int) (TopicUser, error) { } tu := TopicUser{ID: tid} - err := stmts.getTopicUser.QueryRow(tid).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) - tu.Link = buildTopicURL(nameToSlug(tu.Title), tu.ID) - tu.UserLink = buildProfileURL(nameToSlug(tu.CreatedByName), tu.CreatedBy) - tu.Tag = gstore.DirtyGet(tu.Group).Tag + err := topicStmts.getTopicUser.QueryRow(tid).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) + tu.Link = BuildTopicURL(NameToSlug(tu.Title), tu.ID) + tu.UserLink = BuildProfileURL(NameToSlug(tu.CreatedByName), tu.CreatedBy) + tu.Tag = Gstore.DirtyGet(tu.Group).Tag if tok { theTopic := Topic{ID: tu.ID, Link: tu.Link, Title: tu.Title, Content: tu.Content, CreatedBy: tu.CreatedBy, IsClosed: tu.IsClosed, Sticky: tu.Sticky, CreatedAt: tu.CreatedAt, LastReplyAt: tu.LastReplyAt, ParentID: tu.ParentID, IPAddress: tu.IPAddress, PostCount: tu.PostCount, LikeCount: tu.LikeCount} - //log.Printf("the_topic: %+v\n", theTopic) + //log.Printf("theTopic: %+v\n", theTopic) _ = tcache.CacheAdd(&theTopic) } return tu, err @@ -289,18 +330,11 @@ func copyTopicToTopicUser(topic *Topic, user *User) (tu TopicUser) { } // For use in tests and for generating blank topics for forums which don't have a last poster -func getDummyTopic() *Topic { +func BlankTopic() *Topic { return &Topic{ID: 0, Title: ""} } -func getTopicByReply(rid int) (*Topic, error) { - topic := Topic{ID: 0} - err := stmts.getTopicByReply.QueryRow(rid).Scan(&topic.ID, &topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data) - topic.Link = buildTopicURL(nameToSlug(topic.Title), topic.ID) - return &topic, err -} - -func buildTopicURL(slug string, tid int) string { +func BuildTopicURL(slug string, tid int) string { if slug == "" { return "/topic/" + strconv.Itoa(tid) } diff --git a/common/topic_store.go b/common/topic_store.go index fbb165c9..8a1d7c3a 100644 --- a/common/topic_store.go +++ b/common/topic_store.go @@ -20,11 +20,12 @@ import ( // TODO: Add BulkGetMap // TODO: Add some sort of update method // ? - Should we add stick, lock, unstick, and unlock methods? These might be better on the Topics not the TopicStore -var topics TopicStore +var Topics TopicStore var ErrNoTitle = errors.New("This message is missing a title") var ErrNoBody = errors.New("This message is missing a body") type TopicStore interface { + DirtyGet(id int) *Topic Get(id int) (*Topic, error) BypassGet(id int) (*Topic, error) Exists(id int) bool @@ -93,6 +94,24 @@ func (mts *MemoryTopicStore) CacheGetUnsafe(id int) (*Topic, error) { return item, ErrNoRows } +func (mts *MemoryTopicStore) DirtyGet(id int) *Topic { + mts.RLock() + topic, ok := mts.items[id] + mts.RUnlock() + if ok { + return topic + } + + topic = &Topic{ID: id} + err := mts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data) + if err == nil { + topic.Link = BuildTopicURL(NameToSlug(topic.Title), id) + _ = mts.CacheAdd(topic) + return topic + } + return BlankTopic() +} + func (mts *MemoryTopicStore) Get(id int) (*Topic, error) { mts.RLock() topic, ok := mts.items[id] @@ -104,7 +123,7 @@ func (mts *MemoryTopicStore) Get(id int) (*Topic, error) { topic = &Topic{ID: id} err := mts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data) if err == nil { - topic.Link = buildTopicURL(nameToSlug(topic.Title), id) + topic.Link = BuildTopicURL(NameToSlug(topic.Title), id) _ = mts.CacheAdd(topic) } return topic, err @@ -114,7 +133,7 @@ func (mts *MemoryTopicStore) Get(id int) (*Topic, error) { func (mts *MemoryTopicStore) BypassGet(id int) (*Topic, error) { topic := &Topic{ID: id} err := mts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data) - topic.Link = buildTopicURL(nameToSlug(topic.Title), id) + topic.Link = BuildTopicURL(NameToSlug(topic.Title), id) return topic, err } @@ -122,7 +141,7 @@ func (mts *MemoryTopicStore) Reload(id int) error { topic := &Topic{ID: id} err := mts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data) if err == nil { - topic.Link = buildTopicURL(nameToSlug(topic.Title), id) + topic.Link = BuildTopicURL(NameToSlug(topic.Title), id) _ = mts.CacheSet(topic) } else { _ = mts.CacheRemove(id) @@ -141,12 +160,12 @@ func (mts *MemoryTopicStore) Create(fid int, topicName string, content string, u } content = strings.TrimSpace(content) - parsedContent := parseMessage(content, fid, "forums") + parsedContent := ParseMessage(content, fid, "forums") if strings.TrimSpace(parsedContent) == "" { return 0, ErrNoBody } - wcount := wordCount(content) + wcount := WordCount(content) // TODO: Move this statement into the topic store res, err := mts.create.Exec(fid, topicName, content, parsedContent, uid, ipaddress, wcount, uid) if err != nil { @@ -158,8 +177,7 @@ func (mts *MemoryTopicStore) Create(fid int, topicName string, content string, u return 0, err } - err = fstore.AddTopic(int(lastID), uid, fid) - return int(lastID), err + return int(lastID), Fstore.AddTopic(int(lastID), uid, fid) } func (mts *MemoryTopicStore) CacheSet(item *Topic) error { @@ -268,10 +286,20 @@ func NewSQLTopicStore() (*SQLTopicStore, error) { }, acc.FirstError() } +func (sts *SQLTopicStore) DirtyGet(id int) *Topic { + topic := &Topic{ID: id} + err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data) + topic.Link = BuildTopicURL(NameToSlug(topic.Title), id) + if err != nil { + return BlankTopic() + } + return topic +} + func (sts *SQLTopicStore) Get(id int) (*Topic, error) { topic := Topic{ID: id} err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data) - topic.Link = buildTopicURL(nameToSlug(topic.Title), id) + topic.Link = BuildTopicURL(NameToSlug(topic.Title), id) return &topic, err } @@ -279,7 +307,7 @@ func (sts *SQLTopicStore) Get(id int) (*Topic, error) { func (sts *SQLTopicStore) BypassGet(id int) (*Topic, error) { topic := &Topic{ID: id} err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data) - topic.Link = buildTopicURL(nameToSlug(topic.Title), id) + topic.Link = BuildTopicURL(NameToSlug(topic.Title), id) return topic, err } @@ -294,12 +322,12 @@ func (sts *SQLTopicStore) Create(fid int, topicName string, content string, uid } content = strings.TrimSpace(content) - parsedContent := parseMessage(content, fid, "forums") + parsedContent := ParseMessage(content, fid, "forums") if strings.TrimSpace(parsedContent) == "" { return 0, ErrNoBody } - wcount := wordCount(content) + wcount := WordCount(content) // TODO: Move this statement into the topic store res, err := sts.create.Exec(fid, topicName, content, parsedContent, uid, ipaddress, wcount, uid) if err != nil { @@ -311,8 +339,7 @@ func (sts *SQLTopicStore) Create(fid int, topicName string, content string, uid return 0, err } - err = fstore.AddTopic(int(lastID), uid, fid) - return int(lastID), err + return int(lastID), Fstore.AddTopic(int(lastID), uid, fid) } // ? - What're we going to do about this? diff --git a/common/user.go b/common/user.go index 01f0a4d8..7172b049 100644 --- a/common/user.go +++ b/common/user.go @@ -15,12 +15,14 @@ import ( "strings" "time" + "../query_gen/lib" "golang.org/x/crypto/bcrypt" ) // TODO: Replace any literals with this var BanGroup = 4 +// GuestUser is an instance of user which holds guest data to avoid having to initialise a guest every time var GuestUser = User{ID: 0, Link: "#", Group: 6, Perms: GuestPerms} //func(real_password string, password string, salt string) (err error) @@ -57,12 +59,48 @@ type User struct { TempGroup int } -type Email struct { - UserID int - Email string - Validated bool - Primary bool - Token string +type UserStmts struct { + activate *sql.Stmt + changeGroup *sql.Stmt + delete *sql.Stmt + setAvatar *sql.Stmt + setUsername *sql.Stmt + updateGroup *sql.Stmt + incrementTopics *sql.Stmt + updateLevel *sql.Stmt + incrementScore *sql.Stmt + incrementPosts *sql.Stmt + incrementBigposts *sql.Stmt + incrementMegaposts *sql.Stmt + updateLastIP *sql.Stmt + + setPassword *sql.Stmt +} + +var userStmts UserStmts + +func init() { + DbInits.Add(func() error { + acc := qgen.Builder.Accumulator() + userStmts = UserStmts{ + activate: acc.SimpleUpdate("users", "active = 1", "uid = ?"), + changeGroup: acc.SimpleUpdate("users", "group = ?", "uid = ?"), + delete: acc.SimpleDelete("users", "uid = ?"), + setAvatar: acc.SimpleUpdate("users", "avatar = ?", "uid = ?"), + setUsername: acc.SimpleUpdate("users", "name = ?", "uid = ?"), + updateGroup: acc.SimpleUpdate("users", "group = ?", "uid = ?"), + incrementTopics: acc.SimpleUpdate("users", "topics = topics + ?", "uid = ?"), + updateLevel: acc.SimpleUpdate("users", "level = ?", "uid = ?"), + incrementScore: acc.SimpleUpdate("users", "score = score + ?", "uid = ?"), + incrementPosts: acc.SimpleUpdate("users", "posts = posts + ?", "uid = ?"), + incrementBigposts: acc.SimpleUpdate("users", "posts = posts + ?, bigposts = bigposts + ?", "uid = ?"), + incrementMegaposts: acc.SimpleUpdate("users", "posts = posts + ?, bigposts = bigposts + ?, megaposts = megaposts + ?", "uid = ?"), + updateLastIP: acc.SimpleUpdate("users", "last_ip = ?", "uid = ?"), + + setPassword: acc.SimpleUpdate("users", "password = ?, salt = ?", "uid = ?"), + } + return acc.FirstError() + }) } func (user *User) Init() { @@ -71,15 +109,22 @@ func (user *User) Init() { user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + user.Avatar } } else { - user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1) + user.Avatar = strings.Replace(Config.Noavatar, "{id}", strconv.Itoa(user.ID), 1) + } + user.Link = BuildProfileURL(NameToSlug(user.Name), user.ID) + user.Tag = Gstore.DirtyGet(user.Group).Tag + user.InitPerms() +} + +func (user *User) CacheRemove() { + ucache, ok := Users.(UserCache) + if ok { + ucache.CacheRemove(user.ID) } - user.Link = buildProfileURL(nameToSlug(user.Name), user.ID) - user.Tag = gstore.DirtyGet(user.Group).Tag - user.initPerms() } func (user *User) Ban(duration time.Duration, issuedBy int) error { - return user.ScheduleGroupUpdate(banGroup, issuedBy, duration) + return user.ScheduleGroupUpdate(BanGroup, issuedBy, duration) } func (user *User) Unban() error { @@ -112,7 +157,7 @@ func (user *User) ScheduleGroupUpdate(gid int, issuedBy int, duration time.Durat } revertAt := time.Now().Add(duration) - tx, err := db.Begin() + tx, err := qgen.Builder.Begin() if err != nil { return err } @@ -138,15 +183,12 @@ func (user *User) ScheduleGroupUpdate(gid int, issuedBy int, duration time.Durat } err = tx.Commit() - ucache, ok := users.(UserCache) - if ok { - ucache.CacheRemove(user.ID) - } + user.CacheRemove() return err } func (user *User) RevertGroupUpdate() error { - tx, err := db.Begin() + tx, err := qgen.Builder.Begin() if err != nil { return err } @@ -163,25 +205,19 @@ func (user *User) RevertGroupUpdate() error { } err = tx.Commit() - ucache, ok := users.(UserCache) - if ok { - ucache.CacheRemove(user.ID) - } + user.CacheRemove() return err } // TODO: Use a transaction here // ? - Add a Deactivate method? Not really needed, if someone's been bad you could do a ban, I guess it might be useful, if someone says that email x isn't actually owned by the user in question? func (user *User) Activate() (err error) { - _, err = stmts.activateUser.Exec(user.ID) + _, err = userStmts.activate.Exec(user.ID) if err != nil { return err } - _, err = stmts.changeGroup.Exec(config.DefaultGroup, user.ID) - ucache, ok := users.(UserCache) - if ok { - ucache.CacheRemove(user.ID) - } + _, err = userStmts.changeGroup.Exec(Config.DefaultGroup, user.ID) + user.CacheRemove() return err } @@ -189,111 +225,105 @@ func (user *User) Activate() (err error) { // TODO: Delete this user's content too? // TODO: Expose this to the admin? func (user *User) Delete() error { - _, err := stmts.deleteUser.Exec(user.ID) + _, err := userStmts.delete.Exec(user.ID) if err != nil { return err } - ucache, ok := users.(UserCache) - if ok { - ucache.CacheRemove(user.ID) - } + user.CacheRemove() return err } func (user *User) ChangeName(username string) (err error) { - _, err = stmts.setUsername.Exec(username, user.ID) - ucache, ok := users.(UserCache) - if ok { - ucache.CacheRemove(user.ID) - } + _, err = userStmts.setUsername.Exec(username, user.ID) + user.CacheRemove() return err } func (user *User) ChangeAvatar(avatar string) (err error) { - _, err = stmts.setAvatar.Exec(avatar, user.ID) - ucache, ok := users.(UserCache) - if ok { - ucache.CacheRemove(user.ID) - } + _, err = userStmts.setAvatar.Exec(avatar, user.ID) + user.CacheRemove() return err } func (user *User) ChangeGroup(group int) (err error) { - _, err = stmts.updateUserGroup.Exec(group, user.ID) - ucache, ok := users.(UserCache) - if ok { - ucache.CacheRemove(user.ID) - } + _, err = userStmts.updateGroup.Exec(group, user.ID) + user.CacheRemove() return err } -func (user *User) increasePostStats(wcount int, topic bool) (err error) { +// ! Only updates the database not the *User for safety reasons +func (user *User) UpdateIP(host string) error { + _, err := userStmts.updateLastIP.Exec(host, user.ID) + return err +} + +func (user *User) IncreasePostStats(wcount int, topic bool) (err error) { var mod int baseScore := 1 if topic { - _, err = stmts.incrementUserTopics.Exec(1, user.ID) + _, err = userStmts.incrementTopics.Exec(1, user.ID) if err != nil { return err } baseScore = 2 } - settings := settingBox.Load().(SettingBox) + settings := SettingBox.Load().(SettingMap) if wcount >= settings["megapost_min_words"].(int) { - _, err = stmts.incrementUserMegaposts.Exec(1, 1, 1, user.ID) + _, err = userStmts.incrementMegaposts.Exec(1, 1, 1, user.ID) mod = 4 } else if wcount >= settings["bigpost_min_words"].(int) { - _, err = stmts.incrementUserBigposts.Exec(1, 1, user.ID) + _, err = userStmts.incrementBigposts.Exec(1, 1, user.ID) mod = 1 } else { - _, err = stmts.incrementUserPosts.Exec(1, user.ID) + _, err = userStmts.incrementPosts.Exec(1, user.ID) } if err != nil { return err } - _, err = stmts.incrementUserScore.Exec(baseScore+mod, user.ID) + _, err = userStmts.incrementScore.Exec(baseScore+mod, user.ID) if err != nil { return err } //log.Print(user.Score + base_score + mod) //log.Print(getLevel(user.Score + base_score + mod)) // TODO: Use a transaction to prevent level desyncs? - _, err = stmts.updateUserLevel.Exec(getLevel(user.Score+baseScore+mod), user.ID) + _, err = userStmts.updateLevel.Exec(GetLevel(user.Score+baseScore+mod), user.ID) return err } -func (user *User) decreasePostStats(wcount int, topic bool) (err error) { +func (user *User) DecreasePostStats(wcount int, topic bool) (err error) { var mod int baseScore := -1 if topic { - _, err = stmts.incrementUserTopics.Exec(-1, user.ID) + _, err = userStmts.incrementTopics.Exec(-1, user.ID) if err != nil { return err } baseScore = -2 } - settings := settingBox.Load().(SettingBox) + settings := SettingBox.Load().(SettingMap) if wcount >= settings["megapost_min_words"].(int) { - _, err = stmts.incrementUserMegaposts.Exec(-1, -1, -1, user.ID) + _, err = userStmts.incrementMegaposts.Exec(-1, -1, -1, user.ID) mod = 4 } else if wcount >= settings["bigpost_min_words"].(int) { - _, err = stmts.incrementUserBigposts.Exec(-1, -1, user.ID) + _, err = userStmts.incrementBigposts.Exec(-1, -1, user.ID) mod = 1 } else { - _, err = stmts.incrementUserPosts.Exec(-1, user.ID) + _, err = userStmts.incrementPosts.Exec(-1, user.ID) } if err != nil { return err } - _, err = stmts.incrementUserScore.Exec(baseScore-mod, user.ID) + _, err = userStmts.incrementScore.Exec(baseScore-mod, user.ID) if err != nil { return err } // TODO: Use a transaction to prevent level desyncs? - _, err = stmts.updateUserLevel.Exec(getLevel(user.Score-baseScore-mod), user.ID) + _, err = userStmts.updateLevel.Exec(GetLevel(user.Score-baseScore-mod), user.ID) return err } @@ -303,12 +333,12 @@ func (user *User) Copy() User { } // TODO: Write unit tests for this -func (user *User) initPerms() { +func (user *User) InitPerms() { if user.TempGroup != 0 { user.Group = user.TempGroup } - group := gstore.DirtyGet(user.Group) + group := Gstore.DirtyGet(user.Group) if user.IsSuperAdmin { user.Perms = AllPerms user.PluginPerms = AllPluginPerms @@ -332,7 +362,7 @@ func BcryptCheckPassword(realPassword string, password string, salt string) (err // Investigate. Do we need the extra salt? func BcryptGeneratePassword(password string) (hashedPassword string, salt string, err error) { - salt, err = GenerateSafeString(saltLength) + salt, err = GenerateSafeString(SaltLength) if err != nil { return "", "", err } @@ -353,27 +383,16 @@ func BcryptGeneratePasswordNoSalt(password string) (hash string, err error) { return string(hashedPassword), nil } +// TODO: Move this to *User func SetPassword(uid int, password string) error { hashedPassword, salt, err := GeneratePassword(password) if err != nil { return err } - _, err = stmts.setPassword.Exec(hashedPassword, salt, uid) + _, err = userStmts.setPassword.Exec(hashedPassword, salt, uid) return err } -func SendValidationEmail(username string, email string, token string) bool { - var schema = "http" - if site.EnableSsl { - schema += "s" - } - - // TODO: Move these to the phrase system - subject := "Validate Your Email @ " + site.Name - msg := "Dear " + username + ", following your registration on our forums, we ask you to validate your email, so that we can confirm that this email actually belongs to you.\n\nClick on the following link to do so. " + schema + "://" + site.URL + "/user/edit/token/" + token + "\n\nIf you haven't created an account here, then please feel free to ignore this email.\nWe're sorry for the inconvenience this may have caused." - return SendEmail(email, subject, msg) -} - // TODO: Write units tests for this func wordsToScore(wcount int, topic bool) (score int) { if topic { @@ -382,7 +401,7 @@ func wordsToScore(wcount int, topic bool) (score int) { score = 1 } - settings := settingBox.Load().(SettingBox) + settings := SettingBox.Load().(SettingMap) if wcount >= settings["megapost_min_words"].(int) { score += 4 } else if wcount >= settings["bigpost_min_words"].(int) { @@ -392,12 +411,12 @@ func wordsToScore(wcount int, topic bool) (score int) { } // For use in tests and to help generate dummy users for forums which don't have last posters -func getDummyUser() *User { +func BlankUser() *User { return &User{ID: 0, Name: ""} } // TODO: Write unit tests for this -func buildProfileURL(slug string, uid int) string { +func BuildProfileURL(slug string, uid int) string { if slug == "" { return "/user/" + strconv.Itoa(uid) } diff --git a/common/user_store.go b/common/user_store.go index 1ab8f4f1..41f16472 100644 --- a/common/user_store.go +++ b/common/user_store.go @@ -8,15 +8,17 @@ import ( "sync" "sync/atomic" + "../query_gen/lib" "golang.org/x/crypto/bcrypt" ) // TODO: Add the watchdog goroutine // TODO: Add some sort of update method -var users UserStore -var errAccountExists = errors.New("this username is already in use") +var Users UserStore +var ErrAccountExists = errors.New("this username is already in use") type UserStore interface { + DirtyGet(id int) *User Get(id int) (*User, error) Exists(id int) bool //BulkGet(ids []int) ([]*User, error) @@ -86,6 +88,25 @@ func (mus *MemoryUserStore) CacheGetUnsafe(id int) (*User, error) { return item, ErrNoRows } +func (mus *MemoryUserStore) DirtyGet(id int) *User { + mus.RLock() + user, ok := mus.items[id] + mus.RUnlock() + if ok { + return user + } + + user = &User{ID: id, Loggedin: true} + err := mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.LastIP, &user.TempGroup) + + user.Init() + if err == nil { + mus.CacheSet(user) + return user + } + return BlankUser() +} + func (mus *MemoryUserStore) Get(id int) (*User, error) { mus.RLock() user, ok := mus.items[id] @@ -188,7 +209,7 @@ func (mus *MemoryUserStore) BulkGetMap(ids []int) (list map[int]*User, err error // We probably don't need this, but it might be useful in case of bugs in BulkCascadeGetMap if sidList == "" { - if dev.DebugMode { + if Dev.DebugMode { log.Print("This data is sampled later in the BulkCascadeGetMap function, so it might miss the cached IDs") log.Print("idCount", idCount) log.Print("ids", ids) @@ -298,10 +319,10 @@ func (mus *MemoryUserStore) Create(username string, password string, email strin // Is this username already taken..? err := mus.usernameExists.QueryRow(username).Scan(&username) if err != ErrNoRows { - return 0, errAccountExists + return 0, ErrAccountExists } - salt, err := GenerateSafeString(saltLength) + salt, err := GenerateSafeString(SaltLength) if err != nil { return 0, err } @@ -370,6 +391,17 @@ func NewSQLUserStore() (*SQLUserStore, error) { }, acc.FirstError() } +func (mus *SQLUserStore) DirtyGet(id int) *User { + user := &User{ID: id, Loggedin: true} + err := mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.LastIP, &user.TempGroup) + + user.Init() + if err != nil { + return BlankUser() + } + return user +} + func (mus *SQLUserStore) Get(id int) (*User, error) { user := &User{ID: id, Loggedin: true} err := mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.LastIP, &user.TempGroup) @@ -436,10 +468,10 @@ func (mus *SQLUserStore) Create(username string, password string, email string, // Is this username already taken..? err := mus.usernameExists.QueryRow(username).Scan(&username) if err != ErrNoRows { - return 0, errAccountExists + return 0, ErrAccountExists } - salt, err := GenerateSafeString(saltLength) + salt, err := GenerateSafeString(SaltLength) if err != nil { return 0, err } diff --git a/common/utils.go b/common/utils.go index 0b237c45..71a3bc6c 100644 --- a/common/utils.go +++ b/common/utils.go @@ -12,12 +12,13 @@ import ( "errors" "fmt" "math" - "net/smtp" "os" "strconv" "strings" "time" "unicode" + + "../query_gen/lib" ) // Version stores a Gosora version @@ -53,7 +54,7 @@ func GenerateSafeString(length int) (string, error) { } // TODO: Write a test for this -func relativeTimeFromString(in string) (string, error) { +func RelativeTimeFromString(in string) (string, error) { if in == "" { return "", nil } @@ -63,11 +64,11 @@ func relativeTimeFromString(in string) (string, error) { return "", err } - return relativeTime(t), nil + return RelativeTime(t), nil } // TODO: Write a test for this -func relativeTime(t time.Time) string { +func RelativeTime(t time.Time) string { diff := time.Since(t) hours := diff.Hours() seconds := diff.Seconds() @@ -105,36 +106,36 @@ func relativeTime(t time.Time) string { } // TODO: Write a test for this -func convertByteUnit(bytes float64) (float64, string) { +func ConvertByteUnit(bytes float64) (float64, string) { switch { - case bytes >= float64(petabyte): - return bytes / float64(petabyte), "PB" - case bytes >= float64(terabyte): - return bytes / float64(terabyte), "TB" - case bytes >= float64(gigabyte): - return bytes / float64(gigabyte), "GB" - case bytes >= float64(megabyte): - return bytes / float64(megabyte), "MB" - case bytes >= float64(kilobyte): - return bytes / float64(kilobyte), "KB" + case bytes >= float64(Petabyte): + return bytes / float64(Petabyte), "PB" + case bytes >= float64(Terabyte): + return bytes / float64(Terabyte), "TB" + case bytes >= float64(Gigabyte): + return bytes / float64(Gigabyte), "GB" + case bytes >= float64(Megabyte): + return bytes / float64(Megabyte), "MB" + case bytes >= float64(Kilobyte): + return bytes / float64(Kilobyte), "KB" default: return bytes, " bytes" } } // TODO: Write a test for this -func convertByteInUnit(bytes float64, unit string) (count float64) { +func ConvertByteInUnit(bytes float64, unit string) (count float64) { switch unit { case "PB": - count = bytes / float64(petabyte) + count = bytes / float64(Petabyte) case "TB": - count = bytes / float64(terabyte) + count = bytes / float64(Terabyte) case "GB": - count = bytes / float64(gigabyte) + count = bytes / float64(Gigabyte) case "MB": - count = bytes / float64(megabyte) + count = bytes / float64(Megabyte) case "KB": - count = bytes / float64(kilobyte) + count = bytes / float64(Kilobyte) default: count = 0.1 } @@ -146,7 +147,7 @@ func convertByteInUnit(bytes float64, unit string) (count float64) { } // TODO: Write a test for this -func convertUnit(num int) (int, string) { +func ConvertUnit(num int) (int, string) { switch { case num >= 1000000000000: return num / 1000000000000, "T" @@ -162,7 +163,7 @@ func convertUnit(num int) (int, string) { } // TODO: Write a test for this -func convertFriendlyUnit(num int) (int, string) { +func ConvertFriendlyUnit(num int) (int, string) { switch { case num >= 1000000000000000: return 0, " quadrillion" @@ -179,7 +180,7 @@ func convertFriendlyUnit(num int) (int, string) { } } -func nameToSlug(name string) (slug string) { +func NameToSlug(name string) (slug string) { name = strings.TrimSpace(name) name = strings.Replace(name, " ", " ", -1) @@ -199,58 +200,8 @@ func nameToSlug(name string) (slug string) { return slug } -// TODO: Refactor this -func SendEmail(email string, subject string, msg string) bool { - // This hook is useful for plugin_sendmail or for testing tools. Possibly to hook it into some sort of mail server? - if vhooks["email_send_intercept"] != nil { - return vhooks["email_send_intercept"](email, subject, msg).(bool) - } - body := "Subject: " + subject + "\n\n" + msg + "\n" - - con, err := smtp.Dial(config.SMTPServer + ":" + config.SMTPPort) - if err != nil { - return false - } - - if config.SMTPUsername != "" { - auth := smtp.PlainAuth("", config.SMTPUsername, config.SMTPPassword, config.SMTPServer) - err = con.Auth(auth) - if err != nil { - return false - } - } - - err = con.Mail(site.Email) - if err != nil { - return false - } - err = con.Rcpt(email) - if err != nil { - return false - } - - emailData, err := con.Data() - if err != nil { - return false - } - _, err = fmt.Fprintf(emailData, body) - if err != nil { - return false - } - - err = emailData.Close() - if err != nil { - return false - } - err = con.Quit() - if err != nil { - return false - } - return true -} - // TODO: Write a test for this -func weakPassword(password string) error { +func WeakPassword(password string) error { if len(password) < 8 { return errors.New("your password needs to be at-least eight characters long") } @@ -335,7 +286,7 @@ func Stripslashes(text string) string { } // TODO: Write a test for this -func wordCount(input string) (count int) { +func WordCount(input string) (count int) { input = strings.TrimSpace(input) if input == "" { return 0 @@ -355,7 +306,7 @@ func wordCount(input string) (count int) { } // TODO: Write a test for this -func getLevel(score int) (level int) { +func GetLevel(score int) (level int) { var base float64 = 25 var current, prev float64 var expFactor = 2.8 @@ -376,7 +327,7 @@ func getLevel(score int) (level int) { } // TODO: Write a test for this -func getLevelScore(getLevel int) (score int) { +func GetLevelScore(getLevel int) (score int) { var base float64 = 25 var current, prev float64 var level int @@ -398,7 +349,7 @@ func getLevelScore(getLevel int) (score int) { } // TODO: Write a test for this -func getLevels(maxLevel int) []float64 { +func GetLevels(maxLevel int) []float64 { var base float64 = 25 var current, prev float64 // = 0 var expFactor = 2.8 @@ -417,7 +368,7 @@ func getLevels(maxLevel int) []float64 { return out } -func buildSlug(slug string, id int) string { +func BuildSlug(slug string, id int) string { if slug == "" { return strconv.Itoa(id) } @@ -425,13 +376,21 @@ func buildSlug(slug string, id int) string { } // TODO: Make a store for this? -func addModLog(action string, elementID int, elementType string, ipaddress string, actorID int) (err error) { - _, err = stmts.addModlogEntry.Exec(action, elementID, elementType, ipaddress, actorID) +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) { - _, err = stmts.addAdminlogEntry.Exec(action, elementID, elementType, ipaddress, actorID) +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 } diff --git a/widgets.go b/common/widgets.go similarity index 73% rename from widgets.go rename to common/widgets.go index ce00ee67..8c6be918 100644 --- a/widgets.go +++ b/common/widgets.go @@ -1,14 +1,13 @@ /* Copyright Azareal 2017 - 2018 */ -package main +package common import "log" import "bytes" import "sync" import "encoding/json" +import "../query_gen/lib" -//import "html/template" - -var docks WidgetDocks +var Docks WidgetDocks var widgetUpdateMutex sync.RWMutex type WidgetDocks struct { @@ -41,8 +40,12 @@ type NameTextPair struct { } // TODO: Make a store for this? -func initWidgets() error { - rows, err := stmts.getWidgets.Query() +func InitWidgets() error { + getWidgets, err := qgen.Builder.SimpleSelect("widgets", "position, side, type, active, location, data", "", "position ASC", "") + if err != nil { + return err + } + rows, err := getWidgets.Query() if err != nil { return err } @@ -71,7 +74,7 @@ func initWidgets() error { } var b bytes.Buffer - err = templates.ExecuteTemplate(&b, "widget_simple.html", tmp) + err = Templates.ExecuteTemplate(&b, "widget_simple.html", tmp) if err != nil { return err } @@ -92,13 +95,13 @@ func initWidgets() error { } widgetUpdateMutex.Lock() - docks.LeftSidebar = leftWidgets - docks.RightSidebar = rightWidgets + Docks.LeftSidebar = leftWidgets + Docks.RightSidebar = rightWidgets widgetUpdateMutex.Unlock() - if dev.SuperDebug { - log.Print("docks.LeftSidebar", docks.LeftSidebar) - log.Print("docks.RightSidebar", docks.RightSidebar) + if Dev.SuperDebug { + log.Print("Docks.LeftSidebar", Docks.LeftSidebar) + log.Print("Docks.RightSidebar", Docks.RightSidebar) } return nil diff --git a/common/word_filters.go b/common/word_filters.go new file mode 100644 index 00000000..d5512c03 --- /dev/null +++ b/common/word_filters.go @@ -0,0 +1,50 @@ +package common + +import "sync/atomic" +import "../query_gen/lib" + +type WordFilter struct { + ID int + Find string + Replacement string +} +type WordFilterMap map[int]WordFilter + +var WordFilterBox atomic.Value // An atomic value holding a WordFilterBox + +func init() { + WordFilterBox.Store(WordFilterMap(make(map[int]WordFilter))) +} + +func LoadWordFilters() error { + getWordFilters, err := qgen.Builder.SimpleSelect("word_filters", "wfid, find, replacement", "", "", "") + if err != nil { + return err + } + rows, err := getWordFilters.Query() + if err != nil { + return err + } + defer rows.Close() + + var wordFilters = WordFilterMap(make(map[int]WordFilter)) + var wfid int + var find string + var replacement string + + for rows.Next() { + err := rows.Scan(&wfid, &find, &replacement) + if err != nil { + return err + } + wordFilters[wfid] = WordFilter{ID: wfid, Find: find, Replacement: replacement} + } + WordFilterBox.Store(wordFilters) + return rows.Err() +} + +func AddWordFilter(id int, find string, replacement string) { + wordFilters := WordFilterBox.Load().(WordFilterMap) + wordFilters[id] = WordFilter{ID: id, Find: find, Replacement: replacement} + WordFilterBox.Store(wordFilters) +} diff --git a/database.go b/database.go index 323b9080..e4bcd97e 100644 --- a/database.go +++ b/database.go @@ -1,8 +1,11 @@ package main -import "log" +import ( + "database/sql" + "log" -import "database/sql" + "./common" +) var stmts *Stmts @@ -15,7 +18,7 @@ var ErrNoRows = sql.ErrNoRows var _initDatabase func() error -func initDatabase() (err error) { +func InitDatabase() (err error) { stmts = &Stmts{Mocks: false} // Engine specific code @@ -25,70 +28,69 @@ func initDatabase() (err error) { } globs = &Globs{stmts} - log.Print("Loading the usergroups.") - gstore, err = NewMemoryGroupStore() + err = common.DbInits.Run() if err != nil { return err } - err = gstore.LoadGroups() + + log.Print("Loading the usergroups.") + common.Gstore, err = common.NewMemoryGroupStore() if err != nil { return err } + err2 := common.Gstore.LoadGroups() + if err2 != nil { + return err2 + } // We have to put this here, otherwise LoadForums() won't be able to get the last poster data when building it's forums log.Print("Initialising the user and topic stores") - if config.CacheTopicUser == CACHE_STATIC { - users, err = NewMemoryUserStore(config.UserCacheCapacity) - if err != nil { - return err - } - topics, err = NewMemoryTopicStore(config.TopicCacheCapacity) - if err != nil { - return err - } + if common.Config.CacheTopicUser == common.CACHE_STATIC { + common.Users, err = common.NewMemoryUserStore(common.Config.UserCacheCapacity) + common.Topics, err2 = common.NewMemoryTopicStore(common.Config.TopicCacheCapacity) } else { - users, err = NewSQLUserStore() - if err != nil { - return err - } - topics, err = NewSQLTopicStore() - if err != nil { - return err - } + common.Users, err = common.NewSQLUserStore() + common.Topics, err2 = common.NewSQLTopicStore() } - - log.Print("Loading the forums.") - fstore, err = NewMemoryForumStore() if err != nil { return err } - err = fstore.LoadForums() + if err2 != nil { + return err2 + } + + log.Print("Loading the forums.") + common.Fstore, err = common.NewMemoryForumStore() + if err != nil { + return err + } + err = common.Fstore.LoadForums() if err != nil { return err } log.Print("Loading the forum permissions.") - fpstore, err = NewMemoryForumPermsStore() + common.Fpstore, err = common.NewMemoryForumPermsStore() if err != nil { return err } - err = fpstore.Init() + err = common.Fpstore.Init() if err != nil { return err } log.Print("Loading the settings.") - err = LoadSettings() + err = common.LoadSettings() if err != nil { return err } log.Print("Loading the plugins.") - err = initExtend() + err = common.InitExtend() if err != nil { return err } log.Print("Loading the themes.") - return LoadThemeActiveStatus() + return common.Themes.LoadActiveStatus() } diff --git a/extend/guilds/lib/guilds.go b/extend/guilds/lib/guilds.go index 69c2a467..bb9b1572 100644 --- a/extend/guilds/lib/guilds.go +++ b/extend/guilds/lib/guilds.go @@ -14,6 +14,9 @@ import ( "../../../common" ) +// A blank list to fill out that parameter in Page for routes which don't use it +var tList []interface{} + var ListStmt *sql.Stmt var MemberListStmt *sql.Stmt var MemberListJoinStmt *sql.Stmt @@ -45,15 +48,15 @@ type Guild struct { MainForumID int MainForum *common.Forum Forums []*common.Forum - ExtData ExtData + ExtData common.ExtData } type Page struct { Title string - CurrentUser User + CurrentUser common.User Header *common.HeaderVars - ItemList []*TopicsRow - Forum *commmon.Forum + ItemList []*common.TopicsRow + Forum *common.Forum Guild *Guild Page int LastPage int @@ -62,16 +65,16 @@ type Page struct { // ListPage is a page struct for constructing a list of every guild type ListPage struct { Title string - CurrentUser User - Header *HeaderVars + CurrentUser common.User + Header *common.HeaderVars GuildList []*Guild } type MemberListPage struct { Title string - CurrentUser User - Header *HeaderVars - ItemList []GuildMember + CurrentUser common.User + Header *common.HeaderVars + ItemList []Member Guild *Guild Page int LastPage int @@ -86,15 +89,15 @@ type Member struct { JoinedAt string Offline bool // TODO: Need to track the online states of members when WebSockets are enabled - User User + User common.User } -func PrebuildTmplList(user *User, headerVars *HeaderVars) CTmpl { +func PrebuildTmplList(user common.User, headerVars *common.HeaderVars) common.CTmpl { var guildList = []*Guild{ &Guild{ ID: 1, Name: "lol", - Link: guildsBuildGuildURL(nameToSlug("lol"), 1), + Link: BuildGuildURL(common.NameToSlug("lol"), 1), Desc: "A group for people who like to laugh", Active: true, MemberCount: 1, @@ -102,38 +105,38 @@ func PrebuildTmplList(user *User, headerVars *HeaderVars) CTmpl { CreatedAt: "date", LastUpdateTime: "date", MainForumID: 1, - MainForum: fstore.DirtyGet(1), - Forums: []*Forum{fstore.DirtyGet(1)}, + MainForum: common.Fstore.DirtyGet(1), + Forums: []*common.Forum{common.Fstore.DirtyGet(1)}, }, } listPage := ListPage{"Guild List", user, headerVars, guildList} - return CTmpl{"guilds-guild-list", "guilds_guild_list", "templates/", "guilds.ListPage", listPage} + return common.CTmpl{"guilds-guild-list", "guilds_guild_list", "templates/", "guilds.ListPage", listPage} } // TODO: Do this properly via the widget system -func CommonAreaWidgets(headerVars *HeaderVars) { +func CommonAreaWidgets(headerVars *common.HeaderVars) { // TODO: Hot Groups? Featured Groups? Official Groups? var b bytes.Buffer - var menu = WidgetMenu{"Guilds", []WidgetMenuItem{ - WidgetMenuItem{"Create Guild", "/guild/create/", false}, + var menu = common.WidgetMenu{"Guilds", []common.WidgetMenuItem{ + common.WidgetMenuItem{"Create Guild", "/guild/create/", false}, }} - err := templates.ExecuteTemplate(&b, "widget_menu.html", menu) + err := common.Templates.ExecuteTemplate(&b, "widget_menu.html", menu) if err != nil { - LogError(err) + common.LogError(err) return } - if themes[headerVars.ThemeName].Sidebars == "left" { + if common.Themes[headerVars.ThemeName].Sidebars == "left" { headerVars.Widgets.LeftSidebar = template.HTML(string(b.Bytes())) - } else if themes[headerVars.ThemeName].Sidebars == "right" || themes[headerVars.ThemeName].Sidebars == "both" { + } else if common.Themes[headerVars.ThemeName].Sidebars == "right" || common.Themes[headerVars.ThemeName].Sidebars == "both" { headerVars.Widgets.RightSidebar = template.HTML(string(b.Bytes())) } } // TODO: Do this properly via the widget system // TODO: Make a better more customisable group widget system -func GuildWidgets(headerVars *HeaderVars, guildItem *Guild) (success bool) { +func GuildWidgets(headerVars *common.HeaderVars, guildItem *Guild) (success bool) { return false // Disabled until the next commit /*var b bytes.Buffer @@ -144,7 +147,7 @@ func GuildWidgets(headerVars *HeaderVars, guildItem *Guild) (success bool) { err := templates.ExecuteTemplate(&b, "widget_menu.html", menu) if err != nil { - LogError(err) + common.LogError(err) return false } @@ -162,16 +165,16 @@ func GuildWidgets(headerVars *HeaderVars, guildItem *Guild) (success bool) { Custom Pages */ -func routeGuildList(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func RouteGuildList(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } - guildsCommonAreaWidgets(headerVars) + CommonAreaWidgets(headerVars) - rows, err := guildsListStmt.Query() - if err != nil && err != ErrNoRows { - return InternalError(err, w, r) + rows, err := ListStmt.Query() + if err != nil && err != common.ErrNoRows { + return common.InternalError(err, w, r) } defer rows.Close() @@ -180,31 +183,31 @@ func routeGuildList(w http.ResponseWriter, r *http.Request, user User) RouteErro guildItem := &Guild{ID: 0} err := rows.Scan(&guildItem.ID, &guildItem.Name, &guildItem.Desc, &guildItem.Active, &guildItem.Privacy, &guildItem.Joinable, &guildItem.Owner, &guildItem.MemberCount, &guildItem.CreatedAt, &guildItem.LastUpdateTime) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - guildItem.Link = guildsBuildGuildURL(nameToSlug(guildItem.Name), guildItem.ID) + guildItem.Link = BuildGuildURL(common.NameToSlug(guildItem.Name), guildItem.ID) guildList = append(guildList, guildItem) } err = rows.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - pi := GuildListPage{"Guild List", user, headerVars, guildList} - err = RunThemeTemplate(headerVars.ThemeName, "guilds_guild_list", pi, w) + pi := ListPage{"Guild List", user, headerVars, guildList} + err = common.RunThemeTemplate(headerVars.ThemeName, "guilds_guild_list", pi, w) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } func GetGuild(guildID int) (guildItem *Guild, err error) { guildItem = &Guild{ID: guildID} - err = guildsGetGuildStmt.QueryRow(guildID).Scan(&guildItem.Name, &guildItem.Desc, &guildItem.Active, &guildItem.Privacy, &guildItem.Joinable, &guildItem.Owner, &guildItem.MemberCount, &guildItem.MainForumID, &guildItem.Backdrop, &guildItem.CreatedAt, &guildItem.LastUpdateTime) + err = GetGuildStmt.QueryRow(guildID).Scan(&guildItem.Name, &guildItem.Desc, &guildItem.Active, &guildItem.Privacy, &guildItem.Joinable, &guildItem.Owner, &guildItem.MemberCount, &guildItem.MainForumID, &guildItem.Backdrop, &guildItem.CreatedAt, &guildItem.LastUpdateTime) return guildItem, err } -func middleViewGuild(w http.ResponseWriter, r *http.Request, user User) RouteError { +func MiddleViewGuild(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { // SEO URLs... halves := strings.Split(r.URL.Path[len("/guild/"):], ".") if len(halves) < 2 { @@ -212,45 +215,48 @@ func middleViewGuild(w http.ResponseWriter, r *http.Request, user User) RouteErr } guildID, err := strconv.Atoi(halves[1]) if err != nil { - return PreError("Not a valid guild ID", w, r) + return common.PreError("Not a valid guild ID", w, r) } - guildItem, err := guildsGetGuild(guildID) + guildItem, err := GetGuild(guildID) if err != nil { - return LocalError("Bad guild", w, r, user) + return common.LocalError("Bad guild", w, r, user) } if !guildItem.Active { - return NotFound(w, r) + return common.NotFound(w, r) } + return nil + + // TODO: Re-implement this // Re-route the request to routeForums - var ctx = context.WithValue(r.Context(), "guilds_current_guild", guildItem) - return routeForum(w, r.WithContext(ctx), user, strconv.Itoa(guildItem.MainForumID)) + //var ctx = context.WithValue(r.Context(), "guilds_current_guild", guildItem) + //return routeForum(w, r.WithContext(ctx), user, strconv.Itoa(guildItem.MainForumID)) } -func CreateGuild(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func RouteCreateGuild(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } // TODO: Add an approval queue mode for group creation if !user.Loggedin || !user.PluginPerms["CreateGuild"] { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } - guildsCommonAreaWidgets(headerVars) + CommonAreaWidgets(headerVars) - pi := Page{"Create Guild", user, headerVars, tList, nil} - err := templates.ExecuteTemplate(w, "guilds_create_guild.html", pi) + pi := common.Page{"Create Guild", user, headerVars, tList, nil} + err := common.Templates.ExecuteTemplate(w, "guilds_create_guild.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func CreateGuildSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { +func RouteCreateGuildSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { // TODO: Add an approval queue mode for group creation if !user.Loggedin || !user.PluginPerms["CreateGuild"] { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } var guildActive = true @@ -271,37 +277,37 @@ func CreateGuildSubmit(w http.ResponseWriter, r *http.Request, user User) RouteE } // Create the backing forum - fid, err := fstore.Create(guildName, "", true, "") + fid, err := common.Fstore.Create(guildName, "", true, "") if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - res, err := guildsCreateGuildStmt.Exec(guildName, guildDesc, guildActive, guildPrivacy, user.ID, fid) + res, err := CreateGuildStmt.Exec(guildName, guildDesc, guildActive, guildPrivacy, user.ID, fid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } lastID, err := res.LastInsertId() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Add the main backing forum to the forum list - err = guildsAttachForum(int(lastID), fid) + err = AttachForum(int(lastID), fid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - _, err = guildsAddMemberStmt.Exec(lastID, user.ID, 2) + _, err = AddMemberStmt.Exec(lastID, user.ID, 2) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - http.Redirect(w, r, guildsBuildGuildURL(nameToSlug(guildName), int(lastID)), http.StatusSeeOther) + http.Redirect(w, r, BuildGuildURL(common.NameToSlug(guildName), int(lastID)), http.StatusSeeOther) return nil } -func MemberList(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func RouteMemberList(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } @@ -313,40 +319,40 @@ func MemberList(w http.ResponseWriter, r *http.Request, user User) RouteError { } guildID, err := strconv.Atoi(halves[1]) if err != nil { - return PreError("Not a valid group ID", w, r) + return common.PreError("Not a valid group ID", w, r) } var guildItem = &Guild{ID: guildID} var mainForum int // Unused - err = guildsGetGuildStmt.QueryRow(guildID).Scan(&guildItem.Name, &guildItem.Desc, &guildItem.Active, &guildItem.Privacy, &guildItem.Joinable, &guildItem.Owner, &guildItem.MemberCount, &mainForum, &guildItem.Backdrop, &guildItem.CreatedAt, &guildItem.LastUpdateTime) + err = GetGuildStmt.QueryRow(guildID).Scan(&guildItem.Name, &guildItem.Desc, &guildItem.Active, &guildItem.Privacy, &guildItem.Joinable, &guildItem.Owner, &guildItem.MemberCount, &mainForum, &guildItem.Backdrop, &guildItem.CreatedAt, &guildItem.LastUpdateTime) if err != nil { - return LocalError("Bad group", w, r, user) + return common.LocalError("Bad group", w, r, user) } - guildItem.Link = guildsBuildGuildURL(nameToSlug(guildItem.Name), guildItem.ID) + guildItem.Link = BuildGuildURL(common.NameToSlug(guildItem.Name), guildItem.ID) - guildsGuildWidgets(headerVars, guildItem) + GuildWidgets(headerVars, guildItem) - rows, err := guildsMemberListJoinStmt.Query(guildID) - if err != nil && err != ErrNoRows { - return InternalError(err, w, r) + rows, err := MemberListJoinStmt.Query(guildID) + if err != nil && err != common.ErrNoRows { + return common.InternalError(err, w, r) } - var guildMembers []GuildMember + var guildMembers []Member for rows.Next() { - guildMember := GuildMember{PostCount: 0} + guildMember := Member{PostCount: 0} err := rows.Scan(&guildMember.User.ID, &guildMember.Rank, &guildMember.PostCount, &guildMember.JoinedAt, &guildMember.User.Name, &guildMember.User.Avatar) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - guildMember.Link = buildProfileURL(nameToSlug(guildMember.User.Name), guildMember.User.ID) + guildMember.Link = common.BuildProfileURL(common.NameToSlug(guildMember.User.Name), guildMember.User.ID) if guildMember.User.Avatar != "" { if guildMember.User.Avatar[0] == '.' { guildMember.User.Avatar = "/uploads/avatar_" + strconv.Itoa(guildMember.User.ID) + guildMember.User.Avatar } } else { - guildMember.User.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(guildMember.User.ID), 1) + guildMember.User.Avatar = strings.Replace(common.Config.Noavatar, "{id}", strconv.Itoa(guildMember.User.ID), 1) } - guildMember.JoinedAt, _ = relativeTimeFromString(guildMember.JoinedAt) + guildMember.JoinedAt, _ = common.RelativeTimeFromString(guildMember.JoinedAt) if guildItem.Owner == guildMember.User.ID { guildMember.RankString = "Owner" } else { @@ -363,31 +369,31 @@ func MemberList(w http.ResponseWriter, r *http.Request, user User) RouteError { } err = rows.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } rows.Close() - pi := GuildMemberListPage{"Guild Member List", user, headerVars, guildMembers, guildItem, 0, 0} + pi := MemberListPage{"Guild Member List", user, headerVars, guildMembers, guildItem, 0, 0} // A plugin with plugins. Pluginception! - if preRenderHooks["pre_render_guilds_member_list"] != nil { - if runPreRenderHook("pre_render_guilds_member_list", w, r, &user, &pi) { + if common.PreRenderHooks["pre_render_guilds_member_list"] != nil { + if common.RunPreRenderHook("pre_render_guilds_member_list", w, r, &user, &pi) { return nil } } - err = RunThemeTemplate(headerVars.ThemeName, "guilds_member_list", pi, w) + err = common.RunThemeTemplate(headerVars.ThemeName, "guilds_member_list", pi, w) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } func AttachForum(guildID int, fid int) error { - _, err := guildsAttachForumStmt.Exec(guildID, fid) + _, err := AttachForumStmt.Exec(guildID, fid) return err } func UnattachForum(fid int) error { - _, err := guildsAttachForumStmt.Exec(fid) + _, err := AttachForumStmt.Exec(fid) return err } @@ -403,16 +409,16 @@ func BuildGuildURL(slug string, id int) string { */ // TODO: Prebuild this template -func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) { - pi := data.(*ForumPage) - if pi.Header.ExtData.items != nil { - if guildData, ok := pi.Header.ExtData.items["guilds_current_group"]; ok { +func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *common.User, data interface{}) (halt bool) { + pi := data.(*common.ForumPage) + if pi.Header.ExtData.Items != nil { + if guildData, ok := pi.Header.ExtData.Items["guilds_current_group"]; ok { guildItem := guildData.(*Guild) - guildpi := GuildPage{pi.Title, pi.CurrentUser, pi.Header, pi.ItemList, pi.Forum, guildItem, pi.Page, pi.LastPage} - err := templates.ExecuteTemplate(w, "guilds_view_guild.html", guildpi) + guildpi := Page{pi.Title, pi.CurrentUser, pi.Header, pi.ItemList, pi.Forum, guildItem, pi.Page, pi.LastPage} + err := common.Templates.ExecuteTemplate(w, "guilds_view_guild.html", guildpi) if err != nil { - LogError(err) + common.LogError(err) return false } return true @@ -422,10 +428,10 @@ func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *User, data } func TrowAssign(args ...interface{}) interface{} { - var forum = args[1].(*Forum) + var forum = args[1].(*common.Forum) if forum.ParentType == "guild" { - var topicItem = args[0].(*TopicsRow) - topicItem.ForumLink = "/guild/" + strings.TrimPrefix(topicItem.ForumLink, getForumURLPrefix()) + var topicItem = args[0].(*common.TopicsRow) + topicItem.ForumLink = "/guild/" + strings.TrimPrefix(topicItem.ForumLink, common.GetForumURLPrefix()) } return nil } @@ -433,7 +439,7 @@ func TrowAssign(args ...interface{}) interface{} { // TODO: It would be nice, if you could select one of the boards in the group from that drop-down rather than just the one you got linked from func TopicCreatePreLoop(args ...interface{}) interface{} { var fid = args[2].(int) - if fstore.DirtyGet(fid).ParentType == "guild" { + if common.Fstore.DirtyGet(fid).ParentType == "guild" { var strictmode = args[5].(*bool) *strictmode = true } @@ -443,27 +449,27 @@ func TopicCreatePreLoop(args ...interface{}) interface{} { // TODO: Add privacy options // TODO: Add support for multiple boards and add per-board simplified permissions // TODO: Take isJs into account for routes which expect JSON responses -func ForumCheck(args ...interface{}) (skip bool, rerr RouteError) { +func ForumCheck(args ...interface{}) (skip bool, rerr common.RouteError) { var r = args[1].(*http.Request) var fid = args[3].(*int) - var forum = fstore.DirtyGet(*fid) + var forum = common.Fstore.DirtyGet(*fid) if forum.ParentType == "guild" { var err error var w = args[0].(http.ResponseWriter) guildItem, ok := r.Context().Value("guilds_current_group").(*Guild) if !ok { - guildItem, err = guildsGetGuild(forum.ParentID) + guildItem, err = GetGuild(forum.ParentID) if err != nil { - return true, InternalError(errors.New("Unable to find the parent group for a forum"), w, r) + return true, common.InternalError(errors.New("Unable to find the parent group for a forum"), w, r) } if !guildItem.Active { - return true, NotFound(w, r) + return true, common.NotFound(w, r) } r = r.WithContext(context.WithValue(r.Context(), "guilds_current_group", guildItem)) } - var user = args[2].(*User) + var user = args[2].(*common.User) var rank int var posts int var joinedAt string @@ -472,32 +478,32 @@ func ForumCheck(args ...interface{}) (skip bool, rerr RouteError) { // Clear the default group permissions // TODO: Do this more efficiently, doing it quick and dirty for now to get this out quickly - overrideForumPerms(&user.Perms, false) + common.OverrideForumPerms(&user.Perms, false) user.Perms.ViewTopic = true - err = guildsGetMemberStmt.QueryRow(guildItem.ID, user.ID).Scan(&rank, &posts, &joinedAt) - if err != nil && err != ErrNoRows { - return true, InternalError(err, w, r) + err = GetMemberStmt.QueryRow(guildItem.ID, user.ID).Scan(&rank, &posts, &joinedAt) + if err != nil && err != common.ErrNoRows { + return true, common.InternalError(err, w, r) } else if err != nil { // TODO: Should we let admins / guests into public groups? - return true, LocalError("You're not part of this group!", w, r, *user) + return true, common.LocalError("You're not part of this group!", w, r, *user) } // TODO: Implement bans properly by adding the Local Ban API in the next commit // TODO: How does this even work? Refactor it along with the rest of this plugin! if rank < 0 { - return true, LocalError("You've been banned from this group!", w, r, *user) + return true, common.LocalError("You've been banned from this group!", w, r, *user) } // Basic permissions for members, more complicated permissions coming in the next commit! if guildItem.Owner == user.ID { - overrideForumPerms(&user.Perms, true) + common.OverrideForumPerms(&user.Perms, true) } else if rank == 0 { user.Perms.LikeItem = true user.Perms.CreateTopic = true user.Perms.CreateReply = true } else { - overrideForumPerms(&user.Perms, true) + common.OverrideForumPerms(&user.Perms, true) } return true, nil } @@ -509,28 +515,28 @@ func ForumCheck(args ...interface{}) (skip bool, rerr RouteError) { func Widgets(args ...interface{}) interface{} { var zone = args[0].(string) - var headerVars = args[2].(*HeaderVars) + var headerVars = args[2].(*common.HeaderVars) var request = args[3].(*http.Request) if zone != "view_forum" { return false } - var forum = args[1].(*Forum) + var forum = args[1].(*common.Forum) if forum.ParentType == "guild" { // This is why I hate using contexts, all the daisy chains and interface casts x.x guildItem, ok := request.Context().Value("guilds_current_group").(*Guild) if !ok { - LogError(errors.New("Unable to find a parent group in the context data")) + common.LogError(errors.New("Unable to find a parent group in the context data")) return false } - if headerVars.ExtData.items == nil { - headerVars.ExtData.items = make(map[string]interface{}) + if headerVars.ExtData.Items == nil { + headerVars.ExtData.Items = make(map[string]interface{}) } - headerVars.ExtData.items["guilds_current_group"] = guildItem + headerVars.ExtData.Items["guilds_current_group"] = guildItem - return guildsGuildWidgets(headerVars, guildItem) + return GuildWidgets(headerVars, guildItem) } return false } diff --git a/gen_mssql.go b/gen_mssql.go index 90f081ba..c5ce1a4f 100644 --- a/gen_mssql.go +++ b/gen_mssql.go @@ -5,6 +5,7 @@ package main import "log" import "database/sql" +import "./common" // nolint type Stmts struct { @@ -12,21 +13,14 @@ type Stmts struct { getSettings *sql.Stmt getSetting *sql.Stmt getFullSetting *sql.Stmt - getFullSettings *sql.Stmt - getPlugins *sql.Stmt - getThemes *sql.Stmt - getWidgets *sql.Stmt isPluginActive *sql.Stmt getUsersOffset *sql.Stmt - getWordFilters *sql.Stmt isThemeDefault *sql.Stmt getModlogs *sql.Stmt getModlogsOffset *sql.Stmt getReplyTID *sql.Stmt getTopicFID *sql.Stmt getUserReplyUID *sql.Stmt - hasLikedTopic *sql.Stmt - hasLikedReply *sql.Stmt getUserName *sql.Stmt getEmailsByUser *sql.Stmt getTopicBasic *sql.Stmt @@ -34,20 +28,14 @@ type Stmts struct { forumEntryExists *sql.Stmt groupEntryExists *sql.Stmt getForumTopicsOffset *sql.Stmt - getExpiredScheduledGroups *sql.Stmt - getSync *sql.Stmt getAttachment *sql.Stmt getTopicRepliesOffset *sql.Stmt getTopicList *sql.Stmt - getTopicUser *sql.Stmt - getTopicByReply *sql.Stmt getTopicReplies *sql.Stmt getForumTopics *sql.Stmt getProfileReplies *sql.Stmt getWatchers *sql.Stmt createReport *sql.Stmt - createActionReply *sql.Stmt - createLike *sql.Stmt addActivity *sql.Stmt notifyOne *sql.Stmt addEmail *sql.Stmt @@ -55,57 +43,27 @@ type Stmts struct { addForumPermsToForum *sql.Stmt addPlugin *sql.Stmt addTheme *sql.Stmt - addModlogEntry *sql.Stmt - addAdminlogEntry *sql.Stmt addAttachment *sql.Stmt createWordFilter *sql.Stmt - addRepliesToTopic *sql.Stmt - removeRepliesFromTopic *sql.Stmt - addLikesToTopic *sql.Stmt - addLikesToReply *sql.Stmt - editTopic *sql.Stmt editReply *sql.Stmt - stickTopic *sql.Stmt - unstickTopic *sql.Stmt - lockTopic *sql.Stmt - unlockTopic *sql.Stmt - updateLastIP *sql.Stmt - updateSession *sql.Stmt - setPassword *sql.Stmt - setAvatar *sql.Stmt - setUsername *sql.Stmt - changeGroup *sql.Stmt - activateUser *sql.Stmt - updateUserLevel *sql.Stmt - incrementUserScore *sql.Stmt - incrementUserPosts *sql.Stmt - incrementUserBigposts *sql.Stmt - incrementUserMegaposts *sql.Stmt - incrementUserTopics *sql.Stmt editProfileReply *sql.Stmt - updateForum *sql.Stmt updateSetting *sql.Stmt updatePlugin *sql.Stmt updatePluginInstall *sql.Stmt updateTheme *sql.Stmt + updateForum *sql.Stmt updateUser *sql.Stmt - updateUserGroup *sql.Stmt updateGroupPerms *sql.Stmt - updateGroupRank *sql.Stmt updateGroup *sql.Stmt updateEmail *sql.Stmt verifyEmail *sql.Stmt setTempGroup *sql.Stmt updateWordFilter *sql.Stmt bumpSync *sql.Stmt - deleteUser *sql.Stmt - deleteTopic *sql.Stmt - deleteReply *sql.Stmt deleteProfileReply *sql.Stmt deleteActivityStreamMatch *sql.Stmt deleteWordFilter *sql.Stmt reportExists *sql.Stmt - groupCount *sql.Stmt modlogCount *sql.Stmt notifyWatchers *sql.Stmt @@ -124,7 +82,7 @@ type Stmts struct { // nolint func _gen_mssql() (err error) { - if dev.DebugMode { + if common.Dev.DebugMode { log.Print("Building the generated statements") } @@ -156,34 +114,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing getFullSettings statement.") - stmts.getFullSettings, err = db.Prepare("SELECT [name],[content],[type],[constraints] FROM [settings]") - if err != nil { - log.Print("Bad Query: ","SELECT [name],[content],[type],[constraints] FROM [settings]") - return err - } - - log.Print("Preparing getPlugins statement.") - stmts.getPlugins, err = db.Prepare("SELECT [uname],[active],[installed] FROM [plugins]") - if err != nil { - log.Print("Bad Query: ","SELECT [uname],[active],[installed] FROM [plugins]") - return err - } - - log.Print("Preparing getThemes statement.") - stmts.getThemes, err = db.Prepare("SELECT [uname],[default] FROM [themes]") - if err != nil { - log.Print("Bad Query: ","SELECT [uname],[default] FROM [themes]") - return err - } - - log.Print("Preparing getWidgets statement.") - stmts.getWidgets, err = db.Prepare("SELECT [position],[side],[type],[active],[location],[data] FROM [widgets] ORDER BY position ASC") - if err != nil { - log.Print("Bad Query: ","SELECT [position],[side],[type],[active],[location],[data] FROM [widgets] ORDER BY position ASC") - return err - } - log.Print("Preparing isPluginActive statement.") stmts.isPluginActive, err = db.Prepare("SELECT [active] FROM [plugins] WHERE [uname] = ?1") if err != nil { @@ -198,13 +128,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing getWordFilters statement.") - stmts.getWordFilters, err = db.Prepare("SELECT [wfid],[find],[replacement] FROM [word_filters]") - if err != nil { - log.Print("Bad Query: ","SELECT [wfid],[find],[replacement] FROM [word_filters]") - return err - } - log.Print("Preparing isThemeDefault statement.") stmts.isThemeDefault, err = db.Prepare("SELECT [default] FROM [themes] WHERE [uname] = ?1") if err != nil { @@ -247,20 +170,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing hasLikedTopic statement.") - stmts.hasLikedTopic, err = db.Prepare("SELECT [targetItem] FROM [likes] WHERE [sentBy] = ?1 AND [targetItem] = ?2 AND [targetType] = 'topics'") - if err != nil { - log.Print("Bad Query: ","SELECT [targetItem] FROM [likes] WHERE [sentBy] = ?1 AND [targetItem] = ?2 AND [targetType] = 'topics'") - return err - } - - log.Print("Preparing hasLikedReply statement.") - stmts.hasLikedReply, err = db.Prepare("SELECT [targetItem] FROM [likes] WHERE [sentBy] = ?1 AND [targetItem] = ?2 AND [targetType] = 'replies'") - if err != nil { - log.Print("Bad Query: ","SELECT [targetItem] FROM [likes] WHERE [sentBy] = ?1 AND [targetItem] = ?2 AND [targetType] = 'replies'") - return err - } - log.Print("Preparing getUserName statement.") stmts.getUserName, err = db.Prepare("SELECT [name] FROM [users] WHERE [uid] = ?1") if err != nil { @@ -310,20 +219,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing getExpiredScheduledGroups statement.") - stmts.getExpiredScheduledGroups, err = db.Prepare("SELECT [uid] FROM [users_groups_scheduler] WHERE GETDATE() > [revert_at] AND [temporary] = 1") - if err != nil { - log.Print("Bad Query: ","SELECT [uid] FROM [users_groups_scheduler] WHERE GETDATE() > [revert_at] AND [temporary] = 1") - return err - } - - log.Print("Preparing getSync statement.") - stmts.getSync, err = db.Prepare("SELECT [last_update] FROM [sync]") - if err != nil { - log.Print("Bad Query: ","SELECT [last_update] FROM [sync]") - return err - } - log.Print("Preparing getAttachment statement.") stmts.getAttachment, err = db.Prepare("SELECT [sectionID],[sectionTable],[originID],[originTable],[uploadedBy],[path] FROM [attachments] WHERE [path] = ?1 AND [sectionID] = ?2 AND [sectionTable] = ?3") if err != nil { @@ -345,20 +240,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing getTopicUser statement.") - stmts.getTopicUser, err = db.Prepare("SELECT [topics].[title],[topics].[content],[topics].[createdBy],[topics].[createdAt],[topics].[is_closed],[topics].[sticky],[topics].[parentID],[topics].[ipaddress],[topics].[postCount],[topics].[likeCount],[users].[name],[users].[avatar],[users].[group],[users].[url_prefix],[users].[url_name],[users].[level] FROM [topics] LEFT JOIN [users] ON [topics].[createdBy] = [users].[uid] WHERE [tid] = ?1") - if err != nil { - log.Print("Bad Query: ","SELECT [topics].[title],[topics].[content],[topics].[createdBy],[topics].[createdAt],[topics].[is_closed],[topics].[sticky],[topics].[parentID],[topics].[ipaddress],[topics].[postCount],[topics].[likeCount],[users].[name],[users].[avatar],[users].[group],[users].[url_prefix],[users].[url_name],[users].[level] FROM [topics] LEFT JOIN [users] ON [topics].[createdBy] = [users].[uid] WHERE [tid] = ?1") - return err - } - - log.Print("Preparing getTopicByReply statement.") - stmts.getTopicByReply, err = db.Prepare("SELECT [topics].[tid],[topics].[title],[topics].[content],[topics].[createdBy],[topics].[createdAt],[topics].[is_closed],[topics].[sticky],[topics].[parentID],[topics].[ipaddress],[topics].[postCount],[topics].[likeCount],[topics].[data] FROM [replies] LEFT JOIN [topics] ON [replies].[tid] = [topics].[tid] WHERE [rid] = ?1") - if err != nil { - log.Print("Bad Query: ","SELECT [topics].[tid],[topics].[title],[topics].[content],[topics].[createdBy],[topics].[createdAt],[topics].[is_closed],[topics].[sticky],[topics].[parentID],[topics].[ipaddress],[topics].[postCount],[topics].[likeCount],[topics].[data] FROM [replies] LEFT JOIN [topics] ON [replies].[tid] = [topics].[tid] WHERE [rid] = ?1") - return err - } - log.Print("Preparing getTopicReplies statement.") stmts.getTopicReplies, err = db.Prepare("SELECT [replies].[rid],[replies].[content],[replies].[createdBy],[replies].[createdAt],[replies].[lastEdit],[replies].[lastEditBy],[users].[avatar],[users].[name],[users].[group],[users].[url_prefix],[users].[url_name],[users].[level],[replies].[ipaddress] FROM [replies] LEFT JOIN [users] ON [replies].[createdBy] = [users].[uid] WHERE [tid] = ?1") if err != nil { @@ -394,20 +275,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing createActionReply statement.") - stmts.createActionReply, err = db.Prepare("INSERT INTO [replies] ([tid],[actionType],[ipaddress],[createdBy],[createdAt],[lastUpdated],[content],[parsed_content]) VALUES (?,?,?,?,GETUTCDATE(),GETUTCDATE(),'','')") - if err != nil { - log.Print("Bad Query: ","INSERT INTO [replies] ([tid],[actionType],[ipaddress],[createdBy],[createdAt],[lastUpdated],[content],[parsed_content]) VALUES (?,?,?,?,GETUTCDATE(),GETUTCDATE(),'','')") - return err - } - - log.Print("Preparing createLike statement.") - stmts.createLike, err = db.Prepare("INSERT INTO [likes] ([weight],[targetItem],[targetType],[sentBy]) VALUES (?,?,?,?)") - if err != nil { - log.Print("Bad Query: ","INSERT INTO [likes] ([weight],[targetItem],[targetType],[sentBy]) VALUES (?,?,?,?)") - return err - } - log.Print("Preparing addActivity statement.") stmts.addActivity, err = db.Prepare("INSERT INTO [activity_stream] ([actor],[targetUser],[event],[elementType],[elementID]) VALUES (?,?,?,?,?)") if err != nil { @@ -457,20 +324,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing addModlogEntry statement.") - stmts.addModlogEntry, err = db.Prepare("INSERT INTO [moderation_logs] ([action],[elementID],[elementType],[ipaddress],[actorID],[doneAt]) VALUES (?,?,?,?,?,GETUTCDATE())") - if err != nil { - log.Print("Bad Query: ","INSERT INTO [moderation_logs] ([action],[elementID],[elementType],[ipaddress],[actorID],[doneAt]) VALUES (?,?,?,?,?,GETUTCDATE())") - return err - } - - log.Print("Preparing addAdminlogEntry statement.") - stmts.addAdminlogEntry, err = db.Prepare("INSERT INTO [administration_logs] ([action],[elementID],[elementType],[ipaddress],[actorID],[doneAt]) VALUES (?,?,?,?,?,GETUTCDATE())") - if err != nil { - log.Print("Bad Query: ","INSERT INTO [administration_logs] ([action],[elementID],[elementType],[ipaddress],[actorID],[doneAt]) VALUES (?,?,?,?,?,GETUTCDATE())") - return err - } - log.Print("Preparing addAttachment statement.") stmts.addAttachment, err = db.Prepare("INSERT INTO [attachments] ([sectionID],[sectionTable],[originID],[originTable],[uploadedBy],[path]) VALUES (?,?,?,?,?,?)") if err != nil { @@ -485,41 +338,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing addRepliesToTopic statement.") - stmts.addRepliesToTopic, err = db.Prepare("UPDATE [topics] SET [postCount] = [postCount] + ?,[lastReplyBy] = ?,[lastReplyAt] = GETUTCDATE() WHERE [tid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [topics] SET [postCount] = [postCount] + ?,[lastReplyBy] = ?,[lastReplyAt] = GETUTCDATE() WHERE [tid] = ?") - return err - } - - log.Print("Preparing removeRepliesFromTopic statement.") - stmts.removeRepliesFromTopic, err = db.Prepare("UPDATE [topics] SET [postCount] = [postCount] - ? WHERE [tid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [topics] SET [postCount] = [postCount] - ? WHERE [tid] = ?") - return err - } - - log.Print("Preparing addLikesToTopic statement.") - stmts.addLikesToTopic, err = db.Prepare("UPDATE [topics] SET [likeCount] = [likeCount] + ? WHERE [tid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [topics] SET [likeCount] = [likeCount] + ? WHERE [tid] = ?") - return err - } - - log.Print("Preparing addLikesToReply statement.") - stmts.addLikesToReply, err = db.Prepare("UPDATE [replies] SET [likeCount] = [likeCount] + ? WHERE [rid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [replies] SET [likeCount] = [likeCount] + ? WHERE [rid] = ?") - return err - } - - log.Print("Preparing editTopic statement.") - stmts.editTopic, err = db.Prepare("UPDATE [topics] SET [title] = ?,[content] = ?,[parsed_content] = ? WHERE [tid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [topics] SET [title] = ?,[content] = ?,[parsed_content] = ? WHERE [tid] = ?") - return err - } - log.Print("Preparing editReply statement.") stmts.editReply, err = db.Prepare("UPDATE [replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?") if err != nil { @@ -527,125 +345,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing stickTopic statement.") - stmts.stickTopic, err = db.Prepare("UPDATE [topics] SET [sticky] = 1 WHERE [tid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [topics] SET [sticky] = 1 WHERE [tid] = ?") - return err - } - - log.Print("Preparing unstickTopic statement.") - stmts.unstickTopic, err = db.Prepare("UPDATE [topics] SET [sticky] = 0 WHERE [tid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [topics] SET [sticky] = 0 WHERE [tid] = ?") - return err - } - - log.Print("Preparing lockTopic statement.") - stmts.lockTopic, err = db.Prepare("UPDATE [topics] SET [is_closed] = 1 WHERE [tid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [topics] SET [is_closed] = 1 WHERE [tid] = ?") - return err - } - - log.Print("Preparing unlockTopic statement.") - stmts.unlockTopic, err = db.Prepare("UPDATE [topics] SET [is_closed] = 0 WHERE [tid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [topics] SET [is_closed] = 0 WHERE [tid] = ?") - return err - } - - log.Print("Preparing updateLastIP statement.") - stmts.updateLastIP, err = db.Prepare("UPDATE [users] SET [last_ip] = ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [last_ip] = ? WHERE [uid] = ?") - return err - } - - log.Print("Preparing updateSession statement.") - stmts.updateSession, err = db.Prepare("UPDATE [users] SET [session] = ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [session] = ? WHERE [uid] = ?") - return err - } - - log.Print("Preparing setPassword statement.") - stmts.setPassword, err = db.Prepare("UPDATE [users] SET [password] = ?,[salt] = ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [password] = ?,[salt] = ? WHERE [uid] = ?") - return err - } - - log.Print("Preparing setAvatar statement.") - stmts.setAvatar, err = db.Prepare("UPDATE [users] SET [avatar] = ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [avatar] = ? WHERE [uid] = ?") - return err - } - - log.Print("Preparing setUsername statement.") - stmts.setUsername, err = db.Prepare("UPDATE [users] SET [name] = ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [name] = ? WHERE [uid] = ?") - return err - } - - log.Print("Preparing changeGroup statement.") - stmts.changeGroup, err = db.Prepare("UPDATE [users] SET [group] = ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [group] = ? WHERE [uid] = ?") - return err - } - - log.Print("Preparing activateUser statement.") - stmts.activateUser, err = db.Prepare("UPDATE [users] SET [active] = 1 WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [active] = 1 WHERE [uid] = ?") - return err - } - - log.Print("Preparing updateUserLevel statement.") - stmts.updateUserLevel, err = db.Prepare("UPDATE [users] SET [level] = ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [level] = ? WHERE [uid] = ?") - return err - } - - log.Print("Preparing incrementUserScore statement.") - stmts.incrementUserScore, err = db.Prepare("UPDATE [users] SET [score] = [score] + ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [score] = [score] + ? WHERE [uid] = ?") - return err - } - - log.Print("Preparing incrementUserPosts statement.") - stmts.incrementUserPosts, err = db.Prepare("UPDATE [users] SET [posts] = [posts] + ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [posts] = [posts] + ? WHERE [uid] = ?") - return err - } - - log.Print("Preparing incrementUserBigposts statement.") - stmts.incrementUserBigposts, err = db.Prepare("UPDATE [users] SET [posts] = [posts] + ?,[bigposts] = [bigposts] + ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [posts] = [posts] + ?,[bigposts] = [bigposts] + ? WHERE [uid] = ?") - return err - } - - log.Print("Preparing incrementUserMegaposts statement.") - stmts.incrementUserMegaposts, err = db.Prepare("UPDATE [users] SET [posts] = [posts] + ?,[bigposts] = [bigposts] + ?,[megaposts] = [megaposts] + ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [posts] = [posts] + ?,[bigposts] = [bigposts] + ?,[megaposts] = [megaposts] + ? WHERE [uid] = ?") - return err - } - - log.Print("Preparing incrementUserTopics statement.") - stmts.incrementUserTopics, err = db.Prepare("UPDATE [users] SET [topics] = [topics] + ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [topics] = [topics] + ? WHERE [uid] = ?") - return err - } - log.Print("Preparing editProfileReply statement.") stmts.editProfileReply, err = db.Prepare("UPDATE [users_replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?") if err != nil { @@ -653,13 +352,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 updateSetting statement.") stmts.updateSetting, err = db.Prepare("UPDATE [settings] SET [content] = ? WHERE [name] = ?") if err != nil { @@ -688,6 +380,13 @@ 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 { @@ -695,13 +394,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing updateUserGroup statement.") - stmts.updateUserGroup, err = db.Prepare("UPDATE [users] SET [group] = ? WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users] SET [group] = ? WHERE [uid] = ?") - return err - } - log.Print("Preparing updateGroupPerms statement.") stmts.updateGroupPerms, err = db.Prepare("UPDATE [users_groups] SET [permissions] = ? WHERE [gid] = ?") if err != nil { @@ -709,13 +401,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing updateGroupRank statement.") - stmts.updateGroupRank, err = db.Prepare("UPDATE [users_groups] SET [is_admin] = ?,[is_mod] = ?,[is_banned] = ? WHERE [gid] = ?") - if err != nil { - log.Print("Bad Query: ","UPDATE [users_groups] SET [is_admin] = ?,[is_mod] = ?,[is_banned] = ? WHERE [gid] = ?") - return err - } - log.Print("Preparing updateGroup statement.") stmts.updateGroup, err = db.Prepare("UPDATE [users_groups] SET [name] = ?,[tag] = ? WHERE [gid] = ?") if err != nil { @@ -758,27 +443,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing deleteUser statement.") - stmts.deleteUser, err = db.Prepare("DELETE FROM [users] WHERE [uid] = ?") - if err != nil { - log.Print("Bad Query: ","DELETE FROM [users] WHERE [uid] = ?") - return err - } - - log.Print("Preparing deleteTopic statement.") - stmts.deleteTopic, err = db.Prepare("DELETE FROM [topics] WHERE [tid] = ?") - if err != nil { - log.Print("Bad Query: ","DELETE FROM [topics] WHERE [tid] = ?") - return err - } - - log.Print("Preparing deleteReply statement.") - stmts.deleteReply, err = db.Prepare("DELETE FROM [replies] WHERE [rid] = ?") - if err != nil { - log.Print("Bad Query: ","DELETE FROM [replies] WHERE [rid] = ?") - return err - } - log.Print("Preparing deleteProfileReply statement.") stmts.deleteProfileReply, err = db.Prepare("DELETE FROM [users_replies] WHERE [rid] = ?") if err != nil { @@ -807,13 +471,6 @@ func _gen_mssql() (err error) { return err } - log.Print("Preparing groupCount statement.") - stmts.groupCount, err = db.Prepare("SELECT COUNT(*) AS [count] FROM [users_groups]") - if err != nil { - log.Print("Bad Query: ","SELECT COUNT(*) AS [count] FROM [users_groups]") - return err - } - log.Print("Preparing modlogCount statement.") stmts.modlogCount, err = db.Prepare("SELECT COUNT(*) AS [count] FROM [moderation_logs]") if err != nil { diff --git a/gen_mysql.go b/gen_mysql.go index 0d4fc67a..1000bc7c 100644 --- a/gen_mysql.go +++ b/gen_mysql.go @@ -6,6 +6,7 @@ package main import "log" import "database/sql" +import "./common" //import "./query_gen/lib" // nolint @@ -14,21 +15,14 @@ type Stmts struct { getSettings *sql.Stmt getSetting *sql.Stmt getFullSetting *sql.Stmt - getFullSettings *sql.Stmt - getPlugins *sql.Stmt - getThemes *sql.Stmt - getWidgets *sql.Stmt isPluginActive *sql.Stmt getUsersOffset *sql.Stmt - getWordFilters *sql.Stmt isThemeDefault *sql.Stmt getModlogs *sql.Stmt getModlogsOffset *sql.Stmt getReplyTID *sql.Stmt getTopicFID *sql.Stmt getUserReplyUID *sql.Stmt - hasLikedTopic *sql.Stmt - hasLikedReply *sql.Stmt getUserName *sql.Stmt getEmailsByUser *sql.Stmt getTopicBasic *sql.Stmt @@ -36,20 +30,14 @@ type Stmts struct { forumEntryExists *sql.Stmt groupEntryExists *sql.Stmt getForumTopicsOffset *sql.Stmt - getExpiredScheduledGroups *sql.Stmt - getSync *sql.Stmt getAttachment *sql.Stmt getTopicRepliesOffset *sql.Stmt getTopicList *sql.Stmt - getTopicUser *sql.Stmt - getTopicByReply *sql.Stmt getTopicReplies *sql.Stmt getForumTopics *sql.Stmt getProfileReplies *sql.Stmt getWatchers *sql.Stmt createReport *sql.Stmt - createActionReply *sql.Stmt - createLike *sql.Stmt addActivity *sql.Stmt notifyOne *sql.Stmt addEmail *sql.Stmt @@ -57,57 +45,27 @@ type Stmts struct { addForumPermsToForum *sql.Stmt addPlugin *sql.Stmt addTheme *sql.Stmt - addModlogEntry *sql.Stmt - addAdminlogEntry *sql.Stmt addAttachment *sql.Stmt createWordFilter *sql.Stmt - addRepliesToTopic *sql.Stmt - removeRepliesFromTopic *sql.Stmt - addLikesToTopic *sql.Stmt - addLikesToReply *sql.Stmt - editTopic *sql.Stmt editReply *sql.Stmt - stickTopic *sql.Stmt - unstickTopic *sql.Stmt - lockTopic *sql.Stmt - unlockTopic *sql.Stmt - updateLastIP *sql.Stmt - updateSession *sql.Stmt - setPassword *sql.Stmt - setAvatar *sql.Stmt - setUsername *sql.Stmt - changeGroup *sql.Stmt - activateUser *sql.Stmt - updateUserLevel *sql.Stmt - incrementUserScore *sql.Stmt - incrementUserPosts *sql.Stmt - incrementUserBigposts *sql.Stmt - incrementUserMegaposts *sql.Stmt - incrementUserTopics *sql.Stmt editProfileReply *sql.Stmt - updateForum *sql.Stmt updateSetting *sql.Stmt updatePlugin *sql.Stmt updatePluginInstall *sql.Stmt updateTheme *sql.Stmt + updateForum *sql.Stmt updateUser *sql.Stmt - updateUserGroup *sql.Stmt updateGroupPerms *sql.Stmt - updateGroupRank *sql.Stmt updateGroup *sql.Stmt updateEmail *sql.Stmt verifyEmail *sql.Stmt setTempGroup *sql.Stmt updateWordFilter *sql.Stmt bumpSync *sql.Stmt - deleteUser *sql.Stmt - deleteTopic *sql.Stmt - deleteReply *sql.Stmt deleteProfileReply *sql.Stmt deleteActivityStreamMatch *sql.Stmt deleteWordFilter *sql.Stmt reportExists *sql.Stmt - groupCount *sql.Stmt modlogCount *sql.Stmt notifyWatchers *sql.Stmt @@ -126,7 +84,7 @@ type Stmts struct { // nolint func _gen_mysql() (err error) { - if dev.DebugMode { + if common.Dev.DebugMode { log.Print("Building the generated statements") } @@ -154,30 +112,6 @@ func _gen_mysql() (err error) { return err } - log.Print("Preparing getFullSettings statement.") - stmts.getFullSettings, err = db.Prepare("SELECT `name`,`content`,`type`,`constraints` FROM `settings`") - if err != nil { - return err - } - - log.Print("Preparing getPlugins statement.") - stmts.getPlugins, err = db.Prepare("SELECT `uname`,`active`,`installed` FROM `plugins`") - if err != nil { - return err - } - - log.Print("Preparing getThemes statement.") - stmts.getThemes, err = db.Prepare("SELECT `uname`,`default` FROM `themes`") - if err != nil { - return err - } - - log.Print("Preparing getWidgets statement.") - stmts.getWidgets, err = db.Prepare("SELECT `position`,`side`,`type`,`active`,`location`,`data` FROM `widgets` ORDER BY position ASC") - if err != nil { - return err - } - log.Print("Preparing isPluginActive statement.") stmts.isPluginActive, err = db.Prepare("SELECT `active` FROM `plugins` WHERE `uname` = ?") if err != nil { @@ -190,12 +124,6 @@ func _gen_mysql() (err error) { return err } - log.Print("Preparing getWordFilters statement.") - stmts.getWordFilters, err = db.Prepare("SELECT `wfid`,`find`,`replacement` FROM `word_filters`") - if err != nil { - return err - } - log.Print("Preparing isThemeDefault statement.") stmts.isThemeDefault, err = db.Prepare("SELECT `default` FROM `themes` WHERE `uname` = ?") if err != nil { @@ -232,18 +160,6 @@ func _gen_mysql() (err error) { return err } - log.Print("Preparing hasLikedTopic statement.") - stmts.hasLikedTopic, err = db.Prepare("SELECT `targetItem` FROM `likes` WHERE `sentBy` = ? AND `targetItem` = ? AND `targetType` = 'topics'") - if err != nil { - return err - } - - log.Print("Preparing hasLikedReply statement.") - stmts.hasLikedReply, err = db.Prepare("SELECT `targetItem` FROM `likes` WHERE `sentBy` = ? AND `targetItem` = ? AND `targetType` = 'replies'") - if err != nil { - return err - } - log.Print("Preparing getUserName statement.") stmts.getUserName, err = db.Prepare("SELECT `name` FROM `users` WHERE `uid` = ?") if err != nil { @@ -286,18 +202,6 @@ func _gen_mysql() (err error) { return err } - log.Print("Preparing getExpiredScheduledGroups statement.") - stmts.getExpiredScheduledGroups, err = db.Prepare("SELECT `uid` FROM `users_groups_scheduler` WHERE UTC_TIMESTAMP() > `revert_at` AND `temporary` = 1") - if err != nil { - return err - } - - log.Print("Preparing getSync statement.") - stmts.getSync, err = db.Prepare("SELECT `last_update` FROM `sync`") - if err != nil { - return err - } - log.Print("Preparing getAttachment statement.") stmts.getAttachment, err = db.Prepare("SELECT `sectionID`,`sectionTable`,`originID`,`originTable`,`uploadedBy`,`path` FROM `attachments` WHERE `path` = ? AND `sectionID` = ? AND `sectionTable` = ?") if err != nil { @@ -316,18 +220,6 @@ func _gen_mysql() (err error) { return err } - log.Print("Preparing getTopicUser statement.") - stmts.getTopicUser, err = db.Prepare("SELECT `topics`.`title`, `topics`.`content`, `topics`.`createdBy`, `topics`.`createdAt`, `topics`.`is_closed`, `topics`.`sticky`, `topics`.`parentID`, `topics`.`ipaddress`, `topics`.`postCount`, `topics`.`likeCount`, `users`.`name`, `users`.`avatar`, `users`.`group`, `users`.`url_prefix`, `users`.`url_name`, `users`.`level` FROM `topics` LEFT JOIN `users` ON `topics`.`createdBy` = `users`.`uid` WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing getTopicByReply statement.") - stmts.getTopicByReply, err = db.Prepare("SELECT `topics`.`tid`, `topics`.`title`, `topics`.`content`, `topics`.`createdBy`, `topics`.`createdAt`, `topics`.`is_closed`, `topics`.`sticky`, `topics`.`parentID`, `topics`.`ipaddress`, `topics`.`postCount`, `topics`.`likeCount`, `topics`.`data` FROM `replies` LEFT JOIN `topics` ON `replies`.`tid` = `topics`.`tid` WHERE `rid` = ?") - if err != nil { - return err - } - log.Print("Preparing getTopicReplies statement.") stmts.getTopicReplies, err = db.Prepare("SELECT `replies`.`rid`, `replies`.`content`, `replies`.`createdBy`, `replies`.`createdAt`, `replies`.`lastEdit`, `replies`.`lastEditBy`, `users`.`avatar`, `users`.`name`, `users`.`group`, `users`.`url_prefix`, `users`.`url_name`, `users`.`level`, `replies`.`ipaddress` FROM `replies` LEFT JOIN `users` ON `replies`.`createdBy` = `users`.`uid` WHERE `tid` = ?") if err != nil { @@ -358,18 +250,6 @@ func _gen_mysql() (err error) { return err } - log.Print("Preparing createActionReply statement.") - stmts.createActionReply, err = db.Prepare("INSERT INTO `replies`(`tid`,`actionType`,`ipaddress`,`createdBy`,`createdAt`,`lastUpdated`,`content`,`parsed_content`) VALUES (?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'','')") - if err != nil { - return err - } - - log.Print("Preparing createLike statement.") - stmts.createLike, err = db.Prepare("INSERT INTO `likes`(`weight`,`targetItem`,`targetType`,`sentBy`) VALUES (?,?,?,?)") - if err != nil { - return err - } - log.Print("Preparing addActivity statement.") stmts.addActivity, err = db.Prepare("INSERT INTO `activity_stream`(`actor`,`targetUser`,`event`,`elementType`,`elementID`) VALUES (?,?,?,?,?)") if err != nil { @@ -412,18 +292,6 @@ func _gen_mysql() (err error) { return err } - log.Print("Preparing addModlogEntry statement.") - stmts.addModlogEntry, err = db.Prepare("INSERT INTO `moderation_logs`(`action`,`elementID`,`elementType`,`ipaddress`,`actorID`,`doneAt`) VALUES (?,?,?,?,?,UTC_TIMESTAMP())") - if err != nil { - return err - } - - log.Print("Preparing addAdminlogEntry statement.") - stmts.addAdminlogEntry, err = db.Prepare("INSERT INTO `administration_logs`(`action`,`elementID`,`elementType`,`ipaddress`,`actorID`,`doneAt`) VALUES (?,?,?,?,?,UTC_TIMESTAMP())") - if err != nil { - return err - } - log.Print("Preparing addAttachment statement.") stmts.addAttachment, err = db.Prepare("INSERT INTO `attachments`(`sectionID`,`sectionTable`,`originID`,`originTable`,`uploadedBy`,`path`) VALUES (?,?,?,?,?,?)") if err != nil { @@ -436,156 +304,18 @@ func _gen_mysql() (err error) { return err } - log.Print("Preparing addRepliesToTopic statement.") - stmts.addRepliesToTopic, err = db.Prepare("UPDATE `topics` SET `postCount` = `postCount` + ?,`lastReplyBy` = ?,`lastReplyAt` = UTC_TIMESTAMP() WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing removeRepliesFromTopic statement.") - stmts.removeRepliesFromTopic, err = db.Prepare("UPDATE `topics` SET `postCount` = `postCount` - ? WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing addLikesToTopic statement.") - stmts.addLikesToTopic, err = db.Prepare("UPDATE `topics` SET `likeCount` = `likeCount` + ? WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing addLikesToReply statement.") - stmts.addLikesToReply, err = db.Prepare("UPDATE `replies` SET `likeCount` = `likeCount` + ? WHERE `rid` = ?") - if err != nil { - return err - } - - log.Print("Preparing editTopic statement.") - stmts.editTopic, err = db.Prepare("UPDATE `topics` SET `title` = ?,`content` = ?,`parsed_content` = ? WHERE `tid` = ?") - if err != nil { - return err - } - log.Print("Preparing editReply statement.") stmts.editReply, err = db.Prepare("UPDATE `replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?") if err != nil { return err } - log.Print("Preparing stickTopic statement.") - stmts.stickTopic, err = db.Prepare("UPDATE `topics` SET `sticky` = 1 WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing unstickTopic statement.") - stmts.unstickTopic, err = db.Prepare("UPDATE `topics` SET `sticky` = 0 WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing lockTopic statement.") - stmts.lockTopic, err = db.Prepare("UPDATE `topics` SET `is_closed` = 1 WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing unlockTopic statement.") - stmts.unlockTopic, err = db.Prepare("UPDATE `topics` SET `is_closed` = 0 WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing updateLastIP statement.") - stmts.updateLastIP, err = db.Prepare("UPDATE `users` SET `last_ip` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing updateSession statement.") - stmts.updateSession, err = db.Prepare("UPDATE `users` SET `session` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing setPassword statement.") - stmts.setPassword, err = db.Prepare("UPDATE `users` SET `password` = ?,`salt` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing setAvatar statement.") - stmts.setAvatar, err = db.Prepare("UPDATE `users` SET `avatar` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing setUsername statement.") - stmts.setUsername, err = db.Prepare("UPDATE `users` SET `name` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing changeGroup statement.") - stmts.changeGroup, err = db.Prepare("UPDATE `users` SET `group` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing activateUser statement.") - stmts.activateUser, err = db.Prepare("UPDATE `users` SET `active` = 1 WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing updateUserLevel statement.") - stmts.updateUserLevel, err = db.Prepare("UPDATE `users` SET `level` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing incrementUserScore statement.") - stmts.incrementUserScore, err = db.Prepare("UPDATE `users` SET `score` = `score` + ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing incrementUserPosts statement.") - stmts.incrementUserPosts, err = db.Prepare("UPDATE `users` SET `posts` = `posts` + ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing incrementUserBigposts statement.") - stmts.incrementUserBigposts, err = db.Prepare("UPDATE `users` SET `posts` = `posts` + ?,`bigposts` = `bigposts` + ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing incrementUserMegaposts statement.") - stmts.incrementUserMegaposts, err = db.Prepare("UPDATE `users` SET `posts` = `posts` + ?,`bigposts` = `bigposts` + ?,`megaposts` = `megaposts` + ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing incrementUserTopics statement.") - stmts.incrementUserTopics, err = db.Prepare("UPDATE `users` SET `topics` = `topics` + ? WHERE `uid` = ?") - if err != nil { - return err - } - log.Print("Preparing editProfileReply statement.") stmts.editProfileReply, err = db.Prepare("UPDATE `users_replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?") if err != nil { 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 updateSetting statement.") stmts.updateSetting, err = db.Prepare("UPDATE `settings` SET `content` = ? WHERE `name` = ?") if err != nil { @@ -610,30 +340,24 @@ 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 { return err } - log.Print("Preparing updateUserGroup statement.") - stmts.updateUserGroup, err = db.Prepare("UPDATE `users` SET `group` = ? WHERE `uid` = ?") - if err != nil { - return err - } - log.Print("Preparing updateGroupPerms statement.") stmts.updateGroupPerms, err = db.Prepare("UPDATE `users_groups` SET `permissions` = ? WHERE `gid` = ?") if err != nil { return err } - log.Print("Preparing updateGroupRank statement.") - stmts.updateGroupRank, err = db.Prepare("UPDATE `users_groups` SET `is_admin` = ?,`is_mod` = ?,`is_banned` = ? WHERE `gid` = ?") - if err != nil { - return err - } - log.Print("Preparing updateGroup statement.") stmts.updateGroup, err = db.Prepare("UPDATE `users_groups` SET `name` = ?,`tag` = ? WHERE `gid` = ?") if err != nil { @@ -670,24 +394,6 @@ func _gen_mysql() (err error) { return err } - log.Print("Preparing deleteUser statement.") - stmts.deleteUser, err = db.Prepare("DELETE FROM `users` WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing deleteTopic statement.") - stmts.deleteTopic, err = db.Prepare("DELETE FROM `topics` WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing deleteReply statement.") - stmts.deleteReply, err = db.Prepare("DELETE FROM `replies` WHERE `rid` = ?") - if err != nil { - return err - } - log.Print("Preparing deleteProfileReply statement.") stmts.deleteProfileReply, err = db.Prepare("DELETE FROM `users_replies` WHERE `rid` = ?") if err != nil { @@ -712,12 +418,6 @@ func _gen_mysql() (err error) { return err } - log.Print("Preparing groupCount statement.") - stmts.groupCount, err = db.Prepare("SELECT COUNT(*) AS `count` FROM `users_groups`") - if err != nil { - return err - } - log.Print("Preparing modlogCount statement.") stmts.modlogCount, err = db.Prepare("SELECT COUNT(*) AS `count` FROM `moderation_logs`") if err != nil { diff --git a/gen_pgsql.go b/gen_pgsql.go index 6aafb582..a61938c3 100644 --- a/gen_pgsql.go +++ b/gen_pgsql.go @@ -5,42 +5,19 @@ package main import "log" import "database/sql" +import "./common" // nolint type Stmts struct { - addRepliesToTopic *sql.Stmt - removeRepliesFromTopic *sql.Stmt - addLikesToTopic *sql.Stmt - addLikesToReply *sql.Stmt - editTopic *sql.Stmt editReply *sql.Stmt - stickTopic *sql.Stmt - unstickTopic *sql.Stmt - lockTopic *sql.Stmt - unlockTopic *sql.Stmt - updateLastIP *sql.Stmt - updateSession *sql.Stmt - setPassword *sql.Stmt - setAvatar *sql.Stmt - setUsername *sql.Stmt - changeGroup *sql.Stmt - activateUser *sql.Stmt - updateUserLevel *sql.Stmt - incrementUserScore *sql.Stmt - incrementUserPosts *sql.Stmt - incrementUserBigposts *sql.Stmt - incrementUserMegaposts *sql.Stmt - incrementUserTopics *sql.Stmt editProfileReply *sql.Stmt - updateForum *sql.Stmt updateSetting *sql.Stmt updatePlugin *sql.Stmt updatePluginInstall *sql.Stmt updateTheme *sql.Stmt + updateForum *sql.Stmt updateUser *sql.Stmt - updateUserGroup *sql.Stmt updateGroupPerms *sql.Stmt - updateGroupRank *sql.Stmt updateGroup *sql.Stmt updateEmail *sql.Stmt verifyEmail *sql.Stmt @@ -63,160 +40,22 @@ type Stmts struct { // nolint func _gen_pgsql() (err error) { - if dev.DebugMode { + if common.Dev.DebugMode { log.Print("Building the generated statements") } - log.Print("Preparing addRepliesToTopic statement.") - stmts.addRepliesToTopic, err = db.Prepare("UPDATE `topics` SET `postCount` = `postCount` + ?,`lastReplyBy` = ?,`lastReplyAt` = LOCALTIMESTAMP() WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing removeRepliesFromTopic statement.") - stmts.removeRepliesFromTopic, err = db.Prepare("UPDATE `topics` SET `postCount` = `postCount` - ? WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing addLikesToTopic statement.") - stmts.addLikesToTopic, err = db.Prepare("UPDATE `topics` SET `likeCount` = `likeCount` + ? WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing addLikesToReply statement.") - stmts.addLikesToReply, err = db.Prepare("UPDATE `replies` SET `likeCount` = `likeCount` + ? WHERE `rid` = ?") - if err != nil { - return err - } - - log.Print("Preparing editTopic statement.") - stmts.editTopic, err = db.Prepare("UPDATE `topics` SET `title` = ?,`content` = ?,`parsed_content` = ? WHERE `tid` = ?") - if err != nil { - return err - } - log.Print("Preparing editReply statement.") stmts.editReply, err = db.Prepare("UPDATE `replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?") if err != nil { return err } - log.Print("Preparing stickTopic statement.") - stmts.stickTopic, err = db.Prepare("UPDATE `topics` SET `sticky` = 1 WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing unstickTopic statement.") - stmts.unstickTopic, err = db.Prepare("UPDATE `topics` SET `sticky` = 0 WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing lockTopic statement.") - stmts.lockTopic, err = db.Prepare("UPDATE `topics` SET `is_closed` = 1 WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing unlockTopic statement.") - stmts.unlockTopic, err = db.Prepare("UPDATE `topics` SET `is_closed` = 0 WHERE `tid` = ?") - if err != nil { - return err - } - - log.Print("Preparing updateLastIP statement.") - stmts.updateLastIP, err = db.Prepare("UPDATE `users` SET `last_ip` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing updateSession statement.") - stmts.updateSession, err = db.Prepare("UPDATE `users` SET `session` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing setPassword statement.") - stmts.setPassword, err = db.Prepare("UPDATE `users` SET `password` = ?,`salt` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing setAvatar statement.") - stmts.setAvatar, err = db.Prepare("UPDATE `users` SET `avatar` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing setUsername statement.") - stmts.setUsername, err = db.Prepare("UPDATE `users` SET `name` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing changeGroup statement.") - stmts.changeGroup, err = db.Prepare("UPDATE `users` SET `group` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing activateUser statement.") - stmts.activateUser, err = db.Prepare("UPDATE `users` SET `active` = 1 WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing updateUserLevel statement.") - stmts.updateUserLevel, err = db.Prepare("UPDATE `users` SET `level` = ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing incrementUserScore statement.") - stmts.incrementUserScore, err = db.Prepare("UPDATE `users` SET `score` = `score` + ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing incrementUserPosts statement.") - stmts.incrementUserPosts, err = db.Prepare("UPDATE `users` SET `posts` = `posts` + ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing incrementUserBigposts statement.") - stmts.incrementUserBigposts, err = db.Prepare("UPDATE `users` SET `posts` = `posts` + ?,`bigposts` = `bigposts` + ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing incrementUserMegaposts statement.") - stmts.incrementUserMegaposts, err = db.Prepare("UPDATE `users` SET `posts` = `posts` + ?,`bigposts` = `bigposts` + ?,`megaposts` = `megaposts` + ? WHERE `uid` = ?") - if err != nil { - return err - } - - log.Print("Preparing incrementUserTopics statement.") - stmts.incrementUserTopics, err = db.Prepare("UPDATE `users` SET `topics` = `topics` + ? WHERE `uid` = ?") - if err != nil { - return err - } - log.Print("Preparing editProfileReply statement.") stmts.editProfileReply, err = db.Prepare("UPDATE `users_replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?") if err != nil { 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 updateSetting statement.") stmts.updateSetting, err = db.Prepare("UPDATE `settings` SET `content` = ? WHERE `name` = ?") if err != nil { @@ -241,30 +80,24 @@ 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 { return err } - log.Print("Preparing updateUserGroup statement.") - stmts.updateUserGroup, err = db.Prepare("UPDATE `users` SET `group` = ? WHERE `uid` = ?") - if err != nil { - return err - } - log.Print("Preparing updateGroupPerms statement.") stmts.updateGroupPerms, err = db.Prepare("UPDATE `users_groups` SET `permissions` = ? WHERE `gid` = ?") if err != nil { return err } - log.Print("Preparing updateGroupRank statement.") - stmts.updateGroupRank, err = db.Prepare("UPDATE `users_groups` SET `is_admin` = ?,`is_mod` = ?,`is_banned` = ? WHERE `gid` = ?") - if err != nil { - return err - } - log.Print("Preparing updateGroup statement.") stmts.updateGroup, err = db.Prepare("UPDATE `users_groups` SET `name` = ?,`tag` = ? WHERE `gid` = ?") if err != nil { diff --git a/gen_router.go b/gen_router.go index 4cafcdd0..72f62d29 100644 --- a/gen_router.go +++ b/gen_router.go @@ -2,17 +2,21 @@ /* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ package main -import "log" -import "strings" -import "sync" -import "errors" -import "net/http" +import ( + "log" + "strings" + "sync" + "errors" + "net/http" + + "./common" +) var ErrNoRoute = errors.New("That route doesn't exist.") type GenRouter struct { UploadHandler func(http.ResponseWriter, *http.Request) - extra_routes map[string]func(http.ResponseWriter, *http.Request, User) RouteError + extra_routes map[string]func(http.ResponseWriter, *http.Request, common.User) common.RouteError sync.RWMutex } @@ -20,26 +24,26 @@ type GenRouter struct { func NewGenRouter(uploads http.Handler) *GenRouter { return &GenRouter{ UploadHandler: http.StripPrefix("/uploads/",uploads).ServeHTTP, - extra_routes: make(map[string]func(http.ResponseWriter, *http.Request, User) RouteError), + extra_routes: make(map[string]func(http.ResponseWriter, *http.Request, common.User) common.RouteError), } } -func (router *GenRouter) handleError(err RouteError, w http.ResponseWriter, r *http.Request, user User) { +func (router *GenRouter) handleError(err common.RouteError, w http.ResponseWriter, r *http.Request, user common.User) { if err.Handled() { return } if err.Type() == "system" { - InternalErrorJSQ(err,w,r,err.Json()) + common.InternalErrorJSQ(err, w, r, err.JSON()) return } - LocalErrorJSQ(err.Error(),w,r,user,err.Json()) + common.LocalErrorJSQ(err.Error(), w, r, user,err.JSON()) } func (router *GenRouter) Handle(_ string, _ http.Handler) { } -func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, User) RouteError) { +func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, common.User) common.RouteError) { router.Lock() router.extra_routes[pattern] = handle router.Unlock() @@ -52,7 +56,7 @@ func (router *GenRouter) RemoveFunc(pattern string) error { router.Unlock() return ErrNoRoute } - delete(router.extra_routes,pattern) + delete(router.extra_routes, pattern) router.Unlock() return nil } @@ -75,7 +79,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { req.URL.Path = req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/') + 1] } - if dev.SuperDebug { + if common.Dev.SuperDebug { log.Print("before routeStatic") log.Print("prefix: ", prefix) log.Print("req.URL.Path: ", req.URL.Path) @@ -85,25 +89,25 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { if prefix == "/static" { req.URL.Path += extra_data - routeStatic(w,req) + routeStatic(w, req) return } - if dev.SuperDebug { + if common.Dev.SuperDebug { log.Print("before PreRoute") } // Deal with the session stuff, etc. - user, ok := PreRoute(w,req) + user, ok := common.PreRoute(w, req) if !ok { return } - if dev.SuperDebug { + if common.Dev.SuperDebug { log.Print("after PreRoute") } - var err RouteError + var err common.RouteError switch(prefix) { case "/api": err = routeAPI(w,req,user) @@ -136,19 +140,19 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { router.handleError(err,w,req,user) } case "/report": - err = MemberOnly(w,req,user) + err = common.MemberOnly(w,req,user) if err != nil { router.handleError(err,w,req,user) return } - err = NoBanned(w,req,user) + err = common.NoBanned(w,req,user) if err != nil { router.handleError(err,w,req,user) return } - err = NoSessionMismatch(w,req,user) + err = common.NoSessionMismatch(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -164,7 +168,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { case "/topics": switch(req.URL.Path) { case "/topics/create/": - err = MemberOnly(w,req,user) + err = common.MemberOnly(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -178,7 +182,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { router.handleError(err,w,req,user) } case "/panel": - err = SuperModOnly(w,req,user) + err = common.SuperModOnly(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -260,7 +264,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { case "/user": switch(req.URL.Path) { case "/user/edit/critical/": - err = MemberOnly(w,req,user) + err = common.MemberOnly(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -268,13 +272,13 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { err = routeAccountEditCritical(w,req,user) case "/user/edit/critical/submit/": - err = NoSessionMismatch(w,req,user) + err = common.NoSessionMismatch(w,req,user) if err != nil { router.handleError(err,w,req,user) return } - err = MemberOnly(w,req,user) + err = common.MemberOnly(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -282,7 +286,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { err = routeAccountEditCriticalSubmit(w,req,user) case "/user/edit/avatar/": - err = MemberOnly(w,req,user) + err = common.MemberOnly(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -290,7 +294,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { err = routeAccountEditAvatar(w,req,user) case "/user/edit/avatar/submit/": - err = MemberOnly(w,req,user) + err = common.MemberOnly(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -298,7 +302,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { err = routeAccountEditAvatarSubmit(w,req,user) case "/user/edit/username/": - err = MemberOnly(w,req,user) + err = common.MemberOnly(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -306,7 +310,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { err = routeAccountEditUsername(w,req,user) case "/user/edit/username/submit/": - err = MemberOnly(w,req,user) + err = common.MemberOnly(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -314,7 +318,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { err = routeAccountEditUsernameSubmit(w,req,user) case "/user/edit/email/": - err = MemberOnly(w,req,user) + err = common.MemberOnly(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -322,7 +326,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { err = routeAccountEditEmail(w,req,user) case "/user/edit/token/": - err = MemberOnly(w,req,user) + err = common.MemberOnly(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -337,7 +341,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { router.handleError(err,w,req,user) } case "/users": - err = MemberOnly(w,req,user) + err = common.MemberOnly(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -345,7 +349,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { switch(req.URL.Path) { case "/users/ban/submit/": - err = NoSessionMismatch(w,req,user) + err = common.NoSessionMismatch(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -353,7 +357,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { err = routeBanSubmit(w,req,user) case "/users/unban/": - err = NoSessionMismatch(w,req,user) + err = common.NoSessionMismatch(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -361,7 +365,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { err = routeUnban(w,req,user) case "/users/activate/": - err = NoSessionMismatch(w,req,user) + err = common.NoSessionMismatch(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -376,7 +380,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } case "/uploads": if extra_data == "" { - NotFound(w,req) + common.NotFound(w,req) return } req.URL.Path += extra_data @@ -395,10 +399,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } if extra_data != "" { - NotFound(w,req) + common.NotFound(w,req) return } - config.DefaultRoute(w,req,user) + common.Config.DefaultRoute(w,req,user) default: // A fallback for the routes which haven't been converted to the new router yet or plugins router.RLock() @@ -413,6 +417,6 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } return } - NotFound(w,req) + common.NotFound(w,req) } } diff --git a/general_test.go b/general_test.go index 8fb4aef6..ae9f60fe 100644 --- a/general_test.go +++ b/general_test.go @@ -14,6 +14,7 @@ import ( "testing" "time" + "./common" "./install/install" //"runtime/pprof" //_ "github.com/go-sql-driver/mysql" @@ -46,28 +47,28 @@ func ResetTables() (err error) { } func gloinit() (err error) { - dev.DebugMode = false + common.Dev.DebugMode = false //nogrouplog = true startTime = time.Now() - err = processConfig() + err = common.ProcessConfig() if err != nil { return err } - err = initThemes() + err = common.InitThemes() if err != nil { return err } - switchToTestDB() + common.SwitchToTestDB() var ok bool installAdapter, ok = install.Lookup(dbAdapter) if !ok { return errors.New("We couldn't find the adapter '" + dbAdapter + "'") } - installAdapter.SetConfig(dbConfig.Host, dbConfig.Username, dbConfig.Password, dbConfig.Dbname, dbConfig.Port) + installAdapter.SetConfig(common.DbConfig.Host, common.DbConfig.Username, common.DbConfig.Password, common.DbConfig.Dbname, common.DbConfig.Port) err = ResetTables() if err != nil { diff --git a/install/install.go b/install/install.go index bd7a02de..4094fdc9 100644 --- a/install/install.go +++ b/install/install.go @@ -97,67 +97,69 @@ func main() { configContents := []byte(`package main +import "./common" + func init() { // Site Info - site.ShortName = "` + siteShortName + `" // This should be less than three letters to fit in the navbar - site.Name = "` + siteName + `" - site.Email = "" - site.URL = "` + siteURL + `" - site.Port = "` + serverPort + `" - site.EnableSsl = false - site.EnableEmails = false - site.HasProxy = false // Cloudflare counts as this, if it's sitting in the middle - config.SslPrivkey = "" - config.SslFullchain = "" - site.Language = "english" + common.Site.ShortName = "` + siteShortName + `" // This should be less than three letters to fit in the navbar + common.Site.Name = "` + siteName + `" + common.Site.Email = "" + common.Site.URL = "` + siteURL + `" + common.Site.Port = "` + serverPort + `" + common.Site.EnableSsl = false + common.Site.EnableEmails = false + common.Site.HasProxy = false // Cloudflare counts as this, if it's sitting in the middle + common.Config.SslPrivkey = "" + common.Config.SslFullchain = "" + common.Site.Language = "english" // Database details - dbConfig.Host = "` + adap.DBHost() + `" - dbConfig.Username = "` + adap.DBUsername() + `" - dbConfig.Password = "` + adap.DBPassword() + `" - dbConfig.Dbname = "` + adap.DBName() + `" - dbConfig.Port = "` + adap.DBPort() + `" // You probably won't need to change this + common.DbConfig.Host = "` + adap.DBHost() + `" + common.DbConfig.Username = "` + adap.DBUsername() + `" + common.DbConfig.Password = "` + adap.DBPassword() + `" + common.DbConfig.Dbname = "` + adap.DBName() + `" + common.DbConfig.Port = "` + adap.DBPort() + `" // You probably won't need to change this // Test Database details - dbConfig.TestHost = "" - dbConfig.TestUsername = "" - dbConfig.TestPassword = "" - dbConfig.TestDbname = "" // The name of the test database, leave blank to disable. DON'T USE YOUR PRODUCTION DATABASE FOR THIS. LEAVE BLANK IF YOU DON'T KNOW WHAT THIS MEANS. - dbConfig.TestPort = "" + common.DbConfig.TestHost = "" + common.DbConfig.TestUsername = "" + common.DbConfig.TestPassword = "" + common.DbConfig.TestDbname = "" // The name of the test database, leave blank to disable. DON'T USE YOUR PRODUCTION DATABASE FOR THIS. LEAVE BLANK IF YOU DON'T KNOW WHAT THIS MEANS. + common.DbConfig.TestPort = "" // Limiters - config.MaxRequestSize = 5 * megabyte + common.Config.MaxRequestSize = 5 * common.Megabyte // Caching - config.CacheTopicUser = CACHE_STATIC - config.UserCacheCapacity = 120 // The max number of users held in memory - config.TopicCacheCapacity = 200 // The max number of topics held in memory + common.Config.CacheTopicUser = common.CACHE_STATIC + common.Config.UserCacheCapacity = 120 // The max number of users held in memory + common.Config.TopicCacheCapacity = 200 // The max number of topics held in memory // Email - config.SMTPServer = "" - config.SMTPUsername = "" - config.SMTPPassword = "" - config.SMTPPort = "25" + common.Config.SMTPServer = "" + common.Config.SMTPUsername = "" + common.Config.SMTPPassword = "" + common.Config.SMTPPort = "25" // Misc - config.DefaultRoute = routeTopics - config.DefaultGroup = 3 // Should be a setting in the database - config.ActivationGroup = 5 // Should be a setting in the database - config.StaffCSS = "staff_post" - config.DefaultForum = 2 - config.MinifyTemplates = true - config.MultiServer = false // Experimental: Enable Cross-Server Synchronisation and several other features + common.Config.DefaultRoute = routeTopics + common.Config.DefaultGroup = 3 // Should be a setting in the database + common.Config.ActivationGroup = 5 // Should be a setting in the database + common.Config.StaffCSS = "staff_post" + common.Config.DefaultForum = 2 + common.Config.MinifyTemplates = true + common.Config.MultiServer = false // Experimental: Enable Cross-Server Synchronisation and several other features - //config.Noavatar = "https://api.adorable.io/avatars/{width}/{id}@{site_url}.png" - config.Noavatar = "https://api.adorable.io/avatars/285/{id}@{site_url}.png" - config.ItemsPerPage = 25 + //common.Config.Noavatar = "https://api.adorable.io/avatars/{width}/{id}@{site_url}.png" + common.Config.Noavatar = "https://api.adorable.io/avatars/285/{id}@{site_url}.png" + common.Config.ItemsPerPage = 25 // Developer flags - dev.DebugMode = true - //dev.SuperDebug = true - //dev.TemplateDebug = true - //dev.Profiling = true - //dev.TestDB = true + common.Dev.DebugMode = true + //common.Dev.SuperDebug = true + //common.Dev.TemplateDebug = true + //common.Dev.Profiling = true + //common.Dev.TestDB = true } `) diff --git a/main.go b/main.go index 627869d4..312f8f54 100644 --- a/main.go +++ b/main.go @@ -14,65 +14,12 @@ import ( "os" "time" //"runtime/pprof" + "./common" ) -var version = Version{Major: 0, Minor: 1, Patch: 0, Tag: "dev"} - -const hour int = 60 * 60 -const day int = hour * 24 -const week int = day * 7 -const month int = day * 30 -const year int = day * 365 -const kilobyte int = 1024 -const megabyte int = kilobyte * 1024 -const gigabyte int = megabyte * 1024 -const terabyte int = gigabyte * 1024 -const petabyte int = terabyte * 1024 -const saltLength int = 32 -const sessionLength int = 80 - +var version = common.Version{Major: 0, Minor: 1, Patch: 0, Tag: "dev"} var router *GenRouter var startTime time.Time - -// ? - Make this more customisable? -var externalSites = map[string]string{ - "YT": "https://www.youtube.com/", -} - -type StringList []string - -// ? - Should we allow users to upload .php or .go files? It could cause security issues. We could store them with a mangled extension to render them inert -// TODO: Let admins manage this from the Control Panel -var allowedFileExts = StringList{ - "png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp", "apng", // images - - "txt", "xml", "json", "yaml", "toml", "ini", "md", "html", "rtf", "js", "py", "rb", "css", "scss", "less", "eqcss", "pcss", "java", "ts", "cs", "c", "cc", "cpp", "cxx", "C", "c++", "h", "hh", "hpp", "hxx", "h++", "rs", "rlib", "htaccess", "gitignore", // text - - "mp3", "mp4", "avi", "wmv", "webm", // video - - "otf", "woff2", "woff", "ttf", "eot", // fonts -} -var imageFileExts = StringList{ - "png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp", "apng", -} -var archiveFileExts = StringList{ - "bz2", "zip", "gz", "7z", "tar", "cab", -} -var executableFileExts = StringList{ - "exe", "jar", "phar", "shar", "iso", -} - -// TODO: Write a test for this -func (slice StringList) Contains(needle string) bool { - for _, item := range slice { - if item == needle { - return true - } - } - return false -} - -var staticFiles = make(map[string]SFile) var logWriter = io.MultiWriter(os.Stderr) // TODO: Wrap the globals in here so we can pass pointers to them to subpackages @@ -128,58 +75,61 @@ func main() { startTime = time.Now() log.Print("Processing configuration data") - err = processConfig() + err = common.ProcessConfig() if err != nil { log.Fatal(err) } - err = initThemes() + err = common.InitThemes() if err != nil { log.Fatal(err) } - err = initDatabase() + err = InitDatabase() if err != nil { log.Fatal(err) } - rstore, err = NewSQLReplyStore() + common.Rstore, err = common.NewSQLReplyStore() if err != nil { log.Fatal(err) } - prstore, err = NewSQLProfileReplyStore() + common.Prstore, err = common.NewSQLProfileReplyStore() if err != nil { log.Fatal(err) } - initTemplates() + common.InitTemplates() - err = initPhrases() + err = common.InitPhrases() if err != nil { log.Fatal(err) } log.Print("Loading the static files.") - err = initStaticFiles() + err = common.StaticFiles.Init() if err != nil { log.Fatal(err) } log.Print("Initialising the widgets") - err = initWidgets() + err = common.InitWidgets() if err != nil { log.Fatal(err) } log.Print("Initialising the authentication system") - auth = NewDefaultAuth() - - err = LoadWordFilters() + common.Auth, err = common.NewDefaultAuth() if err != nil { log.Fatal(err) } - err = verifyConfig() + err = common.LoadWordFilters() + if err != nil { + log.Fatal(err) + } + + err = common.VerifyConfig() if err != nil { log.Fatal(err) } @@ -195,18 +145,18 @@ func main() { //log.Print("Running the second ticker") // TODO: Add a plugin hook here - err := handleExpiredScheduledGroups() + err := common.HandleExpiredScheduledGroups() if err != nil { - LogError(err) + common.LogError(err) } // TODO: Handle delayed moderation tasks // TODO: Handle the daily clean-up. Move this to a 24 hour task? // Sync with the database, if there are any changes - err = handleServerSync() + err = common.HandleServerSync() if err != nil { - LogError(err) + common.LogError(err) } // TODO: Manage the TopicStore, UserStore, and ForumStore @@ -264,7 +214,7 @@ func main() { router.HandleFunc("/ws/", routeWebsockets) log.Print("Initialising the plugins") - initPlugins() + common.InitPlugins() defer db.Close() @@ -274,17 +224,17 @@ func main() { // TODO: Let users run *both* HTTP and HTTPS log.Print("Initialising the HTTP server") - if !site.EnableSsl { - if site.Port == "" { - site.Port = "80" + if !common.Site.EnableSsl { + if common.Site.Port == "" { + common.Site.Port = "80" } - log.Print("Listening on port " + site.Port) - err = http.ListenAndServe(":"+site.Port, router) + log.Print("Listening on port " + common.Site.Port) + err = http.ListenAndServe(":"+common.Site.Port, router) } else { - if site.Port == "" { - site.Port = "443" + if common.Site.Port == "" { + common.Site.Port = "443" } - if site.Port == "80" || site.Port == "443" { + if common.Site.Port == "80" || common.Site.Port == "443" { // We should also run the server on port 80 // TODO: Redirect to port 443 go func() { @@ -295,8 +245,8 @@ func main() { } }() } - log.Print("Listening on port " + site.Port) - err = http.ListenAndServeTLS(":"+site.Port, config.SslFullchain, config.SslPrivkey, router) + log.Printf("Listening on port %s", common.Site.Port) + err = http.ListenAndServeTLS(":"+common.Site.Port, common.Config.SslFullchain, common.Config.SslPrivkey, router) } // Why did the server stop? diff --git a/member_routes.go b/member_routes.go index b241d504..8beb1aff 100644 --- a/member_routes.go +++ b/member_routes.go @@ -12,6 +12,8 @@ import ( "regexp" "strconv" "strings" + + "./common" ) // ? - Should we add a new permission or permission zone (like per-forum permissions) specifically for profile comment creation @@ -19,50 +21,50 @@ import ( // TODO: Add a permission to stop certain users from using custom avatars // ? - Log username changes and put restrictions on this? -func routeTopicCreate(w http.ResponseWriter, r *http.Request, user User, sfid string) RouteError { +func routeTopicCreate(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError { var fid int var err error if sfid != "" { fid, err = strconv.Atoi(sfid) if err != nil { - return LocalError("You didn't provide a valid number for the forum ID.", w, r, user) + return common.LocalError("You didn't provide a valid number for the forum ID.", w, r, user) } } if fid == 0 { - fid = config.DefaultForum + fid = common.Config.DefaultForum } - headerVars, ferr := ForumUserCheck(w, r, &user, fid) + headerVars, ferr := common.ForumUserCheck(w, r, &user, fid) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.CreateTopic { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } - BuildWidgets("create_topic", nil, headerVars, r) + common.BuildWidgets("create_topic", nil, headerVars, r) // Lock this to the forum being linked? // Should we always put it in strictmode when it's linked from another forum? Well, the user might end up changing their mind on what forum they want to post in and it would be a hassle, if they had to switch pages, even if it is a single click for many (exc. mobile) var strictmode bool - if vhooks["topic_create_pre_loop"] != nil { - runVhook("topic_create_pre_loop", w, r, fid, &headerVars, &user, &strictmode) + if common.Vhooks["topic_create_pre_loop"] != nil { + common.RunVhook("topic_create_pre_loop", w, r, fid, &headerVars, &user, &strictmode) } // TODO: Re-add support for plugin_guilds - var forumList []Forum + var forumList []common.Forum var canSee []int if user.IsSuperAdmin { - canSee, err = fstore.GetAllVisibleIDs() + canSee, err = common.Fstore.GetAllVisibleIDs() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } else { - group, err := gstore.Get(user.Group) + group, err := common.Gstore.Get(user.Group) if err != nil { // TODO: Refactor this - LocalError("Something weird happened behind the scenes", w, r, user) - log.Printf("Group #%d doesn't exist, but it's set on User #%d", user.Group, user.ID) + common.LocalError("Something weird happened behind the scenes", w, r, user) + log.Printf("Group #%d doesn't exist, but it's set on common.User #%d", user.Group, user.ID) return nil } canSee = group.CanSee @@ -76,12 +78,12 @@ func routeTopicCreate(w http.ResponseWriter, r *http.Request, user User, sfid st } // Do a bulk forum fetch, just in case it's the SqlForumStore? - forum := fstore.DirtyGet(ffid) + forum := common.Fstore.DirtyGet(ffid) if forum.Name != "" && forum.Active { fcopy := forum.Copy() - if hooks["topic_create_frow_assign"] != nil { + if common.Hooks["topic_create_frow_assign"] != nil { // TODO: Add the skip feature to all the other row based hooks? - if runHook("topic_create_frow_assign", &fcopy).(bool) { + if common.RunHook("topic_create_frow_assign", &fcopy).(bool) { continue } } @@ -89,72 +91,72 @@ func routeTopicCreate(w http.ResponseWriter, r *http.Request, user User, sfid st } } - ctpage := CreateTopicPage{"Create Topic", user, headerVars, forumList, fid} - if preRenderHooks["pre_render_create_topic"] != nil { - if runPreRenderHook("pre_render_create_topic", w, r, &user, &ctpage) { + ctpage := common.CreateTopicPage{"Create Topic", user, headerVars, forumList, fid} + if common.PreRenderHooks["pre_render_create_topic"] != nil { + if common.RunPreRenderHook("pre_render_create_topic", w, r, &user, &ctpage) { return nil } } - err = RunThemeTemplate(headerVars.ThemeName, "create-topic", ctpage, w) + err = common.RunThemeTemplate(headerVars.ThemeName, "create-topic", ctpage, w) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } // POST functions. Authorised users only. -func routeTopicCreateSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeTopicCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { // TODO: Reduce this to 1MB for attachments for each file? - if r.ContentLength > int64(config.MaxRequestSize) { - size, unit := convertByteUnit(float64(config.MaxRequestSize)) - return CustomError("Your attachments are too big. Your files need to be smaller than "+strconv.Itoa(int(size))+unit+".", http.StatusExpectationFailed, "Error", w, r, user) + if r.ContentLength > int64(common.Config.MaxRequestSize) { + size, unit := common.ConvertByteUnit(float64(common.Config.MaxRequestSize)) + return common.CustomError("Your attachments are too big. Your files need to be smaller than "+strconv.Itoa(int(size))+unit+".", http.StatusExpectationFailed, "Error", w, r, user) } - r.Body = http.MaxBytesReader(w, r.Body, int64(config.MaxRequestSize)) + r.Body = http.MaxBytesReader(w, r.Body, int64(common.Config.MaxRequestSize)) - err := r.ParseMultipartForm(int64(megabyte)) + err := r.ParseMultipartForm(int64(common.Megabyte)) if err != nil { - return LocalError("Unable to parse the form", w, r, user) + return common.LocalError("Unable to parse the form", w, r, user) } fid, err := strconv.Atoi(r.PostFormValue("topic-board")) if err != nil { - return LocalError("The provided ForumID is not a valid number.", w, r, user) + return common.LocalError("The provided ForumID is not a valid number.", w, r, user) } // TODO: Add hooks to make use of headerLite - _, ferr := SimpleForumUserCheck(w, r, &user, fid) + _, ferr := common.SimpleForumUserCheck(w, r, &user, fid) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.CreateTopic { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } topicName := html.EscapeString(r.PostFormValue("topic-name")) - content := html.EscapeString(preparseMessage(r.PostFormValue("topic-content"))) - tid, err := topics.Create(fid, topicName, content, user.ID, user.LastIP) + content := html.EscapeString(common.PreparseMessage(r.PostFormValue("topic-content"))) + tid, err := common.Topics.Create(fid, topicName, content, user.ID, user.LastIP) if err != nil { switch err { - case ErrNoRows: - return LocalError("Something went wrong, perhaps the forum got deleted?", w, r, user) - case ErrNoTitle: - return LocalError("This topic doesn't have a title", w, r, user) - case ErrNoBody: - return LocalError("This topic doesn't have a body", w, r, user) + case common.ErrNoRows: + return common.LocalError("Something went wrong, perhaps the forum got deleted?", w, r, user) + case common.ErrNoTitle: + return common.LocalError("This topic doesn't have a title", w, r, user) + case common.ErrNoBody: + return common.LocalError("This topic doesn't have a body", w, r, user) default: - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } _, err = stmts.addSubscription.Exec(user.ID, tid, "topic") if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - err = user.increasePostStats(wordCount(content), true) + err = user.IncreasePostStats(common.WordCount(content), true) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Handle the file attachments @@ -163,39 +165,39 @@ func routeTopicCreateSubmit(w http.ResponseWriter, r *http.Request, user User) R files, ok := r.MultipartForm.File["upload_files"] if ok { if len(files) > 5 { - return LocalError("You can't attach more than five files", w, r, user) + return common.LocalError("You can't attach more than five files", w, r, user) } for _, file := range files { - if dev.DebugMode { + if common.Dev.DebugMode { log.Print("file.Filename ", file.Filename) } extarr := strings.Split(file.Filename, ".") if len(extarr) < 2 { - return LocalError("Bad file", w, r, user) + return common.LocalError("Bad file", w, r, user) } ext := extarr[len(extarr)-1] // TODO: Can we do this without a regex? reg, err := regexp.Compile("[^A-Za-z0-9]+") if err != nil { - return LocalError("Bad file extension", w, r, user) + return common.LocalError("Bad file extension", w, r, user) } ext = strings.ToLower(reg.ReplaceAllString(ext, "")) - if !allowedFileExts.Contains(ext) { - return LocalError("You're not allowed to upload files with this extension", w, r, user) + if !common.AllowedFileExts.Contains(ext) { + return common.LocalError("You're not allowed to upload files with this extension", w, r, user) } infile, err := file.Open() if err != nil { - return LocalError("Upload failed", w, r, user) + return common.LocalError("Upload failed", w, r, user) } defer infile.Close() hasher := sha256.New() _, err = io.Copy(hasher, infile) if err != nil { - return LocalError("Upload failed [Hashing Failed]", w, r, user) + return common.LocalError("Upload failed [Hashing Failed]", w, r, user) } infile.Close() @@ -203,24 +205,24 @@ func routeTopicCreateSubmit(w http.ResponseWriter, r *http.Request, user User) R filename := checksum + "." + ext outfile, err := os.Create("." + "/attachs/" + filename) if err != nil { - return LocalError("Upload failed [File Creation Failed]", w, r, user) + return common.LocalError("Upload failed [File Creation Failed]", w, r, user) } defer outfile.Close() infile, err = file.Open() if err != nil { - return LocalError("Upload failed", w, r, user) + return common.LocalError("Upload failed", w, r, user) } defer infile.Close() _, err = io.Copy(outfile, infile) if err != nil { - return LocalError("Upload failed [Copy Failed]", w, r, user) + return common.LocalError("Upload failed [Copy Failed]", w, r, user) } _, err = stmts.addAttachment.Exec(fid, "forums", tid, "topics", user.ID, filename) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } } @@ -230,39 +232,39 @@ func routeTopicCreateSubmit(w http.ResponseWriter, r *http.Request, user User) R return nil } -func routeCreateReply(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeCreateReply(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { // TODO: Reduce this to 1MB for attachments for each file? // TODO: Reuse this code more - if r.ContentLength > int64(config.MaxRequestSize) { - size, unit := convertByteUnit(float64(config.MaxRequestSize)) - return CustomError("Your attachments are too big. Your files need to be smaller than "+strconv.Itoa(int(size))+unit+".", http.StatusExpectationFailed, "Error", w, r, user) + if r.ContentLength > int64(common.Config.MaxRequestSize) { + size, unit := common.ConvertByteUnit(float64(common.Config.MaxRequestSize)) + return common.CustomError("Your attachments are too big. Your files need to be smaller than "+strconv.Itoa(int(size))+unit+".", http.StatusExpectationFailed, "Error", w, r, user) } - r.Body = http.MaxBytesReader(w, r.Body, int64(config.MaxRequestSize)) + r.Body = http.MaxBytesReader(w, r.Body, int64(common.Config.MaxRequestSize)) - err := r.ParseMultipartForm(int64(megabyte)) + err := r.ParseMultipartForm(int64(common.Megabyte)) if err != nil { - return LocalError("Unable to parse the form", w, r, user) + return common.LocalError("Unable to parse the form", w, r, user) } tid, err := strconv.Atoi(r.PostFormValue("tid")) if err != nil { - return PreError("Failed to convert the Topic ID", w, r) + return common.PreError("Failed to convert the Topic ID", w, r) } - topic, err := topics.Get(tid) + topic, err := common.Topics.Get(tid) if err == ErrNoRows { - return PreError("Couldn't find the parent topic", w, r) + return common.PreError("Couldn't find the parent topic", w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // TODO: Add hooks to make use of headerLite - _, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID) + _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.CreateReply { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } // Handle the file attachments @@ -271,37 +273,37 @@ func routeCreateReply(w http.ResponseWriter, r *http.Request, user User) RouteEr files, ok := r.MultipartForm.File["upload_files"] if ok { if len(files) > 5 { - return LocalError("You can't attach more than five files", w, r, user) + return common.LocalError("You can't attach more than five files", w, r, user) } for _, file := range files { log.Print("file.Filename ", file.Filename) extarr := strings.Split(file.Filename, ".") if len(extarr) < 2 { - return LocalError("Bad file", w, r, user) + return common.LocalError("Bad file", w, r, user) } ext := extarr[len(extarr)-1] // TODO: Can we do this without a regex? reg, err := regexp.Compile("[^A-Za-z0-9]+") if err != nil { - return LocalError("Bad file extension", w, r, user) + return common.LocalError("Bad file extension", w, r, user) } ext = strings.ToLower(reg.ReplaceAllString(ext, "")) - if !allowedFileExts.Contains(ext) { - return LocalError("You're not allowed to upload files with this extension", w, r, user) + if !common.AllowedFileExts.Contains(ext) { + return common.LocalError("You're not allowed to upload files with this extension", w, r, user) } infile, err := file.Open() if err != nil { - return LocalError("Upload failed", w, r, user) + return common.LocalError("Upload failed", w, r, user) } defer infile.Close() hasher := sha256.New() _, err = io.Copy(hasher, infile) if err != nil { - return LocalError("Upload failed [Hashing Failed]", w, r, user) + return common.LocalError("Upload failed [Hashing Failed]", w, r, user) } infile.Close() @@ -309,52 +311,52 @@ func routeCreateReply(w http.ResponseWriter, r *http.Request, user User) RouteEr filename := checksum + "." + ext outfile, err := os.Create("." + "/attachs/" + filename) if err != nil { - return LocalError("Upload failed [File Creation Failed]", w, r, user) + return common.LocalError("Upload failed [File Creation Failed]", w, r, user) } defer outfile.Close() infile, err = file.Open() if err != nil { - return LocalError("Upload failed", w, r, user) + return common.LocalError("Upload failed", w, r, user) } defer infile.Close() _, err = io.Copy(outfile, infile) if err != nil { - return LocalError("Upload failed [Copy Failed]", w, r, user) + return common.LocalError("Upload failed [Copy Failed]", w, r, user) } _, err = stmts.addAttachment.Exec(topic.ParentID, "forums", tid, "replies", user.ID, filename) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } } } - content := preparseMessage(html.EscapeString(r.PostFormValue("reply-content"))) - _, err = rstore.Create(topic, content, user.LastIP, user.ID) + content := common.PreparseMessage(html.EscapeString(r.PostFormValue("reply-content"))) + _, err = common.Rstore.Create(topic, content, user.LastIP, user.ID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - err = fstore.UpdateLastTopic(tid, user.ID, topic.ParentID) + err = common.Fstore.UpdateLastTopic(tid, user.ID, topic.ParentID) if err != nil && err != ErrNoRows { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } res, err := stmts.addActivity.Exec(user.ID, topic.CreatedBy, "reply", "topic", tid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } lastID, err := res.LastInsertId() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } _, err = stmts.notifyWatchers.Exec(lastID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Alert the subscribers about this post without blocking this post from being posted @@ -364,72 +366,72 @@ func routeCreateReply(w http.ResponseWriter, r *http.Request, user User) RouteEr http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) - wcount := wordCount(content) - err = user.increasePostStats(wcount, false) + wcount := common.WordCount(content) + err = user.IncreasePostStats(wcount, false) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } // TODO: Refactor this -func routeLikeTopic(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeLikeTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { err := r.ParseForm() if err != nil { - return PreError("Bad Form", w, r) + return common.PreError("Bad Form", w, r) } tid, err := strconv.Atoi(r.URL.Path[len("/topic/like/submit/"):]) if err != nil { - return PreError("Topic IDs can only ever be numbers.", w, r) + return common.PreError("Topic IDs can only ever be numbers.", w, r) } - topic, err := topics.Get(tid) + topic, err := common.Topics.Get(tid) if err == ErrNoRows { - return PreError("The requested topic doesn't exist.", w, r) + return common.PreError("The requested topic doesn't exist.", w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // TODO: Add hooks to make use of headerLite - _, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID) + _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.LikeItem { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if topic.CreatedBy == user.ID { - return LocalError("You can't like your own topics", w, r, user) + return common.LocalError("You can't like your own topics", w, r, user) } - _, err = users.Get(topic.CreatedBy) + _, err = common.Users.Get(topic.CreatedBy) if err != nil && err == ErrNoRows { - return LocalError("The target user doesn't exist", w, r, user) + return common.LocalError("The target user doesn't exist", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } score := 1 err = topic.Like(score, user.ID) - if err == ErrAlreadyLiked { - return LocalError("You already liked this", w, r, user) + if err == common.ErrAlreadyLiked { + return common.LocalError("You already liked this", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } res, err := stmts.addActivity.Exec(user.ID, topic.CreatedBy, "like", "topic", tid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } lastID, err := res.LastInsertId() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } _, err = stmts.notifyOne.Exec(topic.CreatedBy, lastID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Live alerts, if the poster is online and WebSockets is enabled @@ -439,70 +441,70 @@ func routeLikeTopic(w http.ResponseWriter, r *http.Request, user User) RouteErro return nil } -func routeReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { err := r.ParseForm() if err != nil { - return PreError("Bad Form", w, r) + return common.PreError("Bad Form", w, r) } rid, err := strconv.Atoi(r.URL.Path[len("/reply/like/submit/"):]) if err != nil { - return PreError("The provided Reply ID is not a valid number.", w, r) + return common.PreError("The provided Reply ID is not a valid number.", w, r) } - reply, err := rstore.Get(rid) + reply, err := common.Rstore.Get(rid) if err == ErrNoRows { - return PreError("You can't like something which doesn't exist!", w, r) + return common.PreError("You can't like something which doesn't exist!", w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } var fid int err = stmts.getTopicFID.QueryRow(reply.ParentID).Scan(&fid) if err == ErrNoRows { - return PreError("The parent topic doesn't exist.", w, r) + return common.PreError("The parent topic doesn't exist.", w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // TODO: Add hooks to make use of headerLite - _, ferr := SimpleForumUserCheck(w, r, &user, fid) + _, ferr := common.SimpleForumUserCheck(w, r, &user, fid) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.LikeItem { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if reply.CreatedBy == user.ID { - return LocalError("You can't like your own replies", w, r, user) + return common.LocalError("You can't like your own replies", w, r, user) } - _, err = users.Get(reply.CreatedBy) + _, err = common.Users.Get(reply.CreatedBy) if err != nil && err != ErrNoRows { - return LocalError("The target user doesn't exist", w, r, user) + return common.LocalError("The target user doesn't exist", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } err = reply.Like(user.ID) - if err == ErrAlreadyLiked { - return LocalError("You've already liked this!", w, r, user) + if err == common.ErrAlreadyLiked { + return common.LocalError("You've already liked this!", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } res, err := stmts.addActivity.Exec(user.ID, reply.CreatedBy, "like", "post", rid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } lastID, err := res.LastInsertId() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } _, err = stmts.notifyOne.Exec(reply.CreatedBy, lastID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Live alerts, if the poster is online and WebSockets is enabled @@ -512,145 +514,145 @@ func routeReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user User) Rou return nil } -func routeProfileReplyCreate(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeProfileReplyCreate(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { if !user.Perms.ViewTopic || !user.Perms.CreateReply { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } err := r.ParseForm() if err != nil { - return LocalError("Bad Form", w, r, user) + return common.LocalError("Bad Form", w, r, user) } uid, err := strconv.Atoi(r.PostFormValue("uid")) if err != nil { - return LocalError("Invalid UID", w, r, user) + return common.LocalError("Invalid UID", w, r, user) } - content := html.EscapeString(preparseMessage(r.PostFormValue("reply-content"))) - _, err = prstore.Create(uid, content, user.ID, user.LastIP) + content := html.EscapeString(common.PreparseMessage(r.PostFormValue("reply-content"))) + _, err = common.Prstore.Create(uid, content, user.ID, user.LastIP) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - if !users.Exists(uid) { - return LocalError("The profile you're trying to post on doesn't exist.", w, r, user) + if !common.Users.Exists(uid) { + return common.LocalError("The profile you're trying to post on doesn't exist.", w, r, user) } http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther) return nil } -func routeReportSubmit(w http.ResponseWriter, r *http.Request, user User, sitemID string) RouteError { +func routeReportSubmit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError { itemID, err := strconv.Atoi(sitemID) if err != nil { - return LocalError("Bad ID", w, r, user) + return common.LocalError("Bad ID", w, r, user) } itemType := r.FormValue("type") var fid = 1 var title, content string if itemType == "reply" { - reply, err := rstore.Get(itemID) + reply, err := common.Rstore.Get(itemID) if err == ErrNoRows { - return LocalError("We were unable to find the reported post", w, r, user) + return common.LocalError("We were unable to find the reported post", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - topic, err := topics.Get(reply.ParentID) + topic, err := common.Topics.Get(reply.ParentID) if err == ErrNoRows { - return LocalError("We weren't able to find the topic the reported post is supposed to be in", w, r, user) + return common.LocalError("We weren't able to find the topic the reported post is supposed to be in", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } title = "Reply: " + topic.Title content = reply.Content + "\n\nOriginal Post: #rid-" + strconv.Itoa(itemID) } else if itemType == "user-reply" { - userReply, err := prstore.Get(itemID) + userReply, err := common.Prstore.Get(itemID) if err == ErrNoRows { - return LocalError("We weren't able to find the reported post", w, r, user) + return common.LocalError("We weren't able to find the reported post", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } err = stmts.getUserName.QueryRow(userReply.ParentID).Scan(&title) if err == ErrNoRows { - return LocalError("We weren't able to find the profile the reported post is supposed to be on", w, r, user) + return common.LocalError("We weren't able to find the profile the reported post is supposed to be on", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } title = "Profile: " + title content = userReply.Content + "\n\nOriginal Post: @" + strconv.Itoa(userReply.ParentID) } else if itemType == "topic" { err = stmts.getTopicBasic.QueryRow(itemID).Scan(&title, &content) if err == ErrNoRows { - return NotFound(w, r) + return common.NotFound(w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } title = "Topic: " + title content = content + "\n\nOriginal Post: #tid-" + strconv.Itoa(itemID) } else { - if vhooks["report_preassign"] != nil { - runVhookNoreturn("report_preassign", &itemID, &itemType) + if common.Vhooks["report_preassign"] != nil { + common.RunVhookNoreturn("report_preassign", &itemID, &itemType) return nil } // Don't try to guess the type - return LocalError("Unknown type", w, r, user) + return common.LocalError("Unknown type", w, r, user) } var count int err = stmts.reportExists.QueryRow(itemType + "_" + strconv.Itoa(itemID)).Scan(&count) if err != nil && err != ErrNoRows { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if count != 0 { - return LocalError("Someone has already reported this!", w, r, user) + return common.LocalError("Someone has already reported this!", w, r, user) } // TODO: Repost attachments in the reports forum, so that the mods can see them // ? - Can we do this via the TopicStore? Should we do a ReportStore? - res, err := stmts.createReport.Exec(title, content, parseMessage(content, 0, ""), user.ID, user.ID, itemType+"_"+strconv.Itoa(itemID)) + res, err := stmts.createReport.Exec(title, content, common.ParseMessage(content, 0, ""), user.ID, user.ID, itemType+"_"+strconv.Itoa(itemID)) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } lastID, err := res.LastInsertId() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - err = fstore.AddTopic(int(lastID), user.ID, fid) + err = common.Fstore.AddTopic(int(lastID), user.ID, fid) if err != nil && err != ErrNoRows { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } http.Redirect(w, r, "/topic/"+strconv.FormatInt(lastID, 10), http.StatusSeeOther) return nil } -func routeAccountEditCritical(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeAccountEditCritical(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } - pi := Page{"Edit Password", user, headerVars, tList, nil} - if preRenderHooks["pre_render_account_own_edit_critical"] != nil { - if runPreRenderHook("pre_render_account_own_edit_critical", w, r, &user, &pi) { + pi := common.Page{"Edit Password", user, headerVars, tList, nil} + if common.PreRenderHooks["pre_render_account_own_edit_critical"] != nil { + if common.RunPreRenderHook("pre_render_account_own_edit_critical", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "account-own-edit.html", pi) + err := common.Templates.ExecuteTemplate(w, "account-own-edit.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeAccountEditCriticalSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeAccountEditCriticalSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } @@ -662,73 +664,73 @@ func routeAccountEditCriticalSubmit(w http.ResponseWriter, r *http.Request, user err := stmts.getPassword.QueryRow(user.ID).Scan(&realPassword, &salt) if err == ErrNoRows { - return LocalError("Your account no longer exists.", w, r, user) + return common.LocalError("Your account no longer exists.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - err = CheckPassword(realPassword, currentPassword, salt) - if err == ErrMismatchedHashAndPassword { - return LocalError("That's not the correct password.", w, r, user) + err = common.CheckPassword(realPassword, currentPassword, salt) + if err == common.ErrMismatchedHashAndPassword { + return common.LocalError("That's not the correct password.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if newPassword != confirmPassword { - return LocalError("The two passwords don't match.", w, r, user) + return common.LocalError("The two passwords don't match.", w, r, user) } - SetPassword(user.ID, newPassword) + common.SetPassword(user.ID, newPassword) // Log the user out as a safety precaution - auth.ForceLogout(user.ID) + common.Auth.ForceLogout(user.ID) headerVars.NoticeList = append(headerVars.NoticeList, "Your password was successfully updated") - pi := Page{"Edit Password", user, headerVars, tList, nil} - if preRenderHooks["pre_render_account_own_edit_critical"] != nil { - if runPreRenderHook("pre_render_account_own_edit_critical", w, r, &user, &pi) { + pi := common.Page{"Edit Password", user, headerVars, tList, nil} + if common.PreRenderHooks["pre_render_account_own_edit_critical"] != nil { + if common.RunPreRenderHook("pre_render_account_own_edit_critical", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "account-own-edit.html", pi) + err = common.Templates.ExecuteTemplate(w, "account-own-edit.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeAccountEditAvatar(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeAccountEditAvatar(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } - pi := Page{"Edit Avatar", user, headerVars, tList, nil} - if preRenderHooks["pre_render_account_own_edit_avatar"] != nil { - if runPreRenderHook("pre_render_account_own_edit_avatar", w, r, &user, &pi) { + pi := common.Page{"Edit Avatar", user, headerVars, tList, nil} + if common.PreRenderHooks["pre_render_account_own_edit_avatar"] != nil { + if common.RunPreRenderHook("pre_render_account_own_edit_avatar", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "account-own-edit-avatar.html", pi) + err := common.Templates.ExecuteTemplate(w, "account-own-edit-avatar.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeAccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { - if r.ContentLength > int64(config.MaxRequestSize) { - size, unit := convertByteUnit(float64(config.MaxRequestSize)) - return CustomError("Your avatar's too big. Avatars must be smaller than "+strconv.Itoa(int(size))+unit, http.StatusExpectationFailed, "Error", w, r, user) +func routeAccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + if r.ContentLength > int64(common.Config.MaxRequestSize) { + size, unit := common.ConvertByteUnit(float64(common.Config.MaxRequestSize)) + return common.CustomError("Your avatar's too big. Avatars must be smaller than "+strconv.Itoa(int(size))+unit, http.StatusExpectationFailed, "Error", w, r, user) } - r.Body = http.MaxBytesReader(w, r.Body, int64(config.MaxRequestSize)) + r.Body = http.MaxBytesReader(w, r.Body, int64(common.Config.MaxRequestSize)) - headerVars, ferr := UserCheck(w, r, &user) + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } - err := r.ParseMultipartForm(int64(megabyte)) + err := r.ParseMultipartForm(int64(common.Megabyte)) if err != nil { - return LocalError("Upload failed", w, r, user) + return common.LocalError("Upload failed", w, r, user) } var filename, ext string @@ -736,7 +738,7 @@ func routeAccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user U for _, hdr := range fheaders { infile, err := hdr.Open() if err != nil { - return LocalError("Upload failed", w, r, user) + return common.LocalError("Upload failed", w, r, user) } defer infile.Close() @@ -745,7 +747,7 @@ func routeAccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user U if filename != "" { if filename != hdr.Filename { os.Remove("./uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext) - return LocalError("You may only upload one avatar", w, r, user) + return common.LocalError("You may only upload one avatar", w, r, user) } } else { filename = hdr.Filename @@ -754,14 +756,14 @@ func routeAccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user U if ext == "" { extarr := strings.Split(hdr.Filename, ".") if len(extarr) < 2 { - return LocalError("Bad file", w, r, user) + return common.LocalError("Bad file", w, r, user) } ext = extarr[len(extarr)-1] // TODO: Can we do this without a regex? reg, err := regexp.Compile("[^A-Za-z0-9]+") if err != nil { - return LocalError("Bad file extension", w, r, user) + return common.LocalError("Bad file extension", w, r, user) } ext = reg.ReplaceAllString(ext, "") ext = strings.ToLower(ext) @@ -769,58 +771,58 @@ func routeAccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user U outfile, err := os.Create("./uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext) if err != nil { - return LocalError("Upload failed [File Creation Failed]", w, r, user) + return common.LocalError("Upload failed [File Creation Failed]", w, r, user) } defer outfile.Close() _, err = io.Copy(outfile, infile) if err != nil { - return LocalError("Upload failed [Copy Failed]", w, r, user) + return common.LocalError("Upload failed [Copy Failed]", w, r, user) } } } err = user.ChangeAvatar("." + ext) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext headerVars.NoticeList = append(headerVars.NoticeList, "Your avatar was successfully updated") - pi := Page{"Edit Avatar", user, headerVars, tList, nil} - if preRenderHooks["pre_render_account_own_edit_avatar"] != nil { - if runPreRenderHook("pre_render_account_own_edit_avatar", w, r, &user, &pi) { + pi := common.Page{"Edit Avatar", user, headerVars, tList, nil} + if common.PreRenderHooks["pre_render_account_own_edit_avatar"] != nil { + if common.RunPreRenderHook("pre_render_account_own_edit_avatar", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "account-own-edit-avatar.html", pi) + err = common.Templates.ExecuteTemplate(w, "account-own-edit-avatar.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeAccountEditUsername(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeAccountEditUsername(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } - pi := Page{"Edit Username", user, headerVars, tList, user.Name} - if preRenderHooks["pre_render_account_own_edit_username"] != nil { - if runPreRenderHook("pre_render_account_own_edit_username", w, r, &user, &pi) { + pi := common.Page{"Edit common.Username", user, headerVars, tList, user.Name} + if common.PreRenderHooks["pre_render_account_own_edit_username"] != nil { + if common.RunPreRenderHook("pre_render_account_own_edit_username", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "account-own-edit-username.html", pi) + err := common.Templates.ExecuteTemplate(w, "account-own-edit-username.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeAccountEditUsernameSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeAccountEditUsernameSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } @@ -828,42 +830,42 @@ func routeAccountEditUsernameSubmit(w http.ResponseWriter, r *http.Request, user newUsername := html.EscapeString(r.PostFormValue("account-new-username")) err := user.ChangeName(newUsername) if err != nil { - return LocalError("Unable to change the username. Does someone else already have this name?", w, r, user) + return common.LocalError("Unable to change the username. Does someone else already have this name?", w, r, user) } user.Name = newUsername headerVars.NoticeList = append(headerVars.NoticeList, "Your username was successfully updated") - pi := Page{"Edit Username", user, headerVars, tList, nil} - if preRenderHooks["pre_render_account_own_edit_username"] != nil { - if runPreRenderHook("pre_render_account_own_edit_username", w, r, &user, &pi) { + pi := common.Page{"Edit common.Username", user, headerVars, tList, nil} + if common.PreRenderHooks["pre_render_account_own_edit_username"] != nil { + if common.RunPreRenderHook("pre_render_account_own_edit_username", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "account-own-edit-username.html", pi) + err = common.Templates.ExecuteTemplate(w, "account-own-edit-username.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeAccountEditEmail(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeAccountEditEmail(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } - email := Email{UserID: user.ID} + email := common.Email{UserID: user.ID} var emailList []interface{} rows, err := stmts.getEmailsByUser.Query(user.ID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } defer rows.Close() for rows.Next() { err := rows.Scan(&email.Email, &email.Validated, &email.Token) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if email.Email == user.Email { @@ -873,7 +875,7 @@ func routeAccountEditEmail(w http.ResponseWriter, r *http.Request, user User) Ro } err = rows.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Was this site migrated from another forum software? Most of them don't have multiple emails for a single user. @@ -885,42 +887,42 @@ func routeAccountEditEmail(w http.ResponseWriter, r *http.Request, user User) Ro emailList = append(emailList, email) } - if !site.EnableEmails { + if !common.Site.EnableEmails { headerVars.NoticeList = append(headerVars.NoticeList, "The mail system is currently disabled.") } - pi := Page{"Email Manager", user, headerVars, emailList, nil} - if preRenderHooks["pre_render_account_own_edit_email"] != nil { - if runPreRenderHook("pre_render_account_own_edit_email", w, r, &user, &pi) { + pi := common.Page{"Email Manager", user, headerVars, emailList, nil} + if common.PreRenderHooks["pre_render_account_own_edit_email"] != nil { + if common.RunPreRenderHook("pre_render_account_own_edit_email", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "account-own-edit-email.html", pi) + err = common.Templates.ExecuteTemplate(w, "account-own-edit-email.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } // TODO: Do a session check on this? -func routeAccountEditEmailTokenSubmit(w http.ResponseWriter, r *http.Request, user User, token string) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeAccountEditEmailTokenSubmit(w http.ResponseWriter, r *http.Request, user common.User, token string) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } - email := Email{UserID: user.ID} - targetEmail := Email{UserID: user.ID} + email := common.Email{UserID: user.ID} + targetEmail := common.Email{UserID: user.ID} var emailList []interface{} rows, err := stmts.getEmailsByUser.Query(user.ID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } defer rows.Close() for rows.Next() { err := rows.Scan(&email.Email, &email.Validated, &email.Token) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if email.Email == user.Email { @@ -933,72 +935,72 @@ func routeAccountEditEmailTokenSubmit(w http.ResponseWriter, r *http.Request, us } err = rows.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if len(emailList) == 0 { - return LocalError("A verification email was never sent for you!", w, r, user) + return common.LocalError("A verification email was never sent for you!", w, r, user) } if targetEmail.Token == "" { - return LocalError("That's not a valid token!", w, r, user) + return common.LocalError("That's not a valid token!", w, r, user) } _, err = stmts.verifyEmail.Exec(user.Email) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // If Email Activation is on, then activate the account while we're here if headerVars.Settings["activation_type"] == 2 { - _, err = stmts.activateUser.Exec(user.ID) + err = user.Activate() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } - if !site.EnableEmails { + if !common.Site.EnableEmails { headerVars.NoticeList = append(headerVars.NoticeList, "The mail system is currently disabled.") } headerVars.NoticeList = append(headerVars.NoticeList, "Your email was successfully verified") - pi := Page{"Email Manager", user, headerVars, emailList, nil} - if preRenderHooks["pre_render_account_own_edit_email"] != nil { - if runPreRenderHook("pre_render_account_own_edit_email", w, r, &user, &pi) { + pi := common.Page{"Email Manager", user, headerVars, emailList, nil} + if common.PreRenderHooks["pre_render_account_own_edit_email"] != nil { + if common.RunPreRenderHook("pre_render_account_own_edit_email", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "account-own-edit-email.html", pi) + err = common.Templates.ExecuteTemplate(w, "account-own-edit-email.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeLogout(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeLogout(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { if !user.Loggedin { - return LocalError("You can't logout without logging in first.", w, r, user) + return common.LocalError("You can't logout without logging in first.", w, r, user) } - auth.Logout(w, user.ID) + common.Auth.Logout(w, user.ID) http.Redirect(w, r, "/", http.StatusSeeOther) return nil } -func routeShowAttachment(w http.ResponseWriter, r *http.Request, user User, filename string) RouteError { +func routeShowAttachment(w http.ResponseWriter, r *http.Request, user common.User, filename string) common.RouteError { err := r.ParseForm() if err != nil { - return PreError("Bad Form", w, r) + return common.PreError("Bad Form", w, r) } - filename = Stripslashes(filename) + filename = common.Stripslashes(filename) var ext = filepath.Ext("./attachs/" + filename) //log.Print("ext ", ext) //log.Print("filename ", filename) - if !allowedFileExts.Contains(strings.TrimPrefix(ext, ".")) { - return LocalError("Bad extension", w, r, user) + if !common.AllowedFileExts.Contains(strings.TrimPrefix(ext, ".")) { + return common.LocalError("Bad extension", w, r, user) } sectionID, err := strconv.Atoi(r.FormValue("sectionID")) if err != nil { - return LocalError("The sectionID is not an integer", w, r, user) + return common.LocalError("The sectionID is not an integer", w, r, user) } var sectionTable = r.FormValue("sectionType") @@ -1006,25 +1008,25 @@ func routeShowAttachment(w http.ResponseWriter, r *http.Request, user User, file var originID, uploadedBy int err = stmts.getAttachment.QueryRow(filename, sectionID, sectionTable).Scan(§ionID, §ionTable, &originID, &originTable, &uploadedBy, &filename) if err == ErrNoRows { - return NotFound(w, r) + return common.NotFound(w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if sectionTable == "forums" { - _, ferr := SimpleForumUserCheck(w, r, &user, sectionID) + _, ferr := common.SimpleForumUserCheck(w, r, &user, sectionID) if ferr != nil { return ferr } if !user.Perms.ViewTopic { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } } else { - return LocalError("Unknown section", w, r, user) + return common.LocalError("Unknown section", w, r, user) } if originTable != "topics" && originTable != "replies" { - return LocalError("Unknown origin", w, r, user) + return common.LocalError("Unknown origin", w, r, user) } // TODO: Fix the problem where non-existent files aren't greeted with custom 404s on ServeFile()'s side diff --git a/misc_test.go b/misc_test.go index 1e25b72c..c9669b1f 100644 --- a/misc_test.go +++ b/misc_test.go @@ -8,6 +8,8 @@ import ( "strconv" "testing" "time" + + "./common" ) func recordMustExist(t *testing.T, err error, errmsg string, args ...interface{}) { @@ -47,22 +49,22 @@ func TestUserStore(t *testing.T) { userStoreTest(t, 3) } func userStoreTest(t *testing.T, newUserID int) { - ucache, hasCache := users.(UserCache) + ucache, hasCache := common.Users.(UserCache) // Go doesn't have short-circuiting, so this'll allow us to do one liner tests if !hasCache { ucache = &NullUserStore{} } expect(t, (!hasCache || ucache.Length() == 0), fmt.Sprintf("The initial ucache length should be zero, not %d", ucache.Length())) - _, err := users.Get(-1) + _, err := common.Users.Get(-1) recordMustNotExist(t, err, "UID #-1 shouldn't exist") expect(t, !hasCache || ucache.Length() == 0, fmt.Sprintf("We found %d items in the user cache and it's supposed to be empty", ucache.Length())) - _, err = users.Get(0) + _, err = common.Users.Get(0) recordMustNotExist(t, err, "UID #0 shouldn't exist") expect(t, !hasCache || ucache.Length() == 0, fmt.Sprintf("We found %d items in the user cache and it's supposed to be empty", ucache.Length())) - user, err := users.Get(1) + user, err := common.Users.Get(1) recordMustExist(t, err, "Couldn't find UID #1") expect(t, user.ID == 1, fmt.Sprintf("user.ID should be 1. Got '%d' instead.", user.ID)) @@ -74,7 +76,7 @@ func userStoreTest(t *testing.T, newUserID int) { expect(t, user.IsMod, "Admin should be a mod") expect(t, !user.IsBanned, "Admin should not be banned") - _, err = users.Get(newUserID) + _, err = common.Users.Get(newUserID) recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't exist", newUserID)) if hasCache { @@ -103,7 +105,7 @@ func userStoreTest(t *testing.T, newUserID int) { // TODO: Lock onto the specific error type. Is this even possible without sacrificing the detailed information in the error message? var userList map[int]*User - userList, _ = users.BulkGetMap([]int{-1}) + userList, _ = common.Users.BulkGetMap([]int{-1}) if len(userList) > 0 { t.Error("There shouldn't be any results for UID #-1") } @@ -112,7 +114,7 @@ func userStoreTest(t *testing.T, newUserID int) { expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d") } - userList, _ = users.BulkGetMap([]int{0}) + userList, _ = common.Users.BulkGetMap([]int{0}) if len(userList) > 0 { t.Error("There shouldn't be any results for UID #0") } @@ -121,7 +123,7 @@ func userStoreTest(t *testing.T, newUserID int) { expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d") } - userList, _ = users.BulkGetMap([]int{1}) + userList, _ = common.Users.BulkGetMap([]int{1}) if len(userList) == 0 { t.Error("The returned map is empty for UID #1") } else if len(userList) > 1 { @@ -151,19 +153,19 @@ func userStoreTest(t *testing.T, newUserID int) { expect(t, !users.Exists(-1), "UID #-1 shouldn't exist") expect(t, !users.Exists(0), "UID #0 shouldn't exist") - expect(t, users.Exists(1), "UID #1 should exist") + expect(t, common.Users.Exists(1), "UID #1 should exist") expect(t, !users.Exists(newUserID), fmt.Sprintf("UID #%d shouldn't exist", newUserID)) expect(t, !hasCache || ucache.Length() == 0, fmt.Sprintf("User cache length should be 0, not %d", ucache.Length())) - expectIntToBeX(t, users.GlobalCount(), 1, "The number of users should be one, not %d") + expectIntToBeX(t, common.Users.GlobalCount(), 1, "The number of users should be one, not %d") var awaitingActivation = 5 - uid, err := users.Create("Sam", "ReallyBadPassword", "sam@localhost.loc", awaitingActivation, false) + uid, err := common.Users.Create("Sam", "ReallyBadPassword", "sam@localhost.loc", awaitingActivation, false) expectNilErr(t, err) expect(t, uid == newUserID, fmt.Sprintf("The UID of the new user should be %d", newUserID)) - expect(t, users.Exists(newUserID), fmt.Sprintf("UID #%d should exist", newUserID)) + expect(t, common.Users.Exists(newUserID), fmt.Sprintf("UID #%d should exist", newUserID)) - user, err = users.Get(newUserID) + user, err = common.Users.Get(newUserID) recordMustExist(t, err, "Couldn't find UID #%d", newUserID) if user.ID != newUserID { t.Errorf("The UID of the user record should be %d", newUserID) @@ -195,7 +197,7 @@ func userStoreTest(t *testing.T, newUserID int) { recordMustNotExist(t, err, "UID #%d shouldn't be in the cache", newUserID) } - user, err = users.Get(newUserID) + user, err = common.Users.Get(newUserID) recordMustExist(t, err, "Couldn't find UID #%d", newUserID) expect(t, user.ID == newUserID, fmt.Sprintf("The UID of the user record should be %d, not %d", newUserID, user.ID)) @@ -221,7 +223,7 @@ func userStoreTest(t *testing.T, newUserID int) { recordMustNotExist(t, err, "UID #%d shouldn't be in the cache", newUserID) } - user, err = users.Get(newUserID) + user, err = common.Users.Get(newUserID) recordMustExist(t, err, "Couldn't find UID #%d", newUserID) if user.ID != newUserID { t.Errorf("The UID of the user record should be %d", newUserID) @@ -247,7 +249,7 @@ func userStoreTest(t *testing.T, newUserID int) { recordMustNotExist(t, err, "UID #%d shouldn't be in the cache", newUserID) } - user, err = users.Get(newUserID) + user, err = common.Users.Get(newUserID) recordMustExist(t, err, "Couldn't find UID #%d", newUserID) expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") @@ -270,7 +272,7 @@ func userStoreTest(t *testing.T, newUserID int) { expectNilErr(t, err) expect(t, user.Group == config.DefaultGroup, "Someone's mutated this pointer elsewhere") - user, err = users.Get(newUserID) + user, err = common.Users.Get(newUserID) recordMustExist(t, err, "Couldn't find UID #%d", newUserID) expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") var user2 *User = getDummyUser() @@ -293,7 +295,7 @@ func userStoreTest(t *testing.T, newUserID int) { expectNilErr(t, err) expect(t, user.Group == 1, "Someone's mutated this pointer elsewhere") - user, err = users.Get(newUserID) + user, err = common.Users.Get(newUserID) recordMustExist(t, err, "Couldn't find UID #%d", newUserID) expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") user2 = getDummyUser() @@ -316,7 +318,7 @@ func userStoreTest(t *testing.T, newUserID int) { expectNilErr(t, err) expect(t, user.Group == 2, "Someone's mutated this pointer elsewhere") - user, err = users.Get(newUserID) + user, err = common.Users.Get(newUserID) recordMustExist(t, err, "Couldn't find UID #%d", newUserID) expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") user2 = getDummyUser() @@ -340,7 +342,7 @@ func userStoreTest(t *testing.T, newUserID int) { expectNilErr(t, err) expect(t, user.Group == 3, "Someone's mutated this pointer elsewhere") - user, err = users.Get(newUserID) + user, err = common.Users.Get(newUserID) recordMustExist(t, err, "Couldn't find UID #%d", newUserID) expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") user2 = getDummyUser() @@ -363,7 +365,7 @@ func userStoreTest(t *testing.T, newUserID int) { expectNilErr(t, err) expect(t, user.Group == 4, "Someone's mutated this pointer elsewhere") - user, err = users.Get(newUserID) + user, err = common.Users.Get(newUserID) recordMustExist(t, err, "Couldn't find UID #%d", newUserID) expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") user2 = getDummyUser() @@ -386,7 +388,7 @@ func userStoreTest(t *testing.T, newUserID int) { expectNilErr(t, err) expect(t, user.Group == 5, "Someone's mutated this pointer elsewhere") - user, err = users.Get(newUserID) + user, err = common.Users.Get(newUserID) recordMustExist(t, err, "Couldn't find UID #%d", newUserID) expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") user2 = getDummyUser() @@ -419,7 +421,7 @@ func userStoreTest(t *testing.T, newUserID int) { recordMustNotExist(t, err, "UID #%d shouldn't be in the cache", newUserID) } - _, err = users.Get(newUserID) + _, err = common.Users.Get(newUserID) recordMustNotExist(t, err, "UID #%d shouldn't exist", newUserID) // TODO: Add tests for the Cache* methods @@ -515,13 +517,13 @@ func topicStoreTest(t *testing.T) { var topic *Topic var err error - _, err = topics.Get(-1) + _, err = common.Topics.Get(-1) recordMustNotExist(t, err, "TID #-1 shouldn't exist") - _, err = topics.Get(0) + _, err = common.Topics.Get(0) recordMustNotExist(t, err, "TID #0 shouldn't exist") - topic, err = topics.Get(1) + topic, err = common.Topics.Get(1) recordMustExist(t, err, "Couldn't find TID #1") if topic.ID != 1 { @@ -530,22 +532,22 @@ func topicStoreTest(t *testing.T) { // TODO: Add BulkGetMap() to the TopicStore - ok := topics.Exists(-1) + ok := common.Topics.Exists(-1) if ok { t.Error("TID #-1 shouldn't exist") } - ok = topics.Exists(0) + ok = common.Topics.Exists(0) if ok { t.Error("TID #0 shouldn't exist") } - ok = topics.Exists(1) + ok = common.Topics.Exists(1) if !ok { t.Error("TID #1 should exist") } - count := topics.GlobalCount() + count := common.Topics.GlobalCount() if count <= 0 { t.Error("The number of topics should be bigger than zero") t.Error("count", count) @@ -620,11 +622,11 @@ func TestGroupStore(t *testing.T) { initPlugins() } - _, err := gstore.Get(-1) + _, err := common.Gstore.Get(-1) recordMustNotExist(t, err, "GID #-1 shouldn't exist") // TODO: Refactor the group store to remove GID #0 - group, err := gstore.Get(0) + group, err := common.Gstore.Get(0) recordMustExist(t, err, "Couldn't find GID #0") if group.ID != 0 { @@ -632,31 +634,31 @@ func TestGroupStore(t *testing.T) { } expect(t, group.Name == "Unknown", fmt.Sprintf("GID #0 is named '%s' and not 'Unknown'", group.Name)) - group, err = gstore.Get(1) + group, err = common.Gstore.Get(1) recordMustExist(t, err, "Couldn't find GID #1") if group.ID != 1 { t.Errorf("group.ID doesn't not match the requested GID. Got '%d' instead.'", group.ID) } - ok := gstore.Exists(-1) + ok := common.Gstore.Exists(-1) expect(t, !ok, "GID #-1 shouldn't exist") // 0 aka Unknown, for system posts and other oddities - ok = gstore.Exists(0) + ok = common.Gstore.Exists(0) expect(t, ok, "GID #0 should exist") - ok = gstore.Exists(1) + ok = common.Gstore.Exists(1) expect(t, ok, "GID #1 should exist") var isAdmin = true var isMod = true var isBanned = false - gid, err := gstore.Create("Testing", "Test", isAdmin, isMod, isBanned) + gid, err := common.Gstore.Create("Testing", "Test", isAdmin, isMod, isBanned) expectNilErr(t, err) - expect(t, gstore.Exists(gid), "The group we just made doesn't exist") + expect(t, common.Gstore.Exists(gid), "The group we just made doesn't exist") - group, err = gstore.Get(gid) + group, err = common.Gstore.Get(gid) expectNilErr(t, err) expect(t, group.ID == gid, "The group ID should match the requested ID") expect(t, group.IsAdmin, "This should be an admin group") @@ -666,11 +668,11 @@ func TestGroupStore(t *testing.T) { isAdmin = false isMod = true isBanned = true - gid, err = gstore.Create("Testing 2", "Test", isAdmin, isMod, isBanned) + gid, err = common.Gstore.Create("Testing 2", "Test", isAdmin, isMod, isBanned) expectNilErr(t, err) - expect(t, gstore.Exists(gid), "The group we just made doesn't exist") + expect(t, common.Gstore.Exists(gid), "The group we just made doesn't exist") - group, err = gstore.Get(gid) + group, err = common.Gstore.Get(gid) expectNilErr(t, err) expect(t, group.ID == gid, "The group ID should match the requested ID") expect(t, !group.IsAdmin, "This should not be an admin group") @@ -681,7 +683,7 @@ func TestGroupStore(t *testing.T) { err = group.ChangeRank(false, false, true) expectNilErr(t, err) - group, err = gstore.Get(gid) + group, err = common.Gstore.Get(gid) expectNilErr(t, err) expect(t, group.ID == gid, "The group ID should match the requested ID") expect(t, !group.IsAdmin, "This shouldn't be an admin group") @@ -691,7 +693,7 @@ func TestGroupStore(t *testing.T) { err = group.ChangeRank(true, true, true) expectNilErr(t, err) - group, err = gstore.Get(gid) + group, err = common.Gstore.Get(gid) expectNilErr(t, err) expect(t, group.ID == gid, "The group ID should match the requested ID") expect(t, group.IsAdmin, "This should be an admin group") @@ -701,7 +703,7 @@ func TestGroupStore(t *testing.T) { err = group.ChangeRank(false, true, true) expectNilErr(t, err) - group, err = gstore.Get(gid) + group, err = common.Gstore.Get(gid) expectNilErr(t, err) expect(t, group.ID == gid, "The group ID should match the requested ID") expect(t, !group.IsAdmin, "This shouldn't be an admin group") @@ -709,9 +711,9 @@ func TestGroupStore(t *testing.T) { expect(t, !group.IsBanned, "This shouldn't be a ban group") // Make sure the data is static - gstore.Reload(gid) + common.Gstore.Reload(gid) - group, err = gstore.Get(gid) + group, err = common.Gstore.Get(gid) expectNilErr(t, err) expect(t, group.ID == gid, "The group ID should match the requested ID") expect(t, !group.IsAdmin, "This shouldn't be an admin group") @@ -731,13 +733,13 @@ func TestReplyStore(t *testing.T) { initPlugins() } - _, err := rstore.Get(-1) + _, err := common.Rstore.Get(-1) recordMustNotExist(t, err, "RID #-1 shouldn't exist") - _, err = rstore.Get(0) + _, err = common.Rstore.Get(0) recordMustNotExist(t, err, "RID #0 shouldn't exist") - reply, err := rstore.Get(1) + reply, err := common.Rstore.Get(1) expectNilErr(t, err) expect(t, reply.ID == 1, fmt.Sprintf("RID #1 has the wrong ID. It should be 1 not %d", reply.ID)) expect(t, reply.ParentID == 1, fmt.Sprintf("The parent topic of RID #1 should be 1 not %d", reply.ParentID)) @@ -745,18 +747,18 @@ func TestReplyStore(t *testing.T) { expect(t, reply.Content == "A reply!", fmt.Sprintf("The contents of RID #1 should be 'A reply!' not %s", reply.Content)) expect(t, reply.IPAddress == "::1", fmt.Sprintf("The IPAddress of RID#1 should be '::1' not %s", reply.IPAddress)) - _, err = rstore.Get(2) + _, err = common.Rstore.Get(2) recordMustNotExist(t, err, "RID #2 shouldn't exist") // TODO: Test Create and Get //Create(tid int, content string, ipaddress string, fid int, uid int) (id int, err error) - topic, err := topics.Get(1) + topic, err := common.Topics.Get(1) expectNilErr(t, err) - rid, err := rstore.Create(topic, "Fofofo", "::1", 1) + rid, err := common.Rstore.Create(topic, "Fofofo", "::1", 1) expectNilErr(t, err) expect(t, rid == 2, fmt.Sprintf("The next reply ID should be 2 not %d", rid)) - reply, err = rstore.Get(2) + reply, err = common.Rstore.Get(2) expectNilErr(t, err) expect(t, reply.ID == 2, fmt.Sprintf("RID #2 has the wrong ID. It should be 2 not %d", reply.ID)) expect(t, reply.ParentID == 1, fmt.Sprintf("The parent topic of RID #2 should be 1 not %d", reply.ParentID)) @@ -773,21 +775,21 @@ func TestProfileReplyStore(t *testing.T) { initPlugins() } - _, err := prstore.Get(-1) + _, err := common.Prstore.Get(-1) recordMustNotExist(t, err, "PRID #-1 shouldn't exist") - _, err = prstore.Get(0) + _, err = common.Prstore.Get(0) recordMustNotExist(t, err, "PRID #0 shouldn't exist") - _, err = prstore.Get(1) + _, err = common.Prstore.Get(1) recordMustNotExist(t, err, "PRID #1 shouldn't exist") var profileID = 1 - prid, err := prstore.Create(profileID, "Haha", 1, "::1") + prid, err := common.Prstore.Create(profileID, "Haha", 1, "::1") expect(t, err == nil, "Unable to create a profile reply") expect(t, prid == 1, "The first profile reply should have an ID of 1") - profileReply, err := prstore.Get(1) + profileReply, err := common.Prstore.Get(1) expect(t, err == nil, "PRID #1 should exist") expect(t, profileReply.ID == 1, fmt.Sprintf("The profile reply should have an ID of 1 not %d", profileReply.ID)) expect(t, profileReply.ParentID == 1, fmt.Sprintf("The parent ID of the profile reply should be 1 not %d", profileReply.ParentID)) @@ -826,7 +828,7 @@ func TestSlugs(t *testing.T) { for _, item := range msgList { t.Log("Testing string '" + item.Msg + "'") - res = nameToSlug(item.Msg) + res = common.NameToSlug(item.Msg) if res != item.Expects { t.Error("Bad output:", "'"+res+"'") t.Error("Expected:", item.Expects) @@ -846,7 +848,7 @@ func TestAuth(t *testing.T) { realPassword = "Madame Cassandra's Mystic Orb" t.Log("Set realPassword to '" + realPassword + "'") t.Log("Hashing the real password") - hashedPassword, err = BcryptGeneratePasswordNoSalt(realPassword) + hashedPassword, err = common.BcryptGeneratePasswordNoSalt(realPassword) if err != nil { t.Error(err) } @@ -854,7 +856,7 @@ func TestAuth(t *testing.T) { password = realPassword t.Log("Testing password '" + password + "'") t.Log("Testing salt '" + salt + "'") - err = CheckPassword(hashedPassword, password, salt) + err = common.CheckPassword(hashedPassword, password, salt) if err == ErrMismatchedHashAndPassword { t.Error("The two don't match") } else if err == ErrPasswordTooLong { @@ -866,7 +868,7 @@ func TestAuth(t *testing.T) { password = "hahaha" t.Log("Testing password '" + password + "'") t.Log("Testing salt '" + salt + "'") - err = CheckPassword(hashedPassword, password, salt) + err = common.CheckPassword(hashedPassword, password, salt) if err == ErrPasswordTooLong { t.Error("CheckPassword thinks the password is too long") } else if err == nil { @@ -876,7 +878,7 @@ func TestAuth(t *testing.T) { password = "Madame Cassandra's Mystic" t.Log("Testing password '" + password + "'") t.Log("Testing salt '" + salt + "'") - err = CheckPassword(hashedPassword, password, salt) + err = common.CheckPassword(hashedPassword, password, salt) if err == ErrPasswordTooLong { t.Error("CheckPassword thinks the password is too long") } else if err == nil { diff --git a/mod_routes.go b/mod_routes.go index a65ad49b..87c6f8d6 100644 --- a/mod_routes.go +++ b/mod_routes.go @@ -9,48 +9,50 @@ import ( "net/http" "strconv" "time" + + "./common" ) // TODO: Update the stats after edits so that we don't under or over decrement stats during deletes // TODO: Disable stat updates in posts handled by plugin_guilds -func routeEditTopic(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeEditTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { err := r.ParseForm() if err != nil { - return PreError("Bad Form", w, r) + return common.PreError("Bad Form", w, r) } isJs := (r.PostFormValue("js") == "1") tid, err := strconv.Atoi(r.URL.Path[len("/topic/edit/submit/"):]) if err != nil { - return PreErrorJSQ("The provided TopicID is not a valid number.", w, r, isJs) + return common.PreErrorJSQ("The provided TopicID is not a valid number.", w, r, isJs) } - topic, err := topics.Get(tid) + topic, err := common.Topics.Get(tid) if err == ErrNoRows { - return PreErrorJSQ("The topic you tried to edit doesn't exist.", w, r, isJs) + return common.PreErrorJSQ("The topic you tried to edit doesn't exist.", w, r, isJs) } else if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } // TODO: Add hooks to make use of headerLite - _, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID) + _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.EditTopic { - return NoPermissionsJSQ(w, r, user, isJs) + return common.NoPermissionsJSQ(w, r, user, isJs) } topicName := r.PostFormValue("topic_name") topicContent := html.EscapeString(r.PostFormValue("topic_content")) err = topic.Update(topicName, topicContent) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } - err = fstore.UpdateLastTopic(topic.ID, user.ID, topic.ParentID) + err = common.Fstore.UpdateLastTopic(topic.ID, user.ID, topic.ParentID) if err != nil && err != ErrNoRows { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } if !isJs { @@ -63,204 +65,204 @@ func routeEditTopic(w http.ResponseWriter, r *http.Request, user User) RouteErro // TODO: Add support for soft-deletion and add a permission for hard delete in addition to the usual // TODO: Disable stat updates in posts handled by plugin_guilds -func routeDeleteTopic(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeDeleteTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { // TODO: Move this to some sort of middleware var tids []int var isJs = false if r.Header.Get("Content-type") == "application/json" { if r.Body == nil { - return PreErrorJS("No request body", w, r) + return common.PreErrorJS("No request body", w, r) } //log.Print("r.Body: ", r.Body) err := json.NewDecoder(r.Body).Decode(&tids) if err != nil { //log.Print("parse err: ", err) - return PreErrorJS("We weren't able to parse your data", w, r) + return common.PreErrorJS("We weren't able to parse your data", w, r) } isJs = true } else { tid, err := strconv.Atoi(r.URL.Path[len("/topic/delete/submit/"):]) if err != nil { - return PreError("The provided TopicID is not a valid number.", w, r) + return common.PreError("The provided TopicID is not a valid number.", w, r) } tids = append(tids, tid) } if len(tids) == 0 { - return LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs) + return common.LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs) } for _, tid := range tids { - topic, err := topics.Get(tid) + topic, err := common.Topics.Get(tid) if err == ErrNoRows { - return PreErrorJSQ("The topic you tried to delete doesn't exist.", w, r, isJs) + return common.PreErrorJSQ("The topic you tried to delete doesn't exist.", w, r, isJs) } else if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } // TODO: Add hooks to make use of headerLite - _, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID) + _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.DeleteTopic { - return NoPermissionsJSQ(w, r, user, isJs) + return common.NoPermissionsJSQ(w, r, user, isJs) } // We might be able to handle this err better err = topic.Delete() if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } - err = addModLog("delete", tid, "topic", user.LastIP, user.ID) + err = common.AddModLog("delete", tid, "topic", user.LastIP, user.ID) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } // ? - We might need to add soft-delete before we can do an action reply for this /*_, err = stmts.createActionReply.Exec(tid,"delete",ipaddress,user.ID) if err != nil { - return InternalErrorJSQ(err,w,r,isJs) + return common.InternalErrorJSQ(err,w,r,isJs) }*/ - log.Printf("Topic #%d was deleted by User #%d", tid, user.ID) + log.Printf("Topic #%d was deleted by common.User #%d", tid, user.ID) } http.Redirect(w, r, "/", http.StatusSeeOther) return nil } -func routeStickTopic(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeStickTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { tid, err := strconv.Atoi(r.URL.Path[len("/topic/stick/submit/"):]) if err != nil { - return PreError("The provided TopicID is not a valid number.", w, r) + return common.PreError("The provided TopicID is not a valid number.", w, r) } - topic, err := topics.Get(tid) + topic, err := common.Topics.Get(tid) if err == ErrNoRows { - return PreError("The topic you tried to pin doesn't exist.", w, r) + return common.PreError("The topic you tried to pin doesn't exist.", w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // TODO: Add hooks to make use of headerLite - _, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID) + _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.PinTopic { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } err = topic.Stick() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - err = addModLog("stick", tid, "topic", user.LastIP, user.ID) + err = common.AddModLog("stick", tid, "topic", user.LastIP, user.ID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } err = topic.CreateActionReply("stick", user.LastIP, user) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) return nil } -func routeUnstickTopic(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeUnstickTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { tid, err := strconv.Atoi(r.URL.Path[len("/topic/unstick/submit/"):]) if err != nil { - return PreError("The provided TopicID is not a valid number.", w, r) + return common.PreError("The provided TopicID is not a valid number.", w, r) } - topic, err := topics.Get(tid) + topic, err := common.Topics.Get(tid) if err == ErrNoRows { - return PreError("The topic you tried to unpin doesn't exist.", w, r) + return common.PreError("The topic you tried to unpin doesn't exist.", w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // TODO: Add hooks to make use of headerLite - _, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID) + _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.PinTopic { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } err = topic.Unstick() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - err = addModLog("unstick", tid, "topic", user.LastIP, user.ID) + err = common.AddModLog("unstick", tid, "topic", user.LastIP, user.ID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } err = topic.CreateActionReply("unstick", user.LastIP, user) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) return nil } -func routeLockTopic(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeLockTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { // TODO: Move this to some sort of middleware var tids []int var isJs = false if r.Header.Get("Content-type") == "application/json" { if r.Body == nil { - return PreErrorJS("No request body", w, r) + return common.PreErrorJS("No request body", w, r) } err := json.NewDecoder(r.Body).Decode(&tids) if err != nil { - return PreErrorJS("We weren't able to parse your data", w, r) + return common.PreErrorJS("We weren't able to parse your data", w, r) } isJs = true } else { tid, err := strconv.Atoi(r.URL.Path[len("/topic/lock/submit/"):]) if err != nil { - return PreError("The provided TopicID is not a valid number.", w, r) + return common.PreError("The provided TopicID is not a valid number.", w, r) } tids = append(tids, tid) } if len(tids) == 0 { - return LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs) + return common.LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs) } for _, tid := range tids { - topic, err := topics.Get(tid) + topic, err := common.Topics.Get(tid) if err == ErrNoRows { - return PreErrorJSQ("The topic you tried to lock doesn't exist.", w, r, isJs) + return common.PreErrorJSQ("The topic you tried to lock doesn't exist.", w, r, isJs) } else if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } // TODO: Add hooks to make use of headerLite - _, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID) + _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.CloseTopic { - return NoPermissionsJSQ(w, r, user, isJs) + return common.NoPermissionsJSQ(w, r, user, isJs) } err = topic.Lock() if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } - err = addModLog("lock", tid, "topic", user.LastIP, user.ID) + err = common.AddModLog("lock", tid, "topic", user.LastIP, user.ID) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } err = topic.CreateActionReply("lock", user.LastIP, user) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } } @@ -270,40 +272,40 @@ func routeLockTopic(w http.ResponseWriter, r *http.Request, user User) RouteErro return nil } -func routeUnlockTopic(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeUnlockTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { tid, err := strconv.Atoi(r.URL.Path[len("/topic/unlock/submit/"):]) if err != nil { - return PreError("The provided TopicID is not a valid number.", w, r) + return common.PreError("The provided TopicID is not a valid number.", w, r) } - topic, err := topics.Get(tid) + topic, err := common.Topics.Get(tid) if err == ErrNoRows { - return PreError("The topic you tried to unlock doesn't exist.", w, r) + return common.PreError("The topic you tried to unlock doesn't exist.", w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // TODO: Add hooks to make use of headerLite - _, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID) + _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.CloseTopic { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } err = topic.Unlock() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - err = addModLog("unlock", tid, "topic", user.LastIP, user.ID) + err = common.AddModLog("unlock", tid, "topic", user.LastIP, user.ID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } err = topic.CreateActionReply("unlock", user.LastIP, user) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) @@ -312,46 +314,46 @@ func routeUnlockTopic(w http.ResponseWriter, r *http.Request, user User) RouteEr // TODO: Disable stat updates in posts handled by plugin_guilds // TODO: Update the stats after edits so that we don't under or over decrement stats during deletes -func routeReplyEditSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { err := r.ParseForm() if err != nil { - return PreError("Bad Form", w, r) + return common.PreError("Bad Form", w, r) } isJs := (r.PostFormValue("js") == "1") rid, err := strconv.Atoi(r.URL.Path[len("/reply/edit/submit/"):]) if err != nil { - return PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs) + return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs) } // Get the Reply ID.. var tid int err = stmts.getReplyTID.QueryRow(rid).Scan(&tid) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } var fid int err = stmts.getTopicFID.QueryRow(tid).Scan(&fid) if err == ErrNoRows { - return PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs) + return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs) } else if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } // TODO: Add hooks to make use of headerLite - _, ferr := SimpleForumUserCheck(w, r, &user, fid) + _, ferr := common.SimpleForumUserCheck(w, r, &user, fid) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.EditReply { - return NoPermissionsJSQ(w, r, user, isJs) + return common.NoPermissionsJSQ(w, r, user, isJs) } - content := html.EscapeString(preparseMessage(r.PostFormValue("edit_item"))) - _, err = stmts.editReply.Exec(content, parseMessage(content, fid, "forums"), rid) + content := html.EscapeString(common.PreparseMessage(r.PostFormValue("edit_item"))) + _, err = stmts.editReply.Exec(content, common.ParseMessage(content, fid, "forums"), rid) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } if !isJs { @@ -364,99 +366,99 @@ func routeReplyEditSubmit(w http.ResponseWriter, r *http.Request, user User) Rou // TODO: Refactor this // TODO: Disable stat updates in posts handled by plugin_guilds -func routeReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { err := r.ParseForm() if err != nil { - return PreError("Bad Form", w, r) + return common.PreError("Bad Form", w, r) } isJs := (r.PostFormValue("isJs") == "1") rid, err := strconv.Atoi(r.URL.Path[len("/reply/delete/submit/"):]) if err != nil { - return PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs) + return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs) } - reply, err := rstore.Get(rid) + reply, err := common.Rstore.Get(rid) if err == ErrNoRows { - return PreErrorJSQ("The reply you tried to delete doesn't exist.", w, r, isJs) + return common.PreErrorJSQ("The reply you tried to delete doesn't exist.", w, r, isJs) } else if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } var fid int err = stmts.getTopicFID.QueryRow(reply.ParentID).Scan(&fid) if err == ErrNoRows { - return PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs) + return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs) } else if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } // TODO: Add hooks to make use of headerLite - _, ferr := SimpleForumUserCheck(w, r, &user, fid) + _, ferr := common.SimpleForumUserCheck(w, r, &user, fid) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.DeleteReply { - return NoPermissionsJSQ(w, r, user, isJs) + return common.NoPermissionsJSQ(w, r, user, isJs) } err = reply.Delete() if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } - //log.Printf("Reply #%d was deleted by User #%d", rid, user.ID) + //log.Printf("Reply #%d was deleted by common.User #%d", rid, user.ID) if !isJs { //http.Redirect(w,r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther) } else { w.Write(successJSONBytes) } - replyCreator, err := users.Get(reply.CreatedBy) + replyCreator, err := common.Users.Get(reply.CreatedBy) if err == nil { - wcount := wordCount(reply.Content) - err = replyCreator.decreasePostStats(wcount, false) + wcount := common.WordCount(reply.Content) + err = replyCreator.DecreasePostStats(wcount, false) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } } else if err != ErrNoRows { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } - err = addModLog("delete", reply.ParentID, "reply", user.LastIP, user.ID) + err = common.AddModLog("delete", reply.ParentID, "reply", user.LastIP, user.ID) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } return nil } -func routeProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { err := r.ParseForm() if err != nil { - return LocalError("Bad Form", w, r, user) + return common.LocalError("Bad Form", w, r, user) } isJs := (r.PostFormValue("js") == "1") rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/edit/submit/"):]) if err != nil { - return LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs) + return common.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs) } // Get the Reply ID.. var uid int err = stmts.getUserReplyUID.QueryRow(rid).Scan(&uid) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } if user.ID != uid && !user.Perms.EditReply { - return NoPermissionsJSQ(w, r, user, isJs) + return common.NoPermissionsJSQ(w, r, user, isJs) } - content := html.EscapeString(preparseMessage(r.PostFormValue("edit_item"))) - _, err = stmts.editProfileReply.Exec(content, parseMessage(content, 0, ""), rid) + content := html.EscapeString(common.PreparseMessage(r.PostFormValue("edit_item"))) + _, err = stmts.editProfileReply.Exec(content, common.ParseMessage(content, 0, ""), rid) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } if !isJs { @@ -467,35 +469,35 @@ func routeProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user Us return nil } -func routeProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { err := r.ParseForm() if err != nil { - return LocalError("Bad Form", w, r, user) + return common.LocalError("Bad Form", w, r, user) } isJs := (r.PostFormValue("isJs") == "1") rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/delete/submit/"):]) if err != nil { - return LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs) + return common.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs) } var uid int err = stmts.getUserReplyUID.QueryRow(rid).Scan(&uid) if err == ErrNoRows { - return LocalErrorJSQ("The reply you tried to delete doesn't exist.", w, r, user, isJs) + return common.LocalErrorJSQ("The reply you tried to delete doesn't exist.", w, r, user, isJs) } else if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } if user.ID != uid && !user.Perms.DeleteReply { - return NoPermissionsJSQ(w, r, user, isJs) + return common.NoPermissionsJSQ(w, r, user, isJs) } _, err = stmts.deleteProfileReply.Exec(rid) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } - //log.Printf("The profile post '%d' was deleted by User #%d", rid, user.ID) + //log.Printf("The profile post '%d' was deleted by common.User #%d", rid, user.ID) if !isJs { //http.Redirect(w,r, "/user/" + strconv.Itoa(uid), http.StatusSeeOther) @@ -505,13 +507,13 @@ func routeProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user return nil } -func routeIps(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeIps(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ViewIPs { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } var ip = r.FormValue("ip") @@ -520,56 +522,56 @@ func routeIps(w http.ResponseWriter, r *http.Request, user User) RouteError { rows, err := stmts.findUsersByIPUsers.Query(ip) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } defer rows.Close() for rows.Next() { err := rows.Scan(&uid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } reqUserList[uid] = true } err = rows.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } rows2, err := stmts.findUsersByIPTopics.Query(ip) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } defer rows2.Close() for rows2.Next() { err := rows2.Scan(&uid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } reqUserList[uid] = true } err = rows2.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } rows3, err := stmts.findUsersByIPReplies.Query(ip) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } defer rows3.Close() for rows3.Next() { err := rows3.Scan(&uid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } reqUserList[uid] = true } err = rows3.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Convert the user ID map to a slice, then bulk load the users @@ -581,68 +583,68 @@ func routeIps(w http.ResponseWriter, r *http.Request, user User) RouteError { } // TODO: What if a user is deleted via the Control Panel? - userList, err := users.BulkGetMap(idSlice) + userList, err := common.Users.BulkGetMap(idSlice) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - pi := IPSearchPage{"IP Search", user, headerVars, userList, ip} - if preRenderHooks["pre_render_ips"] != nil { - if runPreRenderHook("pre_render_ips", w, r, &user, &pi) { + pi := common.IPSearchPage{"IP Search", user, headerVars, userList, ip} + if common.PreRenderHooks["pre_render_ips"] != nil { + if common.RunPreRenderHook("pre_render_ips", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "ip-search.html", pi) + err = common.Templates.ExecuteTemplate(w, "ip-search.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeBanSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeBanSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { if !user.Perms.BanUsers { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } uid, err := strconv.Atoi(r.URL.Path[len("/users/ban/submit/"):]) if err != nil { - return LocalError("The provided User ID is not a valid number.", w, r, user) + return common.LocalError("The provided common.User ID is not a valid number.", w, r, user) } /*if uid == -2 { - return LocalError("Stop trying to ban Merlin! Ban admin! Bad! No!",w,r,user) + return common.LocalError("Stop trying to ban Merlin! Ban admin! Bad! No!",w,r,user) }*/ - targetUser, err := users.Get(uid) + targetUser, err := common.Users.Get(uid) if err == ErrNoRows { - return LocalError("The user you're trying to ban no longer exists.", w, r, user) + return common.LocalError("The user you're trying to ban no longer exists.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // TODO: Is there a difference between IsMod and IsSuperMod? Should we delete the redundant one? if targetUser.IsSuperAdmin || targetUser.IsAdmin || targetUser.IsMod { - return LocalError("You may not ban another staff member.", w, r, user) + return common.LocalError("You may not ban another staff member.", w, r, user) } if uid == user.ID { - return LocalError("Why are you trying to ban yourself? Stop that.", w, r, user) + return common.LocalError("Why are you trying to ban yourself? Stop that.", w, r, user) } if targetUser.IsBanned { - return LocalError("The user you're trying to unban is already banned.", w, r, user) + return common.LocalError("The user you're trying to unban is already banned.", w, r, user) } durationDays, err := strconv.Atoi(r.FormValue("ban-duration-days")) if err != nil { - return LocalError("You can only use whole numbers for the number of days", w, r, user) + return common.LocalError("You can only use whole numbers for the number of days", w, r, user) } durationWeeks, err := strconv.Atoi(r.FormValue("ban-duration-weeks")) if err != nil { - return LocalError("You can only use whole numbers for the number of weeks", w, r, user) + return common.LocalError("You can only use whole numbers for the number of weeks", w, r, user) } durationMonths, err := strconv.Atoi(r.FormValue("ban-duration-months")) if err != nil { - return LocalError("You can only use whole numbers for the number of months", w, r, user) + return common.LocalError("You can only use whole numbers for the number of months", w, r, user) } var duration time.Duration @@ -650,95 +652,95 @@ func routeBanSubmit(w http.ResponseWriter, r *http.Request, user User) RouteErro duration, _ = time.ParseDuration("0") } else { var seconds int - seconds += durationDays * day - seconds += durationWeeks * week - seconds += durationMonths * month + seconds += durationDays * common.Day + seconds += durationWeeks * common.Week + seconds += durationMonths * common.Month duration, _ = time.ParseDuration(strconv.Itoa(seconds) + "s") } err = targetUser.Ban(duration, user.ID) if err == ErrNoRows { - return LocalError("The user you're trying to ban no longer exists.", w, r, user) + return common.LocalError("The user you're trying to ban no longer exists.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - err = addModLog("ban", uid, "user", user.LastIP, user.ID) + err = common.AddModLog("ban", uid, "user", user.LastIP, user.ID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther) return nil } -func routeUnban(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeUnban(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { if !user.Perms.BanUsers { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } uid, err := strconv.Atoi(r.URL.Path[len("/users/unban/"):]) if err != nil { - return LocalError("The provided User ID is not a valid number.", w, r, user) + return common.LocalError("The provided common.User ID is not a valid number.", w, r, user) } - targetUser, err := users.Get(uid) + targetUser, err := common.Users.Get(uid) if err == ErrNoRows { - return LocalError("The user you're trying to unban no longer exists.", w, r, user) + return common.LocalError("The user you're trying to unban no longer exists.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if !targetUser.IsBanned { - return LocalError("The user you're trying to unban isn't banned.", w, r, user) + return common.LocalError("The user you're trying to unban isn't banned.", w, r, user) } err = targetUser.Unban() - if err == ErrNoTempGroup { - return LocalError("The user you're trying to unban is not banned", w, r, user) + if err == common.ErrNoTempGroup { + return common.LocalError("The user you're trying to unban is not banned", w, r, user) } else if err == ErrNoRows { - return LocalError("The user you're trying to unban no longer exists.", w, r, user) + return common.LocalError("The user you're trying to unban no longer exists.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - err = addModLog("unban", uid, "user", user.LastIP, user.ID) + err = common.AddModLog("unban", uid, "user", user.LastIP, user.ID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther) return nil } -func routeActivate(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeActivate(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { if !user.Perms.ActivateUsers { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } uid, err := strconv.Atoi(r.URL.Path[len("/users/activate/"):]) if err != nil { - return LocalError("The provided User ID is not a valid number.", w, r, user) + return common.LocalError("The provided common.User ID is not a valid number.", w, r, user) } - targetUser, err := users.Get(uid) + targetUser, err := common.Users.Get(uid) if err == ErrNoRows { - return LocalError("The account you're trying to activate no longer exists.", w, r, user) + return common.LocalError("The account you're trying to activate no longer exists.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if targetUser.Active { - return LocalError("The account you're trying to activate has already been activated.", w, r, user) + return common.LocalError("The account you're trying to activate has already been activated.", w, r, user) } err = targetUser.Activate() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - err = addModLog("activate", targetUser.ID, "user", user.LastIP, user.ID) + err = common.AddModLog("activate", targetUser.ID, "user", user.LastIP, user.ID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } http.Redirect(w, r, "/user/"+strconv.Itoa(targetUser.ID), http.StatusSeeOther) return nil diff --git a/mysql.go b/mysql.go index fbba9ed0..24146119 100644 --- a/mysql.go +++ b/mysql.go @@ -8,12 +8,16 @@ */ package main -import "log" +import ( + "database/sql" + "log" -//import "time" -import "database/sql" -import _ "github.com/go-sql-driver/mysql" -import "./query_gen/lib" + //import "time" + + "./common" + "./query_gen/lib" + _ "github.com/go-sql-driver/mysql" +) var dbCollation = "utf8mb4_general_ci" @@ -24,13 +28,13 @@ func init() { func initMySQL() (err error) { var _dbpassword string - if dbConfig.Password != "" { - _dbpassword = ":" + dbConfig.Password + if common.DbConfig.Password != "" { + _dbpassword = ":" + common.DbConfig.Password } // TODO: Move this bit to the query gen lib // Open the database connection - db, err = sql.Open("mysql", dbConfig.Username+_dbpassword+"@tcp("+dbConfig.Host+":"+dbConfig.Port+")/"+dbConfig.Dbname+"?collation="+dbCollation+"&parseTime=true") + db, err = sql.Open("mysql", common.DbConfig.Username+_dbpassword+"@tcp("+common.DbConfig.Host+":"+common.DbConfig.Port+")/"+common.DbConfig.Dbname+"?collation="+dbCollation+"&parseTime=true") if err != nil { return err } diff --git a/panel_routes.go b/panel_routes.go index 74b2e1b3..d3910280 100644 --- a/panel_routes.go +++ b/panel_routes.go @@ -14,11 +14,12 @@ import ( "strconv" "strings" + "./common" "github.com/Azareal/gopsutil/mem" ) -func routePanel(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanel(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } @@ -32,8 +33,8 @@ func routePanel(w http.ResponseWriter, r *http.Request, user User) RouteError { if err != nil { ramstr = "Unknown" } else { - totalCount, totalUnit := convertByteUnit(float64(memres.Total)) - usedCount := convertByteInUnit(float64(memres.Total-memres.Available), totalUnit) + totalCount, totalUnit := common.ConvertByteUnit(float64(memres.Total)) + usedCount := common.ConvertByteInUnit(float64(memres.Total-memres.Available), totalUnit) // Round totals with .9s up, it's how most people see it anyway. Floats are notoriously imprecise, so do it off 0.85 //log.Print("pre used_count",used_count) @@ -65,7 +66,7 @@ func routePanel(w http.ResponseWriter, r *http.Request, user User) RouteError { var postCount int err = stmts.todaysPostCount.QueryRow().Scan(&postCount) if err != nil && err != ErrNoRows { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } var postInterval = "day" @@ -81,7 +82,7 @@ func routePanel(w http.ResponseWriter, r *http.Request, user User) RouteError { var topicCount int err = stmts.todaysTopicCount.QueryRow().Scan(&topicCount) if err != nil && err != ErrNoRows { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } var topicInterval = "day" @@ -97,21 +98,21 @@ func routePanel(w http.ResponseWriter, r *http.Request, user User) RouteError { var reportCount int err = stmts.todaysReportCount.QueryRow().Scan(&reportCount) if err != nil && err != ErrNoRows { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } var reportInterval = "week" var newUserCount int err = stmts.todaysNewUserCount.QueryRow().Scan(&newUserCount) if err != nil && err != ErrNoRows { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } var newUserInterval = "week" - var gridElements = []GridElement{ - GridElement{"dash-version", "v" + version.String(), 0, "grid_istat stat_green", "", "", "Gosora is up-to-date :)"}, - GridElement{"dash-cpu", "CPU: " + cpustr, 1, "grid_istat " + cpuColour, "", "", "The global CPU usage of this server"}, - GridElement{"dash-ram", "RAM: " + ramstr, 2, "grid_istat " + ramColour, "", "", "The global RAM usage of this server"}, + var gridElements = []common.GridElement{ + common.GridElement{"dash-version", "v" + version.String(), 0, "grid_istat stat_green", "", "", "Gosora is up-to-date :)"}, + common.GridElement{"dash-cpu", "CPU: " + cpustr, 1, "grid_istat " + cpuColour, "", "", "The global CPU usage of this server"}, + common.GridElement{"dash-ram", "RAM: " + ramstr, 2, "grid_istat " + ramColour, "", "", "The global RAM usage of this server"}, } if enableWebsockets { @@ -146,105 +147,105 @@ func routePanel(w http.ResponseWriter, r *http.Request, user User) RouteError { onlineUsersColour = "stat_red" } - totonline, totunit := convertFriendlyUnit(totonline) - uonline, uunit := convertFriendlyUnit(uonline) - gonline, gunit := convertFriendlyUnit(gonline) + totonline, totunit := common.ConvertFriendlyUnit(totonline) + uonline, uunit := common.ConvertFriendlyUnit(uonline) + gonline, gunit := common.ConvertFriendlyUnit(gonline) - gridElements = append(gridElements, GridElement{"dash-totonline", strconv.Itoa(totonline) + totunit + " online", 3, "grid_stat " + onlineColour, "", "", "The number of people who are currently online"}) - gridElements = append(gridElements, GridElement{"dash-gonline", strconv.Itoa(gonline) + gunit + " guests online", 4, "grid_stat " + onlineGuestsColour, "", "", "The number of guests who are currently online"}) - gridElements = append(gridElements, GridElement{"dash-uonline", strconv.Itoa(uonline) + uunit + " users online", 5, "grid_stat " + onlineUsersColour, "", "", "The number of logged-in users who are currently online"}) + gridElements = append(gridElements, common.GridElement{"dash-totonline", strconv.Itoa(totonline) + totunit + " online", 3, "grid_stat " + onlineColour, "", "", "The number of people who are currently online"}) + gridElements = append(gridElements, common.GridElement{"dash-gonline", strconv.Itoa(gonline) + gunit + " guests online", 4, "grid_stat " + onlineGuestsColour, "", "", "The number of guests who are currently online"}) + gridElements = append(gridElements, common.GridElement{"dash-uonline", strconv.Itoa(uonline) + uunit + " users online", 5, "grid_stat " + onlineUsersColour, "", "", "The number of logged-in users who are currently online"}) } - gridElements = append(gridElements, GridElement{"dash-postsperday", strconv.Itoa(postCount) + " posts / " + postInterval, 6, "grid_stat " + postColour, "", "", "The number of new posts over the last 24 hours"}) - gridElements = append(gridElements, GridElement{"dash-topicsperday", strconv.Itoa(topicCount) + " topics / " + topicInterval, 7, "grid_stat " + topicColour, "", "", "The number of new topics over the last 24 hours"}) - gridElements = append(gridElements, GridElement{"dash-totonlineperday", "20 online / day", 8, "grid_stat stat_disabled", "", "", "Coming Soon!" /*"The people online over the last 24 hours"*/}) + gridElements = append(gridElements, common.GridElement{"dash-postsperday", strconv.Itoa(postCount) + " posts / " + postInterval, 6, "grid_stat " + postColour, "", "", "The number of new posts over the last 24 hours"}) + gridElements = append(gridElements, common.GridElement{"dash-topicsperday", strconv.Itoa(topicCount) + " topics / " + topicInterval, 7, "grid_stat " + topicColour, "", "", "The number of new topics over the last 24 hours"}) + gridElements = append(gridElements, common.GridElement{"dash-totonlineperday", "20 online / day", 8, "grid_stat stat_disabled", "", "", "Coming Soon!" /*"The people online over the last 24 hours"*/}) - gridElements = append(gridElements, GridElement{"dash-searches", "8 searches / week", 9, "grid_stat stat_disabled", "", "", "Coming Soon!" /*"The number of searches over the last 7 days"*/}) - gridElements = append(gridElements, GridElement{"dash-newusers", strconv.Itoa(newUserCount) + " new users / " + newUserInterval, 10, "grid_stat", "", "", "The number of new users over the last 7 days"}) - gridElements = append(gridElements, GridElement{"dash-reports", strconv.Itoa(reportCount) + " reports / " + reportInterval, 11, "grid_stat", "", "", "The number of reports over the last 7 days"}) + gridElements = append(gridElements, common.GridElement{"dash-searches", "8 searches / week", 9, "grid_stat stat_disabled", "", "", "Coming Soon!" /*"The number of searches over the last 7 days"*/}) + gridElements = append(gridElements, common.GridElement{"dash-newusers", strconv.Itoa(newUserCount) + " new users / " + newUserInterval, 10, "grid_stat", "", "", "The number of new users over the last 7 days"}) + gridElements = append(gridElements, common.GridElement{"dash-reports", strconv.Itoa(reportCount) + " reports / " + reportInterval, 11, "grid_stat", "", "", "The number of reports over the last 7 days"}) - gridElements = append(gridElements, GridElement{"dash-minperuser", "2 minutes / user / week", 12, "grid_stat stat_disabled", "", "", "Coming Soon!" /*"The average number of number of minutes spent by each active user over the last 7 days"*/}) - gridElements = append(gridElements, GridElement{"dash-visitorsperweek", "2 visitors / week", 13, "grid_stat stat_disabled", "", "", "Coming Soon!" /*"The number of unique visitors we've had over the last 7 days"*/}) - gridElements = append(gridElements, GridElement{"dash-postsperuser", "5 posts / user / week", 14, "grid_stat stat_disabled", "", "", "Coming Soon!" /*"The average number of posts made by each active user over the past week"*/}) + gridElements = append(gridElements, common.GridElement{"dash-minperuser", "2 minutes / user / week", 12, "grid_stat stat_disabled", "", "", "Coming Soon!" /*"The average number of number of minutes spent by each active user over the last 7 days"*/}) + gridElements = append(gridElements, common.GridElement{"dash-visitorsperweek", "2 visitors / week", 13, "grid_stat stat_disabled", "", "", "Coming Soon!" /*"The number of unique visitors we've had over the last 7 days"*/}) + gridElements = append(gridElements, common.GridElement{"dash-postsperuser", "5 posts / user / week", 14, "grid_stat stat_disabled", "", "", "Coming Soon!" /*"The average number of posts made by each active user over the past week"*/}) - pi := PanelDashboardPage{"Control Panel Dashboard", user, headerVars, stats, gridElements} - if preRenderHooks["pre_render_panel_dashboard"] != nil { - if runPreRenderHook("pre_render_panel_dashboard", w, r, &user, &pi) { + pi := common.PanelDashboardPage{"Control Panel Dashboard", user, headerVars, stats, gridElements} + if common.PreRenderHooks["pre_render_panel_dashboard"] != nil { + if common.RunPreRenderHook("pre_render_panel_dashboard", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "panel-dashboard.html", pi) + err = common.Templates.ExecuteTemplate(w, "panel-dashboard.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelForums(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelForums(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManageForums { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } // TODO: Paginate this? var forumList []interface{} - forums, err := fstore.GetAll() + forums, err := common.Fstore.GetAll() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // ? - Should we generate something similar to the forumView? It might be a little overkill for a page which is rarely loaded in comparison to /forums/ for _, forum := range forums { if forum.Name != "" && forum.ParentID == 0 { - fadmin := ForumAdmin{forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, forum.TopicCount, presetToLang(forum.Preset)} + fadmin := common.ForumAdmin{forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, forum.TopicCount, common.PresetToLang(forum.Preset)} if fadmin.Preset == "" { fadmin.Preset = "custom" } forumList = append(forumList, fadmin) } } - pi := PanelPage{"Forum Manager", user, headerVars, stats, forumList, nil} - if preRenderHooks["pre_render_panel_forums"] != nil { - if runPreRenderHook("pre_render_panel_forums", w, r, &user, &pi) { + pi := common.PanelPage{"Forum Manager", user, headerVars, stats, forumList, nil} + if common.PreRenderHooks["pre_render_panel_forums"] != nil { + if common.RunPreRenderHook("pre_render_panel_forums", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "panel-forums.html", pi) + err = common.Templates.ExecuteTemplate(w, "panel-forums.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelForumsCreateSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelForumsCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManageForums { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } err := r.ParseForm() if err != nil { - return LocalError("Bad Form", w, r, user) + return common.LocalError("Bad Form", w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } fname := r.PostFormValue("forum-name") fdesc := r.PostFormValue("forum-desc") - fpreset := stripInvalidPreset(r.PostFormValue("forum-preset")) + fpreset := common.StripInvalidPreset(r.PostFormValue("forum-preset")) factive := r.PostFormValue("forum-name") active := (factive == "on" || factive == "1") - _, err = fstore.Create(fname, fdesc, active, fpreset) + _, err = common.Fstore.Create(fname, fdesc, active, fpreset) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } http.Redirect(w, r, "/panel/forums/", http.StatusSeeOther) @@ -252,158 +253,158 @@ func routePanelForumsCreateSubmit(w http.ResponseWriter, r *http.Request, user U } // TODO: Revamp this -func routePanelForumsDelete(w http.ResponseWriter, r *http.Request, user User, sfid string) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelForumsDelete(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManageForums { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } fid, err := strconv.Atoi(sfid) if err != nil { - return LocalError("The provided Forum ID is not a valid number.", w, r, user) + return common.LocalError("The provided Forum ID is not a valid number.", w, r, user) } - forum, err := fstore.Get(fid) + forum, err := common.Fstore.Get(fid) if err == ErrNoRows { - return LocalError("The forum you're trying to delete doesn't exist.", w, r, user) + return common.LocalError("The forum you're trying to delete doesn't exist.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } confirmMsg := "Are you sure you want to delete the '" + forum.Name + "' forum?" - yousure := AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid), confirmMsg} + yousure := common.AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid), confirmMsg} - pi := PanelPage{"Delete Forum", user, headerVars, stats, tList, yousure} - if preRenderHooks["pre_render_panel_delete_forum"] != nil { - if runPreRenderHook("pre_render_panel_delete_forum", w, r, &user, &pi) { + pi := common.PanelPage{"Delete Forum", user, headerVars, stats, tList, yousure} + if common.PreRenderHooks["pre_render_panel_delete_forum"] != nil { + if common.RunPreRenderHook("pre_render_panel_delete_forum", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "areyousure.html", pi) + err = common.Templates.ExecuteTemplate(w, "areyousure.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelForumsDeleteSubmit(w http.ResponseWriter, r *http.Request, user User, sfid string) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelForumsDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManageForums { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } fid, err := strconv.Atoi(sfid) if err != nil { - return LocalError("The provided Forum ID is not a valid number.", w, r, user) + return common.LocalError("The provided Forum ID is not a valid number.", w, r, user) } - err = fstore.Delete(fid) + err = common.Fstore.Delete(fid) if err == ErrNoRows { - return LocalError("The forum you're trying to delete doesn't exist.", w, r, user) + return common.LocalError("The forum you're trying to delete doesn't exist.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } http.Redirect(w, r, "/panel/forums/", http.StatusSeeOther) return nil } -func routePanelForumsEdit(w http.ResponseWriter, r *http.Request, user User, sfid string) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelForumsEdit(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManageForums { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } fid, err := strconv.Atoi(sfid) if err != nil { - return LocalError("The provided Forum ID is not a valid number.", w, r, user) + return common.LocalError("The provided Forum ID is not a valid number.", w, r, user) } - forum, err := fstore.Get(fid) + forum, err := common.Fstore.Get(fid) if err == ErrNoRows { - return LocalError("The forum you're trying to edit doesn't exist.", w, r, user) + return common.LocalError("The forum you're trying to edit doesn't exist.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if forum.Preset == "" { forum.Preset = "custom" } - glist, err := gstore.GetAll() + glist, err := common.Gstore.GetAll() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - var gplist []GroupForumPermPreset + var gplist []common.GroupForumPermPreset for gid, group := range glist { if gid == 0 { continue } - gplist = append(gplist, GroupForumPermPreset{group, forumPermsToGroupForumPreset(group.Forums[fid])}) + gplist = append(gplist, common.GroupForumPermPreset{group, common.ForumPermsToGroupForumPreset(group.Forums[fid])}) } - pi := PanelEditForumPage{"Forum Editor", user, headerVars, stats, forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, gplist} - if preRenderHooks["pre_render_panel_edit_forum"] != nil { - if runPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) { + pi := common.PanelEditForumPage{"Forum Editor", user, headerVars, stats, forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, gplist} + if common.PreRenderHooks["pre_render_panel_edit_forum"] != nil { + if common.RunPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "panel-forum-edit.html", pi) + err = common.Templates.ExecuteTemplate(w, "panel-forum-edit.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelForumsEditSubmit(w http.ResponseWriter, r *http.Request, user User, sfid string) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelForumsEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManageForums { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } err := r.ParseForm() if err != nil { - return LocalError("Bad Form", w, r, user) + return common.LocalError("Bad Form", w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } isJs := (r.PostFormValue("js") == "1") fid, err := strconv.Atoi(sfid) if err != nil { - return LocalErrorJSQ("The provided Forum ID is not a valid number.", w, r, user, isJs) + return common.LocalErrorJSQ("The provided Forum ID is not a valid number.", w, r, user, isJs) } - forum, err := fstore.Get(fid) + forum, err := common.Fstore.Get(fid) if err == ErrNoRows { - return LocalErrorJSQ("The forum you're trying to edit doesn't exist.", w, r, user, isJs) + return common.LocalErrorJSQ("The forum you're trying to edit doesn't exist.", w, r, user, isJs) } else if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } forumName := r.PostFormValue("forum_name") forumDesc := r.PostFormValue("forum_desc") - forumPreset := stripInvalidPreset(r.PostFormValue("forum_preset")) + forumPreset := common.StripInvalidPreset(r.PostFormValue("forum_preset")) forumActive := r.PostFormValue("forum_active") var active = false @@ -415,7 +416,7 @@ func routePanelForumsEditSubmit(w http.ResponseWriter, r *http.Request, user Use err = forum.Update(forumName, forumDesc, active, forumPreset) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } if !isJs { @@ -426,70 +427,70 @@ func routePanelForumsEditSubmit(w http.ResponseWriter, r *http.Request, user Use return nil } -func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, user User, sfid string) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManageForums { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } err := r.ParseForm() if err != nil { - return LocalError("Bad Form", w, r, user) + return common.LocalError("Bad Form", w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } isJs := (r.PostFormValue("js") == "1") fid, err := strconv.Atoi(sfid) if err != nil { - return LocalErrorJSQ("The provided Forum ID is not a valid number.", w, r, user, isJs) + return common.LocalErrorJSQ("The provided Forum ID is not a valid number.", w, r, user, isJs) } gid, err := strconv.Atoi(r.PostFormValue("gid")) if err != nil { - return LocalErrorJSQ("Invalid Group ID", w, r, user, isJs) + return common.LocalErrorJSQ("Invalid Group ID", w, r, user, isJs) } - permPreset := stripInvalidGroupForumPreset(r.PostFormValue("perm_preset")) - fperms, changed := groupForumPresetToForumPerms(permPreset) + permPreset := common.StripInvalidGroupForumPreset(r.PostFormValue("perm_preset")) + fperms, changed := common.GroupForumPresetToForumPerms(permPreset) - forum, err := fstore.Get(fid) + forum, err := common.Fstore.Get(fid) if err == ErrNoRows { - return LocalErrorJSQ("This forum doesn't exist", w, r, user, isJs) + return common.LocalErrorJSQ("This forum doesn't exist", w, r, user, isJs) } else if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } // ! IMPORTANT // TODO: Refactor this - forumUpdateMutex.Lock() - defer forumUpdateMutex.Unlock() + common.ForumUpdateMutex.Lock() + defer common.ForumUpdateMutex.Unlock() if changed { - permUpdateMutex.Lock() - defer permUpdateMutex.Unlock() - group, err := gstore.Get(gid) + common.PermUpdateMutex.Lock() + defer common.PermUpdateMutex.Unlock() + group, err := common.Gstore.Get(gid) if err != nil { - return LocalError("The group whose permissions you're updating doesn't exist.", w, r, user) + return common.LocalError("The group whose permissions you're updating doesn't exist.", w, r, user) } group.Forums[fid] = fperms - err = replaceForumPermsForGroup(gid, map[int]string{fid: permPreset}, map[int]ForumPerms{fid: fperms}) + err = common.ReplaceForumPermsForGroup(gid, map[int]string{fid: permPreset}, map[int]common.ForumPerms{fid: fperms}) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + 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 InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } - err = fstore.Reload(fid) + err = common.Fstore.Reload(fid) if err != nil { - return LocalErrorJSQ("Unable to reload forum", w, r, user, isJs) + return common.LocalErrorJSQ("Unable to reload forum", w, r, user, isJs) } } @@ -501,30 +502,30 @@ func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use return nil } -func routePanelSettings(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelSettings(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.EditSettings { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } //log.Print("headerVars.Settings",headerVars.Settings) var settingList = make(map[string]interface{}) rows, err := stmts.getSettings.Query() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } defer rows.Close() // nolint need the type so people viewing this file understand what it returns without visiting setting.go - var settingLabels map[string]string = GetAllSettingLabels() + var settingLabels map[string]string = common.GetAllSettingLabels() var sname, scontent, stype string for rows.Next() { err := rows.Scan(&sname, &scontent, &stype) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if stype == "list" { @@ -532,7 +533,7 @@ func routePanelSettings(w http.ResponseWriter, r *http.Request, user User) Route labels := strings.Split(llist, ",") conv, err := strconv.Atoi(scontent) if err != nil { - return LocalError("The setting '"+sname+"' can't be converted to an integer", w, r, user) + return common.LocalError("The setting '"+sname+"' can't be converted to an integer", w, r, user) } scontent = labels[conv-1] } else if stype == "bool" { @@ -546,50 +547,50 @@ func routePanelSettings(w http.ResponseWriter, r *http.Request, user User) Route } err = rows.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - pi := PanelPage{"Setting Manager", user, headerVars, stats, tList, settingList} - if preRenderHooks["pre_render_panel_settings"] != nil { - if runPreRenderHook("pre_render_panel_settings", w, r, &user, &pi) { + pi := common.PanelPage{"Setting Manager", user, headerVars, stats, tList, settingList} + if common.PreRenderHooks["pre_render_panel_settings"] != nil { + if common.RunPreRenderHook("pre_render_panel_settings", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "panel-settings.html", pi) + err = common.Templates.ExecuteTemplate(w, "panel-settings.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelSetting(w http.ResponseWriter, r *http.Request, user User, sname string) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelSetting(w http.ResponseWriter, r *http.Request, user common.User, sname string) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.EditSettings { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } - setting := Setting{sname, "", "", ""} + setting := common.Setting{sname, "", "", ""} err := stmts.getSetting.QueryRow(setting.Name).Scan(&setting.Content, &setting.Type) if err == ErrNoRows { - return 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 { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } var itemList []interface{} if setting.Type == "list" { - llist := GetSettingLabel(setting.Name) + llist := common.GetSettingLabel(setting.Name) conv, err := strconv.Atoi(setting.Content) if err != nil { - return LocalError("The value of this setting couldn't be converted to an integer", w, r, user) + return common.LocalError("The value of this setting couldn't be converted to an integer", w, r, user) } labels := strings.Split(llist, ",") for index, label := range labels { - itemList = append(itemList, OptionLabel{ + itemList = append(itemList, common.OptionLabel{ Label: label, Value: index + 1, Selected: conv == (index + 1), @@ -597,34 +598,34 @@ func routePanelSetting(w http.ResponseWriter, r *http.Request, user User, sname } } - pi := PanelPage{"Edit Setting", user, headerVars, stats, itemList, setting} - if preRenderHooks["pre_render_panel_setting"] != nil { - if runPreRenderHook("pre_render_panel_setting", w, r, &user, &pi) { + pi := common.PanelPage{"Edit Setting", user, headerVars, stats, itemList, setting} + if common.PreRenderHooks["pre_render_panel_setting"] != nil { + if common.RunPreRenderHook("pre_render_panel_setting", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "panel-setting.html", pi) + err = common.Templates.ExecuteTemplate(w, "panel-setting.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelSettingEdit(w http.ResponseWriter, r *http.Request, user User, sname string) RouteError { - headerLite, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelSettingEdit(w http.ResponseWriter, r *http.Request, user common.User, sname string) common.RouteError { + headerLite, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.EditSettings { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } err := r.ParseForm() if err != nil { - return LocalError("Bad Form", w, r, user) + return common.LocalError("Bad Form", w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } var stype, sconstraints string @@ -632,9 +633,9 @@ func routePanelSettingEdit(w http.ResponseWriter, r *http.Request, user User, sn err = stmts.getFullSetting.QueryRow(sname).Scan(&sname, &stype, &sconstraints) if err == ErrNoRows { - return 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 { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if stype == "bool" { @@ -648,60 +649,60 @@ func routePanelSettingEdit(w http.ResponseWriter, r *http.Request, user User, sn // TODO: Make this a method or function? _, err = stmts.updateSetting.Exec(scontent, sname) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } errmsg := headerLite.Settings.ParseSetting(sname, scontent, stype, sconstraints) if errmsg != "" { - return LocalError(errmsg, w, r, user) + return common.LocalError(errmsg, w, r, user) } - settingBox.Store(headerLite.Settings) + common.SettingBox.Store(headerLite.Settings) http.Redirect(w, r, "/panel/settings/", http.StatusSeeOther) return nil } -func routePanelWordFilters(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelWordFilters(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return nil } if !user.Perms.EditSettings { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } - var filterList = wordFilterBox.Load().(WordFilterBox) - pi := PanelPage{"Word Filter Manager", user, headerVars, stats, tList, filterList} - if preRenderHooks["pre_render_panel_word_filters"] != nil { - if runPreRenderHook("pre_render_panel_word_filters", w, r, &user, &pi) { + var filterList = common.WordFilterBox.Load().(common.WordFilterMap) + pi := common.PanelPage{"Word Filter Manager", user, headerVars, stats, tList, filterList} + if common.PreRenderHooks["pre_render_panel_word_filters"] != nil { + if common.RunPreRenderHook("pre_render_panel_word_filters", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "panel-word-filters.html", pi) + err := common.Templates.ExecuteTemplate(w, "panel-word-filters.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelWordFiltersCreate(w http.ResponseWriter, r *http.Request, user User) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelWordFiltersCreate(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.EditSettings { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } err := r.ParseForm() if err != nil { - return PreError("Bad Form", w, r) + return common.PreError("Bad Form", w, r) } isJs := (r.PostFormValue("js") == "1") find := strings.TrimSpace(r.PostFormValue("find")) if find == "" { - return LocalErrorJSQ("You need to specify what word you want to match", w, r, user, isJs) + return common.LocalErrorJSQ("You need to specify what word you want to match", w, r, user, isJs) } // Unlike with find, it's okay if we leave this blank, as this means that the admin wants to remove the word entirely with no replacement @@ -709,14 +710,14 @@ func routePanelWordFiltersCreate(w http.ResponseWriter, r *http.Request, user Us res, err := stmts.createWordFilter.Exec(find, replacement) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } lastID, err := res.LastInsertId() if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } - addWordFilter(int(lastID), find, replacement) + common.AddWordFilter(int(lastID), find, replacement) if !isJs { http.Redirect(w, r, "/panel/settings/word-filters/", http.StatusSeeOther) } else { @@ -725,54 +726,54 @@ func routePanelWordFiltersCreate(w http.ResponseWriter, r *http.Request, user Us return nil } -func routePanelWordFiltersEdit(w http.ResponseWriter, r *http.Request, user User, wfid string) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelWordFiltersEdit(w http.ResponseWriter, r *http.Request, user common.User, wfid string) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.EditSettings { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } _ = wfid - pi := PanelPage{"Edit Word Filter", user, headerVars, stats, tList, nil} - if preRenderHooks["pre_render_panel_word_filters_edit"] != nil { - if runPreRenderHook("pre_render_panel_word_filters_edit", w, r, &user, &pi) { + pi := common.PanelPage{"Edit Word Filter", user, headerVars, stats, tList, nil} + if common.PreRenderHooks["pre_render_panel_word_filters_edit"] != nil { + if common.RunPreRenderHook("pre_render_panel_word_filters_edit", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "panel-word-filters-edit.html", pi) + err := common.Templates.ExecuteTemplate(w, "panel-word-filters-edit.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelWordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, user User, wfid string) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelWordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, wfid string) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } err := r.ParseForm() if err != nil { - return PreError("Bad Form", w, r) + 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 isJs := (r.PostFormValue("isJs") == "1") if !user.Perms.EditSettings { - return NoPermissionsJSQ(w, r, user, isJs) + return common.NoPermissionsJSQ(w, r, user, isJs) } id, err := strconv.Atoi(wfid) if err != nil { - return LocalErrorJSQ("The word filter ID must be an integer.", w, r, user, isJs) + return common.LocalErrorJSQ("The word filter ID must be an integer.", w, r, user, isJs) } find := strings.TrimSpace(r.PostFormValue("find")) if find == "" { - return LocalErrorJSQ("You need to specify what word you want to match", w, r, user, isJs) + return common.LocalErrorJSQ("You need to specify what word you want to match", w, r, user, isJs) } // Unlike with find, it's okay if we leave this blank, as this means that the admin wants to remove the word entirely with no replacement @@ -780,110 +781,110 @@ func routePanelWordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, use _, err = stmts.updateWordFilter.Exec(find, replacement, id) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } - wordFilters := wordFilterBox.Load().(WordFilterBox) - wordFilters[id] = WordFilter{ID: id, Find: find, Replacement: replacement} - wordFilterBox.Store(wordFilters) + wordFilters := common.WordFilterBox.Load().(common.WordFilterMap) + wordFilters[id] = common.WordFilter{ID: id, Find: find, Replacement: replacement} + common.WordFilterBox.Store(wordFilters) http.Redirect(w, r, "/panel/settings/word-filters/", http.StatusSeeOther) return nil } -func routePanelWordFiltersDeleteSubmit(w http.ResponseWriter, r *http.Request, user User, wfid string) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelWordFiltersDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, wfid string) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } err := r.ParseForm() if err != nil { - return PreError("Bad Form", w, r) + return common.PreError("Bad Form", w, r) } isJs := (r.PostFormValue("isJs") == "1") if !user.Perms.EditSettings { - return NoPermissionsJSQ(w, r, user, isJs) + return common.NoPermissionsJSQ(w, r, user, isJs) } id, err := strconv.Atoi(wfid) if err != nil { - return LocalErrorJSQ("The word filter ID must be an integer.", w, r, user, isJs) + return common.LocalErrorJSQ("The word filter ID must be an integer.", w, r, user, isJs) } _, err = stmts.deleteWordFilter.Exec(id) if err != nil { - return InternalErrorJSQ(err, w, r, isJs) + return common.InternalErrorJSQ(err, w, r, isJs) } - wordFilters := wordFilterBox.Load().(WordFilterBox) + wordFilters := common.WordFilterBox.Load().(common.WordFilterMap) delete(wordFilters, id) - wordFilterBox.Store(wordFilters) + common.WordFilterBox.Store(wordFilters) http.Redirect(w, r, "/panel/settings/word-filters/", http.StatusSeeOther) return nil } -func routePanelPlugins(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelPlugins(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManagePlugins { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } var pluginList []interface{} - for _, plugin := range plugins { + for _, plugin := range common.Plugins { pluginList = append(pluginList, plugin) } - pi := PanelPage{"Plugin Manager", user, headerVars, stats, pluginList, nil} - if preRenderHooks["pre_render_panel_plugins"] != nil { - if runPreRenderHook("pre_render_panel_plugins", w, r, &user, &pi) { + pi := common.PanelPage{"Plugin Manager", user, headerVars, stats, pluginList, nil} + if common.PreRenderHooks["pre_render_panel_plugins"] != nil { + if common.RunPreRenderHook("pre_render_panel_plugins", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "panel-plugins.html", pi) + err := common.Templates.ExecuteTemplate(w, "panel-plugins.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelPluginsActivate(w http.ResponseWriter, r *http.Request, user User, uname string) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelPluginsActivate(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManagePlugins { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } //log.Print("uname","'"+uname+"'") - plugin, ok := plugins[uname] + plugin, ok := common.Plugins[uname] if !ok { - return 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 { - return 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) } var active bool err := stmts.isPluginActive.QueryRow(uname).Scan(&active) if err != nil && err != ErrNoRows { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } var hasPlugin = (err == nil) - if plugins[uname].Activate != nil { - err = plugins[uname].Activate() + if common.Plugins[uname].Activate != nil { + err = common.Plugins[uname].Activate() if err != nil { - return LocalError(err.Error(), w, r, user) + return common.LocalError(err.Error(), w, r, user) } } @@ -891,186 +892,181 @@ func routePanelPluginsActivate(w http.ResponseWriter, r *http.Request, user User //log.Print("active", active) if hasPlugin { if active { - return 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) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } else { //log.Print("addPlugin") _, err := stmts.addPlugin.Exec(uname, 1, 0) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } log.Print("Activating plugin '" + plugin.Name + "'") plugin.Active = true - plugins[uname] = plugin - err = plugins[uname].Init() + common.Plugins[uname] = plugin + err = common.Plugins[uname].Init() if err != nil { - return LocalError(err.Error(), w, r, user) + return common.LocalError(err.Error(), w, r, user) } http.Redirect(w, r, "/panel/plugins/", http.StatusSeeOther) return nil } -func routePanelPluginsDeactivate(w http.ResponseWriter, r *http.Request, user User, uname string) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelPluginsDeactivate(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManagePlugins { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } - plugin, ok := plugins[uname] + plugin, ok := common.Plugins[uname] if !ok { - return 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) } var active bool err := stmts.isPluginActive.QueryRow(uname).Scan(&active) if err == ErrNoRows { - return LocalError("The plugin you're trying to deactivate isn't active", w, r, user) + return common.LocalError("The plugin you're trying to deactivate isn't active", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if !active { - return LocalError("The plugin you're trying to deactivate isn't active", w, r, user) + return common.LocalError("The plugin you're trying to deactivate isn't active", w, r, user) } _, err = stmts.updatePlugin.Exec(0, uname) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } plugin.Active = false - plugins[uname] = plugin - plugins[uname].Deactivate() + common.Plugins[uname] = plugin + common.Plugins[uname].Deactivate() http.Redirect(w, r, "/panel/plugins/", http.StatusSeeOther) return nil } -func routePanelPluginsInstall(w http.ResponseWriter, r *http.Request, user User, uname string) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelPluginsInstall(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManagePlugins { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } - plugin, ok := plugins[uname] + plugin, ok := common.Plugins[uname] if !ok { - return 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 { - return LocalError("This plugin is not installable", w, r, user) + return common.LocalError("This plugin is not installable", w, r, user) } - if plugin.Installed { - return LocalError("This plugin has already been installed", w, r, user) + return common.LocalError("This plugin has already been installed", w, r, user) } var active bool err := stmts.isPluginActive.QueryRow(uname).Scan(&active) if err != nil && err != ErrNoRows { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } var hasPlugin = (err == nil) - if plugins[uname].Install != nil { - err = plugins[uname].Install() + if common.Plugins[uname].Install != nil { + err = common.Plugins[uname].Install() if err != nil { - return LocalError(err.Error(), w, r, user) + return common.LocalError(err.Error(), w, r, user) } } - if plugins[uname].Activate != nil { - err = plugins[uname].Activate() + if common.Plugins[uname].Activate != nil { + err = common.Plugins[uname].Activate() if err != nil { - return LocalError(err.Error(), w, r, user) + return common.LocalError(err.Error(), w, r, user) } } if hasPlugin { _, err = stmts.updatePluginInstall.Exec(1, uname) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } _, err = stmts.updatePlugin.Exec(1, uname) - if err != nil { - return InternalError(err, w, r) - } } else { - _, err := stmts.addPlugin.Exec(uname, 1, 1) - if err != nil { - return InternalError(err, w, r) - } + _, err = stmts.addPlugin.Exec(uname, 1, 1) + } + if err != nil { + return common.InternalError(err, w, r) } - log.Print("Installing plugin '" + plugin.Name + "'") + log.Printf("Installing plugin '%s'", plugin.Name) plugin.Active = true plugin.Installed = true - plugins[uname] = plugin - err = plugins[uname].Init() + common.Plugins[uname] = plugin + err = common.Plugins[uname].Init() if err != nil { - return LocalError(err.Error(), w, r, user) + return common.LocalError(err.Error(), w, r, user) } http.Redirect(w, r, "/panel/plugins/", http.StatusSeeOther) return nil } -func routePanelUsers(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelUsers(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } page, _ := strconv.Atoi(r.FormValue("page")) perPage := 10 - offset, page, lastPage := pageOffset(stats.Users, page, perPage) + offset, page, lastPage := common.PageOffset(stats.Users, page, perPage) - var userList []User - // TODO: Move this into the UserStore + var userList []common.User + // TODO: Move this into the common.UserStore rows, err := stmts.getUsersOffset.Query(offset, perPage) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } defer rows.Close() - // TODO: Add a UserStore method for iterating over global users and global user offsets + // TODO: Add a common.UserStore method for iterating over global users and global user offsets for rows.Next() { - puser := &User{ID: 0} + puser := &common.User{ID: 0} err := rows.Scan(&puser.ID, &puser.Name, &puser.Group, &puser.Active, &puser.IsSuperAdmin, &puser.Avatar) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - puser.initPerms() + puser.InitPerms() if puser.Avatar != "" { if puser.Avatar[0] == '.' { puser.Avatar = "/uploads/avatar_" + strconv.Itoa(puser.ID) + puser.Avatar } } else { - puser.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(puser.ID), 1) + puser.Avatar = strings.Replace(common.Config.Noavatar, "{id}", strconv.Itoa(puser.ID), 1) } - if gstore.DirtyGet(puser.Group).Tag != "" { - puser.Tag = gstore.DirtyGet(puser.Group).Tag + if common.Gstore.DirtyGet(puser.Group).Tag != "" { + puser.Tag = common.Gstore.DirtyGet(puser.Group).Tag } else { puser.Tag = "" } @@ -1078,53 +1074,53 @@ func routePanelUsers(w http.ResponseWriter, r *http.Request, user User) RouteErr } err = rows.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - pageList := paginate(stats.Users, perPage, 5) - pi := PanelUserPage{"User Manager", user, headerVars, stats, userList, pageList, page, lastPage} - if preRenderHooks["pre_render_panel_users"] != nil { - if runPreRenderHook("pre_render_panel_users", w, r, &user, &pi) { + pageList := common.Paginate(stats.Users, perPage, 5) + pi := common.PanelUserPage{"User Manager", user, headerVars, stats, userList, pageList, page, lastPage} + if common.PreRenderHooks["pre_render_panel_users"] != nil { + if common.RunPreRenderHook("pre_render_panel_users", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "panel-users.html", pi) + err = common.Templates.ExecuteTemplate(w, "panel-users.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelUsersEdit(w http.ResponseWriter, r *http.Request, user User, suid string) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelUsersEdit(w http.ResponseWriter, r *http.Request, user common.User, suid string) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.EditUser { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } uid, err := strconv.Atoi(suid) if err != nil { - return LocalError("The provided User ID is not a valid number.", w, r, user) + return common.LocalError("The provided common.User ID is not a valid number.", w, r, user) } - targetUser, err := users.Get(uid) + targetUser, err := common.Users.Get(uid) if err == ErrNoRows { - return LocalError("The user you're trying to edit doesn't exist.", w, r, user) + return common.LocalError("The user you're trying to edit doesn't exist.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if targetUser.IsAdmin && !user.IsAdmin { - return LocalError("Only administrators can edit the account of an administrator.", w, r, user) + return common.LocalError("Only administrators can edit the account of an administrator.", w, r, user) } // ? - Should we stop admins from deleting all the groups? Maybe, protect the group they're currently using? - groups, err := gstore.GetRange(1, 0) // ? - 0 = Go to the end + groups, err := common.Gstore.GetRange(1, 0) // ? - 0 = Go to the end if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } var groupList []interface{} @@ -1138,117 +1134,114 @@ func routePanelUsersEdit(w http.ResponseWriter, r *http.Request, user User, suid groupList = append(groupList, group) } - pi := PanelPage{"User Editor", user, headerVars, stats, groupList, targetUser} - if preRenderHooks["pre_render_panel_edit_user"] != nil { - if runPreRenderHook("pre_render_panel_edit_user", w, r, &user, &pi) { + pi := common.PanelPage{"User Editor", user, headerVars, stats, groupList, targetUser} + if common.PreRenderHooks["pre_render_panel_edit_user"] != nil { + if common.RunPreRenderHook("pre_render_panel_edit_user", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "panel-user-edit.html", pi) + err = common.Templates.ExecuteTemplate(w, "panel-user-edit.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelUsersEditSubmit(w http.ResponseWriter, r *http.Request, user User, suid string) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelUsersEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, suid string) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.EditUser { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } uid, err := strconv.Atoi(suid) if err != nil { - return LocalError("The provided User ID is not a valid number.", w, r, user) + return common.LocalError("The provided common.User ID is not a valid number.", w, r, user) } - targetUser, err := users.Get(uid) + targetUser, err := common.Users.Get(uid) if err == ErrNoRows { - return LocalError("The user you're trying to edit doesn't exist.", w, r, user) + return common.LocalError("The user you're trying to edit doesn't exist.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if targetUser.IsAdmin && !user.IsAdmin { - return LocalError("Only administrators can edit the account of other administrators.", w, r, user) + return common.LocalError("Only administrators can edit the account of other administrators.", w, r, user) } newname := html.EscapeString(r.PostFormValue("user-name")) if newname == "" { - return LocalError("You didn't put in a username.", w, r, user) + return common.LocalError("You didn't put in a username.", w, r, user) } newemail := html.EscapeString(r.PostFormValue("user-email")) if newemail == "" { - return LocalError("You didn't put in an email address.", w, r, user) + return common.LocalError("You didn't put in an email address.", w, r, user) } if (newemail != targetUser.Email) && !user.Perms.EditUserEmail { - return LocalError("You need the EditUserEmail permission to edit the email address of a user.", w, r, user) + return common.LocalError("You need the EditUserEmail permission to edit the email address of a user.", w, r, user) } newpassword := r.PostFormValue("user-password") if newpassword != "" && !user.Perms.EditUserPassword { - return LocalError("You need the EditUserPassword permission to edit the password of a user.", w, r, user) + return common.LocalError("You need the EditUserPassword permission to edit the password of a user.", w, r, user) } newgroup, err := strconv.Atoi(r.PostFormValue("user-group")) if err != nil { - return LocalError("You need to provide a whole number for the group ID", w, r, user) + return common.LocalError("You need to provide a whole number for the group ID", w, r, user) } - group, err := gstore.Get(newgroup) + group, err := common.Gstore.Get(newgroup) if err == ErrNoRows { - return LocalError("The group you're trying to place this user in doesn't exist.", w, r, user) + return common.LocalError("The group you're trying to place this user in doesn't exist.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if !user.Perms.EditUserGroupAdmin && group.IsAdmin { - return LocalError("You need the EditUserGroupAdmin permission to assign someone to an administrator group.", w, r, user) + return common.LocalError("You need the EditUserGroupAdmin permission to assign someone to an administrator group.", w, r, user) } if !user.Perms.EditUserGroupSuperMod && group.IsMod { - return LocalError("You need the EditUserGroupSuperMod permission to assign someone to a super mod group.", w, r, user) + return common.LocalError("You need the EditUserGroupSuperMod permission to assign someone to a super mod group.", w, r, user) } _, err = stmts.updateUser.Exec(newname, newemail, newgroup, targetUser.ID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if newpassword != "" { - SetPassword(targetUser.ID, newpassword) + common.SetPassword(targetUser.ID, newpassword) } - ucache, ok := users.(UserCache) - if ok { - ucache.CacheRemove(targetUser.ID) - } + targetUser.CacheRemove() http.Redirect(w, r, "/panel/users/edit/"+strconv.Itoa(targetUser.ID), http.StatusSeeOther) return nil } -func routePanelGroups(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelGroups(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } page, _ := strconv.Atoi(r.FormValue("page")) perPage := 9 - offset, page, lastPage := pageOffset(stats.Groups, page, perPage) + offset, page, lastPage := common.PageOffset(stats.Groups, page, perPage) // Skip the 'Unknown' group offset++ var count int - var groupList []GroupAdmin - groups, _ := gstore.GetRange(offset, 0) + var groupList []common.GroupAdmin + groups, _ := common.Gstore.GetRange(offset, 0) for _, group := range groups { if count == perPage { break @@ -1277,53 +1270,53 @@ func routePanelGroups(w http.ResponseWriter, r *http.Request, user User) RouteEr } canEdit = user.Perms.EditGroup && (!group.IsAdmin || user.Perms.EditGroupAdmin) && (!group.IsMod || user.Perms.EditGroupSuperMod) - groupList = append(groupList, GroupAdmin{group.ID, group.Name, rank, rankClass, canEdit, canDelete}) + groupList = append(groupList, common.GroupAdmin{group.ID, group.Name, rank, rankClass, canEdit, canDelete}) count++ } //log.Printf("groupList: %+v\n", groupList) - pageList := paginate(stats.Groups, perPage, 5) - pi := PanelGroupPage{"Group Manager", user, headerVars, stats, groupList, pageList, page, lastPage} - if preRenderHooks["pre_render_panel_groups"] != nil { - if runPreRenderHook("pre_render_panel_groups", w, r, &user, &pi) { + pageList := common.Paginate(stats.Groups, perPage, 5) + pi := common.PanelGroupPage{"Group Manager", user, headerVars, stats, groupList, pageList, page, lastPage} + if common.PreRenderHooks["pre_render_panel_groups"] != nil { + if common.RunPreRenderHook("pre_render_panel_groups", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "panel-groups.html", pi) + err := common.Templates.ExecuteTemplate(w, "panel-groups.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelGroupsEdit(w http.ResponseWriter, r *http.Request, user User, sgid string) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelGroupsEdit(w http.ResponseWriter, r *http.Request, user common.User, sgid string) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.EditGroup { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } gid, err := strconv.Atoi(sgid) if err != nil { - return LocalError("You need to provide a whole number for the group ID", w, r, user) + return common.LocalError("You need to provide a whole number for the group ID", w, r, user) } - group, err := gstore.Get(gid) + group, err := common.Gstore.Get(gid) if err == ErrNoRows { //log.Print("aaaaa monsters") - return NotFound(w, r) + return common.NotFound(w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if group.IsAdmin && !user.Perms.EditGroupAdmin { - return LocalError("You need the EditGroupAdmin permission to edit an admin group.", w, r, user) + return common.LocalError("You need the EditGroupAdmin permission to edit an admin group.", w, r, user) } if group.IsMod && !user.Perms.EditGroupSuperMod { - return 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 rank string @@ -1342,132 +1335,132 @@ func routePanelGroupsEdit(w http.ResponseWriter, r *http.Request, user User, sgi disableRank := !user.Perms.EditGroupGlobalPerms || (group.ID == 6) - pi := PanelEditGroupPage{"Group Editor", user, headerVars, stats, group.ID, group.Name, group.Tag, rank, disableRank} - if preRenderHooks["pre_render_panel_edit_group"] != nil { - if runPreRenderHook("pre_render_panel_edit_group", w, r, &user, &pi) { + pi := common.PanelEditGroupPage{"Group Editor", user, headerVars, stats, group.ID, group.Name, group.Tag, rank, disableRank} + if common.PreRenderHooks["pre_render_panel_edit_group"] != nil { + if common.RunPreRenderHook("pre_render_panel_edit_group", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "panel-group-edit.html", pi) + err = common.Templates.ExecuteTemplate(w, "panel-group-edit.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelGroupsEditPerms(w http.ResponseWriter, r *http.Request, user User, sgid string) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelGroupsEditPerms(w http.ResponseWriter, r *http.Request, user common.User, sgid string) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.EditGroup { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } gid, err := strconv.Atoi(sgid) if err != nil { - return LocalError("The Group ID is not a valid integer.", w, r, user) + return common.LocalError("The Group ID is not a valid integer.", w, r, user) } - group, err := gstore.Get(gid) + group, err := common.Gstore.Get(gid) if err == ErrNoRows { //log.Print("aaaaa monsters") - return NotFound(w, r) + return common.NotFound(w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if group.IsAdmin && !user.Perms.EditGroupAdmin { - return LocalError("You need the EditGroupAdmin permission to edit an admin group.", w, r, user) + return common.LocalError("You need the EditGroupAdmin permission to edit an admin group.", w, r, user) } if group.IsMod && !user.Perms.EditGroupSuperMod { - return 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) } // TODO: Load the phrases in bulk for efficiency? - var localPerms []NameLangToggle - localPerms = append(localPerms, NameLangToggle{"ViewTopic", GetLocalPermPhrase("ViewTopic"), group.Perms.ViewTopic}) - localPerms = append(localPerms, NameLangToggle{"LikeItem", GetLocalPermPhrase("LikeItem"), group.Perms.LikeItem}) - localPerms = append(localPerms, NameLangToggle{"CreateTopic", GetLocalPermPhrase("CreateTopic"), group.Perms.CreateTopic}) + var localPerms []common.NameLangToggle + localPerms = append(localPerms, common.NameLangToggle{"ViewTopic", common.GetLocalPermPhrase("ViewTopic"), group.Perms.ViewTopic}) + localPerms = append(localPerms, common.NameLangToggle{"LikeItem", common.GetLocalPermPhrase("LikeItem"), group.Perms.LikeItem}) + localPerms = append(localPerms, common.NameLangToggle{"CreateTopic", common.GetLocalPermPhrase("CreateTopic"), group.Perms.CreateTopic}) //<-- - localPerms = append(localPerms, NameLangToggle{"EditTopic", GetLocalPermPhrase("EditTopic"), group.Perms.EditTopic}) - localPerms = append(localPerms, NameLangToggle{"DeleteTopic", GetLocalPermPhrase("DeleteTopic"), group.Perms.DeleteTopic}) - localPerms = append(localPerms, NameLangToggle{"CreateReply", GetLocalPermPhrase("CreateReply"), group.Perms.CreateReply}) - localPerms = append(localPerms, NameLangToggle{"EditReply", GetLocalPermPhrase("EditReply"), group.Perms.EditReply}) - localPerms = append(localPerms, NameLangToggle{"DeleteReply", GetLocalPermPhrase("DeleteReply"), group.Perms.DeleteReply}) - localPerms = append(localPerms, NameLangToggle{"PinTopic", GetLocalPermPhrase("PinTopic"), group.Perms.PinTopic}) - localPerms = append(localPerms, NameLangToggle{"CloseTopic", GetLocalPermPhrase("CloseTopic"), group.Perms.CloseTopic}) + localPerms = append(localPerms, common.NameLangToggle{"EditTopic", common.GetLocalPermPhrase("EditTopic"), group.Perms.EditTopic}) + localPerms = append(localPerms, common.NameLangToggle{"DeleteTopic", common.GetLocalPermPhrase("DeleteTopic"), group.Perms.DeleteTopic}) + localPerms = append(localPerms, common.NameLangToggle{"CreateReply", common.GetLocalPermPhrase("CreateReply"), group.Perms.CreateReply}) + localPerms = append(localPerms, common.NameLangToggle{"EditReply", common.GetLocalPermPhrase("EditReply"), group.Perms.EditReply}) + localPerms = append(localPerms, common.NameLangToggle{"DeleteReply", common.GetLocalPermPhrase("DeleteReply"), group.Perms.DeleteReply}) + localPerms = append(localPerms, common.NameLangToggle{"PinTopic", common.GetLocalPermPhrase("PinTopic"), group.Perms.PinTopic}) + localPerms = append(localPerms, common.NameLangToggle{"CloseTopic", common.GetLocalPermPhrase("CloseTopic"), group.Perms.CloseTopic}) - var globalPerms []NameLangToggle - globalPerms = append(globalPerms, NameLangToggle{"BanUsers", GetGlobalPermPhrase("BanUsers"), group.Perms.BanUsers}) - globalPerms = append(globalPerms, NameLangToggle{"ActivateUsers", GetGlobalPermPhrase("ActivateUsers"), group.Perms.ActivateUsers}) - globalPerms = append(globalPerms, NameLangToggle{"EditUser", GetGlobalPermPhrase("EditUser"), group.Perms.EditUser}) - globalPerms = append(globalPerms, NameLangToggle{"EditUserEmail", GetGlobalPermPhrase("EditUserEmail"), group.Perms.EditUserEmail}) - globalPerms = append(globalPerms, NameLangToggle{"EditUserPassword", GetGlobalPermPhrase("EditUserPassword"), group.Perms.EditUserPassword}) - globalPerms = append(globalPerms, NameLangToggle{"EditUserGroup", GetGlobalPermPhrase("EditUserGroup"), group.Perms.EditUserGroup}) - globalPerms = append(globalPerms, NameLangToggle{"EditUserGroupSuperMod", GetGlobalPermPhrase("EditUserGroupSuperMod"), group.Perms.EditUserGroupSuperMod}) - globalPerms = append(globalPerms, NameLangToggle{"EditUserGroupAdmin", GetGlobalPermPhrase("EditUserGroupAdmin"), group.Perms.EditUserGroupAdmin}) - globalPerms = append(globalPerms, NameLangToggle{"EditGroup", GetGlobalPermPhrase("EditGroup"), group.Perms.EditGroup}) - globalPerms = append(globalPerms, NameLangToggle{"EditGroupLocalPerms", GetGlobalPermPhrase("EditGroupLocalPerms"), group.Perms.EditGroupLocalPerms}) - globalPerms = append(globalPerms, NameLangToggle{"EditGroupGlobalPerms", GetGlobalPermPhrase("EditGroupGlobalPerms"), group.Perms.EditGroupGlobalPerms}) - globalPerms = append(globalPerms, NameLangToggle{"EditGroupSuperMod", GetGlobalPermPhrase("EditGroupSuperMod"), group.Perms.EditGroupSuperMod}) - globalPerms = append(globalPerms, NameLangToggle{"EditGroupAdmin", GetGlobalPermPhrase("EditGroupAdmin"), group.Perms.EditGroupAdmin}) - globalPerms = append(globalPerms, NameLangToggle{"ManageForums", GetGlobalPermPhrase("ManageForums"), group.Perms.ManageForums}) - globalPerms = append(globalPerms, NameLangToggle{"EditSettings", GetGlobalPermPhrase("EditSettings"), group.Perms.EditSettings}) - globalPerms = append(globalPerms, NameLangToggle{"ManageThemes", GetGlobalPermPhrase("ManageThemes"), group.Perms.ManageThemes}) - globalPerms = append(globalPerms, NameLangToggle{"ManagePlugins", GetGlobalPermPhrase("ManagePlugins"), group.Perms.ManagePlugins}) - globalPerms = append(globalPerms, NameLangToggle{"ViewAdminLogs", GetGlobalPermPhrase("ViewAdminLogs"), group.Perms.ViewAdminLogs}) - globalPerms = append(globalPerms, NameLangToggle{"ViewIPs", GetGlobalPermPhrase("ViewIPs"), group.Perms.ViewIPs}) - globalPerms = append(globalPerms, NameLangToggle{"UploadFiles", GetGlobalPermPhrase("UploadFiles"), group.Perms.UploadFiles}) + var globalPerms []common.NameLangToggle + globalPerms = append(globalPerms, common.NameLangToggle{"BanUsers", common.GetGlobalPermPhrase("BanUsers"), group.Perms.BanUsers}) + globalPerms = append(globalPerms, common.NameLangToggle{"ActivateUsers", common.GetGlobalPermPhrase("ActivateUsers"), group.Perms.ActivateUsers}) + globalPerms = append(globalPerms, common.NameLangToggle{"EditUser", common.GetGlobalPermPhrase("EditUser"), group.Perms.EditUser}) + globalPerms = append(globalPerms, common.NameLangToggle{"EditUserEmail", common.GetGlobalPermPhrase("EditUserEmail"), group.Perms.EditUserEmail}) + globalPerms = append(globalPerms, common.NameLangToggle{"EditUserPassword", common.GetGlobalPermPhrase("EditUserPassword"), group.Perms.EditUserPassword}) + globalPerms = append(globalPerms, common.NameLangToggle{"EditUserGroup", common.GetGlobalPermPhrase("EditUserGroup"), group.Perms.EditUserGroup}) + globalPerms = append(globalPerms, common.NameLangToggle{"EditUserGroupSuperMod", common.GetGlobalPermPhrase("EditUserGroupSuperMod"), group.Perms.EditUserGroupSuperMod}) + globalPerms = append(globalPerms, common.NameLangToggle{"EditUserGroupAdmin", common.GetGlobalPermPhrase("EditUserGroupAdmin"), group.Perms.EditUserGroupAdmin}) + globalPerms = append(globalPerms, common.NameLangToggle{"EditGroup", common.GetGlobalPermPhrase("EditGroup"), group.Perms.EditGroup}) + globalPerms = append(globalPerms, common.NameLangToggle{"EditGroupLocalPerms", common.GetGlobalPermPhrase("EditGroupLocalPerms"), group.Perms.EditGroupLocalPerms}) + globalPerms = append(globalPerms, common.NameLangToggle{"EditGroupGlobalPerms", common.GetGlobalPermPhrase("EditGroupGlobalPerms"), group.Perms.EditGroupGlobalPerms}) + globalPerms = append(globalPerms, common.NameLangToggle{"EditGroupSuperMod", common.GetGlobalPermPhrase("EditGroupSuperMod"), group.Perms.EditGroupSuperMod}) + globalPerms = append(globalPerms, common.NameLangToggle{"EditGroupAdmin", common.GetGlobalPermPhrase("EditGroupAdmin"), group.Perms.EditGroupAdmin}) + globalPerms = append(globalPerms, common.NameLangToggle{"ManageForums", common.GetGlobalPermPhrase("ManageForums"), group.Perms.ManageForums}) + globalPerms = append(globalPerms, common.NameLangToggle{"EditSettings", common.GetGlobalPermPhrase("EditSettings"), group.Perms.EditSettings}) + globalPerms = append(globalPerms, common.NameLangToggle{"ManageThemes", common.GetGlobalPermPhrase("ManageThemes"), group.Perms.ManageThemes}) + globalPerms = append(globalPerms, common.NameLangToggle{"ManagePlugins", common.GetGlobalPermPhrase("ManagePlugins"), group.Perms.ManagePlugins}) + globalPerms = append(globalPerms, common.NameLangToggle{"ViewAdminLogs", common.GetGlobalPermPhrase("ViewAdminLogs"), group.Perms.ViewAdminLogs}) + globalPerms = append(globalPerms, common.NameLangToggle{"ViewIPs", common.GetGlobalPermPhrase("ViewIPs"), group.Perms.ViewIPs}) + globalPerms = append(globalPerms, common.NameLangToggle{"UploadFiles", common.GetGlobalPermPhrase("UploadFiles"), group.Perms.UploadFiles}) - pi := PanelEditGroupPermsPage{"Group Editor", user, headerVars, stats, group.ID, group.Name, localPerms, globalPerms} - if preRenderHooks["pre_render_panel_edit_group_perms"] != nil { - if runPreRenderHook("pre_render_panel_edit_group_perms", w, r, &user, &pi) { + pi := common.PanelEditGroupPermsPage{"Group Editor", user, headerVars, stats, group.ID, group.Name, localPerms, globalPerms} + if common.PreRenderHooks["pre_render_panel_edit_group_perms"] != nil { + if common.RunPreRenderHook("pre_render_panel_edit_group_perms", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "panel-group-edit-perms.html", pi) + err = common.Templates.ExecuteTemplate(w, "panel-group-edit-perms.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelGroupsEditSubmit(w http.ResponseWriter, r *http.Request, user User, sgid string) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelGroupsEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, sgid string) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.EditGroup { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } gid, err := strconv.Atoi(sgid) if err != nil { - return LocalError("You need to provide a whole number for the group ID", w, r, user) + return common.LocalError("You need to provide a whole number for the group ID", w, r, user) } - group, err := gstore.Get(gid) + group, err := common.Gstore.Get(gid) if err == ErrNoRows { //log.Print("aaaaa monsters") - return NotFound(w, r) + return common.NotFound(w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if group.IsAdmin && !user.Perms.EditGroupAdmin { - return LocalError("You need the EditGroupAdmin permission to edit an admin group.", w, r, user) + return common.LocalError("You need the EditGroupAdmin permission to edit an admin group.", w, r, user) } if group.IsMod && !user.Perms.EditGroupSuperMod { - return 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) } gname := r.FormValue("group-name") if gname == "" { - return LocalError("The group name can't be left blank.", w, r, user) + return common.LocalError("The group name can't be left blank.", w, r, user) } gtag := r.FormValue("group-tag") rank := r.FormValue("group-type") @@ -1487,82 +1480,81 @@ func routePanelGroupsEditSubmit(w http.ResponseWriter, r *http.Request, user Use if rank != originalRank { if !user.Perms.EditGroupGlobalPerms { - return LocalError("You need the EditGroupGlobalPerms permission to change the group type.", w, r, user) + return common.LocalError("You need the EditGroupGlobalPerms permission to change the group type.", w, r, user) } switch rank { case "Admin": if !user.Perms.EditGroupAdmin { - return LocalError("You need the EditGroupAdmin permission to designate this group as an admin group.", w, r, user) + return common.LocalError("You need the EditGroupAdmin permission to designate this group as an admin group.", w, r, user) } err = group.ChangeRank(true, true, false) case "Mod": if !user.Perms.EditGroupSuperMod { - return LocalError("You need the EditGroupSuperMod permission to designate this group as a super-mod group.", w, r, user) + return common.LocalError("You need the EditGroupSuperMod permission to designate this group as a super-mod group.", w, r, user) } err = group.ChangeRank(false, true, false) case "Banned": err = group.ChangeRank(false, false, true) case "Guest": - return LocalError("You can't designate a group as a guest group.", w, r, user) + return common.LocalError("You can't designate a group as a guest group.", w, r, user) case "Member": err = group.ChangeRank(false, false, false) default: - return LocalError("Invalid group type.", w, r, user) + return common.LocalError("Invalid group type.", w, r, user) } if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } // TODO: Move this to *Group _, err = stmts.updateGroup.Exec(gname, gtag, gid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - gstore.Reload(gid) + common.Gstore.Reload(gid) http.Redirect(w, r, "/panel/groups/edit/"+strconv.Itoa(gid), http.StatusSeeOther) return nil } -func routePanelGroupsEditPermsSubmit(w http.ResponseWriter, r *http.Request, user User, sgid string) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelGroupsEditPermsSubmit(w http.ResponseWriter, r *http.Request, user common.User, sgid string) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.EditGroup { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } gid, err := strconv.Atoi(sgid) if err != nil { - return LocalError("The Group ID is not a valid integer.", w, r, user) + return common.LocalError("The Group ID is not a valid integer.", w, r, user) } - group, err := gstore.Get(gid) + group, err := common.Gstore.Get(gid) if err == ErrNoRows { //log.Print("aaaaa monsters o.o") - return NotFound(w, r) + return common.NotFound(w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if group.IsAdmin && !user.Perms.EditGroupAdmin { - return LocalError("You need the EditGroupAdmin permission to edit an admin group.", w, r, user) + return common.LocalError("You need the EditGroupAdmin permission to edit an admin group.", w, r, user) } if group.IsMod && !user.Perms.EditGroupSuperMod { - return 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) if user.Perms.EditGroupLocalPerms { - pplist := LocalPermList - for _, perm := range pplist { + for _, perm := range common.LocalPermList { pvalue := r.PostFormValue("group-perm-" + perm) pmap[perm] = (pvalue == "1") } @@ -1570,8 +1562,7 @@ func routePanelGroupsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use ////var gpmap map[string]bool = make(map[string]bool) if user.Perms.EditGroupGlobalPerms { - gplist := GlobalPermList - for _, perm := range gplist { + for _, perm := range common.GlobalPermList { pvalue := r.PostFormValue("group-perm-" + perm) pmap[perm] = (pvalue == "1") } @@ -1579,36 +1570,36 @@ func routePanelGroupsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use pjson, err := json.Marshal(pmap) if err != nil { - return LocalError("Unable to marshal the data", w, r, user) + return common.LocalError("Unable to marshal the data", w, r, user) } _, err = stmts.updateGroupPerms.Exec(pjson, gid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - err = rebuildGroupPermissions(gid) + err = common.RebuildGroupPermissions(gid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } http.Redirect(w, r, "/panel/groups/edit/perms/"+strconv.Itoa(gid), http.StatusSeeOther) return nil } -func routePanelGroupsCreateSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelGroupsCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.EditGroup { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } groupName := r.PostFormValue("group-name") if groupName == "" { - return LocalError("You need a name for this group!", w, r, user) + return common.LocalError("You need a name for this group!", w, r, user) } groupTag := r.PostFormValue("group-tag") @@ -1617,13 +1608,13 @@ func routePanelGroupsCreateSubmit(w http.ResponseWriter, r *http.Request, user U groupType := r.PostFormValue("group-type") if groupType == "Admin" { if !user.Perms.EditGroupAdmin { - return LocalError("You need the EditGroupAdmin permission to create admin groups", w, r, user) + return common.LocalError("You need the EditGroupAdmin permission to create admin groups", w, r, user) } isAdmin = true isMod = true } else if groupType == "Mod" { if !user.Perms.EditGroupSuperMod { - return LocalError("You need the EditGroupSuperMod permission to create admin groups", w, r, user) + return common.LocalError("You need the EditGroupSuperMod permission to create admin groups", w, r, user) } isMod = true } else if groupType == "Banned" { @@ -1631,25 +1622,25 @@ func routePanelGroupsCreateSubmit(w http.ResponseWriter, r *http.Request, user U } } - gid, err := gstore.Create(groupName, groupTag, isAdmin, isMod, isBanned) + gid, err := common.Gstore.Create(groupName, groupTag, isAdmin, isMod, isBanned) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } http.Redirect(w, r, "/panel/groups/edit/"+strconv.Itoa(gid), http.StatusSeeOther) return nil } -func routePanelThemes(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelThemes(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManageThemes { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } - var pThemeList, vThemeList []Theme - for _, theme := range themes { + var pThemeList, vThemeList []common.Theme + for _, theme := range common.Themes { if theme.HideFromThemes { continue } @@ -1661,109 +1652,110 @@ func routePanelThemes(w http.ResponseWriter, r *http.Request, user User) RouteEr } - pi := PanelThemesPage{"Theme Manager", user, headerVars, stats, pThemeList, vThemeList} - if preRenderHooks["pre_render_panel_themes"] != nil { - if runPreRenderHook("pre_render_panel_themes", w, r, &user, &pi) { + pi := common.PanelThemesPage{"Theme Manager", user, headerVars, stats, pThemeList, vThemeList} + if common.PreRenderHooks["pre_render_panel_themes"] != nil { + if common.RunPreRenderHook("pre_render_panel_themes", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "panel-themes.html", pi) + err := common.Templates.ExecuteTemplate(w, "panel-themes.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelThemesSetDefault(w http.ResponseWriter, r *http.Request, user User, uname string) RouteError { - _, ferr := SimplePanelUserCheck(w, r, &user) +func routePanelThemesSetDefault(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError { + _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManageThemes { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if r.FormValue("session") != user.Session { - return SecurityError(w, r, user) + return common.SecurityError(w, r, user) } - theme, ok := themes[uname] + theme, ok := common.Themes[uname] if !ok { - return LocalError("The theme isn't registered in the system", w, r, user) + return common.LocalError("The theme isn't registered in the system", w, r, user) } if theme.Disabled { - return LocalError("You must not enable this theme", w, r, user) + return common.LocalError("You must not enable this theme", w, r, user) } var isDefault bool log.Print("uname", uname) // TODO: Do we need to log this? err := stmts.isThemeDefault.QueryRow(uname).Scan(&isDefault) if err != nil && err != ErrNoRows { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } hasTheme := err != ErrNoRows if hasTheme { log.Print("isDefault", isDefault) // TODO: Do we need to log this? if isDefault { - return 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) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } else { _, err := stmts.addTheme.Exec(uname, 1) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } // TODO: Make this less racey - changeDefaultThemeMutex.Lock() - defaultTheme := defaultThemeBox.Load().(string) + // TODO: Move this to common + common.ChangeDefaultThemeMutex.Lock() + defaultTheme := common.DefaultThemeBox.Load().(string) _, err = stmts.updateTheme.Exec(0, defaultTheme) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - log.Print("Setting theme '" + theme.Name + "' as the default theme") + log.Printf("Setting theme '%s' as the default theme", theme.Name) theme.Active = true - themes[uname] = theme + common.Themes[uname] = theme - dTheme, ok := themes[defaultTheme] + dTheme, ok := common.Themes[defaultTheme] if !ok { - return InternalError(errors.New("The default theme is missing"), w, r) + return common.InternalError(errors.New("The default theme is missing"), w, r) } dTheme.Active = false - themes[defaultTheme] = dTheme + common.Themes[defaultTheme] = dTheme - defaultThemeBox.Store(uname) - resetTemplateOverrides() - mapThemeTemplates(theme) - changeDefaultThemeMutex.Unlock() + common.DefaultThemeBox.Store(uname) + common.ResetTemplateOverrides() + common.MapThemeTemplates(theme) + common.ChangeDefaultThemeMutex.Unlock() http.Redirect(w, r, "/panel/themes/", http.StatusSeeOther) return nil } -func routePanelBackups(w http.ResponseWriter, r *http.Request, user User, backupURL string) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelBackups(w http.ResponseWriter, r *http.Request, user common.User, backupURL string) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.IsSuperAdmin { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } if backupURL != "" { // We don't want them trying to break out of this directory, it shouldn't hurt since it's a super admin, but it's always good to practice good security hygiene, especially if this is one of many instances on a managed server not controlled by the superadmin/s - backupURL = Stripslashes(backupURL) + backupURL = common.Stripslashes(backupURL) var ext = filepath.Ext("./backups/" + backupURL) if ext == ".sql" { info, err := os.Stat("./backups/" + backupURL) if err != nil { - return NotFound(w, r) + return common.NotFound(w, r) } // TODO: Change the served filename to gosora_backup_%timestamp%.sql, the time the file was generated, not when it was modified aka what the name of it should be w.Header().Set("Content-Disposition", "attachment; filename=gosora_backup.sql") @@ -1772,32 +1764,32 @@ func routePanelBackups(w http.ResponseWriter, r *http.Request, user User, backup http.ServeFile(w, r, "./backups/"+backupURL) return nil } - return NotFound(w, r) + return common.NotFound(w, r) } - var backupList []backupItem + var backupList []common.BackupItem backupFiles, err := ioutil.ReadDir("./backups") if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } for _, backupFile := range backupFiles { var ext = filepath.Ext(backupFile.Name()) if ext != ".sql" { continue } - backupList = append(backupList, backupItem{backupFile.Name(), backupFile.ModTime()}) + backupList = append(backupList, common.BackupItem{backupFile.Name(), backupFile.ModTime()}) } - pi := PanelBackupPage{"Backups", user, headerVars, stats, backupList} - err = templates.ExecuteTemplate(w, "panel-backups.html", pi) + pi := common.PanelBackupPage{"Backups", user, headerVars, stats, backupList} + err = common.Templates.ExecuteTemplate(w, "panel-backups.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelLogsMod(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelLogsMod(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } @@ -1805,117 +1797,119 @@ func routePanelLogsMod(w http.ResponseWriter, r *http.Request, user User) RouteE var logCount int err := stmts.modlogCount.QueryRow().Scan(&logCount) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } page, _ := strconv.Atoi(r.FormValue("page")) perPage := 10 - offset, page, lastPage := pageOffset(logCount, page, perPage) + offset, page, lastPage := common.PageOffset(logCount, page, perPage) rows, err := stmts.getModlogsOffset.Query(offset, perPage) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } defer rows.Close() - var logs []logItem + var logs []common.LogItem var action, elementType, ipaddress, doneAt string var elementID, actorID int for rows.Next() { err := rows.Scan(&action, &elementID, &elementType, &ipaddress, &actorID, &doneAt) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - actor, err := users.Get(actorID) + actor, err := common.Users.Get(actorID) if err != nil { - actor = &User{Name: "Unknown", Link: buildProfileURL("unknown", 0)} + actor = &common.User{Name: "Unknown", Link: common.BuildProfileURL("unknown", 0)} } switch action { case "lock": - topic, err := topics.Get(elementID) + topic, err := common.Topics.Get(elementID) if err != nil { - topic = &Topic{Title: "Unknown", Link: buildProfileURL("unknown", 0)} + topic = &common.Topic{Title: "Unknown", Link: common.BuildProfileURL("unknown", 0)} } action = "" + topic.Title + " was locked by " + actor.Name + "" case "unlock": - topic, err := topics.Get(elementID) + topic, err := common.Topics.Get(elementID) if err != nil { - topic = &Topic{Title: "Unknown", Link: buildProfileURL("unknown", 0)} + topic = &common.Topic{Title: "Unknown", Link: common.BuildProfileURL("unknown", 0)} } action = "" + topic.Title + " was reopened by " + actor.Name + "" case "stick": - topic, err := topics.Get(elementID) + topic, err := common.Topics.Get(elementID) if err != nil { - topic = &Topic{Title: "Unknown", Link: buildProfileURL("unknown", 0)} + topic = &common.Topic{Title: "Unknown", Link: common.BuildProfileURL("unknown", 0)} } action = "" + topic.Title + " was pinned by " + actor.Name + "" case "unstick": - topic, err := topics.Get(elementID) + topic, err := common.Topics.Get(elementID) if err != nil { - topic = &Topic{Title: "Unknown", Link: buildProfileURL("unknown", 0)} + topic = &common.Topic{Title: "Unknown", Link: common.BuildProfileURL("unknown", 0)} } action = "" + topic.Title + " was unpinned by " + actor.Name + "" case "delete": if elementType == "topic" { action = "Topic #" + strconv.Itoa(elementID) + " was deleted by " + actor.Name + "" } else { - topic, err := getTopicByReply(elementID) + reply := common.BlankReply() + reply.ID = elementID + topic, err := reply.Topic() if err != nil { - topic = &Topic{Title: "Unknown", Link: buildProfileURL("unknown", 0)} + topic = &common.Topic{Title: "Unknown", Link: common.BuildProfileURL("unknown", 0)} } action = "A reply in " + topic.Title + " was deleted by " + actor.Name + "" } case "ban": - targetUser, err := users.Get(elementID) + targetUser, err := common.Users.Get(elementID) if err != nil { - targetUser = &User{Name: "Unknown", Link: buildProfileURL("unknown", 0)} + targetUser = &common.User{Name: "Unknown", Link: common.BuildProfileURL("unknown", 0)} } action = "" + targetUser.Name + " was banned by " + actor.Name + "" case "unban": - targetUser, err := users.Get(elementID) + targetUser, err := common.Users.Get(elementID) if err != nil { - targetUser = &User{Name: "Unknown", Link: buildProfileURL("unknown", 0)} + targetUser = &common.User{Name: "Unknown", Link: common.BuildProfileURL("unknown", 0)} } action = "" + targetUser.Name + " was unbanned by " + actor.Name + "" case "activate": - targetUser, err := users.Get(elementID) + targetUser, err := common.Users.Get(elementID) if err != nil { - targetUser = &User{Name: "Unknown", Link: buildProfileURL("unknown", 0)} + targetUser = &common.User{Name: "Unknown", Link: common.BuildProfileURL("unknown", 0)} } action = "" + targetUser.Name + " was activated by " + actor.Name + "" default: action = "Unknown action '" + action + "' by " + actor.Name + "" } - logs = append(logs, logItem{Action: template.HTML(action), IPAddress: ipaddress, DoneAt: doneAt}) + logs = append(logs, common.LogItem{Action: template.HTML(action), IPAddress: ipaddress, DoneAt: doneAt}) } err = rows.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - pageList := paginate(logCount, perPage, 5) - pi := PanelLogsPage{"Moderation Logs", user, headerVars, stats, logs, pageList, page, lastPage} - if preRenderHooks["pre_render_panel_mod_log"] != nil { - if runPreRenderHook("pre_render_panel_mod_log", w, r, &user, &pi) { + pageList := common.Paginate(logCount, perPage, 5) + pi := common.PanelLogsPage{"Moderation Logs", user, headerVars, stats, logs, pageList, page, lastPage} + if common.PreRenderHooks["pre_render_panel_mod_log"] != nil { + if common.RunPreRenderHook("pre_render_panel_mod_log", w, r, &user, &pi) { return nil } } - err = templates.ExecuteTemplate(w, "panel-modlogs.html", pi) + err = common.Templates.ExecuteTemplate(w, "panel-modlogs.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routePanelDebug(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, stats, ferr := PanelUserCheck(w, r, &user) +func routePanelDebug(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.IsAdmin { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } uptime := "..." @@ -1923,10 +1917,10 @@ func routePanelDebug(w http.ResponseWriter, r *http.Request, user User) RouteErr openConnCount := dbStats.OpenConnections // Disk I/O? - pi := PanelDebugPage{"Debug", user, headerVars, stats, uptime, openConnCount, dbAdapter} - err := templates.ExecuteTemplate(w, "panel-debug.html", pi) + pi := common.PanelDebugPage{"Debug", user, headerVars, stats, uptime, openConnCount, dbAdapter} + err := common.Templates.ExecuteTemplate(w, "panel-debug.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } diff --git a/plugin_bbcode.go b/plugin_bbcode.go index de9db304..a42ef564 100644 --- a/plugin_bbcode.go +++ b/plugin_bbcode.go @@ -10,9 +10,11 @@ import ( "regexp" "strconv" "time" + + "./common" ) -var random *rand.Rand +var bbcodeRandom *rand.Rand var bbcodeInvalidNumber []byte var bbcodeNoNegative []byte var bbcodeMissingTag []byte @@ -27,12 +29,12 @@ var bbcodeQuotes *regexp.Regexp var bbcodeCode *regexp.Regexp func init() { - plugins["bbcode"] = NewPlugin("bbcode", "BBCode", "Azareal", "http://github.com/Azareal", "", "", "", initBbcode, nil, deactivateBbcode, nil, nil) + common.Plugins["bbcode"] = common.NewPlugin("bbcode", "BBCode", "Azareal", "http://github.com/Azareal", "", "", "", initBbcode, nil, deactivateBbcode, nil, nil) } func initBbcode() error { //plugins["bbcode"].AddHook("parse_assign", bbcode_parse_without_code) - plugins["bbcode"].AddHook("parse_assign", bbcodeFullParse) + common.Plugins["bbcode"].AddHook("parse_assign", bbcodeFullParse) bbcodeInvalidNumber = []byte("[Invalid Number]") bbcodeNoNegative = []byte("[No Negative Numbers]") @@ -48,13 +50,12 @@ func initBbcode() error { bbcodeQuotes = regexp.MustCompile(`\[quote\](.*)\[/quote\]`) bbcodeCode = regexp.MustCompile(`\[code\](.*)\[/code\]`) - random = rand.New(rand.NewSource(time.Now().UnixNano())) + bbcodeRandom = rand.New(rand.NewSource(time.Now().UnixNano())) return nil } func deactivateBbcode() { - //plugins["bbcode"].RemoveHook("parse_assign", bbcode_parse_without_code) - plugins["bbcode"].RemoveHook("parse_assign", bbcodeFullParse) + common.Plugins["bbcode"].RemoveHook("parse_assign", bbcodeFullParse) } func bbcodeRegexParse(msg string) string { @@ -213,7 +214,7 @@ func bbcodeFullParse(msg string) string { var complexBbc bool msgbytes := []byte(msg) - msgbytes = append(msgbytes, spaceGap...) + msgbytes = append(msgbytes, common.SpaceGap...) //log.Print("BBCode Simple Pre:","`"+string(msgbytes)+"`") //log.Print("----") @@ -306,7 +307,7 @@ func bbcodeFullParse(msg string) string { if hasS { msgbytes = append(bytes.TrimSpace(msgbytes), closeStrike...) } - msgbytes = append(msgbytes, spaceGap...) + msgbytes = append(msgbytes, common.SpaceGap...) } if complexBbc { @@ -357,21 +358,21 @@ func bbcodeParseURL(i int, start int, lastTag int, msgbytes []byte, outbytes []b start = i + 5 outbytes = append(outbytes, msgbytes[lastTag:i]...) i = start - i += partialURLBytesLen(msgbytes[start:]) + i += common.PartialURLBytesLen(msgbytes[start:]) //log.Print("Partial Bytes: ", string(msgbytes[start:])) //log.Print("-----") if !bytes.Equal(msgbytes[i:i+6], []byte("[/url]")) { //log.Print("Invalid Bytes: ", string(msgbytes[i:i+6])) //log.Print("-----") - outbytes = append(outbytes, invalidURL...) + outbytes = append(outbytes, common.InvalidURL...) return i, start, lastTag, outbytes } - outbytes = append(outbytes, urlOpen...) + outbytes = append(outbytes, common.UrlOpen...) outbytes = append(outbytes, msgbytes[start:i]...) - outbytes = append(outbytes, urlOpen2...) + outbytes = append(outbytes, common.UrlOpen2...) outbytes = append(outbytes, msgbytes[start:i]...) - outbytes = append(outbytes, urlClose...) + outbytes = append(outbytes, common.UrlClose...) i += 6 lastTag = i @@ -411,7 +412,7 @@ func bbcodeParseRand(i int, start int, lastTag int, msgbytes []byte, outbytes [] if number == 0 { dat = []byte("0") } else { - dat = []byte(strconv.FormatInt((random.Int63n(number)), 10)) + dat = []byte(strconv.FormatInt((bbcodeRandom.Int63n(number)), 10)) } outbytes = append(outbytes, dat...) diff --git a/plugin_guilds.go b/plugin_guilds.go index d8ec5502..1198b7d2 100644 --- a/plugin_guilds.go +++ b/plugin_guilds.go @@ -3,6 +3,7 @@ package main import ( //"fmt" + "./common" "./extend/guilds/lib" "./query_gen/lib" ) @@ -11,75 +12,58 @@ import ( // TODO: Add a plugin interface instead of having a bunch of argument to AddPlugin? func init() { - plugins["guilds"] = NewPlugin("guilds", "Guilds", "Azareal", "http://github.com/Azareal", "", "", "", initGuilds, nil, deactivateGuilds, installGuilds, nil) + common.Plugins["guilds"] = common.NewPlugin("guilds", "Guilds", "Azareal", "http://github.com/Azareal", "", "", "", initGuilds, nil, deactivateGuilds, installGuilds, nil) // TODO: Is it possible to avoid doing this when the plugin isn't activated? - prebuildTmplList = append(prebuildTmplList, guilds.PrebuildTmplList) + common.PrebuildTmplList = append(common.PrebuildTmplList, guilds.PrebuildTmplList) } func initGuilds() (err error) { - plugins["guilds"].AddHook("intercept_build_widgets", guilds.Widgets) - plugins["guilds"].AddHook("trow_assign", guilds.TrowAssign) - plugins["guilds"].AddHook("topic_create_pre_loop", guilds.TopicCreatePreLoop) - plugins["guilds"].AddHook("pre_render_view_forum", guilds.PreRenderViewForum) - plugins["guilds"].AddHook("simple_forum_check_pre_perms", guilds.ForumCheck) - plugins["guilds"].AddHook("forum_check_pre_perms", guilds.ForumCheck) + common.Plugins["guilds"].AddHook("intercept_build_widgets", guilds.Widgets) + common.Plugins["guilds"].AddHook("trow_assign", guilds.TrowAssign) + common.Plugins["guilds"].AddHook("topic_create_pre_loop", guilds.TopicCreatePreLoop) + common.Plugins["guilds"].AddHook("pre_render_view_forum", guilds.PreRenderViewForum) + common.Plugins["guilds"].AddHook("simple_forum_check_pre_perms", guilds.ForumCheck) + common.Plugins["guilds"].AddHook("forum_check_pre_perms", guilds.ForumCheck) // TODO: Auto-grant this perm to admins upon installation? - registerPluginPerm("CreateGuild") - router.HandleFunc("/guilds/", guilds.GuildList) - router.HandleFunc("/guild/", guilds.ViewGuild) - router.HandleFunc("/guild/create/", guilds.CreateGuild) - router.HandleFunc("/guild/create/submit/", guilds.CreateGuildSubmit) - router.HandleFunc("/guild/members/", guilds.MemberList) + common.RegisterPluginPerm("CreateGuild") + router.HandleFunc("/guilds/", guilds.RouteGuildList) + router.HandleFunc("/guild/", guilds.MiddleViewGuild) + router.HandleFunc("/guild/create/", guilds.RouteCreateGuild) + router.HandleFunc("/guild/create/submit/", guilds.RouteCreateGuildSubmit) + router.HandleFunc("/guild/members/", guilds.RouteMemberList) - guilds.ListStmt, err = qgen.Builder.SimpleSelect("guilds", "guildID, name, desc, active, privacy, joinable, owner, memberCount, createdAt, lastUpdateTime", "", "", "") - if err != nil { - return err - } - guilds.GetGuildStmt, err = qgen.Builder.SimpleSelect("guilds", "name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime", "guildID = ?", "", "") - if err != nil { - return err - } - guilds.MemberListStmt, err = qgen.Builder.SimpleSelect("guilds_members", "guildID, uid, rank, posts, joinedAt", "", "", "") - if err != nil { - return err - } - guilds.MemberListJoinStmt, err = qgen.Builder.SimpleLeftJoin("guilds_members", "users", "users.uid, guilds_members.rank, guilds_members.posts, guilds_members.joinedAt, users.name, users.avatar", "guilds_members.uid = users.uid", "guilds_members.guildID = ?", "guilds_members.rank DESC, guilds_members.joinedat ASC", "") - if err != nil { - return err - } - guilds.GetMemberStmt, err = qgen.Builder.SimpleSelect("guilds_members", "rank, posts, joinedAt", "guildID = ? AND uid = ?", "", "") - if err != nil { - return err - } - guilds.CreateGuildStmt, err = qgen.Builder.SimpleInsert("guilds", "name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime", "?,?,?,?,1,?,1,?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()") - if err != nil { - return err - } - guilds.AttachForumStmt, err = qgen.Builder.SimpleUpdate("forums", "parentID = ?, parentType = 'guild'", "fid = ?") - if err != nil { - return err - } - guilds.UnattachForumStmt, err = qgen.Builder.SimpleUpdate("forums", "parentID = 0, parentType = ''", "fid = ?") - if err != nil { - return err - } - guilds.AddMemberStmt, err = qgen.Builder.SimpleInsert("guilds_members", "guildID, uid, rank, posts, joinedAt", "?,?,?,0,UTC_TIMESTAMP()") - if err != nil { - return err - } + acc := qgen.Builder.Accumulator() - return nil + guilds.ListStmt = acc.SimpleSelect("guilds", "guildID, name, desc, active, privacy, joinable, owner, memberCount, createdAt, lastUpdateTime", "", "", "") + + guilds.GetGuildStmt = acc.SimpleSelect("guilds", "name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime", "guildID = ?", "", "") + + guilds.MemberListStmt = acc.SimpleSelect("guilds_members", "guildID, uid, rank, posts, joinedAt", "", "", "") + + guilds.MemberListJoinStmt = acc.SimpleLeftJoin("guilds_members", "users", "users.uid, guilds_members.rank, guilds_members.posts, guilds_members.joinedAt, users.name, users.avatar", "guilds_members.uid = users.uid", "guilds_members.guildID = ?", "guilds_members.rank DESC, guilds_members.joinedat ASC", "") + + guilds.GetMemberStmt = acc.SimpleSelect("guilds_members", "rank, posts, joinedAt", "guildID = ? AND uid = ?", "", "") + + guilds.CreateGuildStmt = acc.SimpleInsert("guilds", "name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime", "?,?,?,?,1,?,1,?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()") + + guilds.AttachForumStmt = acc.SimpleUpdate("forums", "parentID = ?, parentType = 'guild'", "fid = ?") + + guilds.UnattachForumStmt = acc.SimpleUpdate("forums", "parentID = 0, parentType = ''", "fid = ?") + + guilds.AddMemberStmt = acc.SimpleInsert("guilds_members", "guildID, uid, rank, posts, joinedAt", "?,?,?,0,UTC_TIMESTAMP()") + + return acc.FirstError() } func deactivateGuilds() { - plugins["guilds"].RemoveHook("intercept_build_widgets", guilds.Widgets) - plugins["guilds"].RemoveHook("trow_assign", guilds.TrowAssign) - plugins["guilds"].RemoveHook("topic_create_pre_loop", guilds.TopicCreatePreLoop) - plugins["guilds"].RemoveHook("pre_render_view_forum", guilds.PreRenderViewForum) - plugins["guilds"].RemoveHook("simple_forum_check_pre_perms", guilds.ForumCheck) - plugins["guilds"].RemoveHook("forum_check_pre_perms", guilds.ForumCheck) - deregisterPluginPerm("CreateGuild") + common.Plugins["guilds"].RemoveHook("intercept_build_widgets", guilds.Widgets) + common.Plugins["guilds"].RemoveHook("trow_assign", guilds.TrowAssign) + common.Plugins["guilds"].RemoveHook("topic_create_pre_loop", guilds.TopicCreatePreLoop) + common.Plugins["guilds"].RemoveHook("pre_render_view_forum", guilds.PreRenderViewForum) + common.Plugins["guilds"].RemoveHook("simple_forum_check_pre_perms", guilds.ForumCheck) + common.Plugins["guilds"].RemoveHook("forum_check_pre_perms", guilds.ForumCheck) + common.DeregisterPluginPerm("CreateGuild") _ = router.RemoveFunc("/guilds/") _ = router.RemoveFunc("/guild/") _ = router.RemoveFunc("/guild/create/") diff --git a/plugin_heythere.go b/plugin_heythere.go index 1e16aaaf..abb00cc8 100644 --- a/plugin_heythere.go +++ b/plugin_heythere.go @@ -1,22 +1,24 @@ package main +import "./common" + func init() { - plugins["heythere"] = NewPlugin("heythere", "Hey There", "Azareal", "http://github.com/Azareal", "", "", "", initHeythere, nil, deactivateHeythere, nil, nil) + common.Plugins["heythere"] = common.NewPlugin("heythere", "Hey There", "Azareal", "http://github.com/Azareal", "", "", "", initHeythere, nil, deactivateHeythere, nil, nil) } // init_heythere is separate from init() as we don't want the plugin to run if the plugin is disabled func initHeythere() error { - plugins["heythere"].AddHook("topic_reply_row_assign", heythereReply) + common.Plugins["heythere"].AddHook("topic_reply_row_assign", heythereReply) return nil } func deactivateHeythere() { - plugins["heythere"].RemoveHook("topic_reply_row_assign", heythereReply) + common.Plugins["heythere"].RemoveHook("topic_reply_row_assign", heythereReply) } func heythereReply(data ...interface{}) interface{} { - currentUser := data[0].(*TopicPage).CurrentUser - reply := data[1].(*ReplyUser) + currentUser := data[0].(*common.TopicPage).CurrentUser + reply := data[1].(*common.ReplyUser) reply.Content = "Hey there, " + currentUser.Name + "!" reply.ContentHtml = "Hey there, " + currentUser.Name + "!" reply.Tag = "Auto" diff --git a/plugin_markdown.go b/plugin_markdown.go index 90227281..17077d8a 100644 --- a/plugin_markdown.go +++ b/plugin_markdown.go @@ -4,6 +4,8 @@ package main import ( "log" "strings" + + "./common" ) var markdownMaxDepth = 25 // How deep the parser will go when parsing Markdown strings @@ -19,11 +21,11 @@ var markdownStrikeTagOpen []byte var markdownStrikeTagClose []byte func init() { - plugins["markdown"] = NewPlugin("markdown", "Markdown", "Azareal", "http://github.com/Azareal", "", "", "", initMarkdown, nil, deactivateMarkdown, nil, nil) + common.Plugins["markdown"] = common.NewPlugin("markdown", "Markdown", "Azareal", "http://github.com/Azareal", "", "", "", initMarkdown, nil, deactivateMarkdown, nil, nil) } func initMarkdown() error { - plugins["markdown"].AddHook("parse_assign", markdownParse) + common.Plugins["markdown"].AddHook("parse_assign", markdownParse) markdownUnclosedElement = []byte("[Unclosed Element]") @@ -39,7 +41,7 @@ func initMarkdown() error { } func deactivateMarkdown() { - plugins["markdown"].RemoveHook("parse_assign", markdownParse) + common.Plugins["markdown"].RemoveHook("parse_assign", markdownParse) } // An adapter for the parser, so that the parser can call itself recursively. diff --git a/plugin_skeleton.go b/plugin_skeleton.go index d1094628..0ea954c9 100644 --- a/plugin_skeleton.go +++ b/plugin_skeleton.go @@ -1,5 +1,7 @@ package main +import "./common" + func init() { /* The UName field should match the name in the URL minus plugin_ and the file extension. The same name as the map index. Please choose a unique name which won't clash with any other plugins. @@ -26,7 +28,7 @@ func init() { That Uninstallation field which is currently unused is for not only deactivating this plugin, but for purging any data associated with it such a new tables or data produced by the end-user. */ - plugins["skeleton"] = NewPlugin("skeleton", "Skeleton", "Azareal", "", "", "", "", initSkeleton, activateSkeleton, deactivateSkeleton, nil, nil) + common.Plugins["skeleton"] = common.NewPlugin("skeleton", "Skeleton", "Azareal", "", "", "", "", initSkeleton, activateSkeleton, deactivateSkeleton, nil, nil) } func initSkeleton() error { return nil } diff --git a/query_gen/lib/builder.go b/query_gen/lib/builder.go index e6ddfa76..c504b099 100644 --- a/query_gen/lib/builder.go +++ b/query_gen/lib/builder.go @@ -37,6 +37,10 @@ func (build *builder) GetAdapter() DB_Adapter { return build.adapter } +func (build *builder) Begin() (*sql.Tx, error) { + return build.conn.Begin() +} + func (build *builder) Tx(handler func(*TransactionBuilder) error) error { tx, err := build.conn.Begin() if err != nil { @@ -50,101 +54,60 @@ func (build *builder) Tx(handler func(*TransactionBuilder) error) error { return tx.Commit() } -func (build *builder) SimpleSelect(table string, columns string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) { - res, err := build.adapter.SimpleSelect("_builder", table, columns, where, orderby, limit) +func (build *builder) prepare(res string, err error) (*sql.Stmt, error) { if err != nil { - return stmt, err + return nil, err } return build.conn.Prepare(res) } +func (build *builder) SimpleSelect(table string, columns string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) { + return build.prepare(build.adapter.SimpleSelect("_builder", table, columns, where, orderby, limit)) +} + func (build *builder) SimpleCount(table string, where string, limit string) (stmt *sql.Stmt, err error) { - res, err := build.adapter.SimpleCount("_builder", table, where, limit) - if err != nil { - return stmt, err - } - return build.conn.Prepare(res) + return build.prepare(build.adapter.SimpleCount("_builder", table, where, limit)) } func (build *builder) SimpleLeftJoin(table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) { - res, err := build.adapter.SimpleLeftJoin("_builder", table1, table2, columns, joiners, where, orderby, limit) - if err != nil { - return stmt, err - } - return build.conn.Prepare(res) + return build.prepare(build.adapter.SimpleLeftJoin("_builder", table1, table2, columns, joiners, where, orderby, limit)) } func (build *builder) SimpleInnerJoin(table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) { - res, err := build.adapter.SimpleInnerJoin("_builder", table1, table2, columns, joiners, where, orderby, limit) - if err != nil { - return stmt, err - } - return build.conn.Prepare(res) + return build.prepare(build.adapter.SimpleInnerJoin("_builder", table1, table2, columns, joiners, where, orderby, limit)) } func (build *builder) CreateTable(table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (stmt *sql.Stmt, err error) { - res, err := build.adapter.CreateTable("_builder", table, charset, collation, columns, keys) - if err != nil { - return stmt, err - } - return build.conn.Prepare(res) + return build.prepare(build.adapter.CreateTable("_builder", table, charset, collation, columns, keys)) } func (build *builder) SimpleInsert(table string, columns string, fields string) (stmt *sql.Stmt, err error) { - res, err := build.adapter.SimpleInsert("_builder", table, columns, fields) - if err != nil { - return stmt, err - } - return build.conn.Prepare(res) + return build.prepare(build.adapter.SimpleInsert("_builder", table, columns, fields)) } func (build *builder) SimpleInsertSelect(ins DB_Insert, sel DB_Select) (stmt *sql.Stmt, err error) { - res, err := build.adapter.SimpleInsertSelect("_builder", ins, sel) - if err != nil { - return stmt, err - } - return build.conn.Prepare(res) + return build.prepare(build.adapter.SimpleInsertSelect("_builder", ins, sel)) } func (build *builder) SimpleInsertLeftJoin(ins DB_Insert, sel DB_Join) (stmt *sql.Stmt, err error) { - res, err := build.adapter.SimpleInsertLeftJoin("_builder", ins, sel) - if err != nil { - return stmt, err - } - return build.conn.Prepare(res) + return build.prepare(build.adapter.SimpleInsertLeftJoin("_builder", ins, sel)) } func (build *builder) SimpleInsertInnerJoin(ins DB_Insert, sel DB_Join) (stmt *sql.Stmt, err error) { - res, err := build.adapter.SimpleInsertInnerJoin("_builder", ins, sel) - if err != nil { - return stmt, err - } - return build.conn.Prepare(res) + return build.prepare(build.adapter.SimpleInsertInnerJoin("_builder", ins, sel)) } func (build *builder) SimpleUpdate(table string, set string, where string) (stmt *sql.Stmt, err error) { - res, err := build.adapter.SimpleUpdate("_builder", table, set, where) - if err != nil { - return stmt, err - } - return build.conn.Prepare(res) + return build.prepare(build.adapter.SimpleUpdate("_builder", table, set, where)) } func (build *builder) SimpleDelete(table string, where string) (stmt *sql.Stmt, err error) { - res, err := build.adapter.SimpleDelete("_builder", table, where) - if err != nil { - return stmt, err - } - return build.conn.Prepare(res) + return build.prepare(build.adapter.SimpleDelete("_builder", table, where)) } // I don't know why you need this, but here it is x.x func (build *builder) Purge(table string) (stmt *sql.Stmt, err error) { - res, err := build.adapter.Purge("_builder", table) - if err != nil { - return stmt, err - } - return build.conn.Prepare(res) + return build.prepare(build.adapter.Purge("_builder", table)) } // These ones support transactions diff --git a/query_gen/lib/mssql.go b/query_gen/lib/mssql.go index a5b33881..bcce8f6c 100644 --- a/query_gen/lib/mssql.go +++ b/query_gen/lib/mssql.go @@ -1098,6 +1098,7 @@ package main import "log" import "database/sql" +import "./common" // nolint type Stmts struct { @@ -1117,7 +1118,7 @@ type Stmts struct { // nolint func _gen_mssql() (err error) { - if dev.DebugMode { + if common.Dev.DebugMode { log.Print("Building the generated statements") } ` + body + ` diff --git a/query_gen/lib/mysql.go b/query_gen/lib/mysql.go index 69d5af74..37fd6e8c 100644 --- a/query_gen/lib/mysql.go +++ b/query_gen/lib/mysql.go @@ -590,6 +590,7 @@ package main import "log" import "database/sql" +import "./common" //import "./query_gen/lib" // nolint @@ -610,7 +611,7 @@ type Stmts struct { // nolint func _gen_mysql() (err error) { - if dev.DebugMode { + if common.Dev.DebugMode { log.Print("Building the generated statements") } ` + body + ` diff --git a/query_gen/lib/pgsql.go b/query_gen/lib/pgsql.go index 642954b4..437dcacf 100644 --- a/query_gen/lib/pgsql.go +++ b/query_gen/lib/pgsql.go @@ -346,6 +346,7 @@ package main import "log" import "database/sql" +import "./common" // nolint type Stmts struct { @@ -365,7 +366,7 @@ type Stmts struct { // nolint func _gen_pgsql() (err error) { - if dev.DebugMode { + if common.Dev.DebugMode { log.Print("Building the generated statements") } ` + body + ` diff --git a/query_gen/main.go b/query_gen/main.go index 04bd116b..780e4e63 100644 --- a/query_gen/main.go +++ b/query_gen/main.go @@ -230,20 +230,12 @@ func writeSelects(adapter qgen.DB_Adapter) error { adapter.SimpleSelect("getFullSetting", "settings", "name, type, constraints", "name = ?", "", "") - adapter.SimpleSelect("getFullSettings", "settings", "name, content, type, constraints", "", "", "") - - adapter.SimpleSelect("getThemes", "themes", "uname, default", "", "", "") - - adapter.SimpleSelect("getWidgets", "widgets", "position, side, type, active, location, data", "", "position ASC", "") - adapter.SimpleSelect("isPluginActive", "plugins", "active", "uname = ?", "", "") //adapter.SimpleSelect("isPluginInstalled","plugins","installed","uname = ?","","") adapter.SimpleSelect("getUsersOffset", "users", "uid, name, group, active, is_super_admin, avatar", "", "uid ASC", "?,?") - adapter.SimpleSelect("getWordFilters", "word_filters", "wfid, find, replacement", "", "", "") - adapter.SimpleSelect("isThemeDefault", "themes", "default", "uname = ?", "", "") adapter.SimpleSelect("getModlogs", "moderation_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "", "", "") @@ -256,10 +248,6 @@ func writeSelects(adapter qgen.DB_Adapter) error { adapter.SimpleSelect("getUserReplyUID", "users_replies", "uid", "rid = ?", "", "") - adapter.SimpleSelect("hasLikedTopic", "likes", "targetItem", "sentBy = ? and targetItem = ? and targetType = 'topics'", "", "") - - adapter.SimpleSelect("hasLikedReply", "likes", "targetItem", "sentBy = ? and targetItem = ? and targetType = 'replies'", "", "") - adapter.SimpleSelect("getUserName", "users", "name", "uid = ?", "", "") adapter.SimpleSelect("getEmailsByUser", "emails", "email, validated, token", "uid = ?", "", "") @@ -274,10 +262,6 @@ func writeSelects(adapter qgen.DB_Adapter) error { adapter.SimpleSelect("getForumTopicsOffset", "topics", "tid, title, content, createdBy, is_closed, sticky, createdAt, lastReplyAt, lastReplyBy, parentID, postCount, likeCount", "parentID = ?", "sticky DESC, lastReplyAt DESC, createdBy DESC", "?,?") - adapter.SimpleSelect("getExpiredScheduledGroups", "users_groups_scheduler", "uid", "UTC_TIMESTAMP() > revert_at AND temporary = 1", "", "") - - adapter.SimpleSelect("getSync", "sync", "last_update", "", "", "") - adapter.SimpleSelect("getAttachment", "attachments", "sectionID, sectionTable, originID, originTable, uploadedBy, path", "path = ? AND sectionID = ? AND sectionTable = ?", "", "") return nil @@ -288,11 +272,6 @@ func writeLeftJoins(adapter qgen.DB_Adapter) error { adapter.SimpleLeftJoin("getTopicList", "topics", "users", "topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.parentID, users.name, users.avatar", "topics.createdBy = users.uid", "", "topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC", "") - // TODO: Can we get rid of this? - adapter.SimpleLeftJoin("getTopicUser", "topics", "users", "topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level", "topics.createdBy = users.uid", "tid = ?", "", "") - - adapter.SimpleLeftJoin("getTopicByReply", "replies", "topics", "topics.tid, topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, topics.data", "replies.tid = topics.tid", "rid = ?", "", "") - adapter.SimpleLeftJoin("getTopicReplies", "replies", "users", "replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress", "replies.createdBy = users.uid", "tid = ?", "", "") adapter.SimpleLeftJoin("getForumTopics", "topics", "users", "topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, users.name, users.avatar", "topics.createdBy = users.uid", "topics.parentID = ?", "topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy desc", "") @@ -314,10 +293,6 @@ func writeInnerJoins(adapter qgen.DB_Adapter) (err error) { func writeInserts(adapter qgen.DB_Adapter) error { adapter.SimpleInsert("createReport", "topics", "title, content, parsed_content, createdAt, lastReplyAt, createdBy, lastReplyBy, data, parentID, css_class", "?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?,1,'report'") - adapter.SimpleInsert("createActionReply", "replies", "tid, actionType, ipaddress, createdBy, createdAt, lastUpdated, content, parsed_content", "?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'',''") - - adapter.SimpleInsert("createLike", "likes", "weight, targetItem, targetType, sentBy", "?,?,?,?") - adapter.SimpleInsert("addActivity", "activity_stream", "actor, targetUser, event, elementType, elementID", "?,?,?,?,?") adapter.SimpleInsert("notifyOne", "activity_stream_matches", "watcher, asid", "?,?") @@ -332,10 +307,6 @@ func writeInserts(adapter qgen.DB_Adapter) error { adapter.SimpleInsert("addTheme", "themes", "uname, default", "?,?") - adapter.SimpleInsert("addModlogEntry", "moderation_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "?,?,?,?,?,UTC_TIMESTAMP()") - - adapter.SimpleInsert("addAdminlogEntry", "administration_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "?,?,?,?,?,UTC_TIMESTAMP()") - adapter.SimpleInsert("addAttachment", "attachments", "sectionID, sectionTable, originID, originTable, uploadedBy, path", "?,?,?,?,?,?") adapter.SimpleInsert("createWordFilter", "word_filters", "find, replacement", "?,?") @@ -363,56 +334,10 @@ func writeReplaces(adapter qgen.DB_Adapter) (err error) { }*/ func writeUpdates(adapter qgen.DB_Adapter) error { - adapter.SimpleUpdate("addRepliesToTopic", "topics", "postCount = postCount + ?, lastReplyBy = ?, lastReplyAt = UTC_TIMESTAMP()", "tid = ?") - - adapter.SimpleUpdate("removeRepliesFromTopic", "topics", "postCount = postCount - ?", "tid = ?") - - adapter.SimpleUpdate("addLikesToTopic", "topics", "likeCount = likeCount + ?", "tid = ?") - - adapter.SimpleUpdate("addLikesToReply", "replies", "likeCount = likeCount + ?", "rid = ?") - - adapter.SimpleUpdate("editTopic", "topics", "title = ?, content = ?, parsed_content = ?", "tid = ?") - adapter.SimpleUpdate("editReply", "replies", "content = ?, parsed_content = ?", "rid = ?") - adapter.SimpleUpdate("stickTopic", "topics", "sticky = 1", "tid = ?") - - adapter.SimpleUpdate("unstickTopic", "topics", "sticky = 0", "tid = ?") - - adapter.SimpleUpdate("lockTopic", "topics", "is_closed = 1", "tid = ?") - - adapter.SimpleUpdate("unlockTopic", "topics", "is_closed = 0", "tid = ?") - - adapter.SimpleUpdate("updateLastIP", "users", "last_ip = ?", "uid = ?") - - adapter.SimpleUpdate("updateSession", "users", "session = ?", "uid = ?") - - adapter.SimpleUpdate("setPassword", "users", "password = ?, salt = ?", "uid = ?") - - adapter.SimpleUpdate("setAvatar", "users", "avatar = ?", "uid = ?") - - adapter.SimpleUpdate("setUsername", "users", "name = ?", "uid = ?") - - adapter.SimpleUpdate("changeGroup", "users", "group = ?", "uid = ?") - - adapter.SimpleUpdate("activateUser", "users", "active = 1", "uid = ?") - - adapter.SimpleUpdate("updateUserLevel", "users", "level = ?", "uid = ?") - - adapter.SimpleUpdate("incrementUserScore", "users", "score = score + ?", "uid = ?") - - adapter.SimpleUpdate("incrementUserPosts", "users", "posts = posts + ?", "uid = ?") - - adapter.SimpleUpdate("incrementUserBigposts", "users", "posts = posts + ?, bigposts = bigposts + ?", "uid = ?") - - adapter.SimpleUpdate("incrementUserMegaposts", "users", "posts = posts + ?, bigposts = bigposts + ?, megaposts = megaposts + ?", "uid = ?") - - adapter.SimpleUpdate("incrementUserTopics", "users", "topics = topics + ?", "uid = ?") - adapter.SimpleUpdate("editProfileReply", "users_replies", "content = ?, parsed_content = ?", "rid = ?") - adapter.SimpleUpdate("updateForum", "forums", "name = ?, desc = ?, active = ?, preset = ?", "fid = ?") - adapter.SimpleUpdate("updateSetting", "settings", "content = ?", "name = ?") adapter.SimpleUpdate("updatePlugin", "plugins", "active = ?", "uname = ?") @@ -421,14 +346,12 @@ func writeUpdates(adapter qgen.DB_Adapter) error { adapter.SimpleUpdate("updateTheme", "themes", "default = ?", "uname = ?") + adapter.SimpleUpdate("updateForum", "forums", "name = ?, desc = ?, active = ?, preset = ?", "fid = ?") + adapter.SimpleUpdate("updateUser", "users", "name = ?, email = ?, group = ?", "uid = ?") - adapter.SimpleUpdate("updateUserGroup", "users", "group = ?", "uid = ?") - adapter.SimpleUpdate("updateGroupPerms", "users_groups", "permissions = ?", "gid = ?") - adapter.SimpleUpdate("updateGroupRank", "users_groups", "is_admin = ?, is_mod = ?, is_banned = ?", "gid = ?") - adapter.SimpleUpdate("updateGroup", "users_groups", "name = ?, tag = ?", "gid = ?") adapter.SimpleUpdate("updateEmail", "emails", "email = ?, uid = ?, validated = ?, token = ?", "email = ?") @@ -445,12 +368,6 @@ func writeUpdates(adapter qgen.DB_Adapter) error { } func writeDeletes(adapter qgen.DB_Adapter) error { - adapter.SimpleDelete("deleteUser", "users", "uid = ?") - - adapter.SimpleDelete("deleteTopic", "topics", "tid = ?") - - adapter.SimpleDelete("deleteReply", "replies", "rid = ?") - adapter.SimpleDelete("deleteProfileReply", "users_replies", "rid = ?") //adapter.SimpleDelete("deleteForumPermsByForum", "forums_permissions", "fid = ?") @@ -466,8 +383,6 @@ func writeDeletes(adapter qgen.DB_Adapter) error { func writeSimpleCounts(adapter qgen.DB_Adapter) error { adapter.SimpleCount("reportExists", "topics", "data = ? AND data != '' AND parentID = 1", "") - adapter.SimpleCount("groupCount", "users_groups", "", "") - adapter.SimpleCount("modlogCount", "moderation_logs", "", "") return nil diff --git a/router.go b/router.go index 9ee471ed..a966dff2 100644 --- a/router.go +++ b/router.go @@ -2,9 +2,13 @@ package main //import "fmt" -import "strings" -import "sync" -import "net/http" +import ( + "net/http" + "strings" + "sync" + + "./common" +) // TODO: Support the new handler signatures created by our efforts to move the PreRoute middleware into the generated router // nolint Stop linting the uselessness of this file, we never know when we might need this file again @@ -59,5 +63,5 @@ func (router *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } //log.Print("req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/')]",req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/')]) - NotFound(w, req) + common.NotFound(w, req) } diff --git a/router_gen/main.go b/router_gen/main.go index 4213c66f..728a9c21 100644 --- a/router_gen/main.go +++ b/router_gen/main.go @@ -32,7 +32,7 @@ func main() { out += "\n\t\t\t\t\t" + runnable.Contents } else { out += ` - err = ` + runnable.Contents + `(w,req,user) + err = common.` + runnable.Contents + `(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -65,7 +65,7 @@ func main() { out += "\t\t\t" + runnable.Contents } else { out += ` - err = ` + runnable.Contents + `(w,req,user) + err = common.` + runnable.Contents + `(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -89,7 +89,7 @@ func main() { out += "\n\t\t\t\t\t" + runnable.Contents } else { out += ` - err = ` + runnable.Contents + `(w,req,user) + err = common.` + runnable.Contents + `(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -113,7 +113,7 @@ func main() { out += "\n\t\t\t\t\t" + runnable.Contents } else { out += ` - err = ` + runnable.Contents + `(w,req,user) + err = common.` + runnable.Contents + `(w,req,user) if err != nil { router.handleError(err,w,req,user) return @@ -137,17 +137,21 @@ func main() { fileData += `package main -import "log" -import "strings" -import "sync" -import "errors" -import "net/http" +import ( + "log" + "strings" + "sync" + "errors" + "net/http" + + "./common" +) var ErrNoRoute = errors.New("That route doesn't exist.") type GenRouter struct { UploadHandler func(http.ResponseWriter, *http.Request) - extra_routes map[string]func(http.ResponseWriter, *http.Request, User) RouteError + extra_routes map[string]func(http.ResponseWriter, *http.Request, common.User) common.RouteError sync.RWMutex } @@ -155,26 +159,26 @@ type GenRouter struct { func NewGenRouter(uploads http.Handler) *GenRouter { return &GenRouter{ UploadHandler: http.StripPrefix("/uploads/",uploads).ServeHTTP, - extra_routes: make(map[string]func(http.ResponseWriter, *http.Request, User) RouteError), + extra_routes: make(map[string]func(http.ResponseWriter, *http.Request, common.User) common.RouteError), } } -func (router *GenRouter) handleError(err RouteError, w http.ResponseWriter, r *http.Request, user User) { +func (router *GenRouter) handleError(err common.RouteError, w http.ResponseWriter, r *http.Request, user common.User) { if err.Handled() { return } if err.Type() == "system" { - InternalErrorJSQ(err,w,r,err.Json()) + common.InternalErrorJSQ(err, w, r, err.JSON()) return } - LocalErrorJSQ(err.Error(),w,r,user,err.Json()) + common.LocalErrorJSQ(err.Error(), w, r, user,err.JSON()) } func (router *GenRouter) Handle(_ string, _ http.Handler) { } -func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, User) RouteError) { +func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, common.User) common.RouteError) { router.Lock() router.extra_routes[pattern] = handle router.Unlock() @@ -187,7 +191,7 @@ func (router *GenRouter) RemoveFunc(pattern string) error { router.Unlock() return ErrNoRoute } - delete(router.extra_routes,pattern) + delete(router.extra_routes, pattern) router.Unlock() return nil } @@ -210,7 +214,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { req.URL.Path = req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/') + 1] } - if dev.SuperDebug { + if common.Dev.SuperDebug { log.Print("before routeStatic") log.Print("prefix: ", prefix) log.Print("req.URL.Path: ", req.URL.Path) @@ -220,29 +224,29 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { if prefix == "/static" { req.URL.Path += extra_data - routeStatic(w,req) + routeStatic(w, req) return } - if dev.SuperDebug { + if common.Dev.SuperDebug { log.Print("before PreRoute") } // Deal with the session stuff, etc. - user, ok := PreRoute(w,req) + user, ok := common.PreRoute(w, req) if !ok { return } - if dev.SuperDebug { + if common.Dev.SuperDebug { log.Print("after PreRoute") } - var err RouteError + var err common.RouteError switch(prefix) {` + out + ` case "/uploads": if extra_data == "" { - NotFound(w,req) + common.NotFound(w,req) return } req.URL.Path += extra_data @@ -261,10 +265,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } if extra_data != "" { - NotFound(w,req) + common.NotFound(w,req) return } - config.DefaultRoute(w,req,user) + common.Config.DefaultRoute(w,req,user) default: // A fallback for the routes which haven't been converted to the new router yet or plugins router.RLock() @@ -279,7 +283,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } return } - NotFound(w,req) + common.NotFound(w,req) } } ` diff --git a/routes.go b/routes.go index fc30b3ad..10a8a684 100644 --- a/routes.go +++ b/routes.go @@ -26,7 +26,7 @@ var tList []interface{} //var nList []string var successJSONBytes = []byte(`{"success":"1"}`) -var cacheControlMaxAge = "max-age=" + strconv.Itoa(day) // TODO: Make this a config value +var cacheControlMaxAge = "max-age=" + strconv.Itoa(common.Day) // TODO: Make this a common.Config value // HTTPSRedirect is a connection handler which redirects all HTTP requests to HTTPS type HTTPSRedirect struct { @@ -43,9 +43,9 @@ func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) { // GET functions func routeStatic(w http.ResponseWriter, r *http.Request) { //log.Print("Outputting static file '" + r.URL.Path + "'") - file, ok := staticFiles[r.URL.Path] + file, ok := common.StaticFiles[r.URL.Path] if !ok { - if dev.DebugMode { + if common.Dev.DebugMode { log.Print("Failed to find '" + r.URL.Path + "'") } w.WriteHeader(http.StatusNotFound) @@ -78,7 +78,7 @@ func routeStatic(w http.ResponseWriter, r *http.Request) { } // Deprecated: Test route for stopping the server during a performance analysis -/*func routeExit(w http.ResponseWriter, r *http.Request, user User) RouteError{ +/*func routeExit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError{ db.Close() os.Exit(0) }*/ @@ -86,7 +86,7 @@ func routeStatic(w http.ResponseWriter, r *http.Request) { // TODO: Make this a static file somehow? Is it possible for us to put this file somewhere else? // TODO: Add a sitemap // TODO: Add an API so that plugins can register disallowed areas. E.g. /guilds/join for plugin_guilds -func routeRobotsTxt(w http.ResponseWriter, r *http.Request) RouteError { +func routeRobotsTxt(w http.ResponseWriter, r *http.Request) common.RouteError { _, _ = w.Write([]byte(`User-agent: * Disallow: /panel/ Disallow: /topics/create/ @@ -96,85 +96,85 @@ Disallow: /accounts/ return nil } -func routeOverview(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeOverview(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } - BuildWidgets("overview", nil, headerVars, r) + common.BuildWidgets("overview", nil, headerVars, r) pi := common.Page{"Overview", user, headerVars, tList, nil} - if preRenderHooks["pre_render_overview"] != nil { - if runPreRenderHook("pre_render_overview", w, r, &user, &pi) { + if common.PreRenderHooks["pre_render_overview"] != nil { + if common.RunPreRenderHook("pre_render_overview", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "overview.html", pi) + err := common.Templates.ExecuteTemplate(w, "overview.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeCustomPage(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeCustomPage(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } name := r.URL.Path[len("/pages/"):] - if templates.Lookup("page_"+name) == nil { - return NotFound(w, r) + if common.Templates.Lookup("page_"+name) == nil { + return common.NotFound(w, r) } - BuildWidgets("custom_page", name, headerVars, r) + common.BuildWidgets("custom_page", name, headerVars, r) pi := common.Page{"Page", user, headerVars, tList, nil} - if preRenderHooks["pre_render_custom_page"] != nil { - if runPreRenderHook("pre_render_custom_page", w, r, &user, &pi) { + if common.PreRenderHooks["pre_render_custom_page"] != nil { + if common.RunPreRenderHook("pre_render_custom_page", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "page_"+name, pi) + err := common.Templates.ExecuteTemplate(w, "page_"+name, pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeTopics(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeTopics(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } - BuildWidgets("topics", nil, headerVars, r) + common.BuildWidgets("topics", nil, headerVars, r) // TODO: Add a function for the qlist stuff var qlist string - group, err := gstore.Get(user.Group) + group, err := common.Gstore.Get(user.Group) if err != nil { - log.Printf("Group #%d doesn't exist despite being used by User #%d", user.Group, user.ID) - return LocalError("Something weird happened", w, r, user) + log.Printf("Group #%d doesn't exist despite being used by common.User #%d", user.Group, user.ID) + return common.LocalError("Something weird happened", w, r, user) } // TODO: Make CanSee a method on *Group with a canSee field? var canSee []int if user.IsSuperAdmin { - canSee, err = fstore.GetAllVisibleIDs() + canSee, err = common.Fstore.GetAllVisibleIDs() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } else { canSee = group.CanSee } // We need a list of the visible forums for Quick Topic - var forumList []Forum + var forumList []common.Forum var argList []interface{} for _, fid := range canSee { - forum := fstore.DirtyGet(fid) + forum := common.Fstore.DirtyGet(fid) if forum.Name != "" && forum.Active { if forum.ParentType == "" || forum.ParentType == "forum" { // Optimise Quick Topic away for guests @@ -194,19 +194,19 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user User) RouteError { // ! Need an inline error not a page level error if qlist == "" { - return NotFound(w, r) + return common.NotFound(w, r) } qlist = qlist[0 : len(qlist)-1] topicCountStmt, err := qgen.Builder.SimpleCount("topics", "parentID IN("+qlist+")", "") if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } var topicCount int err = topicCountStmt.QueryRow(argList...).Scan(&topicCount) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Get the current page @@ -214,50 +214,50 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user User) RouteError { // Calculate the offset var offset int - lastPage := (topicCount / config.ItemsPerPage) + 1 + lastPage := (topicCount / common.Config.ItemsPerPage) + 1 if page > 1 { - offset = (config.ItemsPerPage * page) - config.ItemsPerPage + offset = (common.Config.ItemsPerPage * page) - common.Config.ItemsPerPage } else if page == -1 { page = lastPage - offset = (config.ItemsPerPage * page) - config.ItemsPerPage + offset = (common.Config.ItemsPerPage * page) - common.Config.ItemsPerPage } else { page = 1 } - var topicList []*TopicsRow + var topicList []*common.TopicsRow stmt, err := qgen.Builder.SimpleSelect("topics", "tid, title, content, createdBy, is_closed, sticky, createdAt, lastReplyAt, lastReplyBy, parentID, postCount, likeCount", "parentID IN("+qlist+")", "sticky DESC, lastReplyAt DESC, createdBy DESC", "?,?") if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } argList = append(argList, offset) - argList = append(argList, config.ItemsPerPage) + argList = append(argList, common.Config.ItemsPerPage) rows, err := stmt.Query(argList...) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } defer rows.Close() var reqUserList = make(map[int]bool) for rows.Next() { - topicItem := TopicsRow{ID: 0} + topicItem := common.TopicsRow{ID: 0} err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.IsClosed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.LastReplyBy, &topicItem.ParentID, &topicItem.PostCount, &topicItem.LikeCount) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - topicItem.Link = buildTopicURL(nameToSlug(topicItem.Title), topicItem.ID) + topicItem.Link = common.BuildTopicURL(common.NameToSlug(topicItem.Title), topicItem.ID) - forum := fstore.DirtyGet(topicItem.ParentID) + forum := common.Fstore.DirtyGet(topicItem.ParentID) topicItem.ForumName = forum.Name topicItem.ForumLink = forum.Link - //topicItem.CreatedAt = relativeTime(topicItem.CreatedAt) - topicItem.RelativeLastReplyAt = relativeTime(topicItem.LastReplyAt) + //topicItem.CreatedAt = common.RelativeTime(topicItem.CreatedAt) + topicItem.RelativeLastReplyAt = common.RelativeTime(topicItem.LastReplyAt) - if vhooks["topics_topic_row_assign"] != nil { - runVhook("topics_topic_row_assign", &topicItem, &forum) + if common.Vhooks["topics_topic_row_assign"] != nil { + common.RunVhook("topics_topic_row_assign", &topicItem, &forum) } topicList = append(topicList, &topicItem) reqUserList[topicItem.CreatedBy] = true @@ -265,7 +265,7 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user User) RouteError { } err = rows.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Convert the user ID map to a slice, then bulk load the users @@ -277,9 +277,9 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user User) RouteError { } // TODO: What if a user is deleted via the Control Panel? - userList, err := users.BulkGetMap(idSlice) + userList, err := common.Users.BulkGetMap(idSlice) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Second pass to the add the user data @@ -289,20 +289,20 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user User) RouteError { topicItem.LastUser = userList[topicItem.LastReplyBy] } - pi := TopicsPage{"All Topics", user, headerVars, topicList, forumList, config.DefaultForum} - if preRenderHooks["pre_render_topic_list"] != nil { - if runPreRenderHook("pre_render_topic_list", w, r, &user, &pi) { + pi := common.TopicsPage{"All Topics", user, headerVars, topicList, forumList, common.Config.DefaultForum} + if common.PreRenderHooks["pre_render_topic_list"] != nil { + if common.RunPreRenderHook("pre_render_topic_list", w, r, &user, &pi) { return nil } } - err = RunThemeTemplate(headerVars.ThemeName, "topics", pi, w) + err = common.RunThemeTemplate(headerVars.ThemeName, "topics", pi, w) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeForum(w http.ResponseWriter, r *http.Request, user User, sfid string) RouteError { +func routeForum(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError { page, _ := strconv.Atoi(r.FormValue("page")) // SEO URLs... @@ -312,63 +312,63 @@ func routeForum(w http.ResponseWriter, r *http.Request, user User, sfid string) } fid, err := strconv.Atoi(halves[1]) if err != nil { - return PreError("The provided ForumID is not a valid number.", w, r) + return common.PreError("The provided ForumID is not a valid number.", w, r) } - headerVars, ferr := ForumUserCheck(w, r, &user, fid) + headerVars, ferr := common.ForumUserCheck(w, r, &user, fid) if ferr != nil { return ferr } if !user.Perms.ViewTopic { - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } // TODO: Fix this double-check - forum, err := fstore.Get(fid) + forum, err := common.Fstore.Get(fid) if err == ErrNoRows { - return NotFound(w, r) + return common.NotFound(w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - BuildWidgets("view_forum", forum, headerVars, r) + common.BuildWidgets("view_forum", forum, headerVars, r) // Calculate the offset var offset int // TODO: Does forum.TopicCount take the deleted items into consideration for guests? - lastPage := (forum.TopicCount / config.ItemsPerPage) + 1 + lastPage := (forum.TopicCount / common.Config.ItemsPerPage) + 1 if page > 1 { - offset = (config.ItemsPerPage * page) - config.ItemsPerPage + offset = (common.Config.ItemsPerPage * page) - common.Config.ItemsPerPage } else if page == -1 { page = lastPage - offset = (config.ItemsPerPage * page) - config.ItemsPerPage + offset = (common.Config.ItemsPerPage * page) - common.Config.ItemsPerPage } else { page = 1 } // TODO: Move this to *Forum - rows, err := stmts.getForumTopicsOffset.Query(fid, offset, config.ItemsPerPage) + rows, err := stmts.getForumTopicsOffset.Query(fid, offset, common.Config.ItemsPerPage) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } defer rows.Close() // TODO: Use something other than TopicsRow as we don't need to store the forum name and link on each and every topic item? - var topicList []*TopicsRow + var topicList []*common.TopicsRow var reqUserList = make(map[int]bool) for rows.Next() { - var topicItem = TopicsRow{ID: 0} + var topicItem = common.TopicsRow{ID: 0} err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.IsClosed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.LastReplyBy, &topicItem.ParentID, &topicItem.PostCount, &topicItem.LikeCount) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - topicItem.Link = buildTopicURL(nameToSlug(topicItem.Title), topicItem.ID) - topicItem.RelativeLastReplyAt = relativeTime(topicItem.LastReplyAt) + topicItem.Link = common.BuildTopicURL(common.NameToSlug(topicItem.Title), topicItem.ID) + topicItem.RelativeLastReplyAt = common.RelativeTime(topicItem.LastReplyAt) - if vhooks["forum_trow_assign"] != nil { - runVhook("forum_trow_assign", &topicItem, &forum) + if common.Vhooks["forum_trow_assign"] != nil { + common.RunVhook("forum_trow_assign", &topicItem, &forum) } topicList = append(topicList, &topicItem) reqUserList[topicItem.CreatedBy] = true @@ -376,7 +376,7 @@ func routeForum(w http.ResponseWriter, r *http.Request, user User, sfid string) } err = rows.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Convert the user ID map to a slice, then bulk load the users @@ -388,9 +388,9 @@ func routeForum(w http.ResponseWriter, r *http.Request, user User, sfid string) } // TODO: What if a user is deleted via the Control Panel? - userList, err := users.BulkGetMap(idSlice) + userList, err := common.Users.BulkGetMap(idSlice) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Second pass to the add the user data @@ -400,84 +400,81 @@ func routeForum(w http.ResponseWriter, r *http.Request, user User, sfid string) topicItem.LastUser = userList[topicItem.LastReplyBy] } - pi := ForumPage{forum.Name, user, headerVars, topicList, forum, page, lastPage} - if preRenderHooks["pre_render_view_forum"] != nil { - if runPreRenderHook("pre_render_view_forum", w, r, &user, &pi) { + pi := common.ForumPage{forum.Name, user, headerVars, topicList, forum, page, lastPage} + if common.PreRenderHooks["pre_render_view_forum"] != nil { + if common.RunPreRenderHook("pre_render_view_forum", w, r, &user, &pi) { return nil } } - err = RunThemeTemplate(headerVars.ThemeName, "forum", pi, w) + err = common.RunThemeTemplate(headerVars.ThemeName, "forum", pi, w) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeForums(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeForums(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } - BuildWidgets("forums", nil, headerVars, r) + common.BuildWidgets("forums", nil, headerVars, r) var err error - var forumList []Forum + var forumList []common.Forum var canSee []int if user.IsSuperAdmin { - canSee, err = fstore.GetAllVisibleIDs() + canSee, err = common.Fstore.GetAllVisibleIDs() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } //log.Print("canSee ", canSee) } else { - group, err := gstore.Get(user.Group) + group, err := common.Gstore.Get(user.Group) if err != nil { - log.Printf("Group #%d doesn't exist despite being used by User #%d", user.Group, user.ID) - return LocalError("Something weird happened", w, r, user) + log.Printf("Group #%d doesn't exist despite being used by common.User #%d", user.Group, user.ID) + return common.LocalError("Something weird happened", w, r, user) } canSee = group.CanSee - //log.Print("group.CanSee ", group.CanSee) } for _, fid := range canSee { // Avoid data races by copying the struct into something we can freely mold without worrying about breaking something somewhere else - var forum = fstore.DirtyGet(fid).Copy() + var forum = common.Fstore.DirtyGet(fid).Copy() if forum.ParentID == 0 && forum.Name != "" && forum.Active { if forum.LastTopicID != 0 { - //topic, user := forum.GetLast() - //if topic.ID != 0 && user.ID != 0 { if forum.LastTopic.ID != 0 && forum.LastReplyer.ID != 0 { - forum.LastTopicTime = relativeTime(forum.LastTopic.LastReplyAt) + forum.LastTopicTime = common.RelativeTime(forum.LastTopic.LastReplyAt) } else { forum.LastTopicTime = "" } } else { forum.LastTopicTime = "" } - if hooks["forums_frow_assign"] != nil { - runHook("forums_frow_assign", &forum) + if common.Hooks["forums_frow_assign"] != nil { + common.RunHook("forums_frow_assign", &forum) } forumList = append(forumList, forum) } } - pi := ForumsPage{"Forum List", user, headerVars, forumList} - if preRenderHooks["pre_render_forum_list"] != nil { - if runPreRenderHook("pre_render_forum_list", w, r, &user, &pi) { + pi := common.ForumsPage{"Forum List", user, headerVars, forumList} + if common.PreRenderHooks["pre_render_forum_list"] != nil { + if common.RunPreRenderHook("pre_render_forum_list", w, r, &user, &pi) { return nil } } - err = RunThemeTemplate(headerVars.ThemeName, "forums", pi, w) + err = common.RunThemeTemplate(headerVars.ThemeName, "forums", pi, w) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeTopicID(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeTopicID(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { var err error var page, offset int - var replyList []ReplyUser + var replyList []common.ReplyUser page, _ = strconv.Atoi(r.FormValue("page")) @@ -489,31 +486,31 @@ func routeTopicID(w http.ResponseWriter, r *http.Request, user User) RouteError tid, err := strconv.Atoi(halves[1]) if err != nil { - return PreError("The provided TopicID is not a valid number.", w, r) + return common.PreError("The provided TopicID is not a valid number.", w, r) } // Get the topic... - topic, err := getTopicUser(tid) + topic, err := common.GetTopicUser(tid) if err == ErrNoRows { - return NotFound(w, r) + return common.NotFound(w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } topic.ClassName = "" //log.Printf("topic: %+v\n", topic) - headerVars, ferr := ForumUserCheck(w, r, &user, topic.ParentID) + headerVars, ferr := common.ForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic { //log.Printf("user.Perms: %+v\n", user.Perms) - return NoPermissions(w, r, user) + return common.NoPermissions(w, r, user) } - BuildWidgets("view_topic", &topic, headerVars, r) + common.BuildWidgets("view_topic", &topic, headerVars, r) - topic.ContentHTML = parseMessage(topic.Content, topic.ParentID, "forums") + topic.ContentHTML = common.ParseMessage(topic.Content, topic.ParentID, "forums") topic.ContentLines = strings.Count(topic.Content, "\n") // We don't want users posting in locked topics... @@ -521,16 +518,16 @@ func routeTopicID(w http.ResponseWriter, r *http.Request, user User) RouteError user.Perms.CreateReply = false } - postGroup, err := gstore.Get(topic.Group) + postGroup, err := common.Gstore.Get(topic.Group) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } topic.Tag = postGroup.Tag if postGroup.IsMod || postGroup.IsAdmin { - topic.ClassName = config.StaffCSS + topic.ClassName = common.Config.StaffCSS } - topic.RelativeCreatedAt = relativeTime(topic.CreatedAt) + topic.RelativeCreatedAt = common.RelativeTime(topic.CreatedAt) // TODO: Make a function for this? Build a more sophisticated noavatar handling system? if topic.Avatar != "" { @@ -538,65 +535,65 @@ func routeTopicID(w http.ResponseWriter, r *http.Request, user User) RouteError topic.Avatar = "/uploads/avatar_" + strconv.Itoa(topic.CreatedBy) + topic.Avatar } } else { - topic.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(topic.CreatedBy), 1) + topic.Avatar = strings.Replace(common.Config.Noavatar, "{id}", strconv.Itoa(topic.CreatedBy), 1) } // Calculate the offset - lastPage := (topic.PostCount / config.ItemsPerPage) + 1 + lastPage := (topic.PostCount / common.Config.ItemsPerPage) + 1 if page > 1 { - offset = (config.ItemsPerPage * page) - config.ItemsPerPage + offset = (common.Config.ItemsPerPage * page) - common.Config.ItemsPerPage } else if page == -1 { page = lastPage - offset = (config.ItemsPerPage * page) - config.ItemsPerPage + offset = (common.Config.ItemsPerPage * page) - common.Config.ItemsPerPage } else { page = 1 } - tpage := TopicPage{topic.Title, user, headerVars, replyList, topic, page, lastPage} + tpage := common.TopicPage{topic.Title, user, headerVars, replyList, topic, page, lastPage} // Get the replies.. - rows, err := stmts.getTopicRepliesOffset.Query(topic.ID, offset, config.ItemsPerPage) + rows, err := stmts.getTopicRepliesOffset.Query(topic.ID, offset, common.Config.ItemsPerPage) if err == ErrNoRows { - return LocalError("Bad Page. Some of the posts may have been deleted or you got here by directly typing in the page number.", w, r, user) + return common.LocalError("Bad Page. Some of the posts may have been deleted or you got here by directly typing in the page number.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } defer rows.Close() - replyItem := ReplyUser{ClassName: ""} + replyItem := common.ReplyUser{ClassName: ""} for rows.Next() { err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &replyItem.Group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IPAddress, &replyItem.LikeCount, &replyItem.ActionType) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - replyItem.UserLink = buildProfileURL(nameToSlug(replyItem.CreatedByName), replyItem.CreatedBy) + replyItem.UserLink = common.BuildProfileURL(common.NameToSlug(replyItem.CreatedByName), replyItem.CreatedBy) replyItem.ParentID = topic.ID - replyItem.ContentHtml = parseMessage(replyItem.Content, topic.ParentID, "forums") + replyItem.ContentHtml = common.ParseMessage(replyItem.Content, topic.ParentID, "forums") replyItem.ContentLines = strings.Count(replyItem.Content, "\n") - postGroup, err = gstore.Get(replyItem.Group) + postGroup, err = common.Gstore.Get(replyItem.Group) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } if postGroup.IsMod || postGroup.IsAdmin { - replyItem.ClassName = config.StaffCSS + replyItem.ClassName = common.Config.StaffCSS } else { replyItem.ClassName = "" } - // TODO: Make a function for this? Build a more sophisticated noavatar handling system? Do bulk user loads and let the UserStore initialise this? + // TODO: Make a function for this? Build a more sophisticated noavatar handling system? Do bulk user loads and let the common.UserStore initialise this? if replyItem.Avatar != "" { if replyItem.Avatar[0] == '.' { replyItem.Avatar = "/uploads/avatar_" + strconv.Itoa(replyItem.CreatedBy) + replyItem.Avatar } } else { - replyItem.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(replyItem.CreatedBy), 1) + replyItem.Avatar = strings.Replace(common.Config.Noavatar, "{id}", strconv.Itoa(replyItem.CreatedBy), 1) } replyItem.Tag = postGroup.Tag - replyItem.RelativeCreatedAt = relativeTime(replyItem.CreatedAt) + replyItem.RelativeCreatedAt = common.RelativeTime(replyItem.CreatedAt) // We really shouldn't have inline HTML, we should do something about this... if replyItem.ActionType != "" { @@ -620,31 +617,31 @@ func routeTopicID(w http.ResponseWriter, r *http.Request, user User) RouteError } replyItem.Liked = false - if vhooks["topic_reply_row_assign"] != nil { - runVhook("topic_reply_row_assign", &tpage, &replyItem) + if common.Vhooks["topic_reply_row_assign"] != nil { + common.RunVhook("topic_reply_row_assign", &tpage, &replyItem) } replyList = append(replyList, replyItem) } err = rows.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } tpage.ItemList = replyList - if preRenderHooks["pre_render_view_topic"] != nil { - if runPreRenderHook("pre_render_view_topic", w, r, &user, &tpage) { + if common.PreRenderHooks["pre_render_view_topic"] != nil { + if common.RunPreRenderHook("pre_render_view_topic", w, r, &user, &tpage) { return nil } } - err = RunThemeTemplate(headerVars.ThemeName, "topic", tpage, w) + err = common.RunThemeTemplate(headerVars.ThemeName, "topic", tpage, w) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeProfile(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeProfile(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } @@ -653,7 +650,7 @@ func routeProfile(w http.ResponseWriter, r *http.Request, user User) RouteError var replyCreatedAt time.Time var replyContent, replyCreatedByName, replyRelativeCreatedAt, replyAvatar, replyTag, replyClassName string var rid, replyCreatedBy, replyLastEdit, replyLastEditBy, replyLines, replyGroup int - var replyList []ReplyUser + var replyList []common.ReplyUser // SEO URLs... halves := strings.Split(r.URL.Path[len("/user/"):], ".") @@ -663,44 +660,44 @@ func routeProfile(w http.ResponseWriter, r *http.Request, user User) RouteError pid, err := strconv.Atoi(halves[1]) if err != nil { - return LocalError("The provided User ID is not a valid number.", w, r, user) + return common.LocalError("The provided common.User ID is not a valid number.", w, r, user) } - var puser *User + var puser *common.User if pid == user.ID { user.IsMod = true puser = &user } else { // Fetch the user data - puser, err = users.Get(pid) + puser, err = common.Users.Get(pid) if err == ErrNoRows { - return NotFound(w, r) + return common.NotFound(w, r) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } // Get the replies.. rows, err := stmts.getProfileReplies.Query(puser.ID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } defer rows.Close() for rows.Next() { err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &replyGroup) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - group, err := gstore.Get(replyGroup) + group, err := common.Gstore.Get(replyGroup) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } replyLines = strings.Count(replyContent, "\n") if group.IsMod || group.IsAdmin { - replyClassName = config.StaffCSS + replyClassName = common.Config.StaffCSS } else { replyClassName = "" } @@ -710,7 +707,7 @@ func routeProfile(w http.ResponseWriter, r *http.Request, user User) RouteError replyAvatar = "/uploads/avatar_" + strconv.Itoa(replyCreatedBy) + replyAvatar } } else { - replyAvatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(replyCreatedBy), 1) + replyAvatar = strings.Replace(common.Config.Noavatar, "{id}", strconv.Itoa(replyCreatedBy), 1) } if group.Tag != "" { @@ -723,48 +720,48 @@ func routeProfile(w http.ResponseWriter, r *http.Request, user User) RouteError replyLiked := false replyLikeCount := 0 - replyRelativeCreatedAt = relativeTime(replyCreatedAt) + replyRelativeCreatedAt = common.RelativeTime(replyCreatedAt) // TODO: Add a hook here - replyList = append(replyList, ReplyUser{rid, puser.ID, replyContent, parseMessage(replyContent, 0, ""), replyCreatedBy, buildProfileURL(nameToSlug(replyCreatedByName), replyCreatedBy), replyCreatedByName, replyGroup, replyCreatedAt, replyRelativeCreatedAt, replyLastEdit, replyLastEditBy, replyAvatar, replyClassName, replyLines, replyTag, "", "", "", 0, "", replyLiked, replyLikeCount, "", ""}) + replyList = append(replyList, common.ReplyUser{rid, puser.ID, replyContent, common.ParseMessage(replyContent, 0, ""), replyCreatedBy, common.BuildProfileURL(common.NameToSlug(replyCreatedByName), replyCreatedBy), replyCreatedByName, replyGroup, replyCreatedAt, replyRelativeCreatedAt, replyLastEdit, replyLastEditBy, replyAvatar, replyClassName, replyLines, replyTag, "", "", "", 0, "", replyLiked, replyLikeCount, "", ""}) } err = rows.Err() if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - ppage := ProfilePage{puser.Name + "'s Profile", user, headerVars, replyList, *puser} - if preRenderHooks["pre_render_profile"] != nil { - if runPreRenderHook("pre_render_profile", w, r, &user, &ppage) { + ppage := common.ProfilePage{puser.Name + "'s Profile", user, headerVars, replyList, *puser} + if common.PreRenderHooks["pre_render_profile"] != nil { + if common.RunPreRenderHook("pre_render_profile", w, r, &user, &ppage) { return nil } } - err = template_profile_handle(ppage, w) + err = common.RunThemeTemplate(headerVars.ThemeName, "profile", ppage, w) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeLogin(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeLogin(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } if user.Loggedin { - return LocalError("You're already logged in.", w, r, user) + return common.LocalError("You're already logged in.", w, r, user) } - pi := Page{"Login", user, headerVars, tList, nil} - if preRenderHooks["pre_render_login"] != nil { - if runPreRenderHook("pre_render_login", w, r, &user, &pi) { + pi := common.Page{"Login", user, headerVars, tList, nil} + if common.PreRenderHooks["pre_render_login"] != nil { + if common.RunPreRenderHook("pre_render_login", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "login.html", pi) + err := common.Templates.ExecuteTemplate(w, "login.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } @@ -772,37 +769,37 @@ func routeLogin(w http.ResponseWriter, r *http.Request, user User) RouteError { // TODO: Log failed attempted logins? // TODO: Lock IPS out if they have too many failed attempts? // TODO: Log unusual countries in comparison to the country a user usually logs in from? Alert the user about this? -func routeLoginSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeLoginSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { if user.Loggedin { - return LocalError("You're already logged in.", w, r, user) + return common.LocalError("You're already logged in.", w, r, user) } err := r.ParseForm() if err != nil { - return LocalError("Bad Form", w, r, user) + return common.LocalError("Bad Form", w, r, user) } - uid, err := auth.Authenticate(html.EscapeString(r.PostFormValue("username")), r.PostFormValue("password")) + uid, err := common.Auth.Authenticate(html.EscapeString(r.PostFormValue("username")), r.PostFormValue("password")) if err != nil { - return LocalError(err.Error(), w, r, user) + return common.LocalError(err.Error(), w, r, user) } - userPtr, err := users.Get(uid) + userPtr, err := common.Users.Get(uid) if err != nil { - return LocalError("Bad account", w, r, user) + return common.LocalError("Bad account", w, r, user) } user = *userPtr var session string if user.Session == "" { - session, err = auth.CreateSession(uid) + session, err = common.Auth.CreateSession(uid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } } else { session = user.Session } - auth.SetCookies(w, uid, session) + common.Auth.SetCookies(w, uid, session) if user.IsAdmin { // Is this error check reundant? We already check for the error in PreRoute for the same IP // TODO: Should we be logging this? @@ -812,66 +809,65 @@ func routeLoginSubmit(w http.ResponseWriter, r *http.Request, user User) RouteEr return nil } -func routeRegister(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerVars, ferr := UserCheck(w, r, &user) +func routeRegister(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { return ferr } if user.Loggedin { - return LocalError("You're already logged in.", w, r, user) + return common.LocalError("You're already logged in.", w, r, user) } - pi := Page{"Registration", user, headerVars, tList, nil} - if preRenderHooks["pre_render_register"] != nil { - if runPreRenderHook("pre_render_register", w, r, &user, &pi) { + pi := common.Page{"Registration", user, headerVars, tList, nil} + if common.PreRenderHooks["pre_render_register"] != nil { + if common.RunPreRenderHook("pre_render_register", w, r, &user, &pi) { return nil } } - err := templates.ExecuteTemplate(w, "register.html", pi) + err := common.Templates.ExecuteTemplate(w, "register.html", pi) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } return nil } -func routeRegisterSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError { - headerLite, _ := SimpleUserCheck(w, r, &user) +func routeRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerLite, _ := common.SimpleUserCheck(w, r, &user) err := r.ParseForm() if err != nil { - return LocalError("Bad Form", w, r, user) + return common.LocalError("Bad Form", w, r, user) } - username := html.EscapeString(r.PostFormValue("username")) if username == "" { - return LocalError("You didn't put in a username.", w, r, user) + return common.LocalError("You didn't put in a username.", w, r, user) } email := html.EscapeString(r.PostFormValue("email")) if email == "" { - return LocalError("You didn't put in an email.", w, r, user) + return common.LocalError("You didn't put in an email.", w, r, user) } password := r.PostFormValue("password") if password == "" { - return LocalError("You didn't put in a password.", w, r, user) + return common.LocalError("You didn't put in a password.", w, r, user) } if password == username { - return LocalError("You can't use your username as your password.", w, r, user) + return common.LocalError("You can't use your username as your password.", w, r, user) } if password == email { - return LocalError("You can't use your email as your password.", w, r, user) + return common.LocalError("You can't use your email as your password.", w, r, user) } - err = weakPassword(password) + err = common.WeakPassword(password) if err != nil { - return LocalError(err.Error(), w, r, user) + return common.LocalError(err.Error(), w, r, user) } confirmPassword := r.PostFormValue("confirm_password") - log.Print("Registration Attempt! Username: " + username) // TODO: Add more controls over what is logged when? + log.Print("Registration Attempt! common.Username: " + username) // TODO: Add more controls over what is logged when? // Do the two inputted passwords match..? if password != confirmPassword { - return LocalError("The two passwords don't match.", w, r, user) + return common.LocalError("The two passwords don't match.", w, r, user) } var active bool @@ -879,50 +875,50 @@ func routeRegisterSubmit(w http.ResponseWriter, r *http.Request, user User) Rout switch headerLite.Settings["activation_type"] { case 1: // Activate All active = true - group = config.DefaultGroup + group = common.Config.DefaultGroup default: // Anything else. E.g. Admin Activation or Email Activation. - group = config.ActivationGroup + group = common.Config.ActivationGroup } - uid, err := users.Create(username, password, email, group, active) - if err == errAccountExists { - return LocalError("This username isn't available. Try another.", w, r, user) + uid, err := common.Users.Create(username, password, email, group, active) + if err == common.ErrAccountExists { + return common.LocalError("This username isn't available. Try another.", w, r, user) } else if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } // Check if this user actually owns this email, if email activation is on, automatically flip their account to active when the email is validated. Validation is also useful for determining whether this user should receive any alerts, etc. via email - if site.EnableEmails { - token, err := GenerateSafeString(80) + if common.Site.EnableEmails { + token, err := common.GenerateSafeString(80) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } _, err = stmts.addEmail.Exec(email, uid, 0, token) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - if !SendValidationEmail(username, email, token) { - return LocalError("We were unable to send the email for you to confirm that this email address belongs to you. You may not have access to some functionality until you do so. Please ask an administrator for assistance.", w, r, user) + if !common.SendValidationEmail(username, email, token) { + return common.LocalError("We were unable to send the email for you to confirm that this email address belongs to you. You may not have access to some functionality until you do so. Please ask an administrator for assistance.", w, r, user) } } - session, err := auth.CreateSession(uid) + session, err := common.Auth.CreateSession(uid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } - auth.SetCookies(w, uid, session) + common.Auth.SetCookies(w, uid, session) http.Redirect(w, r, "/", http.StatusSeeOther) return nil } // TODO: Set the cookie domain -func routeChangeTheme(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeChangeTheme(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { //headerLite, _ := SimpleUserCheck(w, r, &user) err := r.ParseForm() if err != nil { - return PreError("Bad Form", w, r) + return common.PreError("Bad Form", w, r) } // TODO: Rename isJs to something else, just in case we rewrite the JS side in WebAssembly? @@ -930,22 +926,22 @@ func routeChangeTheme(w http.ResponseWriter, r *http.Request, user User) RouteEr newTheme := html.EscapeString(r.PostFormValue("newTheme")) - theme, ok := themes[newTheme] + theme, ok := common.Themes[newTheme] if !ok || theme.HideFromThemes { // TODO: Should we be logging this? log.Print("Bad Theme: ", newTheme) - return LocalErrorJSQ("That theme doesn't exist", w, r, user, isJs) + return common.LocalErrorJSQ("That theme doesn't exist", w, r, user, isJs) } // TODO: Store the current theme in the user's account? /*if user.Loggedin { _, err = stmts.changeTheme.Exec(newTheme, user.ID) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } }*/ - cookie := http.Cookie{Name: "current_theme", Value: newTheme, Path: "/", MaxAge: year} + cookie := http.Cookie{Name: "current_theme", Value: newTheme, Path: "/", MaxAge: common.Year} http.SetCookie(w, &cookie) if !isJs { @@ -959,16 +955,16 @@ func routeChangeTheme(w http.ResponseWriter, r *http.Request, user User) RouteEr // TODO: We don't need support XML here to support sitemaps, we could handle those elsewhere var phraseLoginAlerts = []byte(`{"msgs":[{"msg":"Login to see your alerts","path":"/accounts/login"}]}`) -func routeAPI(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeAPI(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { w.Header().Set("Content-Type", "application/json") err := r.ParseForm() if err != nil { - return PreErrorJS("Bad Form", w, r) + return common.PreErrorJS("Bad Form", w, r) } action := r.FormValue("action") if action != "get" && action != "set" { - return PreErrorJS("Invalid Action", w, r) + return common.PreErrorJS("Invalid Action", w, r) } module := r.FormValue("module") @@ -976,12 +972,12 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user User) RouteError { case "dismiss-alert": asid, err := strconv.Atoi(r.FormValue("asid")) if err != nil { - return PreErrorJS("Invalid asid", w, r) + return common.PreErrorJS("Invalid asid", w, r) } _, err = stmts.deleteActivityStreamMatch.Exec(user.ID, asid) if err != nil { - return InternalError(err, w, r) + return common.InternalError(err, w, r) } case "alerts": // A feed of events tailored for a specific user if !user.Loggedin { @@ -995,32 +991,32 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user User) RouteError { err = stmts.getActivityCountByWatcher.QueryRow(user.ID).Scan(&msgCount) if err == ErrNoRows { - return PreErrorJS("Couldn't find the parent topic", w, r) + return common.PreErrorJS("Couldn't find the parent topic", w, r) } else if err != nil { - return InternalErrorJS(err, w, r) + return common.InternalErrorJS(err, w, r) } rows, err := stmts.getActivityFeedByWatcher.Query(user.ID) if err != nil { - return InternalErrorJS(err, w, r) + return common.InternalErrorJS(err, w, r) } defer rows.Close() for rows.Next() { err = rows.Scan(&asid, &actorID, &targetUserID, &event, &elementType, &elementID) if err != nil { - return InternalErrorJS(err, w, r) + return common.InternalErrorJS(err, w, r) } res, err := buildAlert(asid, event, elementType, actorID, targetUserID, elementID, user) if err != nil { - return LocalErrorJS(err.Error(), w, r) + return common.LocalErrorJS(err.Error(), w, r) } msglist += res + "," } err = rows.Err() if err != nil { - return InternalErrorJS(err, w, r) + return common.InternalErrorJS(err, w, r) } if len(msglist) != 0 { @@ -1039,7 +1035,7 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user User) RouteError { return }*/ default: - return PreErrorJS("Invalid Module", w, r) + return common.PreErrorJS("Invalid Module", w, r) } return nil } diff --git a/template_forum.go b/template_forum.go deleted file mode 100644 index 2ddb9080..00000000 --- a/template_forum.go +++ /dev/null @@ -1,230 +0,0 @@ -// +build !no_templategen - -// Code generated by Gosora. More below: -/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ -package main -import "net/http" -import "strconv" - -// nolint -func init() { - template_forum_handle = template_forum - //o_template_forum_handle = template_forum - ctemplates = append(ctemplates,"forum") - tmplPtrMap["forum"] = &template_forum_handle - tmplPtrMap["o_forum"] = template_forum -} - -// nolint -func template_forum(tmpl_forum_vars ForumPage, w http.ResponseWriter) error { -w.Write(header_0) -w.Write([]byte(tmpl_forum_vars.Title)) -w.Write(header_1) -w.Write([]byte(tmpl_forum_vars.Header.Site.Name)) -w.Write(header_2) -w.Write([]byte(tmpl_forum_vars.Header.ThemeName)) -w.Write(header_3) -if len(tmpl_forum_vars.Header.Stylesheets) != 0 { -for _, item := range tmpl_forum_vars.Header.Stylesheets { -w.Write(header_4) -w.Write([]byte(item)) -w.Write(header_5) -} -} -w.Write(header_6) -if len(tmpl_forum_vars.Header.Scripts) != 0 { -for _, item := range tmpl_forum_vars.Header.Scripts { -w.Write(header_7) -w.Write([]byte(item)) -w.Write(header_8) -} -} -w.Write(header_9) -w.Write([]byte(tmpl_forum_vars.CurrentUser.Session)) -w.Write(header_10) -w.Write([]byte(tmpl_forum_vars.Header.Site.URL)) -w.Write(header_11) -if !tmpl_forum_vars.CurrentUser.IsSuperMod { -w.Write(header_12) -} -w.Write(header_13) -w.Write(menu_0) -w.Write(menu_1) -w.Write([]byte(tmpl_forum_vars.Header.Site.ShortName)) -w.Write(menu_2) -if tmpl_forum_vars.CurrentUser.Loggedin { -w.Write(menu_3) -w.Write([]byte(tmpl_forum_vars.CurrentUser.Link)) -w.Write(menu_4) -w.Write([]byte(tmpl_forum_vars.CurrentUser.Session)) -w.Write(menu_5) -} else { -w.Write(menu_6) -} -w.Write(menu_7) -w.Write(header_14) -if tmpl_forum_vars.Header.Widgets.RightSidebar != "" { -w.Write(header_15) -} -w.Write(header_16) -if len(tmpl_forum_vars.Header.NoticeList) != 0 { -for _, item := range tmpl_forum_vars.Header.NoticeList { -w.Write(header_17) -w.Write([]byte(item)) -w.Write(header_18) -} -} -if tmpl_forum_vars.Page > 1 { -w.Write(forum_0) -w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID))) -w.Write(forum_1) -w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Page - 1))) -w.Write(forum_2) -} -if tmpl_forum_vars.LastPage != tmpl_forum_vars.Page { -w.Write(forum_3) -w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID))) -w.Write(forum_4) -w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Page + 1))) -w.Write(forum_5) -w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID))) -w.Write(forum_6) -w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Page + 1))) -w.Write(forum_7) -} -w.Write(forum_8) -if tmpl_forum_vars.CurrentUser.ID != 0 { -w.Write(forum_9) -} -w.Write(forum_10) -w.Write([]byte(tmpl_forum_vars.Title)) -w.Write(forum_11) -if tmpl_forum_vars.CurrentUser.ID != 0 { -if tmpl_forum_vars.CurrentUser.Perms.CreateTopic { -w.Write(forum_12) -w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID))) -w.Write(forum_13) -w.Write(forum_14) -} else { -w.Write(forum_15) -} -w.Write(forum_16) -} -w.Write(forum_17) -if tmpl_forum_vars.CurrentUser.ID != 0 { -w.Write(forum_18) -if tmpl_forum_vars.CurrentUser.Perms.CreateTopic { -w.Write(forum_19) -if tmpl_forum_vars.CurrentUser.Avatar != "" { -w.Write(forum_20) -w.Write([]byte(tmpl_forum_vars.CurrentUser.Avatar)) -w.Write(forum_21) -} -w.Write(forum_22) -w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID))) -w.Write(forum_23) -if tmpl_forum_vars.CurrentUser.Perms.UploadFiles { -w.Write(forum_24) -} -w.Write(forum_25) -} -} -w.Write(forum_26) -if len(tmpl_forum_vars.ItemList) != 0 { -for _, item := range tmpl_forum_vars.ItemList { -w.Write(forum_27) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(forum_28) -if item.Sticky { -w.Write(forum_29) -} else { -if item.IsClosed { -w.Write(forum_30) -} -} -w.Write(forum_31) -if item.Creator.Avatar != "" { -w.Write(forum_32) -w.Write([]byte(item.Creator.Link)) -w.Write(forum_33) -w.Write([]byte(item.Creator.Avatar)) -w.Write(forum_34) -} -w.Write(forum_35) -w.Write([]byte(item.Link)) -w.Write(forum_36) -w.Write([]byte(item.Title)) -w.Write(forum_37) -w.Write([]byte(item.Creator.Link)) -w.Write(forum_38) -w.Write([]byte(item.Creator.Name)) -w.Write(forum_39) -if item.IsClosed { -w.Write(forum_40) -} -if item.Sticky { -w.Write(forum_41) -} -w.Write(forum_42) -w.Write([]byte(strconv.Itoa(item.PostCount))) -w.Write(forum_43) -w.Write([]byte(strconv.Itoa(item.LikeCount))) -w.Write(forum_44) -if item.Sticky { -w.Write(forum_45) -} else { -if item.IsClosed { -w.Write(forum_46) -} -} -w.Write(forum_47) -if item.LastUser.Avatar != "" { -w.Write(forum_48) -w.Write([]byte(item.LastUser.Link)) -w.Write(forum_49) -w.Write([]byte(item.LastUser.Avatar)) -w.Write(forum_50) -} -w.Write(forum_51) -w.Write([]byte(item.LastUser.Link)) -w.Write(forum_52) -w.Write([]byte(item.LastUser.Name)) -w.Write(forum_53) -w.Write([]byte(item.RelativeLastReplyAt)) -w.Write(forum_54) -} -} else { -w.Write(forum_55) -if tmpl_forum_vars.CurrentUser.Perms.CreateTopic { -w.Write(forum_56) -w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID))) -w.Write(forum_57) -} -w.Write(forum_58) -} -w.Write(forum_59) -w.Write(footer_0) -if len(tmpl_forum_vars.Header.Themes) != 0 { -for _, item := range tmpl_forum_vars.Header.Themes { -if !item.HideFromThemes { -w.Write(footer_1) -w.Write([]byte(item.Name)) -w.Write(footer_2) -if tmpl_forum_vars.Header.ThemeName == item.Name { -w.Write(footer_3) -} -w.Write(footer_4) -w.Write([]byte(item.FriendlyName)) -w.Write(footer_5) -} -} -} -w.Write(footer_6) -if tmpl_forum_vars.Header.Widgets.RightSidebar != "" { -w.Write(footer_7) -w.Write([]byte(string(tmpl_forum_vars.Header.Widgets.RightSidebar))) -w.Write(footer_8) -} -w.Write(footer_9) - return nil -} diff --git a/template_forums.go b/template_forums.go deleted file mode 100644 index ef8fbcec..00000000 --- a/template_forums.go +++ /dev/null @@ -1,145 +0,0 @@ -// +build !no_templategen - -// Code generated by Gosora. More below: -/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ -package main -import "net/http" - -// nolint -func init() { - template_forums_handle = template_forums - //o_template_forums_handle = template_forums - ctemplates = append(ctemplates,"forums") - tmplPtrMap["forums"] = &template_forums_handle - tmplPtrMap["o_forums"] = template_forums -} - -// nolint -func template_forums(tmpl_forums_vars ForumsPage, w http.ResponseWriter) error { -w.Write(header_0) -w.Write([]byte(tmpl_forums_vars.Title)) -w.Write(header_1) -w.Write([]byte(tmpl_forums_vars.Header.Site.Name)) -w.Write(header_2) -w.Write([]byte(tmpl_forums_vars.Header.ThemeName)) -w.Write(header_3) -if len(tmpl_forums_vars.Header.Stylesheets) != 0 { -for _, item := range tmpl_forums_vars.Header.Stylesheets { -w.Write(header_4) -w.Write([]byte(item)) -w.Write(header_5) -} -} -w.Write(header_6) -if len(tmpl_forums_vars.Header.Scripts) != 0 { -for _, item := range tmpl_forums_vars.Header.Scripts { -w.Write(header_7) -w.Write([]byte(item)) -w.Write(header_8) -} -} -w.Write(header_9) -w.Write([]byte(tmpl_forums_vars.CurrentUser.Session)) -w.Write(header_10) -w.Write([]byte(tmpl_forums_vars.Header.Site.URL)) -w.Write(header_11) -if !tmpl_forums_vars.CurrentUser.IsSuperMod { -w.Write(header_12) -} -w.Write(header_13) -w.Write(menu_0) -w.Write(menu_1) -w.Write([]byte(tmpl_forums_vars.Header.Site.ShortName)) -w.Write(menu_2) -if tmpl_forums_vars.CurrentUser.Loggedin { -w.Write(menu_3) -w.Write([]byte(tmpl_forums_vars.CurrentUser.Link)) -w.Write(menu_4) -w.Write([]byte(tmpl_forums_vars.CurrentUser.Session)) -w.Write(menu_5) -} else { -w.Write(menu_6) -} -w.Write(menu_7) -w.Write(header_14) -if tmpl_forums_vars.Header.Widgets.RightSidebar != "" { -w.Write(header_15) -} -w.Write(header_16) -if len(tmpl_forums_vars.Header.NoticeList) != 0 { -for _, item := range tmpl_forums_vars.Header.NoticeList { -w.Write(header_17) -w.Write([]byte(item)) -w.Write(header_18) -} -} -w.Write(forums_0) -if len(tmpl_forums_vars.ItemList) != 0 { -for _, item := range tmpl_forums_vars.ItemList { -w.Write(forums_1) -if item.Desc != "" || item.LastTopic.Title != "" { -w.Write(forums_2) -} -w.Write(forums_3) -w.Write([]byte(item.Link)) -w.Write(forums_4) -w.Write([]byte(item.Name)) -w.Write(forums_5) -if item.Desc != "" { -w.Write(forums_6) -w.Write([]byte(item.Desc)) -w.Write(forums_7) -} else { -w.Write(forums_8) -} -w.Write(forums_9) -if item.LastReplyer.Avatar != "" { -w.Write(forums_10) -w.Write([]byte(item.LastReplyer.Avatar)) -w.Write(forums_11) -} -w.Write(forums_12) -w.Write([]byte(item.LastTopic.Link)) -w.Write(forums_13) -if item.LastTopic.Title != "" { -w.Write([]byte(item.LastTopic.Title)) -} else { -w.Write(forums_14) -} -w.Write(forums_15) -if item.LastTopicTime != "" { -w.Write(forums_16) -w.Write([]byte(item.LastTopicTime)) -w.Write(forums_17) -} -w.Write(forums_18) -} -} else { -w.Write(forums_19) -} -w.Write(forums_20) -w.Write(footer_0) -if len(tmpl_forums_vars.Header.Themes) != 0 { -for _, item := range tmpl_forums_vars.Header.Themes { -if !item.HideFromThemes { -w.Write(footer_1) -w.Write([]byte(item.Name)) -w.Write(footer_2) -if tmpl_forums_vars.Header.ThemeName == item.Name { -w.Write(footer_3) -} -w.Write(footer_4) -w.Write([]byte(item.FriendlyName)) -w.Write(footer_5) -} -} -} -w.Write(footer_6) -if tmpl_forums_vars.Header.Widgets.RightSidebar != "" { -w.Write(footer_7) -w.Write([]byte(string(tmpl_forums_vars.Header.Widgets.RightSidebar))) -w.Write(footer_8) -} -w.Write(footer_9) - return nil -} diff --git a/template_list.go b/template_list.go deleted file mode 100644 index c5bfbb55..00000000 --- a/template_list.go +++ /dev/null @@ -1,1022 +0,0 @@ -package main - -// nolint -var header_0 = []byte(` - - - `) -var header_1 = []byte(` | `) -var header_2 = []byte(` - - `) -var header_4 = []byte(` - - `) -var header_6 = []byte(` - - `) -var header_7 = []byte(` - - `) -var header_9 = []byte(` - - - - - - -
-`) -var menu_0 = []byte(` -`) -var header_14 = []byte(` -
-`) -var header_17 = []byte(`
`) -var header_18 = []byte(`
`) -var topic_0 = []byte(` - -
-`) -var topic_2 = []byte(` -`) -var topic_7 = []byte(` -
- -
`) -var topic_12 = []byte(` - -
- -
-
-

`) -var topic_16 = []byte(`

- `) -var topic_17 = []byte(`🔒︎`) -var topic_18 = []byte(` - - - `) -var topic_20 = []byte(` -
-
- -
-
-

`) -var topic_28 = []byte(`

- - - - -    - `) -var topic_32 = []byte(` - `) -var topic_36 = []byte(``) -var topic_38 = []byte(``) -var topic_40 = []byte(``) -var topic_42 = []byte(``) -var topic_44 = []byte(``) -var topic_46 = []byte(``) -var topic_48 = []byte(``) -var topic_50 = []byte(` - - - `) -var topic_53 = []byte(``) -var topic_55 = []byte(``) -var topic_56 = []byte(``) -var topic_57 = []byte(``) -var topic_58 = []byte(``) -var topic_59 = []byte(` - - -
-
- -
`) -var topic_60 = []byte(` -
- `) -var topic_61 = []byte(` - `) -var topic_62 = []byte(` -
-`) -var topic_63 = []byte(` - -`) -var topic_95 = []byte(`
- -`) -var topic_96 = []byte(` -
-
- -
-
- -
-
-
-
- - `) -var topic_98 = []byte(` - - -
`) -var topic_99 = []byte(` -
-
-
-`) -var topic_100 = []byte(` - -
- -`) -var footer_0 = []byte(` -
- `) -var footer_7 = []byte(``) -var footer_9 = []byte(` -
-
-
- - -`) -var topic_alt_0 = []byte(` -
`) -var topic_alt_5 = []byte(` -
`) -var topic_alt_10 = []byte(` - -
- -
-
-
-

`) -var topic_alt_15 = []byte(`

- `) -var topic_alt_16 = []byte(`🔒︎`) -var topic_alt_17 = []byte(` - - - `) -var topic_alt_19 = []byte(` -
-
-
- -
-
-
-
 
- - `) -var topic_alt_23 = []byte(`
`) -var topic_alt_25 = []byte(`
`) -var topic_alt_27 = []byte(` -
-
-
`) -var topic_alt_28 = []byte(`
- -
- `) -var topic_alt_30 = []byte(``) -var topic_alt_32 = []byte(`Edit`) -var topic_alt_34 = []byte(`Delete`) -var topic_alt_36 = []byte(`Unlock`) -var topic_alt_38 = []byte(`Lock`) -var topic_alt_40 = []byte(`Unpin`) -var topic_alt_42 = []byte(`Pin`) -var topic_alt_44 = []byte(` - Report - `) -var topic_alt_47 = []byte(` -
- `) -var topic_alt_48 = []byte(``) -var topic_alt_50 = []byte(` - `) -var topic_alt_51 = []byte(` - `) -var topic_alt_52 = []byte(``) -var topic_alt_53 = []byte(``) -var topic_alt_54 = []byte(` -
-
-
-
- - `) -var topic_alt_55 = []byte(` -
-
-
 
- - `) -var topic_alt_61 = []byte(`
`) -var topic_alt_63 = []byte(`
`) -var topic_alt_65 = []byte(` -
-
- `) -var topic_alt_68 = []byte(` - `) -var topic_alt_69 = []byte(` - `) -var topic_alt_70 = []byte(` - `) -var topic_alt_71 = []byte(` -
`) -var topic_alt_72 = []byte(`
-
- `) -var topic_alt_73 = []byte(``) -var topic_alt_75 = []byte(`Edit`) -var topic_alt_77 = []byte(`Delete`) -var topic_alt_79 = []byte(` - Report - `) -var topic_alt_82 = []byte(` -
- `) -var topic_alt_83 = []byte(``) -var topic_alt_85 = []byte(` - `) -var topic_alt_86 = []byte(` - `) -var topic_alt_87 = []byte(``) -var topic_alt_88 = []byte(``) -var topic_alt_89 = []byte(` -
-
- `) -var topic_alt_90 = []byte(` -
-
-
-`) -var topic_alt_91 = []byte(`
- -`) -var topic_alt_92 = []byte(` -
-
-
 
- - `) -var topic_alt_96 = []byte(`
`) -var topic_alt_98 = []byte(`
`) -var topic_alt_100 = []byte(` -
-
-
- -
-
- -
-
-
-
- - `) -var topic_alt_102 = []byte(` - - -
`) -var topic_alt_103 = []byte(` -
-
-
-
-`) -var topic_alt_104 = []byte(` - -
- -`) -var profile_0 = []byte(` - -
- -
- -
-
- -
-
- `) -var profile_2 = []byte(``) -var profile_3 = []byte(``) -var profile_4 = []byte(``) -var profile_5 = []byte(` -
-
- - `) -var profile_6 = []byte(`
- `) -var profile_7 = []byte(`Unban - `) -var profile_10 = []byte(`Ban`) -var profile_11 = []byte(` -
`) -var profile_12 = []byte(` -
- Report -
-
-
-
- -
- `) -var profile_15 = []byte(` - - - - `) -var profile_19 = []byte(` - -
-

Comments

-
-
`) -var profile_20 = []byte(` -
- `) -var profile_27 = []byte(` - - `) -var profile_29 = []byte(`   - - `) -var profile_30 = []byte(` - - `) -var profile_33 = []byte(` - - - - `) -var profile_36 = []byte(``) -var profile_37 = []byte(``) -var profile_38 = []byte(` - -
- `) -var profile_39 = []byte(`
- -`) -var profile_40 = []byte(` -
- -
-
-
-
-
-
-
-
-
-`) -var profile_42 = []byte(` -
- -
- -`) -var profile_43 = []byte(` - - -`) -var forums_0 = []byte(` -
- -
-

Forums

-
-
- `) -var forums_1 = []byte(`
- - `) -var forums_5 = []byte(` - `) -var forums_6 = []byte(` -
`) -var forums_7 = []byte(` - `) -var forums_8 = []byte(` -
No description - `) -var forums_9 = []byte(` -
- - - `) -var forums_10 = []byte(``) -var forums_12 = []byte(` - - `) -var forums_14 = []byte(`None`) -var forums_15 = []byte(` - `) -var forums_16 = []byte(`
`) -var forums_17 = []byte(``) -var forums_18 = []byte(` -
-
-
-
- `) -var forums_19 = []byte(`
You don't have access to any forums.
`) -var forums_20 = []byte(` -
- -
-`) -var topics_0 = []byte(` -
- -
-

All Topics

- `) -var topics_3 = []byte(` -
-
- `) -var topics_4 = []byte(` -
- -
- `) -var topics_5 = []byte(`
`) -var topics_6 = []byte(` -
- `) -var topics_7 = []byte(` -
- -`) -var topics_8 = []byte(` -
-
-
- What do you want to do with these 18 topics? -
-
- - -
-
-
- -`) -var topics_9 = []byte(` - - `) -var topics_21 = []byte(` -
- `) -var topics_22 = []byte(`
-
- - `) -var topics_27 = []byte(``) -var topics_30 = []byte(` - - `) -var topics_32 = []byte(` `) -var topics_33 = []byte(``) -var topics_35 = []byte(``) -var topics_36 = []byte(` -
`) -var topics_38 = []byte(` - `) -var topics_39 = []byte(` | 🔒︎`) -var topics_40 = []byte(` | 📍︎`) -var topics_41 = []byte(` -
- - `) -var topics_42 = []byte(`
- `) -var topics_43 = []byte(` -
-
-
- `) -var topics_47 = []byte(``) -var topics_50 = []byte(` - - `) -var topics_52 = []byte(`
- `) -var topics_53 = []byte(` -
-
-
`) -var topics_54 = []byte(`
There aren't any topics yet.`) -var topics_55 = []byte(` Start one?`) -var topics_56 = []byte(`
`) -var topics_57 = []byte(` -
- -
-`) -var forum_0 = []byte(`
`) -var forum_3 = []byte(` -
`) -var forum_8 = []byte(` - -
- -
-

`) -var forum_11 = []byte(`

-
- `) -var forum_12 = []byte(` -
-
- `) -var forum_14 = []byte(` -
- -
- `) -var forum_15 = []byte(`
`) -var forum_16 = []byte(` -
- `) -var forum_17 = []byte(` -
-`) -var forum_18 = []byte(` -
-
-
- What do you want to do with these 18 topics? -
-
- - -
-
-
- -`) -var forum_19 = []byte(` - -`) -var forum_26 = []byte(` -
- `) -var forum_27 = []byte(`
-
- - `) -var forum_32 = []byte(``) -var forum_35 = []byte(` - - `) -var forum_37 = []byte(` -
`) -var forum_39 = []byte(` - `) -var forum_40 = []byte(` | 🔒︎`) -var forum_41 = []byte(` | 📍︎`) -var forum_42 = []byte(` -
- - `) -var forum_43 = []byte(`
- `) -var forum_44 = []byte(` -
-
-
- `) -var forum_48 = []byte(``) -var forum_51 = []byte(` - - `) -var forum_53 = []byte(`
- `) -var forum_54 = []byte(` -
-
-
`) -var forum_55 = []byte(`
There aren't any topics in this forum yet.`) -var forum_56 = []byte(` Start one?`) -var forum_58 = []byte(`
`) -var forum_59 = []byte(` -
- -
-`) diff --git a/template_profile.go b/template_profile.go deleted file mode 100644 index 66876500..00000000 --- a/template_profile.go +++ /dev/null @@ -1,188 +0,0 @@ -// +build !no_templategen - -// Code generated by Gosora. More below: -/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ -package main -import "net/http" -import "strconv" - -// nolint -func init() { - template_profile_handle = template_profile - //o_template_profile_handle = template_profile - ctemplates = append(ctemplates,"profile") - tmplPtrMap["profile"] = &template_profile_handle - tmplPtrMap["o_profile"] = template_profile -} - -// nolint -func template_profile(tmpl_profile_vars ProfilePage, w http.ResponseWriter) error { -w.Write(header_0) -w.Write([]byte(tmpl_profile_vars.Title)) -w.Write(header_1) -w.Write([]byte(tmpl_profile_vars.Header.Site.Name)) -w.Write(header_2) -w.Write([]byte(tmpl_profile_vars.Header.ThemeName)) -w.Write(header_3) -if len(tmpl_profile_vars.Header.Stylesheets) != 0 { -for _, item := range tmpl_profile_vars.Header.Stylesheets { -w.Write(header_4) -w.Write([]byte(item)) -w.Write(header_5) -} -} -w.Write(header_6) -if len(tmpl_profile_vars.Header.Scripts) != 0 { -for _, item := range tmpl_profile_vars.Header.Scripts { -w.Write(header_7) -w.Write([]byte(item)) -w.Write(header_8) -} -} -w.Write(header_9) -w.Write([]byte(tmpl_profile_vars.CurrentUser.Session)) -w.Write(header_10) -w.Write([]byte(tmpl_profile_vars.Header.Site.URL)) -w.Write(header_11) -if !tmpl_profile_vars.CurrentUser.IsSuperMod { -w.Write(header_12) -} -w.Write(header_13) -w.Write(menu_0) -w.Write(menu_1) -w.Write([]byte(tmpl_profile_vars.Header.Site.ShortName)) -w.Write(menu_2) -if tmpl_profile_vars.CurrentUser.Loggedin { -w.Write(menu_3) -w.Write([]byte(tmpl_profile_vars.CurrentUser.Link)) -w.Write(menu_4) -w.Write([]byte(tmpl_profile_vars.CurrentUser.Session)) -w.Write(menu_5) -} else { -w.Write(menu_6) -} -w.Write(menu_7) -w.Write(header_14) -if tmpl_profile_vars.Header.Widgets.RightSidebar != "" { -w.Write(header_15) -} -w.Write(header_16) -if len(tmpl_profile_vars.Header.NoticeList) != 0 { -for _, item := range tmpl_profile_vars.Header.NoticeList { -w.Write(header_17) -w.Write([]byte(item)) -w.Write(header_18) -} -} -w.Write(profile_0) -w.Write([]byte(tmpl_profile_vars.ProfileOwner.Avatar)) -w.Write(profile_1) -w.Write([]byte(tmpl_profile_vars.ProfileOwner.Name)) -w.Write(profile_2) -if tmpl_profile_vars.ProfileOwner.Tag != "" { -w.Write(profile_3) -w.Write([]byte(tmpl_profile_vars.ProfileOwner.Tag)) -w.Write(profile_4) -} -w.Write(profile_5) -if tmpl_profile_vars.CurrentUser.IsSuperMod && !tmpl_profile_vars.ProfileOwner.IsSuperMod { -w.Write(profile_6) -if tmpl_profile_vars.ProfileOwner.IsBanned { -w.Write(profile_7) -w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID))) -w.Write(profile_8) -w.Write([]byte(tmpl_profile_vars.CurrentUser.Session)) -w.Write(profile_9) -} else { -w.Write(profile_10) -} -w.Write(profile_11) -} -w.Write(profile_12) -w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID))) -w.Write(profile_13) -w.Write([]byte(tmpl_profile_vars.CurrentUser.Session)) -w.Write(profile_14) -if tmpl_profile_vars.CurrentUser.Perms.BanUsers { -w.Write(profile_15) -w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID))) -w.Write(profile_16) -w.Write([]byte(tmpl_profile_vars.CurrentUser.Session)) -w.Write(profile_17) -w.Write(profile_18) -} -w.Write(profile_19) -if len(tmpl_profile_vars.ItemList) != 0 { -for _, item := range tmpl_profile_vars.ItemList { -w.Write(profile_20) -w.Write([]byte(item.ClassName)) -w.Write(profile_21) -if item.Avatar != "" { -w.Write(profile_22) -w.Write([]byte(item.Avatar)) -w.Write(profile_23) -if item.ContentLines <= 5 { -w.Write(profile_24) -} -w.Write(profile_25) -} -w.Write(profile_26) -w.Write([]byte(item.ContentHtml)) -w.Write(profile_27) -w.Write([]byte(item.UserLink)) -w.Write(profile_28) -w.Write([]byte(item.CreatedByName)) -w.Write(profile_29) -if tmpl_profile_vars.CurrentUser.IsMod { -w.Write(profile_30) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(profile_31) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(profile_32) -} -w.Write(profile_33) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(profile_34) -w.Write([]byte(tmpl_profile_vars.CurrentUser.Session)) -w.Write(profile_35) -if item.Tag != "" { -w.Write(profile_36) -w.Write([]byte(item.Tag)) -w.Write(profile_37) -} -w.Write(profile_38) -} -} -w.Write(profile_39) -if !tmpl_profile_vars.CurrentUser.IsBanned { -w.Write(profile_40) -w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID))) -w.Write(profile_41) -} -w.Write(profile_42) -w.Write(profile_43) -w.Write(footer_0) -if len(tmpl_profile_vars.Header.Themes) != 0 { -for _, item := range tmpl_profile_vars.Header.Themes { -if !item.HideFromThemes { -w.Write(footer_1) -w.Write([]byte(item.Name)) -w.Write(footer_2) -if tmpl_profile_vars.Header.ThemeName == item.Name { -w.Write(footer_3) -} -w.Write(footer_4) -w.Write([]byte(item.FriendlyName)) -w.Write(footer_5) -} -} -} -w.Write(footer_6) -if tmpl_profile_vars.Header.Widgets.RightSidebar != "" { -w.Write(footer_7) -w.Write([]byte(string(tmpl_profile_vars.Header.Widgets.RightSidebar))) -w.Write(footer_8) -} -w.Write(footer_9) - return nil -} diff --git a/template_topic.go b/template_topic.go deleted file mode 100644 index 9494842e..00000000 --- a/template_topic.go +++ /dev/null @@ -1,323 +0,0 @@ -// +build !no_templategen - -// Code generated by Gosora. More below: -/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ -package main -import "strconv" -import "net/http" - -// nolint -func init() { - template_topic_handle = template_topic - //o_template_topic_handle = template_topic - ctemplates = append(ctemplates,"topic") - tmplPtrMap["topic"] = &template_topic_handle - tmplPtrMap["o_topic"] = template_topic -} - -// nolint -func template_topic(tmpl_topic_vars TopicPage, w http.ResponseWriter) error { -w.Write(header_0) -w.Write([]byte(tmpl_topic_vars.Title)) -w.Write(header_1) -w.Write([]byte(tmpl_topic_vars.Header.Site.Name)) -w.Write(header_2) -w.Write([]byte(tmpl_topic_vars.Header.ThemeName)) -w.Write(header_3) -if len(tmpl_topic_vars.Header.Stylesheets) != 0 { -for _, item := range tmpl_topic_vars.Header.Stylesheets { -w.Write(header_4) -w.Write([]byte(item)) -w.Write(header_5) -} -} -w.Write(header_6) -if len(tmpl_topic_vars.Header.Scripts) != 0 { -for _, item := range tmpl_topic_vars.Header.Scripts { -w.Write(header_7) -w.Write([]byte(item)) -w.Write(header_8) -} -} -w.Write(header_9) -w.Write([]byte(tmpl_topic_vars.CurrentUser.Session)) -w.Write(header_10) -w.Write([]byte(tmpl_topic_vars.Header.Site.URL)) -w.Write(header_11) -if !tmpl_topic_vars.CurrentUser.IsSuperMod { -w.Write(header_12) -} -w.Write(header_13) -w.Write(menu_0) -w.Write(menu_1) -w.Write([]byte(tmpl_topic_vars.Header.Site.ShortName)) -w.Write(menu_2) -if tmpl_topic_vars.CurrentUser.Loggedin { -w.Write(menu_3) -w.Write([]byte(tmpl_topic_vars.CurrentUser.Link)) -w.Write(menu_4) -w.Write([]byte(tmpl_topic_vars.CurrentUser.Session)) -w.Write(menu_5) -} else { -w.Write(menu_6) -} -w.Write(menu_7) -w.Write(header_14) -if tmpl_topic_vars.Header.Widgets.RightSidebar != "" { -w.Write(header_15) -} -w.Write(header_16) -if len(tmpl_topic_vars.Header.NoticeList) != 0 { -for _, item := range tmpl_topic_vars.Header.NoticeList { -w.Write(header_17) -w.Write([]byte(item)) -w.Write(header_18) -} -} -w.Write(topic_0) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_1) -if tmpl_topic_vars.Page > 1 { -w.Write(topic_2) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_3) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Page - 1))) -w.Write(topic_4) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_5) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Page - 1))) -w.Write(topic_6) -} -if tmpl_topic_vars.LastPage != tmpl_topic_vars.Page { -w.Write(topic_7) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_8) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Page + 1))) -w.Write(topic_9) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_10) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Page + 1))) -w.Write(topic_11) -} -w.Write(topic_12) -if tmpl_topic_vars.Topic.Sticky { -w.Write(topic_13) -} else { -if tmpl_topic_vars.Topic.IsClosed { -w.Write(topic_14) -} -} -w.Write(topic_15) -w.Write([]byte(tmpl_topic_vars.Topic.Title)) -w.Write(topic_16) -if tmpl_topic_vars.Topic.IsClosed { -w.Write(topic_17) -} -if tmpl_topic_vars.CurrentUser.Perms.EditTopic { -w.Write(topic_18) -w.Write([]byte(tmpl_topic_vars.Topic.Title)) -w.Write(topic_19) -} -w.Write(topic_20) -w.Write([]byte(tmpl_topic_vars.Topic.ClassName)) -w.Write(topic_21) -if tmpl_topic_vars.Topic.Avatar != "" { -w.Write(topic_22) -w.Write([]byte(tmpl_topic_vars.Topic.Avatar)) -w.Write(topic_23) -w.Write([]byte(tmpl_topic_vars.Header.ThemeName)) -w.Write(topic_24) -if tmpl_topic_vars.Topic.ContentLines <= 5 { -w.Write(topic_25) -} -w.Write(topic_26) -} -w.Write(topic_27) -w.Write([]byte(tmpl_topic_vars.Topic.ContentHTML)) -w.Write(topic_28) -w.Write([]byte(tmpl_topic_vars.Topic.Content)) -w.Write(topic_29) -w.Write([]byte(tmpl_topic_vars.Topic.UserLink)) -w.Write(topic_30) -w.Write([]byte(tmpl_topic_vars.Topic.CreatedByName)) -w.Write(topic_31) -if tmpl_topic_vars.CurrentUser.Perms.LikeItem { -w.Write(topic_32) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_33) -if tmpl_topic_vars.Topic.Liked { -w.Write(topic_34) -} -w.Write(topic_35) -} -if tmpl_topic_vars.CurrentUser.Perms.EditTopic { -w.Write(topic_36) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_37) -} -if tmpl_topic_vars.CurrentUser.Perms.DeleteTopic { -w.Write(topic_38) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_39) -} -if tmpl_topic_vars.CurrentUser.Perms.CloseTopic { -if tmpl_topic_vars.Topic.IsClosed { -w.Write(topic_40) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_41) -} else { -w.Write(topic_42) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_43) -} -} -if tmpl_topic_vars.CurrentUser.Perms.PinTopic { -if tmpl_topic_vars.Topic.Sticky { -w.Write(topic_44) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_45) -} else { -w.Write(topic_46) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_47) -} -} -if tmpl_topic_vars.CurrentUser.Perms.ViewIPs { -w.Write(topic_48) -w.Write([]byte(tmpl_topic_vars.Topic.IPAddress)) -w.Write(topic_49) -} -w.Write(topic_50) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_51) -w.Write([]byte(tmpl_topic_vars.CurrentUser.Session)) -w.Write(topic_52) -if tmpl_topic_vars.Topic.LikeCount > 0 { -w.Write(topic_53) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.LikeCount))) -w.Write(topic_54) -} -if tmpl_topic_vars.Topic.Tag != "" { -w.Write(topic_55) -w.Write([]byte(tmpl_topic_vars.Topic.Tag)) -w.Write(topic_56) -} else { -w.Write(topic_57) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.Level))) -w.Write(topic_58) -} -w.Write(topic_59) -if len(tmpl_topic_vars.ItemList) != 0 { -for _, item := range tmpl_topic_vars.ItemList { -if item.ActionType != "" { -w.Write(topic_60) -w.Write([]byte(item.ActionIcon)) -w.Write(topic_61) -w.Write([]byte(item.ActionType)) -w.Write(topic_62) -} else { -w.Write(topic_63) -w.Write([]byte(item.ClassName)) -w.Write(topic_64) -if item.Avatar != "" { -w.Write(topic_65) -w.Write([]byte(item.Avatar)) -w.Write(topic_66) -w.Write([]byte(tmpl_topic_vars.Header.ThemeName)) -w.Write(topic_67) -if item.ContentLines <= 5 { -w.Write(topic_68) -} -w.Write(topic_69) -} -w.Write(topic_70) -w.Write(topic_71) -w.Write([]byte(item.ContentHtml)) -w.Write(topic_72) -w.Write([]byte(item.UserLink)) -w.Write(topic_73) -w.Write([]byte(item.CreatedByName)) -w.Write(topic_74) -if tmpl_topic_vars.CurrentUser.Perms.LikeItem { -w.Write(topic_75) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topic_76) -if item.Liked { -w.Write(topic_77) -} -w.Write(topic_78) -} -if tmpl_topic_vars.CurrentUser.Perms.EditReply { -w.Write(topic_79) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topic_80) -} -if tmpl_topic_vars.CurrentUser.Perms.DeleteReply { -w.Write(topic_81) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topic_82) -} -if tmpl_topic_vars.CurrentUser.Perms.ViewIPs { -w.Write(topic_83) -w.Write([]byte(item.IPAddress)) -w.Write(topic_84) -} -w.Write(topic_85) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topic_86) -w.Write([]byte(tmpl_topic_vars.CurrentUser.Session)) -w.Write(topic_87) -if item.LikeCount > 0 { -w.Write(topic_88) -w.Write([]byte(strconv.Itoa(item.LikeCount))) -w.Write(topic_89) -} -if item.Tag != "" { -w.Write(topic_90) -w.Write([]byte(item.Tag)) -w.Write(topic_91) -} else { -w.Write(topic_92) -w.Write([]byte(strconv.Itoa(item.Level))) -w.Write(topic_93) -} -w.Write(topic_94) -} -} -} -w.Write(topic_95) -if tmpl_topic_vars.CurrentUser.Perms.CreateReply { -w.Write(topic_96) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_97) -if tmpl_topic_vars.CurrentUser.Perms.UploadFiles { -w.Write(topic_98) -} -w.Write(topic_99) -} -w.Write(topic_100) -w.Write(footer_0) -if len(tmpl_topic_vars.Header.Themes) != 0 { -for _, item := range tmpl_topic_vars.Header.Themes { -if !item.HideFromThemes { -w.Write(footer_1) -w.Write([]byte(item.Name)) -w.Write(footer_2) -if tmpl_topic_vars.Header.ThemeName == item.Name { -w.Write(footer_3) -} -w.Write(footer_4) -w.Write([]byte(item.FriendlyName)) -w.Write(footer_5) -} -} -} -w.Write(footer_6) -if tmpl_topic_vars.Header.Widgets.RightSidebar != "" { -w.Write(footer_7) -w.Write([]byte(string(tmpl_topic_vars.Header.Widgets.RightSidebar))) -w.Write(footer_8) -} -w.Write(footer_9) - return nil -} diff --git a/template_topic_alt.go b/template_topic_alt.go deleted file mode 100644 index 60f3acea..00000000 --- a/template_topic_alt.go +++ /dev/null @@ -1,329 +0,0 @@ -// +build !no_templategen - -// Code generated by Gosora. More below: -/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ -package main -import "strconv" -import "net/http" - -// nolint -func init() { - template_topic_alt_handle = template_topic_alt - //o_template_topic_alt_handle = template_topic_alt - ctemplates = append(ctemplates,"topic_alt") - tmplPtrMap["topic_alt"] = &template_topic_alt_handle - tmplPtrMap["o_topic_alt"] = template_topic_alt -} - -// nolint -func template_topic_alt(tmpl_topic_alt_vars TopicPage, w http.ResponseWriter) error { -w.Write(header_0) -w.Write([]byte(tmpl_topic_alt_vars.Title)) -w.Write(header_1) -w.Write([]byte(tmpl_topic_alt_vars.Header.Site.Name)) -w.Write(header_2) -w.Write([]byte(tmpl_topic_alt_vars.Header.ThemeName)) -w.Write(header_3) -if len(tmpl_topic_alt_vars.Header.Stylesheets) != 0 { -for _, item := range tmpl_topic_alt_vars.Header.Stylesheets { -w.Write(header_4) -w.Write([]byte(item)) -w.Write(header_5) -} -} -w.Write(header_6) -if len(tmpl_topic_alt_vars.Header.Scripts) != 0 { -for _, item := range tmpl_topic_alt_vars.Header.Scripts { -w.Write(header_7) -w.Write([]byte(item)) -w.Write(header_8) -} -} -w.Write(header_9) -w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session)) -w.Write(header_10) -w.Write([]byte(tmpl_topic_alt_vars.Header.Site.URL)) -w.Write(header_11) -if !tmpl_topic_alt_vars.CurrentUser.IsSuperMod { -w.Write(header_12) -} -w.Write(header_13) -w.Write(menu_0) -w.Write(menu_1) -w.Write([]byte(tmpl_topic_alt_vars.Header.Site.ShortName)) -w.Write(menu_2) -if tmpl_topic_alt_vars.CurrentUser.Loggedin { -w.Write(menu_3) -w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Link)) -w.Write(menu_4) -w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session)) -w.Write(menu_5) -} else { -w.Write(menu_6) -} -w.Write(menu_7) -w.Write(header_14) -if tmpl_topic_alt_vars.Header.Widgets.RightSidebar != "" { -w.Write(header_15) -} -w.Write(header_16) -if len(tmpl_topic_alt_vars.Header.NoticeList) != 0 { -for _, item := range tmpl_topic_alt_vars.Header.NoticeList { -w.Write(header_17) -w.Write([]byte(item)) -w.Write(header_18) -} -} -if tmpl_topic_alt_vars.Page > 1 { -w.Write(topic_alt_0) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_1) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Page - 1))) -w.Write(topic_alt_2) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_3) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Page - 1))) -w.Write(topic_alt_4) -} -if tmpl_topic_alt_vars.LastPage != tmpl_topic_alt_vars.Page { -w.Write(topic_alt_5) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_6) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Page + 1))) -w.Write(topic_alt_7) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_8) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Page + 1))) -w.Write(topic_alt_9) -} -w.Write(topic_alt_10) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_11) -if tmpl_topic_alt_vars.Topic.Sticky { -w.Write(topic_alt_12) -} else { -if tmpl_topic_alt_vars.Topic.IsClosed { -w.Write(topic_alt_13) -} -} -w.Write(topic_alt_14) -w.Write([]byte(tmpl_topic_alt_vars.Topic.Title)) -w.Write(topic_alt_15) -if tmpl_topic_alt_vars.Topic.IsClosed { -w.Write(topic_alt_16) -} -if tmpl_topic_alt_vars.CurrentUser.Perms.EditTopic { -w.Write(topic_alt_17) -w.Write([]byte(tmpl_topic_alt_vars.Topic.Title)) -w.Write(topic_alt_18) -} -w.Write(topic_alt_19) -w.Write([]byte(tmpl_topic_alt_vars.Topic.Avatar)) -w.Write(topic_alt_20) -w.Write([]byte(tmpl_topic_alt_vars.Topic.UserLink)) -w.Write(topic_alt_21) -w.Write([]byte(tmpl_topic_alt_vars.Topic.CreatedByName)) -w.Write(topic_alt_22) -if tmpl_topic_alt_vars.Topic.Tag != "" { -w.Write(topic_alt_23) -w.Write([]byte(tmpl_topic_alt_vars.Topic.Tag)) -w.Write(topic_alt_24) -} else { -w.Write(topic_alt_25) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.Level))) -w.Write(topic_alt_26) -} -w.Write(topic_alt_27) -w.Write([]byte(tmpl_topic_alt_vars.Topic.ContentHTML)) -w.Write(topic_alt_28) -w.Write([]byte(tmpl_topic_alt_vars.Topic.Content)) -w.Write(topic_alt_29) -if tmpl_topic_alt_vars.CurrentUser.Loggedin { -if tmpl_topic_alt_vars.CurrentUser.Perms.LikeItem { -w.Write(topic_alt_30) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_31) -} -if tmpl_topic_alt_vars.CurrentUser.Perms.EditTopic { -w.Write(topic_alt_32) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_33) -} -if tmpl_topic_alt_vars.CurrentUser.Perms.DeleteTopic { -w.Write(topic_alt_34) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_35) -} -if tmpl_topic_alt_vars.CurrentUser.Perms.CloseTopic { -if tmpl_topic_alt_vars.Topic.IsClosed { -w.Write(topic_alt_36) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_37) -} else { -w.Write(topic_alt_38) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_39) -} -} -if tmpl_topic_alt_vars.CurrentUser.Perms.PinTopic { -if tmpl_topic_alt_vars.Topic.Sticky { -w.Write(topic_alt_40) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_41) -} else { -w.Write(topic_alt_42) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_43) -} -} -w.Write(topic_alt_44) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_45) -w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session)) -w.Write(topic_alt_46) -} -w.Write(topic_alt_47) -if tmpl_topic_alt_vars.Topic.LikeCount > 0 { -w.Write(topic_alt_48) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.LikeCount))) -w.Write(topic_alt_49) -} -w.Write(topic_alt_50) -w.Write([]byte(tmpl_topic_alt_vars.Topic.RelativeCreatedAt)) -w.Write(topic_alt_51) -if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs { -w.Write(topic_alt_52) -w.Write([]byte(tmpl_topic_alt_vars.Topic.IPAddress)) -w.Write(topic_alt_53) -} -w.Write(topic_alt_54) -if len(tmpl_topic_alt_vars.ItemList) != 0 { -for _, item := range tmpl_topic_alt_vars.ItemList { -w.Write(topic_alt_55) -if item.ActionType != "" { -w.Write(topic_alt_56) -} -w.Write(topic_alt_57) -w.Write([]byte(item.Avatar)) -w.Write(topic_alt_58) -w.Write([]byte(item.UserLink)) -w.Write(topic_alt_59) -w.Write([]byte(item.CreatedByName)) -w.Write(topic_alt_60) -if item.Tag != "" { -w.Write(topic_alt_61) -w.Write([]byte(item.Tag)) -w.Write(topic_alt_62) -} else { -w.Write(topic_alt_63) -w.Write([]byte(strconv.Itoa(item.Level))) -w.Write(topic_alt_64) -} -w.Write(topic_alt_65) -if item.ActionType != "" { -w.Write(topic_alt_66) -} -w.Write(topic_alt_67) -if item.ActionType != "" { -w.Write(topic_alt_68) -w.Write([]byte(item.ActionIcon)) -w.Write(topic_alt_69) -w.Write([]byte(item.ActionType)) -w.Write(topic_alt_70) -} else { -w.Write(topic_alt_71) -w.Write([]byte(item.ContentHtml)) -w.Write(topic_alt_72) -if tmpl_topic_alt_vars.CurrentUser.Loggedin { -if tmpl_topic_alt_vars.CurrentUser.Perms.LikeItem { -w.Write(topic_alt_73) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topic_alt_74) -} -if tmpl_topic_alt_vars.CurrentUser.Perms.EditReply { -w.Write(topic_alt_75) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topic_alt_76) -} -if tmpl_topic_alt_vars.CurrentUser.Perms.DeleteReply { -w.Write(topic_alt_77) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topic_alt_78) -} -w.Write(topic_alt_79) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topic_alt_80) -w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session)) -w.Write(topic_alt_81) -} -w.Write(topic_alt_82) -if item.LikeCount > 0 { -w.Write(topic_alt_83) -w.Write([]byte(strconv.Itoa(item.LikeCount))) -w.Write(topic_alt_84) -} -w.Write(topic_alt_85) -w.Write([]byte(item.RelativeCreatedAt)) -w.Write(topic_alt_86) -if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs { -w.Write(topic_alt_87) -w.Write([]byte(item.IPAddress)) -w.Write(topic_alt_88) -} -w.Write(topic_alt_89) -} -w.Write(topic_alt_90) -} -} -w.Write(topic_alt_91) -if tmpl_topic_alt_vars.CurrentUser.Perms.CreateReply { -w.Write(topic_alt_92) -w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Avatar)) -w.Write(topic_alt_93) -w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Link)) -w.Write(topic_alt_94) -w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Name)) -w.Write(topic_alt_95) -if tmpl_topic_alt_vars.CurrentUser.Tag != "" { -w.Write(topic_alt_96) -w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Tag)) -w.Write(topic_alt_97) -} else { -w.Write(topic_alt_98) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.CurrentUser.Level))) -w.Write(topic_alt_99) -} -w.Write(topic_alt_100) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_101) -if tmpl_topic_alt_vars.CurrentUser.Perms.UploadFiles { -w.Write(topic_alt_102) -} -w.Write(topic_alt_103) -} -w.Write(topic_alt_104) -w.Write(footer_0) -if len(tmpl_topic_alt_vars.Header.Themes) != 0 { -for _, item := range tmpl_topic_alt_vars.Header.Themes { -if !item.HideFromThemes { -w.Write(footer_1) -w.Write([]byte(item.Name)) -w.Write(footer_2) -if tmpl_topic_alt_vars.Header.ThemeName == item.Name { -w.Write(footer_3) -} -w.Write(footer_4) -w.Write([]byte(item.FriendlyName)) -w.Write(footer_5) -} -} -} -w.Write(footer_6) -if tmpl_topic_alt_vars.Header.Widgets.RightSidebar != "" { -w.Write(footer_7) -w.Write([]byte(string(tmpl_topic_alt_vars.Header.Widgets.RightSidebar))) -w.Write(footer_8) -} -w.Write(footer_9) - return nil -} diff --git a/template_topics.go b/template_topics.go deleted file mode 100644 index 38d1dee6..00000000 --- a/template_topics.go +++ /dev/null @@ -1,226 +0,0 @@ -// +build !no_templategen - -// Code generated by Gosora. More below: -/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ -package main -import "net/http" -import "strconv" - -// nolint -func init() { - template_topics_handle = template_topics - //o_template_topics_handle = template_topics - ctemplates = append(ctemplates,"topics") - tmplPtrMap["topics"] = &template_topics_handle - tmplPtrMap["o_topics"] = template_topics -} - -// nolint -func template_topics(tmpl_topics_vars TopicsPage, w http.ResponseWriter) error { -w.Write(header_0) -w.Write([]byte(tmpl_topics_vars.Title)) -w.Write(header_1) -w.Write([]byte(tmpl_topics_vars.Header.Site.Name)) -w.Write(header_2) -w.Write([]byte(tmpl_topics_vars.Header.ThemeName)) -w.Write(header_3) -if len(tmpl_topics_vars.Header.Stylesheets) != 0 { -for _, item := range tmpl_topics_vars.Header.Stylesheets { -w.Write(header_4) -w.Write([]byte(item)) -w.Write(header_5) -} -} -w.Write(header_6) -if len(tmpl_topics_vars.Header.Scripts) != 0 { -for _, item := range tmpl_topics_vars.Header.Scripts { -w.Write(header_7) -w.Write([]byte(item)) -w.Write(header_8) -} -} -w.Write(header_9) -w.Write([]byte(tmpl_topics_vars.CurrentUser.Session)) -w.Write(header_10) -w.Write([]byte(tmpl_topics_vars.Header.Site.URL)) -w.Write(header_11) -if !tmpl_topics_vars.CurrentUser.IsSuperMod { -w.Write(header_12) -} -w.Write(header_13) -w.Write(menu_0) -w.Write(menu_1) -w.Write([]byte(tmpl_topics_vars.Header.Site.ShortName)) -w.Write(menu_2) -if tmpl_topics_vars.CurrentUser.Loggedin { -w.Write(menu_3) -w.Write([]byte(tmpl_topics_vars.CurrentUser.Link)) -w.Write(menu_4) -w.Write([]byte(tmpl_topics_vars.CurrentUser.Session)) -w.Write(menu_5) -} else { -w.Write(menu_6) -} -w.Write(menu_7) -w.Write(header_14) -if tmpl_topics_vars.Header.Widgets.RightSidebar != "" { -w.Write(header_15) -} -w.Write(header_16) -if len(tmpl_topics_vars.Header.NoticeList) != 0 { -for _, item := range tmpl_topics_vars.Header.NoticeList { -w.Write(header_17) -w.Write([]byte(item)) -w.Write(header_18) -} -} -w.Write(topics_0) -if tmpl_topics_vars.CurrentUser.ID != 0 { -w.Write(topics_1) -} -w.Write(topics_2) -if tmpl_topics_vars.CurrentUser.ID != 0 { -if len(tmpl_topics_vars.ForumList) != 0 { -w.Write(topics_3) -w.Write(topics_4) -} else { -w.Write(topics_5) -} -w.Write(topics_6) -} -w.Write(topics_7) -if tmpl_topics_vars.CurrentUser.ID != 0 { -w.Write(topics_8) -if len(tmpl_topics_vars.ForumList) != 0 { -w.Write(topics_9) -if tmpl_topics_vars.CurrentUser.Avatar != "" { -w.Write(topics_10) -w.Write([]byte(tmpl_topics_vars.CurrentUser.Avatar)) -w.Write(topics_11) -} -w.Write(topics_12) -if len(tmpl_topics_vars.ForumList) != 0 { -for _, item := range tmpl_topics_vars.ForumList { -w.Write(topics_13) -if item.ID == tmpl_topics_vars.DefaultForum { -w.Write(topics_14) -} -w.Write(topics_15) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topics_16) -w.Write([]byte(item.Name)) -w.Write(topics_17) -} -} -w.Write(topics_18) -if tmpl_topics_vars.CurrentUser.Perms.UploadFiles { -w.Write(topics_19) -} -w.Write(topics_20) -} -} -w.Write(topics_21) -if len(tmpl_topics_vars.TopicList) != 0 { -for _, item := range tmpl_topics_vars.TopicList { -w.Write(topics_22) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topics_23) -if item.Sticky { -w.Write(topics_24) -} else { -if item.IsClosed { -w.Write(topics_25) -} -} -w.Write(topics_26) -if item.Creator.Avatar != "" { -w.Write(topics_27) -w.Write([]byte(item.Creator.Link)) -w.Write(topics_28) -w.Write([]byte(item.Creator.Avatar)) -w.Write(topics_29) -} -w.Write(topics_30) -w.Write([]byte(item.Link)) -w.Write(topics_31) -w.Write([]byte(item.Title)) -w.Write(topics_32) -if item.ForumName != "" { -w.Write(topics_33) -w.Write([]byte(item.ForumLink)) -w.Write(topics_34) -w.Write([]byte(item.ForumName)) -w.Write(topics_35) -} -w.Write(topics_36) -w.Write([]byte(item.Creator.Link)) -w.Write(topics_37) -w.Write([]byte(item.Creator.Name)) -w.Write(topics_38) -if item.IsClosed { -w.Write(topics_39) -} -if item.Sticky { -w.Write(topics_40) -} -w.Write(topics_41) -w.Write([]byte(strconv.Itoa(item.PostCount))) -w.Write(topics_42) -w.Write([]byte(strconv.Itoa(item.LikeCount))) -w.Write(topics_43) -if item.Sticky { -w.Write(topics_44) -} else { -if item.IsClosed { -w.Write(topics_45) -} -} -w.Write(topics_46) -if item.LastUser.Avatar != "" { -w.Write(topics_47) -w.Write([]byte(item.LastUser.Link)) -w.Write(topics_48) -w.Write([]byte(item.LastUser.Avatar)) -w.Write(topics_49) -} -w.Write(topics_50) -w.Write([]byte(item.LastUser.Link)) -w.Write(topics_51) -w.Write([]byte(item.LastUser.Name)) -w.Write(topics_52) -w.Write([]byte(item.RelativeLastReplyAt)) -w.Write(topics_53) -} -} else { -w.Write(topics_54) -if tmpl_topics_vars.CurrentUser.Perms.CreateTopic { -w.Write(topics_55) -} -w.Write(topics_56) -} -w.Write(topics_57) -w.Write(footer_0) -if len(tmpl_topics_vars.Header.Themes) != 0 { -for _, item := range tmpl_topics_vars.Header.Themes { -if !item.HideFromThemes { -w.Write(footer_1) -w.Write([]byte(item.Name)) -w.Write(footer_2) -if tmpl_topics_vars.Header.ThemeName == item.Name { -w.Write(footer_3) -} -w.Write(footer_4) -w.Write([]byte(item.FriendlyName)) -w.Write(footer_5) -} -} -} -w.Write(footer_6) -if tmpl_topics_vars.Header.Widgets.RightSidebar != "" { -w.Write(footer_7) -w.Write([]byte(string(tmpl_topics_vars.Header.Widgets.RightSidebar))) -w.Write(footer_8) -} -w.Write(footer_9) - return nil -} diff --git a/websockets.go b/websockets.go index 906b24dc..75548933 100644 --- a/websockets.go +++ b/websockets.go @@ -18,6 +18,7 @@ import ( "sync" "time" + "./common" "github.com/Azareal/gopsutil/cpu" "github.com/Azareal/gopsutil/mem" "github.com/gorilla/websocket" @@ -25,7 +26,7 @@ import ( type WSUser struct { conn *websocket.Conn - User *User + User *common.User } type WSHub struct { @@ -164,13 +165,13 @@ func (hub *WSHub) pushAlerts(users []int, asid int, event string, elementType st } // TODO: How should we handle errors for this? -func routeWebsockets(w http.ResponseWriter, r *http.Request, user User) RouteError { +func routeWebsockets(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { conn, err := wsUpgrader.Upgrade(w, r, nil) if err != nil { return nil } - userptr, err := users.Get(user.ID) - if err != nil && err != ErrStoreCapacityOverflow { + userptr, err := common.Users.Get(user.ID) + if err != nil && err != common.ErrStoreCapacityOverflow { return nil } @@ -341,9 +342,9 @@ AdminStatLoop: onlineUsersColour = "stat_red" } - totonline, totunit = convertFriendlyUnit(totonline) - uonline, uunit = convertFriendlyUnit(uonline) - gonline, gunit = convertFriendlyUnit(gonline) + totonline, totunit = common.ConvertFriendlyUnit(totonline) + uonline, uunit = common.ConvertFriendlyUnit(uonline) + gonline, gunit = common.ConvertFriendlyUnit(gonline) } if cpuerr != nil { @@ -364,8 +365,8 @@ AdminStatLoop: if ramerr != nil { ramstr = "Unknown" } else { - totalCount, totalUnit := convertByteUnit(float64(memres.Total)) - usedCount := convertByteInUnit(float64(memres.Total-memres.Available), totalUnit) + totalCount, totalUnit := common.ConvertByteUnit(float64(memres.Total)) + usedCount := common.ConvertByteInUnit(float64(memres.Total-memres.Available), totalUnit) // Round totals with .9s up, it's how most people see it anyway. Floats are notoriously imprecise, so do it off 0.85 var totstr string diff --git a/word_filters.go b/word_filters.go deleted file mode 100644 index 338a0e85..00000000 --- a/word_filters.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import "sync/atomic" - -type WordFilter struct { - ID int - Find string - Replacement string -} -type WordFilterBox map[int]WordFilter - -var wordFilterBox atomic.Value // An atomic value holding a WordFilterBox - -func init() { - wordFilterBox.Store(WordFilterBox(make(map[int]WordFilter))) -} - -func LoadWordFilters() error { - rows, err := stmts.getWordFilters.Query() - if err != nil { - return err - } - defer rows.Close() - - var wordFilters = WordFilterBox(make(map[int]WordFilter)) - var wfid int - var find string - var replacement string - - for rows.Next() { - err := rows.Scan(&wfid, &find, &replacement) - if err != nil { - return err - } - wordFilters[wfid] = WordFilter{ID: wfid, Find: find, Replacement: replacement} - } - wordFilterBox.Store(wordFilters) - return rows.Err() -} - -func addWordFilter(id int, find string, replacement string) { - wordFilters := wordFilterBox.Load().(WordFilterBox) - wordFilters[id] = WordFilter{ID: id, Find: find, Replacement: replacement} - wordFilterBox.Store(wordFilters) -}