Finished moving the files into the subpackage, this should open more doors to us.

Moved more queries out of the global stmt holder.
Refactored several things.
This commit is contained in:
Azareal 2017-11-11 04:06:16 +00:00
parent 10e681f15f
commit f30ea7a9bb
72 changed files with 2959 additions and 6076 deletions

View File

@ -6,10 +6,14 @@
*/ */
package main package main
import "log" import (
import "strings" "errors"
import "strconv" "log"
import "errors" "strconv"
"strings"
"./common"
)
// These notes are for me, don't worry about it too much ^_^ // These notes are for me, don't worry about it too much ^_^
/* /*
@ -26,10 +30,10 @@ import "errors"
"{x}{created a new topic}{topic}" "{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) { func buildAlert(asid int, event string, elementType string, actorID int, targetUserID int, elementID int, user common.User /* The current user */) (string, error) {
var targetUser *User var targetUser *common.User
actor, err := users.Get(actorID) actor, err := common.Users.Get(actorID)
if err != nil { if err != nil {
return "", errors.New("Unable to find the actor") 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": case "forum":
if event == "reply" { if event == "reply" {
act = "created a new topic" act = "created a new topic"
topic, err := topics.Get(elementID) topic, err := common.Topics.Get(elementID)
if err != nil { if err != nil {
return "", errors.New("Unable to find the linked topic") 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" act = "did something in a forum"
} }
case "topic": case "topic":
topic, err := topics.Get(elementID) topic, err := common.Topics.Get(elementID)
if err != nil { if err != nil {
return "", errors.New("Unable to find the linked topic") 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" postAct = " your topic"
} }
case "user": case "user":
targetUser, err = users.Get(elementID) targetUser, err = common.Users.Get(elementID)
if err != nil { if err != nil {
return "", errors.New("Unable to find the target user") 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" endFrag = "'s profile"
url = targetUser.Link url = targetUser.Link
case "post": case "post":
topic, err := getTopicByReply(elementID) reply := common.BlankReply()
reply.ID = elementID
topic, err := reply.Topic()
if err != nil { if err != nil {
return "", errors.New("Unable to find the linked reply or parent topic") return "", errors.New("Unable to find the linked reply or parent topic")
} }

View File

@ -4,18 +4,17 @@
* Copyright Azareal 2017 - 2018 * Copyright Azareal 2017 - 2018
* *
*/ */
package main package common
import "log"
import "errors" import "errors"
import "strconv" import "strconv"
import "net/http" import "net/http"
import "database/sql" import "database/sql"
import "./query_gen/lib"
import "golang.org/x/crypto/bcrypt" 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 // ErrMismatchedHashAndPassword is thrown whenever a hash doesn't match it's unhashed password
var ErrMismatchedHashAndPassword = bcrypt.ErrMismatchedHashAndPassword 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 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.") var ErrNoUserByName = errors.New("We couldn't find an account with that username.")
// Auth is the main authentication interface. // AuthInt is the main authentication interface.
type Auth interface { type AuthInt interface {
Authenticate(username string, password string) (uid int, err error) Authenticate(username string, password string) (uid int, err error)
Logout(w http.ResponseWriter, uid int) Logout(w http.ResponseWriter, uid int)
ForceLogout(uid int) error 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. // 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 { type DefaultAuth struct {
login *sql.Stmt login *sql.Stmt
logout *sql.Stmt logout *sql.Stmt
updateSession *sql.Stmt
} }
// NewDefaultAuth is a factory for spitting out DefaultAuths // NewDefaultAuth is a factory for spitting out DefaultAuths
func NewDefaultAuth() *DefaultAuth { func NewDefaultAuth() (*DefaultAuth, error) {
loginStmt, err := qgen.Builder.SimpleSelect("users", "uid, password, salt", "name = ?", "", "") acc := qgen.Builder.Accumulator()
if err != nil {
log.Fatal(err)
}
logoutStmt, err := qgen.Builder.SimpleUpdate("users", "session = ''", "uid = ?")
if err != nil {
log.Fatal(err)
}
return &DefaultAuth{ return &DefaultAuth{
login: loginStmt, login: acc.SimpleSelect("users", "uid, password, salt", "name = ?", "", ""),
logout: logoutStmt, 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. // 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 // Flush the user out of the cache
ucache, ok := users.(UserCache) ucache, ok := Users.(UserCache)
if ok { if ok {
ucache.CacheRemove(uid) 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 // 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) { 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) 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) http.SetCookie(w, &cookie)
} }
// TODO: Set the cookie domain // 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 // 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) { 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) 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) 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) { func (auth *DefaultAuth) SessionCheck(w http.ResponseWriter, r *http.Request) (user *User, halt bool) {
uid, session, err := auth.GetCookies(r) uid, session, err := auth.GetCookies(r)
if err != nil { if err != nil {
return &guestUser, false return &GuestUser, false
} }
// Is this session valid..? // Is this session valid..?
user, err = users.Get(uid) user, err = Users.Get(uid)
if err == ErrNoRows { if err == ErrNoRows {
return &guestUser, false return &GuestUser, false
} else if err != nil { } else if err != nil {
InternalError(err, w, r) InternalError(err, w, r)
return &guestUser, true return &GuestUser, true
} }
if user.Session == "" || session != user.Session { if user.Session == "" || session != user.Session {
return &guestUser, false return &GuestUser, false
} }
return user, 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 // 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) { func (auth *DefaultAuth) CreateSession(uid int) (session string, err error) {
session, err = GenerateSafeString(sessionLength) session, err = GenerateSafeString(SessionLength)
if err != nil { if err != nil {
return "", err return "", err
} }
_, err = stmts.updateSession.Exec(session, uid) _, err = auth.updateSession.Exec(session, uid)
if err != nil { if err != nil {
return "", err return "", err
} }
// Flush the user data from the cache // Flush the user data from the cache
ucache, ok := users.(UserCache) ucache, ok := Users.(UserCache)
if ok { if ok {
ucache.CacheRemove(uid) ucache.CacheRemove(uid)
} }

View File

@ -1,4 +1,4 @@
package main package common
import "errors" import "errors"
@ -17,10 +17,10 @@ var ErrStoreCapacityOverflow = errors.New("This datastore has reached it's maxim
// nolint // nolint
type DataStore interface { type DataStore interface {
Load(id int) error DirtyGet(id int) interface{}
Get(id int) (interface{}, error) Get(id int) (interface{}, error)
BypassGet(id int) (interface{}, error) BypassGet(id int) (interface{}, error)
//GetGlobalCount() //GlobalCount()
} }
// nolint // nolint
@ -32,6 +32,9 @@ type DataCache interface {
CacheAddUnsafe(item interface{}) error CacheAddUnsafe(item interface{}) error
CacheRemove(id int) error CacheRemove(id int) error
CacheRemoveUnsafe(id int) error CacheRemoveUnsafe(id int) error
GetLength() int Reload(id int) error
Flush()
Length() int
SetCapacity(capacity int)
GetCapacity() int GetCapacity() int
} }

View File

@ -2,5 +2,78 @@ package common
import "database/sql" 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 // ErrNoRows is an alias of sql.ErrNoRows, just in case we end up with non-database/sql datastores
var ErrNoRows = sql.ErrNoRows 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...)
}

73
common/email.go Normal file
View File

@ -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
}

View File

@ -21,7 +21,7 @@ var tList []interface{}
type RouteError interface { type RouteError interface {
Type() string Type() string
Error() string Error() string
Json() bool JSON() bool
Handled() bool Handled() bool
} }
@ -49,7 +49,7 @@ func (err *RouteErrorImpl) Error() string {
} }
// Respond with JSON? // Respond with JSON?
func (err *RouteErrorImpl) Json() bool { func (err *RouteErrorImpl) JSON() bool {
return err.json 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 // 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} 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."} 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 { if err != nil {
log.Print(err) log.Print(err)
} }
@ -119,33 +119,16 @@ func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) RouteErr
return HandledRouteError() 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 { func PreError(errmsg string, w http.ResponseWriter, r *http.Request) RouteError {
w.WriteHeader(500) w.WriteHeader(500)
user := User{ID: 0, Group: 6, Perms: GuestPerms} user := User{ID: 0, Group: 6, Perms: GuestPerms}
pi := Page{"Error", user, DefaultHeaderVar(), tList, errmsg} pi := Page{"Error", user, DefaultHeaderVar(), tList, errmsg}
if preRenderHooks["pre_render_error"] != nil { if PreRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) { if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) 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 { func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(500) w.WriteHeader(500)
pi := Page{"Local Error", user, DefaultHeaderVar(), tList, errmsg} pi := Page{"Local Error", user, DefaultHeaderVar(), tList, errmsg}
if preRenderHooks["pre_render_error"] != nil { if PreRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) { if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
@ -200,12 +183,12 @@ func NoPermissions(w http.ResponseWriter, r *http.Request, user User) RouteError
w.WriteHeader(403) w.WriteHeader(403)
pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You don't have permission to do that."} pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You don't have permission to do that."}
// TODO: What to do about this hook? // TODO: What to do about this hook?
if preRenderHooks["pre_render_error"] != nil { if PreRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) { if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) 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 { func Banned(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(403) w.WriteHeader(403)
pi := Page{"Banned", user, DefaultHeaderVar(), tList, "You have been banned from this site."} pi := Page{"Banned", user, DefaultHeaderVar(), tList, "You have been banned from this site."}
if preRenderHooks["pre_render_error"] != nil { if PreRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) { if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
@ -258,21 +241,33 @@ func BannedJS(w http.ResponseWriter, r *http.Request, user User) RouteError {
// nolint // nolint
func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) RouteError { func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) RouteError {
w.WriteHeader(401)
if !isJs { if !isJs {
pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You need to login to do that."} return LoginRequired(w, r, user)
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 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() 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 { func SecurityError(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(403) w.WriteHeader(403)
pi := Page{"Security Error", user, DefaultHeaderVar(), tList, "There was a security issue with your request."} pi := Page{"Security Error", user, DefaultHeaderVar(), tList, "There was a security issue with your request."}
if preRenderHooks["pre_render_security_error"] != nil { if PreRenderHooks["pre_render_security_error"] != nil {
if runPreRenderHook("pre_render_security_error", w, r, &user, &pi) { if RunPreRenderHook("pre_render_security_error", w, r, &user, &pi) {
return nil return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
@ -301,7 +296,7 @@ func NotFound(w http.ResponseWriter, r *http.Request) RouteError {
// TODO: Centralise the user struct somewhere else // 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} 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."} 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 { if err != nil {
LogError(err) 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 { func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(errcode) w.WriteHeader(errcode)
pi := Page{errtitle, user, DefaultHeaderVar(), tList, errmsg} pi := Page{errtitle, user, DefaultHeaderVar(), tList, errmsg}
if preRenderHooks["pre_render_error"] != nil { if PreRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) { if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil return nil
} }
} }
err := templates.ExecuteTemplate(w, "error.html", pi) err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil { if err != nil {
LogError(err) LogError(err)
} }

View File

@ -18,13 +18,13 @@ type PluginList map[string]*Plugin
var Plugins PluginList = make(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? // 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, "forums_frow_assign": nil,
"topic_create_frow_assign": nil, "topic_create_frow_assign": nil,
} }
// Hooks with a variable number of arguments // 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, "intercept_build_widgets": nil,
"forum_trow_assign": nil, "forum_trow_assign": nil,
"topics_topic_row_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 // 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, "simple_forum_check_pre_perms": nil,
"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 // 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, "preparse_preassign": nil,
"parse_assign": nil, "parse_assign": nil,
} }
// The hooks which run before the template is rendered for a route // 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": nil,
"pre_render_forum_list": 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 Data interface{} // Usually used for hosting the VMs / reusable elements of non-native plugins
} }
func initExtend() (err error) { func InitExtend() (err error) {
err = InitPluginLangs() err = InitPluginLangs()
if err != nil { if err != nil {
return err return err
@ -145,7 +145,7 @@ func initExtend() (err error) {
return Plugins.Load() 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 { func (plugins PluginList) Load() error {
getPlugins, err := qgen.Builder.SimpleSelect("plugins", "uname, active, installed", "", "", "") getPlugins, err := qgen.Builder.SimpleSelect("plugins", "uname, active, installed", "", "", "")
if err != nil { 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{}) { func (plugin *Plugin) AddHook(name string, handler interface{}) {
switch h := handler.(type) { switch h := handler.(type) {
case func(interface{}) interface{}: case func(interface{}) interface{}:
if len(hooks[name]) == 0 { if len(Hooks[name]) == 0 {
var hookSlice []func(interface{}) interface{} var hookSlice []func(interface{}) interface{}
hookSlice = append(hookSlice, h) hookSlice = append(hookSlice, h)
hooks[name] = hookSlice Hooks[name] = hookSlice
} else { } 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: case func(string) string:
if len(sshooks[name]) == 0 { if len(Sshooks[name]) == 0 {
var hookSlice []func(string) string var hookSlice []func(string) string
hookSlice = append(hookSlice, h) hookSlice = append(hookSlice, h)
sshooks[name] = hookSlice Sshooks[name] = hookSlice
} else { } 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: 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 var hookSlice []func(http.ResponseWriter, *http.Request, *User, interface{}) bool
hookSlice = append(hookSlice, h) hookSlice = append(hookSlice, h)
preRenderHooks[name] = hookSlice PreRenderHooks[name] = hookSlice
} else { } 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{}: case func(...interface{}) interface{}:
vhooks[name] = h Vhooks[name] = h
plugin.Hooks[name] = 0 plugin.Hooks[name] = 0
case func(...interface{}) (bool, RouteError): case func(...interface{}) (bool, RouteError):
vhookSkippable[name] = h VhookSkippable[name] = h
plugin.Hooks[name] = 0 plugin.Hooks[name] = 0
default: default:
panic("I don't recognise this kind of handler!") // Should this be an error for the plugin instead of a panic()? 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) { switch handler.(type) {
case func(interface{}) interface{}: case func(interface{}) interface{}:
key := plugin.Hooks[name] key := plugin.Hooks[name]
hook := hooks[name] hook := Hooks[name]
if len(hook) == 1 { if len(hook) == 1 {
hook = []func(interface{}) interface{}{} hook = []func(interface{}) interface{}{}
} else { } else {
hook = append(hook[:key], hook[key+1:]...) hook = append(hook[:key], hook[key+1:]...)
} }
hooks[name] = hook Hooks[name] = hook
case func(string) string: case func(string) string:
key := plugin.Hooks[name] key := plugin.Hooks[name]
hook := sshooks[name] hook := Sshooks[name]
if len(hook) == 1 { if len(hook) == 1 {
hook = []func(string) string{} hook = []func(string) string{}
} else { } else {
hook = append(hook[:key], hook[key+1:]...) hook = append(hook[:key], hook[key+1:]...)
} }
sshooks[name] = hook Sshooks[name] = hook
case func(http.ResponseWriter, *http.Request, *User, interface{}) bool: case func(http.ResponseWriter, *http.Request, *User, interface{}) bool:
key := plugin.Hooks[name] key := plugin.Hooks[name]
hook := preRenderHooks[name] hook := PreRenderHooks[name]
if len(hook) == 1 { if len(hook) == 1 {
hook = []func(http.ResponseWriter, *http.Request, *User, interface{}) bool{} hook = []func(http.ResponseWriter, *http.Request, *User, interface{}) bool{}
} else { } else {
hook = append(hook[:key], hook[key+1:]...) hook = append(hook[:key], hook[key+1:]...)
} }
preRenderHooks[name] = hook PreRenderHooks[name] = hook
case func(...interface{}) interface{}: case func(...interface{}) interface{}:
delete(vhooks, name) delete(Vhooks, name)
case func(...interface{}) (bool, RouteError): case func(...interface{}) (bool, RouteError):
delete(vhookSkippable, name) delete(VhookSkippable, name)
default: default:
panic("I don't recognise this kind of handler!") // Should this be an error for the plugin instead of a panic()? 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 var pluginsInited = false
func initPlugins() { func InitPlugins() {
for name, body := range Plugins { for name, body := range Plugins {
log.Print("Added plugin " + name) log.Printf("Added plugin %s", name)
if body.Active { if body.Active {
log.Print("Initialised plugin " + name) log.Printf("Initialised plugin %s", name)
if Plugins[name].Init != nil { if Plugins[name].Init != nil {
err := Plugins[name].Init() err := Plugins[name].Init()
if err != nil { if err != nil {
log.Print(err) log.Print(err)
} }
} else { } else {
log.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? // ? - Are the following functions racey?
func runHook(name string, data interface{}) interface{} { func RunHook(name string, data interface{}) interface{} {
for _, hook := range hooks[name] { for _, hook := range Hooks[name] {
data = hook(data) data = hook(data)
} }
return data return data
} }
func runHookNoreturn(name string, data interface{}) { func RunHookNoreturn(name string, data interface{}) {
for _, hook := range hooks[name] { for _, hook := range Hooks[name] {
_ = hook(data) _ = hook(data)
} }
} }
func runVhook(name string, data ...interface{}) interface{} { func RunVhook(name string, data ...interface{}) interface{} {
return vhooks[name](data...) return Vhooks[name](data...)
} }
func runVhookSkippable(name string, data ...interface{}) (bool, RouteError) { func RunVhookSkippable(name string, data ...interface{}) (bool, RouteError) {
return vhookSkippable[name](data...) return VhookSkippable[name](data...)
} }
func runVhookNoreturn(name string, data ...interface{}) { func RunVhookNoreturn(name string, data ...interface{}) {
_ = vhooks[name](data...) _ = Vhooks[name](data...)
} }
// Trying to get a teeny bit of type-safety where-ever possible, especially for such a critical set of hooks // 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 { func RunSshook(name string, data string) string {
for _, hook := range sshooks[name] { for _, hook := range Sshooks[name] {
data = hook(data) data = hook(data)
} }
return 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 // 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) { if hook(w, r, user, data) {
return true return true
} }
} }
// The actual pre_render hook // The actual pre_render hook
for _, hook := range preRenderHooks[name] { for _, hook := range PreRenderHooks[name] {
if hook(w, r, user, data) { if hook(w, r, user, data) {
return true return true
} }

View File

@ -1,4 +1,4 @@
package main package common
import ( import (
"bytes" "bytes"
@ -13,6 +13,10 @@ import (
"path/filepath" "path/filepath"
) )
type SFileList map[string]SFile
var StaticFiles SFileList = make(map[string]SFile)
type SFile struct { type SFile struct {
Data []byte Data []byte
GzipData []byte GzipData []byte
@ -28,7 +32,7 @@ type CSSData struct {
ComingSoon string ComingSoon string
} }
func initStaticFiles() error { func (list SFileList) Init() error {
return filepath.Walk("./public", func(path string, f os.FileInfo, err error) error { return filepath.Walk("./public", func(path string, f os.FileInfo, err error) error {
if f.IsDir() { if f.IsDir() {
return nil return nil
@ -44,16 +48,16 @@ func initStaticFiles() error {
var ext = filepath.Ext("/public/" + path) var ext = filepath.Ext("/public/" + path)
gzipData := compressBytesGzip(data) 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.") log.Print("Added the '" + path + "' static file.")
} }
return nil return nil
}) })
} }
func addStaticFile(path string, prefix string) error { func (list SFileList) Add(path string, prefix string) error {
data, err := ioutil.ReadFile(path) data, err := ioutil.ReadFile(path)
if err != nil { if err != nil {
return err return err
@ -71,10 +75,10 @@ func addStaticFile(path string, prefix string) error {
path = strings.TrimPrefix(path, prefix) path = strings.TrimPrefix(path, prefix)
gzipData := compressBytesGzip(data) 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") log.Printf("Added the '%s' static file", path)
} }
return nil return nil
} }

View File

@ -2,12 +2,15 @@ package common
//import "fmt" //import "fmt"
import ( import (
"database/sql"
"strconv" "strconv"
"strings" "strings"
"../query_gen/lib"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
) )
// TODO: Do we really need this?
type ForumAdmin struct { type ForumAdmin struct {
ID int ID int
Name string Name string
@ -44,11 +47,25 @@ type ForumSimple struct {
Preset string 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 // Copy gives you a non-pointer concurrency safe copy of the forum
func (forum *Forum) Copy() (fcopy Forum) { func (forum *Forum) Copy() (fcopy Forum) {
//forum.LastLock.RLock()
fcopy = *forum fcopy = *forum
//forum.LastLock.RUnlock()
return fcopy return fcopy
} }
@ -58,17 +75,17 @@ func (forum *Forum) Update(name string, desc string, active bool, preset string)
name = forum.Name name = forum.Name
} }
preset = strings.TrimSpace(preset) 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 { if err != nil {
return err return err
} }
if forum.Preset != preset || preset == "custom" || preset == "" { if forum.Preset != preset || preset == "custom" || preset == "" {
err = permmapToQuery(presetToPermmap(preset), forum.ID) err = PermmapToQuery(PresetToPermmap(preset), forum.ID)
if err != nil { if err != nil {
return err return err
} }
} }
_ = fstore.Reload(forum.ID) _ = Fstore.Reload(forum.ID)
return nil 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} 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 == "" { if slug == "" {
return "/forum/" + strconv.Itoa(fid) return "/forum/" + strconv.Itoa(fid)
} }
return "/forum/" + slug + "." + strconv.Itoa(fid) return "/forum/" + slug + "." + strconv.Itoa(fid)
} }
func getForumURLPrefix() string { func GetForumURLPrefix() string {
return "/forum/" return "/forum/"
} }

View File

@ -8,7 +8,7 @@ import (
"../query_gen/lib" "../query_gen/lib"
) )
var fpstore ForumPermsStore var Fpstore ForumPermsStore
type ForumPermsStore interface { type ForumPermsStore interface {
Init() error Init() error
@ -40,11 +40,11 @@ func NewMemoryForumPermsStore() (*MemoryForumPermsStore, error) {
} }
func (fps *MemoryForumPermsStore) Init() error { func (fps *MemoryForumPermsStore) Init() error {
fids, err := fstore.GetAllIDs() fids, err := Fstore.GetAllIDs()
if err != nil { if err != nil {
return err return err
} }
if dev.SuperDebug { if Dev.SuperDebug {
log.Print("fids: ", fids) log.Print("fids: ", fids)
} }
@ -54,9 +54,9 @@ func (fps *MemoryForumPermsStore) Init() error {
} }
defer rows.Close() defer rows.Close()
if dev.DebugMode { if Dev.DebugMode {
log.Print("Adding the forum permissions") log.Print("Adding the forum permissions")
if dev.SuperDebug { if Dev.SuperDebug {
log.Print("forumPerms[gid][fid]") log.Print("forumPerms[gid][fid]")
} }
} }
@ -72,7 +72,7 @@ func (fps *MemoryForumPermsStore) Init() error {
return err return err
} }
if dev.SuperDebug { if Dev.SuperDebug {
log.Print("perms: ", string(perms)) log.Print("perms: ", string(perms))
} }
err = json.Unmarshal(perms, &pperms) err = json.Unmarshal(perms, &pperms)
@ -86,7 +86,7 @@ func (fps *MemoryForumPermsStore) Init() error {
forumPerms[gid] = make(map[int]ForumPerms) forumPerms[gid] = make(map[int]ForumPerms)
} }
if dev.SuperDebug { if Dev.SuperDebug {
log.Print("gid: ", gid) log.Print("gid: ", gid)
log.Print("fid: ", fid) log.Print("fid: ", fid)
log.Printf("perms: %+v\n", pperms) 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? // TODO: Need a more thread-safe way of doing this. Possibly with sync.Map?
func (fps *MemoryForumPermsStore) Reload(fid int) error { func (fps *MemoryForumPermsStore) Reload(fid int) error {
if dev.DebugMode { if Dev.DebugMode {
log.Printf("Reloading the forum permissions for forum #%d", fid) log.Printf("Reloading the forum permissions for forum #%d", fid)
} }
fids, err := fstore.GetAllIDs() fids, err := Fstore.GetAllIDs()
if err != nil { if err != nil {
return err return err
} }
@ -138,20 +138,20 @@ func (fps *MemoryForumPermsStore) Reload(fid int) error {
} }
func (fps *MemoryForumPermsStore) cascadePermSetToGroups(forumPerms map[int]map[int]ForumPerms, fids []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 { if err != nil {
return err return err
} }
for _, group := range groups { for _, group := range groups {
if dev.DebugMode { if Dev.DebugMode {
log.Printf("Updating the forum permissions for Group #%d", group.ID) log.Printf("Updating the forum permissions for Group #%d", group.ID)
} }
group.Forums = []ForumPerms{BlankForumPerms} group.Forums = []ForumPerms{BlankForumPerms}
group.CanSee = []int{} group.CanSee = []int{}
fps.cascadePermSetToGroup(forumPerms, group, fids) fps.cascadePermSetToGroup(forumPerms, group, fids)
if dev.SuperDebug { if Dev.SuperDebug {
log.Printf("group.CanSee (length %d): %+v \n", len(group.CanSee), group.CanSee) 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) 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) { func (fps *MemoryForumPermsStore) cascadePermSetToGroup(forumPerms map[int]map[int]ForumPerms, group *Group, fids []int) {
for _, fid := range fids { for _, fid := range fids {
if dev.SuperDebug { if Dev.SuperDebug {
log.Printf("Forum #%+v\n", fid) log.Printf("Forum #%+v\n", fid)
} }
forumPerm, ok := forumPerms[group.ID][fid] forumPerm, ok := forumPerms[group.ID][fid]
if ok { if ok {
//log.Print("Overriding permissions for forum #%d",fid) //log.Printf("Overriding permissions for forum #%d",fid)
group.Forums = append(group.Forums, forumPerm) group.Forums = append(group.Forums, forumPerm)
} else { } else {
//log.Printf("Inheriting from group defaults for forum #%d",fid) //log.Printf("Inheriting from group defaults for forum #%d",fid)
@ -181,7 +181,7 @@ func (fps *MemoryForumPermsStore) cascadePermSetToGroup(forumPerms map[int]map[i
group.CanSee = append(group.CanSee, fid) group.CanSee = append(group.CanSee, fid)
} }
if dev.SuperDebug { if Dev.SuperDebug {
log.Print("group.ID: ", group.ID) log.Print("group.ID: ", group.ID)
log.Printf("forumPerm: %+v\n", forumPerm) log.Printf("forumPerm: %+v\n", forumPerm)
log.Print("group.CanSee: ", group.CanSee) 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) { func (fps *MemoryForumPermsStore) Get(fid int, gid int) (fperms ForumPerms, err error) {
// TODO: Add a hook here and have plugin_guilds use it // TODO: Add a hook here and have plugin_guilds use it
group, err := gstore.Get(gid) group, err := Gstore.Get(gid)
if err != nil { if err != nil {
return fperms, ErrNoRows return fperms, ErrNoRows
} }

View File

@ -17,10 +17,10 @@ import (
"../query_gen/lib" "../query_gen/lib"
) )
var forumUpdateMutex sync.Mutex var ForumUpdateMutex sync.Mutex
var forumCreateMutex sync.Mutex var forumCreateMutex sync.Mutex
var forumPerms map[int]map[int]ForumPerms // [gid][fid]Perms // TODO: Add an abstraction around this and make it more thread-safe var forumPerms map[int]map[int]ForumPerms // [gid][fid]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 // ForumStore is an interface for accessing the forums and the metadata stored on them
type ForumStore interface { type ForumStore interface {
@ -110,26 +110,16 @@ func (mfs *MemoryForumStore) LoadForums() error {
} }
if forum.Name == "" { if forum.Name == "" {
if dev.DebugMode { if Dev.DebugMode {
log.Print("Adding a placeholder forum") log.Print("Adding a placeholder forum")
} }
} else { } else {
log.Printf("Adding the %s forum", forum.Name) log.Printf("Adding the '%s' forum", forum.Name)
} }
forum.Link = buildForumURL(nameToSlug(forum.Name), forum.ID) forum.Link = BuildForumURL(NameToSlug(forum.Name), forum.ID)
forum.LastTopic = Topics.DirtyGet(forum.LastTopicID)
topic, err := topics.Get(forum.LastTopicID) forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID)
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)
addForum(forum) addForum(forum)
} }
@ -178,19 +168,9 @@ func (mfs *MemoryForumStore) Get(id int) (*Forum, error) {
return forum, err return forum, err
} }
forum.Link = buildForumURL(nameToSlug(forum.Name), forum.ID) forum.Link = BuildForumURL(NameToSlug(forum.Name), forum.ID)
forum.LastTopic = Topics.DirtyGet(forum.LastTopicID)
topic, err := topics.Get(forum.LastTopicID) forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID)
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)
mfs.CacheSet(forum) mfs.CacheSet(forum)
return forum, err return forum, err
@ -205,19 +185,9 @@ func (mfs *MemoryForumStore) BypassGet(id int) (*Forum, error) {
return nil, err return nil, err
} }
forum.Link = buildForumURL(nameToSlug(forum.Name), forum.ID) forum.Link = BuildForumURL(NameToSlug(forum.Name), forum.ID)
forum.LastTopic = Topics.DirtyGet(forum.LastTopicID)
topic, err := topics.Get(forum.LastTopicID) forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID)
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)
return forum, err return forum, err
} }
@ -228,19 +198,9 @@ func (mfs *MemoryForumStore) Reload(id int) error {
if err != nil { if err != nil {
return err return err
} }
forum.Link = buildForumURL(nameToSlug(forum.Name), forum.ID) forum.Link = BuildForumURL(NameToSlug(forum.Name), forum.ID)
forum.LastTopic = Topics.DirtyGet(forum.LastTopicID)
topic, err := topics.Get(forum.LastTopicID) forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID)
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)
mfs.CacheSet(forum) mfs.CacheSet(forum)
return nil return nil
@ -372,7 +332,7 @@ func (mfs *MemoryForumStore) Create(forumName string, forumDesc string, active b
return 0, err return 0, err
} }
permmapToQuery(presetToPermmap(preset), fid) PermmapToQuery(PresetToPermmap(preset), fid)
forumCreateMutex.Unlock() forumCreateMutex.Unlock()
return fid, nil return fid, nil
} }

View File

@ -1,5 +1,8 @@
package common package common
import "database/sql"
import "../query_gen/lib"
var blankGroup = Group{ID: 0, Name: ""} var blankGroup = Group{ID: 0, Name: ""}
type GroupAdmin struct { type GroupAdmin struct {
@ -27,13 +30,29 @@ type Group struct {
CanSee []int // The IDs of the forums this group can see 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) { 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 { if err != nil {
return err return err
} }
gstore.Reload(group.ID) Gstore.Reload(group.ID)
return nil return nil
} }

View File

@ -12,7 +12,7 @@ import (
"../query_gen/lib" "../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? // ? - We could fallback onto the database when an item can't be found in the cache?
type GroupStore interface { type GroupStore interface {
@ -38,6 +38,7 @@ type MemoryGroupStore struct {
groupCount int groupCount int
getAll *sql.Stmt getAll *sql.Stmt
get *sql.Stmt get *sql.Stmt
count *sql.Stmt
sync.RWMutex sync.RWMutex
} }
@ -49,6 +50,7 @@ func NewMemoryGroupStore() (*MemoryGroupStore, error) {
groupCount: 0, groupCount: 0,
getAll: acc.SimpleSelect("users_groups", "gid, name, permissions, plugin_perms, is_mod, is_admin, is_banned, tag", "", "", ""), 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 = ?", "", ""), get: acc.SimpleSelect("users_groups", "name, permissions, plugin_perms, is_mod, is_admin, is_banned, tag", "gid = ?", "", ""),
count: acc.SimpleCount("users_groups", "", ""),
}, acc.FirstError() }, acc.FirstError()
} }
@ -84,7 +86,7 @@ func (mgs *MemoryGroupStore) LoadGroups() error {
} }
mgs.groupCount = i mgs.groupCount = i
if dev.DebugMode { if Dev.DebugMode {
log.Print("Binding the Not Loggedin Group") log.Print("Binding the Not Loggedin Group")
} }
GuestPerms = mgs.dirtyGetUnsafe(6).Perms GuestPerms = mgs.dirtyGetUnsafe(6).Perms
@ -146,7 +148,7 @@ func (mgs *MemoryGroupStore) Reload(id int) error {
} }
mgs.CacheSet(group) mgs.CacheSet(group)
err = rebuildGroupPermissions(id) err = RebuildGroupPermissions(id)
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
@ -160,7 +162,7 @@ func (mgs *MemoryGroupStore) initGroup(group *Group) error {
log.Print("bad group perms: ", group.PermissionsText) log.Print("bad group perms: ", group.PermissionsText)
return err return err
} }
if dev.DebugMode { if Dev.DebugMode {
log.Printf(group.Name+": %+v\n", group.Perms) 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) log.Print("bad group plugin perms: ", group.PluginPermsText)
return err return err
} }
if dev.DebugMode { if Dev.DebugMode {
log.Printf(group.Name+": %+v\n", group.PluginPerms) 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? // ? 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) { func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod bool, isBanned bool) (gid int, err error) {
var permstr = "{}" var permstr = "{}"
tx, err := db.Begin() tx, err := qgen.Builder.Begin()
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -226,20 +228,20 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod
var blankIntList []int var blankIntList []int
var pluginPerms = make(map[string]bool) var pluginPerms = make(map[string]bool)
var pluginPermsBytes = []byte("{}") var pluginPermsBytes = []byte("{}")
if vhooks["create_group_preappend"] != nil { if Vhooks["create_group_preappend"] != nil {
runVhook("create_group_preappend", &pluginPerms, &pluginPermsBytes) RunVhook("create_group_preappend", &pluginPerms, &pluginPermsBytes)
} }
// Generate the forum permissions based on the presets... // Generate the forum permissions based on the presets...
fdata, err := fstore.GetAll() fdata, err := Fstore.GetAll()
if err != nil { if err != nil {
return 0, err return 0, err
} }
var presetSet = make(map[int]string) var presetSet = make(map[int]string)
var permSet = make(map[int]ForumPerms) var permSet = make(map[int]ForumPerms)
permUpdateMutex.Lock() PermUpdateMutex.Lock()
defer permUpdateMutex.Unlock() defer PermUpdateMutex.Unlock()
for _, forum := range fdata { for _, forum := range fdata {
var thePreset string var thePreset string
if isAdmin { if isAdmin {
@ -252,7 +254,7 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod
thePreset = "members" thePreset = "members"
} }
permmap := presetToPermmap(forum.Preset) permmap := PresetToPermmap(forum.Preset)
permItem := permmap[thePreset] permItem := permmap[thePreset]
permItem.Overrides = true permItem.Overrides = true
@ -260,7 +262,7 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod
presetSet[forum.ID] = forum.Preset presetSet[forum.ID] = forum.Preset
} }
err = replaceForumPermsForGroupTx(tx, gid, presetSet, permSet) err = ReplaceForumPermsForGroupTx(tx, gid, presetSet, permSet)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -281,7 +283,7 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod
mgs.Unlock() mgs.Unlock()
for _, forum := range fdata { for _, forum := range fdata {
err = fpstore.Reload(forum.ID) err = Fpstore.Reload(forum.ID)
if err != nil { if err != nil {
return gid, err return gid, err
} }
@ -344,8 +346,10 @@ func (mgs *MemoryGroupStore) Length() int {
return mgs.groupCount return mgs.groupCount
} }
func (mgs *MemoryGroupStore) GlobalCount() int { func (mgs *MemoryGroupStore) GlobalCount() (count int) {
mgs.RLock() err := mgs.count.QueryRow().Scan(&count)
defer mgs.RUnlock() if err != nil {
return mgs.groupCount LogError(err)
}
return count
} }

View File

@ -4,7 +4,7 @@
* Copyright Azareal 2016 - 2018 * Copyright Azareal 2016 - 2018
* *
*/ */
package main package common
import ( import (
"errors" "errors"

View File

@ -11,7 +11,7 @@ type HeaderVars struct {
Scripts []string Scripts []string
Stylesheets []string Stylesheets []string
Widgets PageWidgets Widgets PageWidgets
Site *Site Site *site
Settings map[string]interface{} Settings map[string]interface{}
Themes map[string]Theme // TODO: Use a slice containing every theme instead of the main map for speed Themes map[string]Theme // TODO: Use a slice containing every theme instead of the main map for speed
ThemeName string ThemeName string
@ -21,7 +21,7 @@ type HeaderVars struct {
// TODO: Add this to routes which don't use templates. E.g. Json APIs. // TODO: Add this to routes which don't use templates. E.g. Json APIs.
type HeaderLite struct { type HeaderLite struct {
Site *Site Site *site
Settings SettingMap Settings SettingMap
ExtData ExtData ExtData ExtData
} }
@ -34,7 +34,7 @@ type PageWidgets struct {
// TODO: Add a ExtDataHolder interface with methods for manipulating the contents? // TODO: Add a ExtDataHolder interface with methods for manipulating the contents?
// ? - Could we use a sync.Map instead? // ? - Could we use a sync.Map instead?
type ExtData struct { type ExtData struct {
items map[string]interface{} // Key: pluginname Items map[string]interface{} // Key: pluginname
sync.RWMutex sync.RWMutex
} }
@ -226,7 +226,7 @@ type PanelEditGroupPermsPage struct {
GlobalPerms []NameLangToggle GlobalPerms []NameLangToggle
} }
type backupItem struct { type BackupItem struct {
SQLURL string 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) // 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 CurrentUser User
Header *HeaderVars Header *HeaderVars
Stats PanelStats Stats PanelStats
Backups []backupItem Backups []BackupItem
} }
type logItem struct { type LogItem struct {
Action template.HTML Action template.HTML
IPAddress string IPAddress string
DoneAt string DoneAt string
@ -253,7 +253,7 @@ type PanelLogsPage struct {
CurrentUser User CurrentUser User
Header *HeaderVars Header *HeaderVars
Stats PanelStats Stats PanelStats
Logs []logItem Logs []LogItem
PageList []int PageList []int
Page int Page int
LastPage 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 // 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 // TODO: Write a test for this
func DefaultHeaderVar() *HeaderVars { func DefaultHeaderVar() *HeaderVars {
return &HeaderVars{Site: site, ThemeName: fallbackTheme} return &HeaderVars{Site: Site, ThemeName: fallbackTheme}
} }

View File

@ -1,4 +1,4 @@
package main package common
import ( import (
//"fmt" //"fmt"
@ -9,19 +9,19 @@ import (
"strings" "strings"
) )
var spaceGap = []byte(" ") var SpaceGap = []byte(" ")
var httpProtBytes = []byte("http://") var httpProtBytes = []byte("http://")
var invalidURL = []byte("<span style='color: red;'>[Invalid URL]</span>") var InvalidURL = []byte("<span style='color: red;'>[Invalid URL]</span>")
var invalidTopic = []byte("<span style='color: red;'>[Invalid Topic]</span>") var InvalidTopic = []byte("<span style='color: red;'>[Invalid Topic]</span>")
var invalidProfile = []byte("<span style='color: red;'>[Invalid Profile]</span>") var InvalidProfile = []byte("<span style='color: red;'>[Invalid Profile]</span>")
var invalidForum = []byte("<span style='color: red;'>[Invalid Forum]</span>") var InvalidForum = []byte("<span style='color: red;'>[Invalid Forum]</span>")
var unknownMedia = []byte("<span style='color: red;'>[Unknown Media]</span>") var unknownMedia = []byte("<span style='color: red;'>[Unknown Media]</span>")
var urlOpen = []byte("<a href='") var UrlOpen = []byte("<a href='")
var urlOpen2 = []byte("'>") var UrlOpen2 = []byte("'>")
var bytesSinglequote = []byte("'") var bytesSinglequote = []byte("'")
var bytesGreaterthan = []byte(">") var bytesGreaterthan = []byte(">")
var urlMention = []byte(" class='mention'") var urlMention = []byte(" class='mention'")
var urlClose = []byte("</a>") var UrlClose = []byte("</a>")
var imageOpen = []byte("<a href=\"") var imageOpen = []byte("<a href=\"")
var imageOpen2 = []byte("\"><img src='") var imageOpen2 = []byte("\"><img src='")
var imageClose = []byte("' class='postImage' /></a>") var imageClose = []byte("' class='postImage' /></a>")
@ -164,16 +164,16 @@ func shortcodeToUnicode(msg string) string {
return msg return msg
} }
func preparseMessage(msg string) string { func PreparseMessage(msg string) string {
if sshooks["preparse_preassign"] != nil { if Sshooks["preparse_preassign"] != nil {
msg = runSshook("preparse_preassign", msg) msg = RunSshook("preparse_preassign", msg)
} }
return shortcodeToUnicode(msg) return shortcodeToUnicode(msg)
} }
// TODO: Write a test for this // TODO: Write a test for this
// TODO: We need a lot more hooks here. E.g. To add custom media types and handlers. // 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, ":(", "😞", -1) msg = strings.Replace(msg, ":(", "😞", -1)
msg = strings.Replace(msg, ":D", "😃", -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,"<a href=\"$2$3//$4\" rel=\"nofollow\">$2$3//$4</a>") //msg = url_reg.ReplaceAllString(msg,"<a href=\"$2$3//$4\" rel=\"nofollow\">$2$3//$4</a>")
// Word filter list. E.g. Swear words and other things the admins don't like // 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 { for _, filter := range wordFilters {
msg = strings.Replace(msg, filter.Find, filter.Replacement, -1) 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!") //log.Print("Parser Loop!")
var msgbytes = []byte(msg) var msgbytes = []byte(msg)
var outbytes []byte var outbytes []byte
msgbytes = append(msgbytes, spaceGap...) msgbytes = append(msgbytes, SpaceGap...)
//log.Printf("string(msgbytes) %+v\n", `"`+string(msgbytes)+`"`) //log.Printf("string(msgbytes) %+v\n", `"`+string(msgbytes)+`"`)
var lastItem = 0 var lastItem = 0
var i = 0 var i = 0
@ -215,23 +215,23 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
outbytes = append(outbytes, msgbytes[lastItem:i]...) outbytes = append(outbytes, msgbytes[lastItem:i]...)
i += 5 i += 5
start := i start := i
tid, intLen := coerceIntBytes(msgbytes[start:]) tid, intLen := CoerceIntBytes(msgbytes[start:])
i += intLen i += intLen
topic, err := topics.Get(tid) topic, err := Topics.Get(tid)
if err != nil || !fstore.Exists(topic.ParentID) { if err != nil || !Fstore.Exists(topic.ParentID) {
outbytes = append(outbytes, invalidTopic...) outbytes = append(outbytes, InvalidTopic...)
lastItem = i lastItem = i
continue continue
} }
outbytes = append(outbytes, urlOpen...) outbytes = append(outbytes, UrlOpen...)
var urlBit = []byte(buildTopicURL("", tid)) var urlBit = []byte(BuildTopicURL("", tid))
outbytes = append(outbytes, urlBit...) outbytes = append(outbytes, urlBit...)
outbytes = append(outbytes, urlOpen2...) outbytes = append(outbytes, UrlOpen2...)
var tidBit = []byte("#tid-" + strconv.Itoa(tid)) var tidBit = []byte("#tid-" + strconv.Itoa(tid))
outbytes = append(outbytes, tidBit...) outbytes = append(outbytes, tidBit...)
outbytes = append(outbytes, urlClose...) outbytes = append(outbytes, UrlClose...)
lastItem = i lastItem = i
//log.Print("string(msgbytes): ",string(msgbytes)) //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]...) outbytes = append(outbytes, msgbytes[lastItem:i]...)
i += 5 i += 5
start := i start := i
rid, intLen := coerceIntBytes(msgbytes[start:]) rid, intLen := CoerceIntBytes(msgbytes[start:])
i += intLen i += intLen
topic, err := getTopicByReply(rid) reply := BlankReply()
if err != nil || !fstore.Exists(topic.ParentID) { reply.ID = rid
outbytes = append(outbytes, invalidTopic...) topic, err := reply.Topic()
if err != nil || !Fstore.Exists(topic.ParentID) {
outbytes = append(outbytes, InvalidTopic...)
lastItem = i lastItem = i
continue continue
} }
outbytes = append(outbytes, urlOpen...) outbytes = append(outbytes, UrlOpen...)
var urlBit = []byte(buildTopicURL("", topic.ID)) var urlBit = []byte(BuildTopicURL("", topic.ID))
outbytes = append(outbytes, urlBit...) outbytes = append(outbytes, urlBit...)
outbytes = append(outbytes, urlOpen2...) outbytes = append(outbytes, UrlOpen2...)
var ridBit = []byte("#rid-" + strconv.Itoa(rid)) var ridBit = []byte("#rid-" + strconv.Itoa(rid))
outbytes = append(outbytes, ridBit...) outbytes = append(outbytes, ridBit...)
outbytes = append(outbytes, urlClose...) outbytes = append(outbytes, UrlClose...)
lastItem = i lastItem = i
} else if bytes.Equal(msgbytes[i+1:i+5], []byte("fid-")) { } else if bytes.Equal(msgbytes[i+1:i+5], []byte("fid-")) {
outbytes = append(outbytes, msgbytes[lastItem:i]...) outbytes = append(outbytes, msgbytes[lastItem:i]...)
i += 5 i += 5
start := i start := i
fid, intLen := coerceIntBytes(msgbytes[start:]) fid, intLen := CoerceIntBytes(msgbytes[start:])
i += intLen i += intLen
if !fstore.Exists(fid) { if !Fstore.Exists(fid) {
outbytes = append(outbytes, invalidForum...) outbytes = append(outbytes, InvalidForum...)
lastItem = i lastItem = i
continue continue
} }
outbytes = append(outbytes, urlOpen...) outbytes = append(outbytes, UrlOpen...)
var urlBit = []byte(buildForumURL("", fid)) var urlBit = []byte(BuildForumURL("", fid))
outbytes = append(outbytes, urlBit...) outbytes = append(outbytes, urlBit...)
outbytes = append(outbytes, urlOpen2...) outbytes = append(outbytes, UrlOpen2...)
var fidBit = []byte("#fid-" + strconv.Itoa(fid)) var fidBit = []byte("#fid-" + strconv.Itoa(fid))
outbytes = append(outbytes, fidBit...) outbytes = append(outbytes, fidBit...)
outbytes = append(outbytes, urlClose...) outbytes = append(outbytes, UrlClose...)
lastItem = i lastItem = i
} else { } else {
// TODO: Forum Shortcode Link // TODO: Forum Shortcode Link
@ -291,17 +293,17 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
outbytes = append(outbytes, msgbytes[lastItem:i]...) outbytes = append(outbytes, msgbytes[lastItem:i]...)
i++ i++
start := i start := i
uid, intLen := coerceIntBytes(msgbytes[start:]) uid, intLen := CoerceIntBytes(msgbytes[start:])
i += intLen i += intLen
menUser, err := users.Get(uid) menUser, err := Users.Get(uid)
if err != nil { if err != nil {
outbytes = append(outbytes, invalidProfile...) outbytes = append(outbytes, InvalidProfile...)
lastItem = i lastItem = i
continue continue
} }
outbytes = append(outbytes, urlOpen...) outbytes = append(outbytes, UrlOpen...)
var urlBit = []byte(menUser.Link) var urlBit = []byte(menUser.Link)
outbytes = append(outbytes, urlBit...) outbytes = append(outbytes, urlBit...)
outbytes = append(outbytes, bytesSinglequote...) outbytes = append(outbytes, bytesSinglequote...)
@ -309,7 +311,7 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
outbytes = append(outbytes, bytesGreaterthan...) outbytes = append(outbytes, bytesGreaterthan...)
var uidBit = []byte("@" + menUser.Name) var uidBit = []byte("@" + menUser.Name)
outbytes = append(outbytes, uidBit...) outbytes = append(outbytes, uidBit...)
outbytes = append(outbytes, urlClose...) outbytes = append(outbytes, UrlClose...)
lastItem = i lastItem = i
//log.Print(string(msgbytes)) //log.Print(string(msgbytes))
@ -338,21 +340,21 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
//log.Print("Normal URL") //log.Print("Normal URL")
outbytes = append(outbytes, msgbytes[lastItem:i]...) outbytes = append(outbytes, msgbytes[lastItem:i]...)
urlLen := partialURLBytesLen(msgbytes[i:]) urlLen := PartialURLBytesLen(msgbytes[i:])
if msgbytes[i+urlLen] > 32 { // space and invisibles if msgbytes[i+urlLen] > 32 { // space and invisibles
//log.Print("INVALID URL") //log.Print("INVALID URL")
//log.Print("msgbytes[i+urlLen]: ", msgbytes[i+urlLen]) //log.Print("msgbytes[i+urlLen]: ", msgbytes[i+urlLen])
//log.Print("string(msgbytes[i+urlLen]): ", string(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("msgbytes[i:i+urlLen]: ", msgbytes[i:i+urlLen])
//log.Print("string(msgbytes[i:i+urlLen]): ", string(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 i += urlLen
continue continue
} }
media, ok := parseMediaBytes(msgbytes[i : i+urlLen]) media, ok := parseMediaBytes(msgbytes[i : i+urlLen])
if !ok { if !ok {
outbytes = append(outbytes, invalidURL...) outbytes = append(outbytes, InvalidURL...)
i += urlLen i += urlLen
continue continue
} }
@ -386,23 +388,23 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
continue continue
} }
outbytes = append(outbytes, urlOpen...) outbytes = append(outbytes, UrlOpen...)
outbytes = append(outbytes, msgbytes[i:i+urlLen]...) 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, msgbytes[i:i+urlLen]...)
outbytes = append(outbytes, urlClose...) outbytes = append(outbytes, UrlClose...)
i += urlLen i += urlLen
lastItem = i lastItem = i
} else if msgbytes[i] == '/' && msgbytes[i+1] == '/' { } else if msgbytes[i] == '/' && msgbytes[i+1] == '/' {
outbytes = append(outbytes, msgbytes[lastItem:i]...) outbytes = append(outbytes, msgbytes[lastItem:i]...)
urlLen := partialURLBytesLen(msgbytes[i:]) urlLen := PartialURLBytesLen(msgbytes[i:])
if msgbytes[i+urlLen] > 32 { // space and invisibles if msgbytes[i+urlLen] > 32 { // space and invisibles
//log.Print("INVALID URL") //log.Print("INVALID URL")
//log.Print("msgbytes[i+urlLen]: ", msgbytes[i+urlLen]) //log.Print("msgbytes[i+urlLen]: ", msgbytes[i+urlLen])
//log.Print("string(msgbytes[i+urlLen]): ", string(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("msgbytes[i:i+urlLen]: ", msgbytes[i:i+urlLen])
//log.Print("string(msgbytes[i:i+urlLen]): ", string(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 i += urlLen
continue 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])) //log.Print("string(msgbytes[i:i+urlLen]): ", string(msgbytes[i:i+urlLen]))
media, ok := parseMediaBytes(msgbytes[i : i+urlLen]) media, ok := parseMediaBytes(msgbytes[i : i+urlLen])
if !ok { if !ok {
outbytes = append(outbytes, invalidURL...) outbytes = append(outbytes, InvalidURL...)
i += urlLen i += urlLen
continue continue
} }
@ -446,11 +448,11 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
continue continue
} }
outbytes = append(outbytes, urlOpen...) outbytes = append(outbytes, UrlOpen...)
outbytes = append(outbytes, msgbytes[i:i+urlLen]...) 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, msgbytes[i:i+urlLen]...)
outbytes = append(outbytes, urlClose...) outbytes = append(outbytes, UrlClose...)
i += urlLen i += urlLen
lastItem = i lastItem = i
} }
@ -474,25 +476,12 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
//log.Print("msg",`"`+msg+`"`) //log.Print("msg",`"`+msg+`"`)
msg = strings.Replace(msg, "\n", "<br>", -1) msg = strings.Replace(msg, "\n", "<br>", -1)
if sshooks["parse_assign"] != nil { if Sshooks["parse_assign"] != nil {
msg = runSshook("parse_assign", msg) msg = RunSshook("parse_assign", msg)
} }
return 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, "<a href=\"$2$3//$4\" rel=\"nofollow\">$2$3//$4</a>")
msg = strings.Replace(msg, "\n", "<br>", -1)
if sshooks["parse_assign"] != nil {
msg = runSshook("parse_assign", msg)
}
return msg
}*/
// 6, 7, 8, 6, 2, 7 // 6, 7, 8, 6, 2, 7
// ftp://, http://, https:// git://, //, mailto: (not a URL, just here for length comparison purposes) // ftp://, http://, https:// git://, //, mailto: (not a URL, just here for length comparison purposes)
// TODO: Write a test for this // 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. // ? - 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++ { 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) { 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 // TODO: Write a test for this
func partialURLBytes(data []byte) (url []byte) { func PartialURLBytes(data []byte) (url []byte) {
datalen := len(data) datalen := len(data)
i := 0 i := 0
end := datalen - 1 end := datalen - 1
@ -579,7 +568,7 @@ func partialURLBytes(data []byte) (url []byte) {
} }
// TODO: Write a test for this // TODO: Write a test for this
func partialURLBytesLen(data []byte) int { func PartialURLBytesLen(data []byte) int {
datalen := len(data) datalen := len(data)
i := 0 i := 0
@ -632,13 +621,12 @@ func parseMediaBytes(data []byte) (media MediaEmbed, ok bool) {
query := url.Query() query := url.Query()
//log.Printf("query %+v\n", query) //log.Printf("query %+v\n", query)
var samesite = hostname == "localhost" || hostname == site.URL var samesite = hostname == "localhost" || hostname == Site.URL
if samesite { 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... // ?- 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 port = Site.Port
if scheme == "" && site.EnableSsl { if scheme == "" && Site.EnableSsl {
scheme = "https" scheme = "https"
} }
} }
@ -684,7 +672,7 @@ func parseMediaBytes(data []byte) (media MediaEmbed, ok bool) {
extarr := strings.Split(lastFrag, ".") extarr := strings.Split(lastFrag, ".")
if len(extarr) >= 2 { if len(extarr) >= 2 {
ext := extarr[len(extarr)-1] ext := extarr[len(extarr)-1]
if imageFileExts.Contains(ext) { if ImageFileExts.Contains(ext) {
media.Type = "image" media.Type = "image"
var sport string var sport string
if port != "443" && port != "80" { if port != "443" && port != "80" {
@ -704,7 +692,7 @@ func parseURL(data []byte) (*url.URL, error) {
} }
// TODO: Write a test for this // 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) { if !(data[0] > 47 && data[0] < 58) {
return 0, 1 return 0, 1
} }
@ -728,7 +716,7 @@ func coerceIntBytes(data []byte) (res int, length int) {
} }
// TODO: Write tests for this // 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 { if count < perPage {
return []int{1} return []int{1}
} }
@ -745,7 +733,7 @@ func paginate(count int, perPage int, maxPages int) []int {
} }
// TODO: Write tests for this // 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 var offset int
lastPage := (count / perPage) + 1 lastPage := (count / perPage) + 1
if page > 1 { if page > 1 {

View File

@ -5,18 +5,24 @@ import (
"encoding/json" "encoding/json"
"log" "log"
"sync" "sync"
"../query_gen/lib"
) )
// TODO: Refactor the perms system // TODO: Refactor the perms system
var permUpdateMutex sync.Mutex var PermUpdateMutex sync.Mutex
var BlankPerms Perms var BlankPerms Perms
var BlankForumPerms ForumPerms var BlankForumPerms ForumPerms
var GuestPerms Perms var GuestPerms Perms
var ReadForumPerms ForumPerms var ReadForumPerms ForumPerms
var ReadReplyForumPerms ForumPerms var ReadReplyForumPerms ForumPerms
var ReadWriteForumPerms ForumPerms var ReadWriteForumPerms ForumPerms
// AllPerms is a set of global permissions with everything set to true
var AllPerms Perms var AllPerms Perms
// AllForumPerms is a set of forum local permissions with everything set to true
var AllForumPerms ForumPerms var AllForumPerms ForumPerms
var AllPluginPerms = make(map[string]bool) var AllPluginPerms = make(map[string]bool)
@ -216,15 +222,15 @@ func init() {
ExtData: make(map[string]bool), 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("Guest Perms: %+v\n", GuestPerms)
log.Printf("All Perms: %+v\n", AllPerms) 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) out = make(map[string]ForumPerms)
switch preset { switch preset {
case "all": case "all":
@ -266,8 +272,8 @@ func presetToPermmap(preset string) (out map[string]ForumPerms) {
return out return out
} }
func permmapToQuery(permmap map[string]ForumPerms, fid int) error { func PermmapToQuery(permmap map[string]ForumPerms, fid int) error {
tx, err := db.Begin() tx, err := qgen.Builder.Begin()
if err != nil { if err != nil {
return err return err
} }
@ -337,7 +343,7 @@ func permmapToQuery(permmap map[string]ForumPerms, fid int) error {
// 6 is the ID of the Not Loggedin Group // 6 is the ID of the Not Loggedin Group
// TODO: Use a shared variable rather than a literal for the group ID // 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 { if err != nil {
return err return err
} }
@ -347,25 +353,25 @@ func permmapToQuery(permmap map[string]ForumPerms, fid int) error {
return err return err
} }
permUpdateMutex.Lock() PermUpdateMutex.Lock()
defer permUpdateMutex.Unlock() defer PermUpdateMutex.Unlock()
return fpstore.Reload(fid) return Fpstore.Reload(fid)
} }
func replaceForumPermsForGroup(gid int, presetSet map[int]string, permSets map[int]ForumPerms) error { func ReplaceForumPermsForGroup(gid int, presetSet map[int]string, permSets map[int]ForumPerms) error {
tx, err := db.Begin() tx, err := qgen.Builder.Begin()
if err != nil { if err != nil {
return err return err
} }
defer tx.Rollback() defer tx.Rollback()
err = replaceForumPermsForGroupTx(tx, gid, presetSet, permSets) err = ReplaceForumPermsForGroupTx(tx, gid, presetSet, permSets)
if err != nil { if err != nil {
return err return err
} }
return tx.Commit() 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 = ?") deleteForumPermsForGroupTx, err := qgen.Builder.SimpleDeleteTx(tx, "forums_permissions", "gid = ? AND fid = ?")
if err != nil { if err != nil {
return err 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 // TODO: Refactor this and write tests for it
func forumPermsToGroupForumPreset(fperms ForumPerms) string { func ForumPermsToGroupForumPreset(fperms ForumPerms) string {
if !fperms.Overrides { if !fperms.Overrides {
return "default" return "default"
} }
@ -422,7 +428,7 @@ func forumPermsToGroupForumPreset(fperms ForumPerms) string {
return "custom" return "custom"
} }
func groupForumPresetToForumPerms(preset string) (fperms ForumPerms, changed bool) { func GroupForumPresetToForumPerms(preset string) (fperms ForumPerms, changed bool) {
switch preset { switch preset {
case "read_only": case "read_only":
return ReadForumPerms, true return ReadForumPerms, true
@ -439,7 +445,7 @@ func groupForumPresetToForumPerms(preset string) (fperms ForumPerms, changed boo
return fperms, false return fperms, false
} }
func stripInvalidGroupForumPreset(preset string) string { func StripInvalidGroupForumPreset(preset string) string {
switch preset { switch preset {
case "read_only", "can_post", "can_moderate", "no_access", "default", "custom": case "read_only", "can_post", "can_moderate", "no_access", "default", "custom":
return preset return preset
@ -447,7 +453,7 @@ func stripInvalidGroupForumPreset(preset string) string {
return "" return ""
} }
func stripInvalidPreset(preset string) string { func StripInvalidPreset(preset string) string {
switch preset { switch preset {
case "all", "announce", "members", "staff", "admins", "archive", "custom": case "all", "announce", "members", "staff", "admins", "archive", "custom":
return preset return preset
@ -457,7 +463,7 @@ func stripInvalidPreset(preset string) string {
} }
// TODO: Move this into the phrase system? // TODO: Move this into the phrase system?
func presetToLang(preset string) string { func PresetToLang(preset string) string {
phrases := GetAllPermPresets() phrases := GetAllPermPresets()
phrase, ok := phrases[preset] phrase, ok := phrases[preset]
if !ok { if !ok {
@ -467,10 +473,18 @@ func presetToLang(preset string) string {
} }
// TODO: Is this racey? // 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 var permstr []byte
log.Print("Reloading a group") 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 { if err != nil {
return err return err
} }
@ -483,7 +497,7 @@ func rebuildGroupPermissions(gid int) error {
return err return err
} }
group, err := gstore.Get(gid) group, err := Gstore.Get(gid)
if err != nil { if err != nil {
return err return err
} }
@ -491,7 +505,7 @@ func rebuildGroupPermissions(gid int) error {
return nil return nil
} }
func overridePerms(perms *Perms, status bool) { func OverridePerms(perms *Perms, status bool) {
if status { if status {
*perms = AllPerms *perms = AllPerms
} else { } 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 // 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.ViewTopic = status
perms.LikeItem = status perms.LikeItem = status
perms.CreateTopic = status perms.CreateTopic = status
@ -513,10 +527,10 @@ func overrideForumPerms(perms *Perms, status bool) {
perms.CloseTopic = status perms.CloseTopic = status
} }
func registerPluginPerm(name string) { func RegisterPluginPerm(name string) {
AllPluginPerms[name] = true AllPluginPerms[name] = true
} }
func deregisterPluginPerm(name string) { func DeregisterPluginPerm(name string) {
delete(AllPluginPerms, name) delete(AllPluginPerms, name)
} }

View File

@ -4,7 +4,7 @@
* Copyright Azareal 2017 - 2018 * Copyright Azareal 2017 - 2018
* *
*/ */
package main package common
import ( import (
"encoding/json" "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? // 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 // nolint Be quiet megacheck, this *is* used
var currentLangPack atomic.Value 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! // TODO: We'll be implementing the level phrases in the software proper very very soon!
type LevelPhrases struct { 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 // 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") log.Print("Loading the language packs")
err := filepath.Walk("./langs", func(path string, f os.FileInfo, err error) error { err := filepath.Walk("./langs", func(path string, f os.FileInfo, err error) error {
if f.IsDir() { if f.IsDir() {
@ -61,8 +60,8 @@ func initPhrases() error {
var ext = filepath.Ext("/langs/" + path) var ext = filepath.Ext("/langs/" + path)
if ext != ".json" { if ext != ".json" {
if dev.DebugMode { if Dev.DebugMode {
log.Print("Found a " + ext + "in /langs/") log.Printf("Found a '%s' in /langs/", ext)
} }
return nil return nil
} }
@ -74,8 +73,8 @@ func initPhrases() error {
} }
log.Print("Adding the '" + langPack.Name + "' language pack") log.Print("Adding the '" + langPack.Name + "' language pack")
langpacks.Store(langPack.Name, &langPack) langPacks.Store(langPack.Name, &langPack)
langpackCount++ langPackCount++
return nil return nil
}) })
@ -83,13 +82,13 @@ func initPhrases() error {
if err != nil { if err != nil {
return err return err
} }
if langpackCount == 0 { if langPackCount == 0 {
return errors.New("You don't have any language packs") return errors.New("You don't have any language packs")
} }
langPack, ok := langpacks.Load(site.Language) langPack, ok := langPacks.Load(Site.Language)
if !ok { 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) currentLangPack.Store(langPack)
return nil return nil
@ -167,7 +166,7 @@ func DeletePhrase() {
// TODO: Use atomics to store the pointer of the current active langpack? // TODO: Use atomics to store the pointer of the current active langpack?
// nolint // nolint
func ChangeLanguagePack(name string) (exists bool) { func ChangeLanguagePack(name string) (exists bool) {
pack, ok := langpacks.Load(name) pack, ok := langPacks.Load(name)
if !ok { if !ok {
return false return false
} }

View File

@ -89,7 +89,7 @@ func InitPluginLangs() error {
if err != nil { if err != nil {
return err return err
} }
plugins[plugin.UName] = pplugin Plugins[plugin.UName] = pplugin
} }
return nil return nil
} }

View File

@ -2,9 +2,11 @@ package common
import ( import (
"database/sql" "database/sql"
"../query_gen/lib"
) )
var prstore ProfileReplyStore var Prstore ProfileReplyStore
type ProfileReplyStore interface { type ProfileReplyStore interface {
Get(id int) (*Reply, error) 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) { 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 { if err != nil {
return 0, err return 0, err
} }

View File

@ -7,8 +7,11 @@
package common package common
import ( import (
"database/sql"
"errors" "errors"
"time" "time"
"../query_gen/lib"
) )
type ReplyUser struct { type ReplyUser struct {
@ -56,12 +59,37 @@ type Reply struct {
} }
var ErrAlreadyLiked = errors.New("You already liked this!") 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: Write tests for this
// TODO: Wrap these queries in a transaction to make sure the state is consistent // TODO: Wrap these queries in a transaction to make sure the state is consistent
func (reply *Reply) Like(uid int) (err error) { func (reply *Reply) Like(uid int) (err error) {
var rid int // unused, just here to avoid mutating reply.ID 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 { if err != nil && err != ErrNoRows {
return err return err
} else if err != ErrNoRows { } else if err != ErrNoRows {
@ -69,29 +97,41 @@ func (reply *Reply) Like(uid int) (err error) {
} }
score := 1 score := 1
_, err = stmts.createLike.Exec(score, reply.ID, "replies", uid) _, err = replyStmts.createLike.Exec(score, reply.ID, "replies", uid)
if err != nil { if err != nil {
return err return err
} }
_, err = stmts.addLikesToReply.Exec(1, reply.ID) _, err = replyStmts.addLikesToReply.Exec(1, reply.ID)
return err return err
} }
// TODO: Write tests for this // TODO: Write tests for this
func (reply *Reply) Delete() error { func (reply *Reply) Delete() error {
_, err := stmts.deleteReply.Exec(reply.ID) _, err := replyStmts.delete.Exec(reply.ID)
if err != nil { if err != nil {
return err return err
} }
_, err = stmts.removeRepliesFromTopic.Exec(1, reply.ParentID) // TODO: Move this bit to *Topic
tcache, ok := topics.(TopicCache) _, err = replyStmts.removeRepliesFromTopic.Exec(1, reply.ParentID)
tcache, ok := Topics.(TopicCache)
if ok { if ok {
tcache.CacheRemove(reply.ParentID) tcache.CacheRemove(reply.ParentID)
} }
return err 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 // Copy gives you a non-pointer concurrency safe copy of the reply
func (reply *Reply) Copy() Reply { func (reply *Reply) Copy() Reply {
return *reply return *reply
} }
func BlankReply() *Reply {
return &Reply{ID: 0}
}

View File

@ -3,7 +3,7 @@ package common
import "database/sql" import "database/sql"
import "../query_gen/lib" import "../query_gen/lib"
var rstore ReplyStore var Rstore ReplyStore
type ReplyStore interface { type ReplyStore interface {
Get(id int) (*Reply, error) Get(id int) (*Reply, error)
@ -31,8 +31,8 @@ func (store *SQLReplyStore) Get(id int) (*Reply, error) {
// TODO: Write a test for this // TODO: Write a test for this
func (store *SQLReplyStore) Create(topic *Topic, content string, ipaddress string, uid int) (id int, err error) { func (store *SQLReplyStore) Create(topic *Topic, content string, ipaddress string, uid int) (id int, err error) {
wcount := wordCount(content) wcount := WordCount(content)
res, err := store.create.Exec(topic.ID, content, parseMessage(content, topic.ParentID, "forums"), ipaddress, wcount, uid) res, err := store.create.Exec(topic.ID, content, ParseMessage(content, topic.ParentID, "forums"), ipaddress, wcount, uid)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View File

@ -1,4 +1,4 @@
package main package common
import ( import (
"html" "html"
@ -7,8 +7,6 @@ import (
"net" "net"
"net/http" "net/http"
"strings" "strings"
"./common"
) )
// nolint // nolint
@ -16,28 +14,28 @@ var PreRoute func(http.ResponseWriter, *http.Request) (User, bool) = preRoute
// TODO: Come up with a better middleware solution // 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 // 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 PanelUserCheck func(http.ResponseWriter, *http.Request, *User) (*HeaderVars, PanelStats, RouteError) = panelUserCheck
var SimplePanelUserCheck func(http.ResponseWriter, *http.Request, *User) (*common.HeaderLite, RouteError) = simplePanelUserCheck 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 *common.HeaderLite, err RouteError) = simpleForumUserCheck 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 *common.HeaderVars, err RouteError) = forumUserCheck 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 *common.HeaderVars, err RouteError) = memberCheck var MemberCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, err RouteError) = memberCheck
var UserCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, err RouteError) = userCheck 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 *common.HeaderVars, err RouteError) = userCheck 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 // TODO: Support for left sidebars and sidebars on both sides
// http.Request is for context.Context middleware. Mostly for plugin_guilds right now // 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) { func BuildWidgets(zone string, data interface{}, headerVars *HeaderVars, r *http.Request) {
if vhooks["intercept_build_widgets"] != nil { if Vhooks["intercept_build_widgets"] != nil {
if runVhook("intercept_build_widgets", zone, data, headerVars, r).(bool) { if RunVhook("intercept_build_widgets", zone, data, headerVars, r).(bool) {
return return
} }
} }
//log.Print("themes[headerVars.ThemeName].Sidebars",themes[headerVars.ThemeName].Sidebars) //log.Print("Themes[headerVars.ThemeName].Sidebars", Themes[headerVars.ThemeName].Sidebars)
if themes[headerVars.ThemeName].Sidebars == "right" { if Themes[headerVars.ThemeName].Sidebars == "right" {
if len(docks.RightSidebar) != 0 { if len(Docks.RightSidebar) != 0 {
var sbody string var sbody string
for _, widget := range docks.RightSidebar { for _, widget := range Docks.RightSidebar {
if widget.Enabled { if widget.Enabled {
if widget.Location == "global" || widget.Location == zone { if widget.Location == "global" || widget.Location == zone {
sbody += widget.Body 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) { func simpleForumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *HeaderLite, rerr RouteError) {
if !fstore.Exists(fid) { if !Fstore.Exists(fid) {
return nil, PreError("The target forum doesn't exist.", w, r) 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? // 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 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 { if skip || rerr != nil {
return headerLite, rerr return headerLite, rerr
} }
} }
fperms, err := fpstore.Get(fid, user.Group) fperms, err := Fpstore.Get(fid, user.Group)
if err != nil { if err != nil {
// TODO: Refactor this // TODO: Refactor this
log.Printf("Unable to get the forum perms for Group #%d for User #%d", user.Group, user.ID) 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 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) headerVars, rerr = UserCheck(w, r, user)
if rerr != nil { if rerr != nil {
return headerVars, rerr return headerVars, rerr
} }
if !fstore.Exists(fid) { if !Fstore.Exists(fid) {
return headerVars, NotFound(w, r) return headerVars, NotFound(w, r)
} }
if vhookSkippable["forum_check_pre_perms"] != nil { if VhookSkippable["forum_check_pre_perms"] != nil {
var skip bool 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 { if skip || rerr != nil {
return headerVars, rerr return headerVars, rerr
} }
} }
fperms, err := fpstore.Get(fid, user.Group) fperms, err := Fpstore.Get(fid, user.Group)
if err != nil { if err != nil {
// TODO: Refactor this // TODO: Refactor this
log.Printf("Unable to get the forum perms for Group #%d for User #%d", user.Group, user.ID) 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 // 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? // TODO: Do a panel specific theme?
func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, stats common.PanelStats, rerr RouteError) { func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, stats PanelStats, rerr RouteError) {
var themeName = defaultThemeBox.Load().(string) var themeName = DefaultThemeBox.Load().(string)
cookie, err := r.Cookie("current_theme") cookie, err := r.Cookie("current_theme")
if err == nil { if err == nil {
cookie := html.EscapeString(cookie.Value) cookie := html.EscapeString(cookie.Value)
theme, ok := themes[cookie] theme, ok := Themes[cookie]
if ok && !theme.HideFromThemes { if ok && !theme.HideFromThemes {
themeName = cookie themeName = cookie
} }
} }
headerVars = &HeaderVars{ headerVars = &HeaderVars{
Site: site, Site: Site,
Settings: settingBox.Load().(SettingBox), Settings: SettingBox.Load().(SettingMap),
Themes: themes, Themes: Themes,
ThemeName: themeName, ThemeName: themeName,
} }
// TODO: We should probably initialise headerVars.ExtData // TODO: We should probably initialise headerVars.ExtData
headerVars.Stylesheets = append(headerVars.Stylesheets, headerVars.ThemeName+"/panel.css") headerVars.Stylesheets = append(headerVars.Stylesheets, headerVars.ThemeName+"/panel.css")
if len(themes[headerVars.ThemeName].Resources) > 0 { if len(Themes[headerVars.ThemeName].Resources) > 0 {
rlist := themes[headerVars.ThemeName].Resources rlist := Themes[headerVars.ThemeName].Resources
for _, resource := range rlist { for _, resource := range rlist {
if resource.Location == "global" || resource.Location == "panel" { if resource.Location == "global" || resource.Location == "panel" {
extarr := strings.Split(resource.Name, ".") 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) stats.Users = Users.GlobalCount()
if err != nil { stats.Groups = Gstore.GlobalCount()
return headerVars, stats, InternalError(err, w, r) stats.Forums = Fstore.GlobalCount() // TODO: Stop it from showing the blanked forums
}
stats.Users = users.GlobalCount()
stats.Forums = fstore.GlobalCount() // TODO: Stop it from showing the blanked forums
stats.Settings = len(headerVars.Settings) stats.Settings = len(headerVars.Settings)
stats.WordFilters = len(wordFilterBox.Load().(WordFilterBox)) stats.WordFilters = len(WordFilterBox.Load().(WordFilterMap))
stats.Themes = len(themes) stats.Themes = len(Themes)
stats.Reports = 0 // TODO: Do the report count. Only show open threads? stats.Reports = 0 // TODO: Do the report count. Only show open threads?
pusher, ok := w.(http.Pusher) pusher, ok := w.(http.Pusher)
@ -188,15 +182,15 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerV
return headerVars, stats, nil 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{ return &HeaderLite{
Site: site, Site: Site,
Settings: settingBox.Load().(SettingBox), Settings: SettingBox.Load().(SettingMap),
}, nil }, nil
} }
// TODO: Add this to the member routes // 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) headerVars, rerr = UserCheck(w, r, user)
if !user.Loggedin { if !user.Loggedin {
return headerVars, NoPermissions(w, r, *user) 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 // 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{ headerLite = &HeaderLite{
Site: site, Site: Site,
Settings: settingBox.Load().(SettingBox), Settings: SettingBox.Load().(SettingMap),
} }
return headerLite, nil return headerLite, nil
} }
// TODO: Add the ability for admins to restrict certain themes to certain groups? // 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) { func userCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, rerr RouteError) {
var themeName = defaultThemeBox.Load().(string) var themeName = DefaultThemeBox.Load().(string)
cookie, err := r.Cookie("current_theme") cookie, err := r.Cookie("current_theme")
if err == nil { if err == nil {
cookie := html.EscapeString(cookie.Value) cookie := html.EscapeString(cookie.Value)
theme, ok := themes[cookie] theme, ok := Themes[cookie]
if ok && !theme.HideFromThemes { if ok && !theme.HideFromThemes {
themeName = cookie themeName = cookie
} }
} }
headerVars = &HeaderVars{ headerVars = &HeaderVars{
Site: site, Site: Site,
Settings: settingBox.Load().(SettingBox), Settings: SettingBox.Load().(SettingMap),
Themes: themes, Themes: Themes,
ThemeName: themeName, 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.") 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 { if len(Themes[headerVars.ThemeName].Resources) > 0 {
rlist := themes[headerVars.ThemeName].Resources rlist := Themes[headerVars.ThemeName].Resources
for _, resource := range rlist { for _, resource := range rlist {
if resource.Location == "global" || resource.Location == "frontend" { if resource.Location == "global" || resource.Location == "frontend" {
extarr := strings.Split(resource.Name, ".") 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) { func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) {
user, halt := auth.SessionCheck(w, r) user, halt := Auth.SessionCheck(w, r)
if halt { if halt {
return *user, false return *user, false
} }
if user == &guestUser { if user == &GuestUser {
return *user, true return *user, true
} }
var usercpy = *user var usercpy *User
*usercpy = *user
// TODO: WIP. Refactor this to eliminate the unnecessary query // TODO: WIP. Refactor this to eliminate the unnecessary query
host, _, err := net.SplitHostPort(r.RemoteAddr) host, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil { if err != nil {
PreError("Bad IP", w, r) PreError("Bad IP", w, r)
return usercpy, false return *usercpy, false
} }
if host != usercpy.LastIP { if host != usercpy.LastIP {
_, err = stmts.updateLastIP.Exec(host, usercpy.ID) err = usercpy.UpdateIP(host)
if err != nil { if err != nil {
InternalError(err, w, r) InternalError(err, w, r)
return usercpy, false return *usercpy, false
} }
usercpy.LastIP = host usercpy.LastIP = host
} }
@ -296,7 +291,7 @@ func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) {
//h.Set("X-XSS-Protection", "1") //h.Set("X-XSS-Protection", "1")
// TODO: Set the content policy header // 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 // SuperModeOnly makes sure that only super mods or higher can access the panel routes

View File

@ -3,6 +3,7 @@ package common
import "strconv" import "strconv"
import "strings" import "strings"
import "sync/atomic" 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 // SettingMap is a map type specifically for holding the various settings admins set to toggle features on and off or to otherwise alter Gosora's behaviour from the Control Panel
type SettingMap map[string]interface{} type SettingMap map[string]interface{}
@ -27,7 +28,12 @@ func init() {
} }
func LoadSettings() error { 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 { if err != nil {
return err return err
} }

View File

@ -6,24 +6,31 @@ import (
"strings" "strings"
) )
var site = &Site{Name: "Magical Fairy Land", Language: "english"} // 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 dbConfig = DBConfig{Host: "localhost"} var Site = &site{Name: "Magical Fairy Land", Language: "english"}
var config Config
var dev DevConfig
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 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? Name string
Email string // ? - Move this into the settings table? Email string
URL string URL string
Port string Port string
EnableSsl bool EnableSsl bool
EnableEmails bool EnableEmails bool
HasProxy bool HasProxy bool
Language string // ? - Move this into the settings table? Language string
} }
type DBConfig struct { type dbConfig struct {
// Production database // Production database
Host string Host string
Username string Username string
@ -39,7 +46,7 @@ type DBConfig struct {
TestPort string TestPort string
} }
type Config struct { type config struct {
SslPrivkey string SslPrivkey string
SslFullchain string SslFullchain string
@ -65,7 +72,7 @@ type Config struct {
ItemsPerPage int // ? - Move this into the settings table? ItemsPerPage int // ? - Move this into the settings table?
} }
type DevConfig struct { type devConfig struct {
DebugMode bool DebugMode bool
SuperDebug bool SuperDebug bool
TemplateDebug bool TemplateDebug bool
@ -73,35 +80,35 @@ type DevConfig struct {
TestDB bool TestDB bool
} }
func processConfig() error { func ProcessConfig() error {
config.Noavatar = strings.Replace(config.Noavatar, "{site_url}", site.URL, -1) Config.Noavatar = strings.Replace(Config.Noavatar, "{site_url}", Site.URL, -1)
if site.Port != "80" && site.Port != "443" { 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 = strings.TrimSuffix(Site.URL, "\\")
site.URL = strings.TrimSuffix(site.URL, ":") Site.URL = strings.TrimSuffix(Site.URL, ":")
site.URL = site.URL + ":" + site.Port Site.URL = Site.URL + ":" + Site.Port
} }
// We need this in here rather than verifyConfig as switchToTestDB() currently overwrites the values it verifies // 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") return errors.New("Your test database can't have the same name as your production database")
} }
if dev.TestDB { if Dev.TestDB {
switchToTestDB() SwitchToTestDB()
} }
return nil return nil
} }
func verifyConfig() error { func VerifyConfig() error {
if !fstore.Exists(config.DefaultForum) { if !Fstore.Exists(Config.DefaultForum) {
return errors.New("Invalid default forum") return errors.New("Invalid default forum")
} }
return nil return nil
} }
func switchToTestDB() { func SwitchToTestDB() {
dbConfig.Host = dbConfig.TestHost DbConfig.Host = DbConfig.TestHost
dbConfig.Username = dbConfig.TestUsername DbConfig.Username = DbConfig.TestUsername
dbConfig.Password = dbConfig.TestPassword DbConfig.Password = DbConfig.TestPassword
dbConfig.Dbname = dbConfig.TestDbname DbConfig.Dbname = DbConfig.TestDbname
dbConfig.Port = dbConfig.TestPort DbConfig.Port = DbConfig.TestPort
} }

View File

@ -4,11 +4,13 @@
* Copyright Azareal 2017 - 2018 * Copyright Azareal 2017 - 2018
* *
*/ */
package main package common
import ( import (
"log" "log"
"time" "time"
"../query_gen/lib"
) )
var lastSync time.Time var lastSync time.Time
@ -17,8 +19,12 @@ func init() {
lastSync = time.Now() lastSync = time.Now()
} }
func handleExpiredScheduledGroups() error { func HandleExpiredScheduledGroups() error {
rows, err := stmts.getExpiredScheduledGroups.Query() 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 { if err != nil {
return err return err
} }
@ -32,7 +38,7 @@ func handleExpiredScheduledGroups() error {
} }
// Sneaky way of initialising a *User, please use the methods on the UserStore instead // Sneaky way of initialising a *User, please use the methods on the UserStore instead
user := getDummyUser() user := BlankUser()
user.ID = uid user.ID = uid
err = user.RevertGroupUpdate() err = user.RevertGroupUpdate()
if err != nil { if err != nil {
@ -42,16 +48,20 @@ func handleExpiredScheduledGroups() error {
return rows.Err() return rows.Err()
} }
func handleServerSync() error { func HandleServerSync() error {
var lastUpdate time.Time 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 { if err != nil {
return err return err
} }
if lastUpdate.After(lastSync) { if lastUpdate.After(lastSync) {
// TODO: A more granular sync // TODO: A more granular sync
err = fstore.LoadForums() err = Fstore.LoadForums()
if err != nil { if err != nil {
log.Print("Unable to reload the forums") log.Print("Unable to reload the forums")
return err return err

View File

@ -5,10 +5,12 @@ import (
"log" "log"
"net/http" "net/http"
"time" "time"
"./templates"
) )
var templates = template.New("") var Templates = template.New("")
var prebuildTmplList []func(*User, *HeaderVars) CTmpl var PrebuildTmplList []func(User, *HeaderVars) CTmpl
type CTmpl struct { type CTmpl struct {
Name string Name string
@ -20,11 +22,11 @@ type CTmpl struct {
// nolint // nolint
func interpreted_topic_template(pi TopicPage, w http.ResponseWriter) error { 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 { if !ok {
mapping = "topic" mapping = "topic"
} }
return templates.ExecuteTemplate(w, mapping+".html", pi) return Templates.ExecuteTemplate(w, mapping+".html", pi)
} }
// nolint // nolint
@ -33,64 +35,66 @@ var template_topic_alt_handle func(TopicPage, http.ResponseWriter) error = inter
// nolint // nolint
var template_topics_handle func(TopicsPage, http.ResponseWriter) error = func(pi TopicsPage, w http.ResponseWriter) error { 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 { if !ok {
mapping = "topics" mapping = "topics"
} }
return templates.ExecuteTemplate(w, mapping+".html", pi) return Templates.ExecuteTemplate(w, mapping+".html", pi)
} }
// nolint // nolint
var template_forum_handle func(ForumPage, http.ResponseWriter) error = func(pi ForumPage, w http.ResponseWriter) error { 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 { if !ok {
mapping = "forum" mapping = "forum"
} }
return templates.ExecuteTemplate(w, mapping+".html", pi) return Templates.ExecuteTemplate(w, mapping+".html", pi)
} }
// nolint // nolint
var template_forums_handle func(ForumsPage, http.ResponseWriter) error = func(pi ForumsPage, w http.ResponseWriter) error { 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 { if !ok {
mapping = "forums" mapping = "forums"
} }
return templates.ExecuteTemplate(w, mapping+".html", pi) return Templates.ExecuteTemplate(w, mapping+".html", pi)
} }
// nolint // nolint
var template_profile_handle func(ProfilePage, http.ResponseWriter) error = func(pi ProfilePage, w http.ResponseWriter) error { 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 { if !ok {
mapping = "profile" mapping = "profile"
} }
return templates.ExecuteTemplate(w, mapping+".html", pi) return Templates.ExecuteTemplate(w, mapping+".html", pi)
} }
// nolint // nolint
var template_create_topic_handle func(CreateTopicPage, http.ResponseWriter) error = func(pi CreateTopicPage, w http.ResponseWriter) error { 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 { if !ok {
mapping = "create-topic" mapping = "create-topic"
} }
return templates.ExecuteTemplate(w, mapping+".html", pi) return Templates.ExecuteTemplate(w, mapping+".html", pi)
} }
// ? - Add template hooks? // ? - Add template hooks?
func compileTemplates() error { 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 // Schemas to train the template compiler on what to expect
// TODO: Add support for interface{}s // 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? // 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} 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} 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{ headerVars := &HeaderVars{
Site: site, Site: Site,
Settings: settingBox.Load().(SettingBox), Settings: SettingBox.Load().(SettingMap),
Themes: themes, Themes: Themes,
ThemeName: defaultThemeBox.Load().(string), ThemeName: DefaultThemeBox.Load().(string),
NoticeList: []string{"test"}, NoticeList: []string{"test"},
Stylesheets: []string{"panel"}, Stylesheets: []string{"panel"},
Scripts: []string{"whatever"}, Scripts: []string{"whatever"},
@ -102,31 +106,31 @@ func compileTemplates() error {
log.Print("Compiling the templates") log.Print("Compiling the templates")
var now = time.Now() 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 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} 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 { if err != nil {
return err 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 { if err != nil {
return err return err
} }
varList = make(map[string]VarItem) varList = make(map[string]tmpl.VarItem)
ppage := ProfilePage{"User 526", user, headerVars, replyList, user} 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 { if err != nil {
return err return err
} }
// TODO: Use a dummy forum list to avoid o(n) problems // TODO: Use a dummy forum list to avoid o(n) problems
var forumList []Forum var forumList []Forum
forums, err := fstore.GetAll() forums, err := Fstore.GetAll()
if err != nil { if err != nil {
return err return err
} }
@ -135,17 +139,17 @@ func compileTemplates() error {
//log.Printf("*forum %+v\n", *forum) //log.Printf("*forum %+v\n", *forum)
forumList = append(forumList, *forum) forumList = append(forumList, *forum)
} }
varList = make(map[string]VarItem) varList = make(map[string]tmpl.VarItem)
forumsPage := ForumsPage{"Forum List", user, headerVars, forumList} 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 { if err != nil {
return err return err
} }
var topicsList []*TopicsRow 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"}) 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} topicsPage := TopicsPage{"Topic List", user, headerVars, topicsList, forumList, Config.DefaultForum}
topicsTmpl, err := c.compileTemplate("topics.html", "templates/", "TopicsPage", topicsPage, varList) topicsTmpl, err := c.Compile("topics.html", "templates/", "TopicsPage", topicsPage, varList)
if err != nil { if err != nil {
return err 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}) //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) 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} 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 { if err != nil {
return err return err
} }
// Let plugins register their own templates // Let plugins register their own templates
for _, tmplfunc := range prebuildTmplList { for _, tmplfunc := range PrebuildTmplList {
tmpl := tmplfunc(user, headerVars) tmplItem := tmplfunc(user, headerVars)
varList = make(map[string]VarItem) varList = make(map[string]tmpl.VarItem)
compiledTmpl, err := c.compileTemplate(tmpl.Filename, tmpl.Path, tmpl.StructName, tmpl.Data, varList) compiledTmpl, err := c.Compile(tmplItem.Filename, tmplItem.Path, tmplItem.StructName, tmplItem.Data, varList)
if err != nil { if err != nil {
return err return err
} }
go writeTemplate(tmpl.Name, compiledTmpl) go writeTemplate(tmplItem.Name, compiledTmpl)
} }
log.Print("Writing the templates") log.Print("Writing the templates")
@ -194,8 +198,8 @@ func writeTemplate(name string, content string) {
} }
} }
func initTemplates() { func InitTemplates() {
if dev.DebugMode { if Dev.DebugMode {
log.Print("Initialising the template system") log.Print("Initialising the template system")
} }
compileTemplates() compileTemplates()
@ -259,10 +263,10 @@ func initTemplates() {
} }
// The interpreted templates... // The interpreted templates...
if dev.DebugMode { if Dev.DebugMode {
log.Print("Loading the template files...") log.Print("Loading the template files...")
} }
templates.Funcs(fmap) Templates.Funcs(fmap)
template.Must(templates.ParseGlob("templates/*")) template.Must(Templates.ParseGlob("templates/*"))
template.Must(templates.ParseGlob("pages/*")) template.Must(Templates.ParseGlob("pages/*"))
} }

View File

@ -1,4 +1,4 @@
package main package tmpl
import ( import (
"bytes" "bytes"
@ -14,8 +14,7 @@ import (
) )
// TODO: Turn this file into a library // TODO: Turn this file into a library
var ctemplates []string var cTemplates []string
var tmplPtrMap = make(map[string]interface{})
var textOverlapList = make(map[string]int) var textOverlapList = make(map[string]int)
// nolint // nolint
@ -47,11 +46,26 @@ type CTemplateSet struct {
nextNode parse.NodeType nextNode parse.NodeType
//tempVars map[string]string //tempVars map[string]string
doImports bool doImports bool
minify bool
debug bool
superDebug bool
expectsInt interface{} expectsInt interface{}
} }
func (c *CTemplateSet) compileTemplate(name string, dir string, expects string, expectsInt interface{}, varList map[string]VarItem) (out string, err error) { func (c *CTemplateSet) Minify(on bool) {
if dev.DebugMode { 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 + "'") fmt.Println("Compiling template '" + name + "'")
} }
@ -75,6 +89,7 @@ func (c *CTemplateSet) compileTemplate(name string, dir string, expects string,
c.importMap = map[string]string{ c.importMap = map[string]string{
"net/http": "net/http", "net/http": "net/http",
"./common": "./common",
} }
c.varList = varList c.varList = varList
//c.pVarList = "" //c.pVarList = ""
@ -89,7 +104,7 @@ func (c *CTemplateSet) compileTemplate(name string, dir string, expects string,
} }
content := string(res) content := string(res)
if config.MinifyTemplates { if c.minify {
content = minify(content) 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 := "// +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 += "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 += "// nolint\nfunc template_" + fname + "(tmpl_" + fname + "_vars " + expects + ", w http.ResponseWriter) error {\n" + varString + out + "\treturn nil\n}\n"
fout = strings.Replace(fout, `)) fout = strings.Replace(fout, `))
@ -143,7 +158,7 @@ w.Write([]byte(`, " + ", -1)
//whitespaceWrites := regexp.MustCompile(`(?s)w.Write\(\[\]byte\(`+spstr+`\)\)`) //whitespaceWrites := regexp.MustCompile(`(?s)w.Write\(\[\]byte\(`+spstr+`\)\)`)
//fout = whitespaceWrites.ReplaceAllString(fout,"") //fout = whitespaceWrites.ReplaceAllString(fout,"")
if dev.DebugMode { if c.debug {
for index, count := range c.stats { for index, count := range c.stats {
fmt.Println(index+": ", strconv.Itoa(count)) fmt.Println(index+": ", strconv.Itoa(count))
} }
@ -160,9 +175,7 @@ func (c *CTemplateSet) rootIterate(tree *parse.Tree, varholder string, holdrefle
c.log(tree.Root) c.log(tree.Root)
treeLength := len(tree.Root.Nodes) treeLength := len(tree.Root.Nodes)
for index, node := range tree.Root.Nodes { for index, node := range tree.Root.Nodes {
if dev.TemplateDebug { c.log("Node:", node.String())
fmt.Println("Node:", node.String())
}
c.previousNode = c.currentNode c.previousNode = c.currentNode
c.currentNode = node.Type() c.currentNode = node.Type()
if treeLength != (index + 1) { if treeLength != (index + 1) {
@ -245,9 +258,7 @@ func (c *CTemplateSet) compileRangeNode(varholder string, holdreflect reflect.Va
var outVal reflect.Value var outVal reflect.Value
for _, cmd := range node.Pipe.Cmds { for _, cmd := range node.Pipe.Cmds {
if dev.TemplateDebug { c.log("Range Bit:", cmd)
fmt.Println("Range Bit:", cmd)
}
out, outVal = c.compileReflectSwitch(varholder, holdreflect, templateName, cmd) out, outVal = c.compileReflectSwitch(varholder, holdreflect, templateName, cmd)
} }
c.log("Returned:", out) c.log("Returned:", out)
@ -259,7 +270,7 @@ func (c *CTemplateSet) compileRangeNode(varholder string, holdreflect reflect.Va
for _, key := range outVal.MapKeys() { for _, key := range outVal.MapKeys() {
item = outVal.MapIndex(key) item = outVal.MapIndex(key)
} }
if dev.DebugMode { if c.debug {
fmt.Println("Range item:", item) fmt.Println("Range item:", item)
} }
if !item.IsValid() { if !item.IsValid() {
@ -317,11 +328,11 @@ func (c *CTemplateSet) compileSubswitch(varholder string, holdreflect reflect.Va
} }
if !cur.IsValid() { if !cur.IsValid() {
if dev.DebugMode { if c.debug {
fmt.Println("Debug Data:") fmt.Println("Debug Data:")
fmt.Println("Holdreflect:", holdreflect) fmt.Println("Holdreflect:", holdreflect)
fmt.Println("Holdreflect.Kind():", holdreflect.Kind()) fmt.Println("Holdreflect.Kind():", holdreflect.Kind())
if !dev.TemplateDebug { if !c.superDebug {
fmt.Println("cur.Kind():", cur.Kind().String()) fmt.Println("cur.Kind():", cur.Kind().String())
} }
fmt.Println("") fmt.Println("")
@ -382,7 +393,7 @@ func (c *CTemplateSet) compileVarswitch(varholder string, holdreflect reflect.Va
firstWord := node.Args[0] firstWord := node.Args[0]
switch n := firstWord.(type) { switch n := firstWord.(type) {
case *parse.FieldNode: case *parse.FieldNode:
if dev.TemplateDebug { if c.superDebug {
fmt.Println("Field Node:", n.Ident) fmt.Println("Field Node:", n.Ident)
for _, id := range n.Ident { for _, id := range n.Ident {
fmt.Println("Field Bit:", id) fmt.Println("Field Bit:", id)
@ -564,7 +575,7 @@ func (c *CTemplateSet) compileReflectSwitch(varholder string, holdreflect reflec
firstWord := node.Args[0] firstWord := node.Args[0]
switch n := firstWord.(type) { switch n := firstWord.(type) {
case *parse.FieldNode: case *parse.FieldNode:
if dev.TemplateDebug { if c.superDebug {
fmt.Println("Field Node:", n.Ident) fmt.Println("Field Node:", n.Ident)
for _, id := range n.Ident { for _, id := range n.Ident {
fmt.Println("Field Bit:", id) fmt.Println("Field Bit:", id)
@ -771,7 +782,7 @@ func (c *CTemplateSet) compileSubtemplate(pvarholder string, pholdreflect reflec
} }
content := string(res) content := string(res)
if config.MinifyTemplates { if c.minify {
content = minify(content) content = minify(content)
} }
@ -795,7 +806,7 @@ func (c *CTemplateSet) compileSubtemplate(pvarholder string, pholdreflect reflec
} }
func (c *CTemplateSet) log(args ...interface{}) { func (c *CTemplateSet) log(args ...interface{}) {
if dev.TemplateDebug { if c.superDebug {
fmt.Println(args...) fmt.Println(args...)
} }
} }

View File

@ -17,13 +17,15 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"text/template" "text/template"
"../query_gen/lib"
) )
type ThemeList map[string]Theme type ThemeList map[string]Theme
//var themes ThemeList = make(map[string]Theme) var Themes ThemeList = make(map[string]Theme)
var DefaultThemeBox atomic.Value var DefaultThemeBox atomic.Value
var changeDefaultThemeMutex sync.Mutex var ChangeDefaultThemeMutex sync.Mutex
// TODO: Use this when the default theme doesn't exist // TODO: Use this when the default theme doesn't exist
var fallbackTheme = "shadow" var fallbackTheme = "shadow"
@ -73,14 +75,19 @@ type ThemeResource struct {
} }
func init() { func init() {
defaultThemeBox.Store(fallbackTheme) DefaultThemeBox.Store(fallbackTheme)
} }
// TODO: Make the initThemes and LoadThemes functions less confusing // TODO: Make the initThemes and LoadThemes functions less confusing
// ? - Delete themes which no longer exist in the themes folder from the database? // ? - Delete themes which no longer exist in the themes folder from the database?
func LoadThemeActiveStatus() error { func (themes ThemeList) LoadActiveStatus() error {
changeDefaultThemeMutex.Lock() getThemes, err := qgen.Builder.SimpleSelect("themes", "uname, default", "", "", "")
rows, err := stmts.getThemes.Query() if err != nil {
return err
}
ChangeDefaultThemeMutex.Lock()
rows, err := getThemes.Query()
if err != nil { if err != nil {
return err return err
} }
@ -103,8 +110,8 @@ func LoadThemeActiveStatus() error {
if defaultThemeSwitch { if defaultThemeSwitch {
log.Print("Loading the default theme '" + theme.Name + "'") log.Print("Loading the default theme '" + theme.Name + "'")
theme.Active = true theme.Active = true
defaultThemeBox.Store(theme.Name) DefaultThemeBox.Store(theme.Name)
mapThemeTemplates(theme) MapThemeTemplates(theme)
} else { } else {
log.Print("Loading the theme '" + theme.Name + "'") log.Print("Loading the theme '" + theme.Name + "'")
theme.Active = false theme.Active = false
@ -112,11 +119,11 @@ func LoadThemeActiveStatus() error {
themes[uname] = theme themes[uname] = theme
} }
changeDefaultThemeMutex.Unlock() ChangeDefaultThemeMutex.Unlock()
return rows.Err() return rows.Err()
} }
func initThemes() error { func InitThemes() error {
themeFiles, err := ioutil.ReadDir("./themes") themeFiles, err := ioutil.ReadDir("./themes")
if err != nil { if err != nil {
return err return err
@ -156,10 +163,10 @@ func initThemes() error {
} }
if theme.FullImage != "" { if theme.FullImage != "" {
if dev.DebugMode { if Dev.DebugMode {
log.Print("Adding theme image") 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 { if err != nil {
return err return err
} }
@ -170,7 +177,7 @@ func initThemes() error {
if theme.Templates != nil { if theme.Templates != nil {
for _, themeTmpl := range theme.Templates { for _, themeTmpl := range theme.Templates {
theme.TemplatesMap[themeTmpl.Name] = themeTmpl.Source 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")) 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 // 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 { if err != nil {
return err return err
} }
themes[theme.Name] = theme Themes[theme.Name] = theme
} }
return nil 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? // 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 { 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 + "'") log.Print("Attempting to add static file '" + path + "' for default theme '" + theme.Name + "'")
} }
if err != nil { if err != nil {
@ -224,16 +231,16 @@ func addThemeStaticFiles(theme Theme) error {
path = strings.TrimPrefix(path, "themes/"+theme.Name+"/public") path = strings.TrimPrefix(path, "themes/"+theme.Name+"/public")
gzipData := compressBytesGzip(data) 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 + ".") log.Print("Added the '/" + theme.Name + path + "' static file for theme " + theme.Name + ".")
} }
return nil return nil
}) })
} }
func mapThemeTemplates(theme Theme) { func MapThemeTemplates(theme Theme) {
if theme.Templates != nil { if theme.Templates != nil {
for _, themeTmpl := range theme.Templates { for _, themeTmpl := range theme.Templates {
if themeTmpl.Name == "" { 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? // `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 { if !ok {
return return
} }
sourceTmplPtr, ok := tmplPtrMap[themeTmpl.Source] sourceTmplPtr, ok := TmplPtrMap[themeTmpl.Source]
if !ok { if !ok {
log.Fatal("The source template doesn't exist!") 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") log.Print("Resetting the template overrides")
for name := range overridenTemplates { for name := range overridenTemplates {
log.Print("Resetting '" + name + "' template override") log.Print("Resetting '" + name + "' template override")
originPointer, ok := tmplPtrMap["o_"+name] originPointer, ok := TmplPtrMap["o_"+name]
if !ok { if !ok {
//log.Fatal("The origin template doesn't exist!") //log.Fatal("The origin template doesn't exist!")
log.Print("The origin template doesn't exist!") log.Print("The origin template doesn't exist!")
return return
} }
destTmplPtr, ok := tmplPtrMap[name] destTmplPtr, ok := TmplPtrMap[name]
if !ok { if !ok {
//log.Fatal("The destination template doesn't exist!") //log.Fatal("The destination template doesn't exist!")
log.Print("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: case func(Page, http.ResponseWriter) error:
return tmplO(pi.(Page), w) return tmplO(pi.(Page), w)
case string: case string:
mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap[template] mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap[template]
if !ok { if !ok {
mapping = template mapping = template
} }
return templates.ExecuteTemplate(w, mapping+".html", pi) return Templates.ExecuteTemplate(w, mapping+".html", pi)
default: default:
log.Print("theme ", theme) log.Print("theme ", theme)
log.Print("template ", template) 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 // 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{} { func GetThemeTemplate(theme string, template string) interface{} {
tmpl, ok := themes[theme].TmplPtr[template] tmpl, ok := Themes[theme].TmplPtr[template]
if ok { if ok {
return tmpl return tmpl
} }
tmpl, ok = tmplPtrMap[template] tmpl, ok = TmplPtrMap[template]
if ok { if ok {
return tmpl return tmpl
} }
@ -487,19 +494,19 @@ func GetThemeTemplate(theme string, template string) interface{} {
// CreateThemeTemplate creates a theme template on the current default theme // CreateThemeTemplate creates a theme template on the current default theme
func CreateThemeTemplate(theme string, name string) { func CreateThemeTemplate(theme string, name string) {
themes[theme].TmplPtr[name] = func(pi Page, w http.ResponseWriter) error { Themes[theme].TmplPtr[name] = func(pi Page, w http.ResponseWriter) error {
mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap[name] mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap[name]
if !ok { if !ok {
mapping = name mapping = name
} }
return templates.ExecuteTemplate(w, mapping+".html", pi) return Templates.ExecuteTemplate(w, mapping+".html", pi)
} }
} }
func GetDefaultThemeName() string { func GetDefaultThemeName() string {
return defaultThemeBox.Load().(string) return DefaultThemeBox.Load().(string)
} }
func SetDefaultThemeName(name string) { func SetDefaultThemeName(name string) {
defaultThemeBox.Store(name) DefaultThemeBox.Store(name)
} }

View File

@ -6,12 +6,14 @@
*/ */
package common package common
//import "fmt"
import ( import (
"database/sql"
"html" "html"
"html/template" "html/template"
"strconv" "strconv"
"time" "time"
"../query_gen/lib"
) )
// This is also in reply.go // This is also in reply.go
@ -105,10 +107,49 @@ type TopicsRow struct {
ForumLink string 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 // Flush the topic out of the cache
// ? - We do a CacheRemove() here instead of mutating the pointer to avoid creating a race condition // ? - We do a CacheRemove() here instead of mutating the pointer to avoid creating a race condition
func (topic *Topic) cacheRemove() { func (topic *Topic) cacheRemove() {
tcache, ok := topics.(TopicCache) tcache, ok := Topics.(TopicCache)
if ok { if ok {
tcache.CacheRemove(topic.ID) tcache.CacheRemove(topic.ID)
} }
@ -116,32 +157,32 @@ func (topic *Topic) cacheRemove() {
// TODO: Write a test for this // TODO: Write a test for this
func (topic *Topic) AddReply(uid int) (err error) { 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() topic.cacheRemove()
return err return err
} }
func (topic *Topic) Lock() (err error) { func (topic *Topic) Lock() (err error) {
_, err = stmts.lockTopic.Exec(topic.ID) _, err = topicStmts.lock.Exec(topic.ID)
topic.cacheRemove() topic.cacheRemove()
return err return err
} }
func (topic *Topic) Unlock() (err error) { func (topic *Topic) Unlock() (err error) {
_, err = stmts.unlockTopic.Exec(topic.ID) _, err = topicStmts.unlock.Exec(topic.ID)
topic.cacheRemove() topic.cacheRemove()
return err 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. // 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) { func (topic *Topic) Stick() (err error) {
_, err = stmts.stickTopic.Exec(topic.ID) _, err = topicStmts.stick.Exec(topic.ID)
topic.cacheRemove() topic.cacheRemove()
return err return err
} }
func (topic *Topic) Unstick() (err error) { func (topic *Topic) Unstick() (err error) {
_, err = stmts.unstickTopic.Exec(topic.ID) _, err = topicStmts.unstick.Exec(topic.ID)
topic.cacheRemove() topic.cacheRemove()
return err return err
} }
@ -150,19 +191,19 @@ func (topic *Topic) Unstick() (err error) {
// TODO: Use a transaction for this // TODO: Use a transaction for this
func (topic *Topic) Like(score int, uid int) (err error) { func (topic *Topic) Like(score int, uid int) (err error) {
var tid int // Unused 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 { if err != nil && err != ErrNoRows {
return err return err
} else if err != ErrNoRows { } else if err != ErrNoRows {
return ErrAlreadyLiked return ErrAlreadyLiked
} }
_, err = stmts.createLike.Exec(score, tid, "topics", uid) _, err = topicStmts.createLike.Exec(score, tid, "topics", uid)
if err != nil { if err != nil {
return err return err
} }
_, err = stmts.addLikesToTopic.Exec(1, tid) _, err = topicStmts.addLikesToTopic.Exec(1, tid)
topic.cacheRemove() topic.cacheRemove()
return err return err
} }
@ -174,10 +215,10 @@ func (topic *Topic) Unlike(uid int) error {
// TODO: Use a transaction here // TODO: Use a transaction here
func (topic *Topic) Delete() error { func (topic *Topic) Delete() error {
topicCreator, err := users.Get(topic.CreatedBy) topicCreator, err := Users.Get(topic.CreatedBy)
if err == nil { if err == nil {
wcount := wordCount(topic.Content) wcount := WordCount(topic.Content)
err = topicCreator.decreasePostStats(wcount, true) err = topicCreator.DecreasePostStats(wcount, true)
if err != nil { if err != nil {
return err return err
} }
@ -185,31 +226,31 @@ func (topic *Topic) Delete() error {
return err return err
} }
err = fstore.RemoveTopic(topic.ParentID) err = Fstore.RemoveTopic(topic.ParentID)
if err != nil && err != ErrNoRows { if err != nil && err != ErrNoRows {
return err return err
} }
_, err = stmts.deleteTopic.Exec(topic.ID) _, err = topicStmts.delete.Exec(topic.ID)
topic.cacheRemove() topic.cacheRemove()
return err return err
} }
func (topic *Topic) Update(name string, content string) error { func (topic *Topic) Update(name string, content string) error {
content = preparseMessage(content) content = PreparseMessage(content)
parsed_content := parseMessage(html.EscapeString(content), topic.ParentID, "forums") parsedContent := ParseMessage(html.EscapeString(content), topic.ParentID, "forums")
_, err := topicStmts.edit.Exec(name, content, parsedContent, topic.ID)
_, err := stmts.editTopic.Exec(name, content, parsed_content, topic.ID)
topic.cacheRemove() topic.cacheRemove()
return err return err
} }
// TODO: Have this go through the ReplyStore?
func (topic *Topic) CreateActionReply(action string, ipaddress string, user User) (err error) { 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 { if err != nil {
return err return err
} }
_, err = stmts.addRepliesToTopic.Exec(1, user.ID, topic.ID) _, err = topicStmts.addRepliesToTopic.Exec(1, user.ID, topic.ID)
topic.cacheRemove() topic.cacheRemove()
// ? - Update the last topic cache for the parent forum? // ? - Update the last topic cache for the parent forum?
return err 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 // TODO: Refactor the caller to take a Topic and a User rather than a combined TopicUser
func getTopicUser(tid int) (TopicUser, error) { func GetTopicUser(tid int) (TopicUser, error) {
tcache, tok := topics.(TopicCache) tcache, tok := Topics.(TopicCache)
ucache, uok := users.(UserCache) ucache, uok := Users.(UserCache)
if tok && uok { if tok && uok {
topic, err := tcache.CacheGet(tid) topic, err := tcache.CacheGet(tid)
if err == nil { if err == nil {
user, err := users.Get(topic.CreatedBy) user, err := Users.Get(topic.CreatedBy)
if err != nil { if err != nil {
return TopicUser{ID: tid}, err 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? // We might be better off just passing separate topic and user structs to the caller?
return copyTopicToTopicUser(topic, user), nil return copyTopicToTopicUser(topic, user), nil
} else if ucache.Length() < ucache.GetCapacity() { } else if ucache.Length() < ucache.GetCapacity() {
topic, err = topics.Get(tid) topic, err = Topics.Get(tid)
if err != nil { if err != nil {
return TopicUser{ID: tid}, err return TopicUser{ID: tid}, err
} }
user, err := users.Get(topic.CreatedBy) user, err := Users.Get(topic.CreatedBy)
if err != nil { if err != nil {
return TopicUser{ID: tid}, err return TopicUser{ID: tid}, err
} }
@ -248,14 +289,14 @@ func getTopicUser(tid int) (TopicUser, error) {
} }
tu := TopicUser{ID: tid} 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) 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.Link = BuildTopicURL(NameToSlug(tu.Title), tu.ID)
tu.UserLink = buildProfileURL(nameToSlug(tu.CreatedByName), tu.CreatedBy) tu.UserLink = BuildProfileURL(NameToSlug(tu.CreatedByName), tu.CreatedBy)
tu.Tag = gstore.DirtyGet(tu.Group).Tag tu.Tag = Gstore.DirtyGet(tu.Group).Tag
if tok { 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} 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) _ = tcache.CacheAdd(&theTopic)
} }
return tu, err 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 // 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: ""} return &Topic{ID: 0, Title: ""}
} }
func getTopicByReply(rid int) (*Topic, error) { func BuildTopicURL(slug string, tid int) string {
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 {
if slug == "" { if slug == "" {
return "/topic/" + strconv.Itoa(tid) return "/topic/" + strconv.Itoa(tid)
} }

View File

@ -20,11 +20,12 @@ import (
// TODO: Add BulkGetMap // TODO: Add BulkGetMap
// TODO: Add some sort of update method // 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 // ? - 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 ErrNoTitle = errors.New("This message is missing a title")
var ErrNoBody = errors.New("This message is missing a body") var ErrNoBody = errors.New("This message is missing a body")
type TopicStore interface { type TopicStore interface {
DirtyGet(id int) *Topic
Get(id int) (*Topic, error) Get(id int) (*Topic, error)
BypassGet(id int) (*Topic, error) BypassGet(id int) (*Topic, error)
Exists(id int) bool Exists(id int) bool
@ -93,6 +94,24 @@ func (mts *MemoryTopicStore) CacheGetUnsafe(id int) (*Topic, error) {
return item, ErrNoRows 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) { func (mts *MemoryTopicStore) Get(id int) (*Topic, error) {
mts.RLock() mts.RLock()
topic, ok := mts.items[id] topic, ok := mts.items[id]
@ -104,7 +123,7 @@ func (mts *MemoryTopicStore) Get(id int) (*Topic, error) {
topic = &Topic{ID: id} 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) 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 { if err == nil {
topic.Link = buildTopicURL(nameToSlug(topic.Title), id) topic.Link = BuildTopicURL(NameToSlug(topic.Title), id)
_ = mts.CacheAdd(topic) _ = mts.CacheAdd(topic)
} }
return topic, err return topic, err
@ -114,7 +133,7 @@ func (mts *MemoryTopicStore) Get(id int) (*Topic, error) {
func (mts *MemoryTopicStore) BypassGet(id int) (*Topic, error) { func (mts *MemoryTopicStore) BypassGet(id int) (*Topic, error) {
topic := &Topic{ID: id} 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) 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 return topic, err
} }
@ -122,7 +141,7 @@ func (mts *MemoryTopicStore) Reload(id int) error {
topic := &Topic{ID: id} 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) 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 { if err == nil {
topic.Link = buildTopicURL(nameToSlug(topic.Title), id) topic.Link = BuildTopicURL(NameToSlug(topic.Title), id)
_ = mts.CacheSet(topic) _ = mts.CacheSet(topic)
} else { } else {
_ = mts.CacheRemove(id) _ = mts.CacheRemove(id)
@ -141,12 +160,12 @@ func (mts *MemoryTopicStore) Create(fid int, topicName string, content string, u
} }
content = strings.TrimSpace(content) content = strings.TrimSpace(content)
parsedContent := parseMessage(content, fid, "forums") parsedContent := ParseMessage(content, fid, "forums")
if strings.TrimSpace(parsedContent) == "" { if strings.TrimSpace(parsedContent) == "" {
return 0, ErrNoBody return 0, ErrNoBody
} }
wcount := wordCount(content) wcount := WordCount(content)
// TODO: Move this statement into the topic store // TODO: Move this statement into the topic store
res, err := mts.create.Exec(fid, topicName, content, parsedContent, uid, ipaddress, wcount, uid) res, err := mts.create.Exec(fid, topicName, content, parsedContent, uid, ipaddress, wcount, uid)
if err != nil { if err != nil {
@ -158,8 +177,7 @@ func (mts *MemoryTopicStore) Create(fid int, topicName string, content string, u
return 0, err return 0, err
} }
err = fstore.AddTopic(int(lastID), uid, fid) return int(lastID), Fstore.AddTopic(int(lastID), uid, fid)
return int(lastID), err
} }
func (mts *MemoryTopicStore) CacheSet(item *Topic) error { func (mts *MemoryTopicStore) CacheSet(item *Topic) error {
@ -268,10 +286,20 @@ func NewSQLTopicStore() (*SQLTopicStore, error) {
}, acc.FirstError() }, 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) { func (sts *SQLTopicStore) Get(id int) (*Topic, error) {
topic := Topic{ID: id} 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) 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 return &topic, err
} }
@ -279,7 +307,7 @@ func (sts *SQLTopicStore) Get(id int) (*Topic, error) {
func (sts *SQLTopicStore) BypassGet(id int) (*Topic, error) { func (sts *SQLTopicStore) BypassGet(id int) (*Topic, error) {
topic := &Topic{ID: id} 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) 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 return topic, err
} }
@ -294,12 +322,12 @@ func (sts *SQLTopicStore) Create(fid int, topicName string, content string, uid
} }
content = strings.TrimSpace(content) content = strings.TrimSpace(content)
parsedContent := parseMessage(content, fid, "forums") parsedContent := ParseMessage(content, fid, "forums")
if strings.TrimSpace(parsedContent) == "" { if strings.TrimSpace(parsedContent) == "" {
return 0, ErrNoBody return 0, ErrNoBody
} }
wcount := wordCount(content) wcount := WordCount(content)
// TODO: Move this statement into the topic store // TODO: Move this statement into the topic store
res, err := sts.create.Exec(fid, topicName, content, parsedContent, uid, ipaddress, wcount, uid) res, err := sts.create.Exec(fid, topicName, content, parsedContent, uid, ipaddress, wcount, uid)
if err != nil { if err != nil {
@ -311,8 +339,7 @@ func (sts *SQLTopicStore) Create(fid int, topicName string, content string, uid
return 0, err return 0, err
} }
err = fstore.AddTopic(int(lastID), uid, fid) return int(lastID), Fstore.AddTopic(int(lastID), uid, fid)
return int(lastID), err
} }
// ? - What're we going to do about this? // ? - What're we going to do about this?

View File

@ -15,12 +15,14 @@ import (
"strings" "strings"
"time" "time"
"../query_gen/lib"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
// TODO: Replace any literals with this // TODO: Replace any literals with this
var BanGroup = 4 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} var GuestUser = User{ID: 0, Link: "#", Group: 6, Perms: GuestPerms}
//func(real_password string, password string, salt string) (err error) //func(real_password string, password string, salt string) (err error)
@ -57,12 +59,48 @@ type User struct {
TempGroup int TempGroup int
} }
type Email struct { type UserStmts struct {
UserID int activate *sql.Stmt
Email string changeGroup *sql.Stmt
Validated bool delete *sql.Stmt
Primary bool setAvatar *sql.Stmt
Token string 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() { func (user *User) Init() {
@ -71,15 +109,22 @@ func (user *User) Init() {
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + user.Avatar user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + user.Avatar
} }
} else { } 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 { 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 { 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) revertAt := time.Now().Add(duration)
tx, err := db.Begin() tx, err := qgen.Builder.Begin()
if err != nil { if err != nil {
return err return err
} }
@ -138,15 +183,12 @@ func (user *User) ScheduleGroupUpdate(gid int, issuedBy int, duration time.Durat
} }
err = tx.Commit() err = tx.Commit()
ucache, ok := users.(UserCache) user.CacheRemove()
if ok {
ucache.CacheRemove(user.ID)
}
return err return err
} }
func (user *User) RevertGroupUpdate() error { func (user *User) RevertGroupUpdate() error {
tx, err := db.Begin() tx, err := qgen.Builder.Begin()
if err != nil { if err != nil {
return err return err
} }
@ -163,25 +205,19 @@ func (user *User) RevertGroupUpdate() error {
} }
err = tx.Commit() err = tx.Commit()
ucache, ok := users.(UserCache) user.CacheRemove()
if ok {
ucache.CacheRemove(user.ID)
}
return err return err
} }
// TODO: Use a transaction here // 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? // ? - 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) { func (user *User) Activate() (err error) {
_, err = stmts.activateUser.Exec(user.ID) _, err = userStmts.activate.Exec(user.ID)
if err != nil { if err != nil {
return err return err
} }
_, err = stmts.changeGroup.Exec(config.DefaultGroup, user.ID) _, err = userStmts.changeGroup.Exec(Config.DefaultGroup, user.ID)
ucache, ok := users.(UserCache) user.CacheRemove()
if ok {
ucache.CacheRemove(user.ID)
}
return err return err
} }
@ -189,111 +225,105 @@ func (user *User) Activate() (err error) {
// TODO: Delete this user's content too? // TODO: Delete this user's content too?
// TODO: Expose this to the admin? // TODO: Expose this to the admin?
func (user *User) Delete() error { func (user *User) Delete() error {
_, err := stmts.deleteUser.Exec(user.ID) _, err := userStmts.delete.Exec(user.ID)
if err != nil { if err != nil {
return err return err
} }
ucache, ok := users.(UserCache) user.CacheRemove()
if ok {
ucache.CacheRemove(user.ID)
}
return err return err
} }
func (user *User) ChangeName(username string) (err error) { func (user *User) ChangeName(username string) (err error) {
_, err = stmts.setUsername.Exec(username, user.ID) _, err = userStmts.setUsername.Exec(username, user.ID)
ucache, ok := users.(UserCache) user.CacheRemove()
if ok {
ucache.CacheRemove(user.ID)
}
return err return err
} }
func (user *User) ChangeAvatar(avatar string) (err error) { func (user *User) ChangeAvatar(avatar string) (err error) {
_, err = stmts.setAvatar.Exec(avatar, user.ID) _, err = userStmts.setAvatar.Exec(avatar, user.ID)
ucache, ok := users.(UserCache) user.CacheRemove()
if ok {
ucache.CacheRemove(user.ID)
}
return err return err
} }
func (user *User) ChangeGroup(group int) (err error) { func (user *User) ChangeGroup(group int) (err error) {
_, err = stmts.updateUserGroup.Exec(group, user.ID) _, err = userStmts.updateGroup.Exec(group, user.ID)
ucache, ok := users.(UserCache) user.CacheRemove()
if ok {
ucache.CacheRemove(user.ID)
}
return err 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 var mod int
baseScore := 1 baseScore := 1
if topic { if topic {
_, err = stmts.incrementUserTopics.Exec(1, user.ID) _, err = userStmts.incrementTopics.Exec(1, user.ID)
if err != nil { if err != nil {
return err return err
} }
baseScore = 2 baseScore = 2
} }
settings := settingBox.Load().(SettingBox) settings := SettingBox.Load().(SettingMap)
if wcount >= settings["megapost_min_words"].(int) { 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 mod = 4
} else if wcount >= settings["bigpost_min_words"].(int) { } 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 mod = 1
} else { } else {
_, err = stmts.incrementUserPosts.Exec(1, user.ID) _, err = userStmts.incrementPosts.Exec(1, user.ID)
} }
if err != nil { if err != nil {
return err return err
} }
_, err = stmts.incrementUserScore.Exec(baseScore+mod, user.ID) _, err = userStmts.incrementScore.Exec(baseScore+mod, user.ID)
if err != nil { if err != nil {
return err return err
} }
//log.Print(user.Score + base_score + mod) //log.Print(user.Score + base_score + mod)
//log.Print(getLevel(user.Score + base_score + mod)) //log.Print(getLevel(user.Score + base_score + mod))
// TODO: Use a transaction to prevent level desyncs? // 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 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 var mod int
baseScore := -1 baseScore := -1
if topic { if topic {
_, err = stmts.incrementUserTopics.Exec(-1, user.ID) _, err = userStmts.incrementTopics.Exec(-1, user.ID)
if err != nil { if err != nil {
return err return err
} }
baseScore = -2 baseScore = -2
} }
settings := settingBox.Load().(SettingBox) settings := SettingBox.Load().(SettingMap)
if wcount >= settings["megapost_min_words"].(int) { 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 mod = 4
} else if wcount >= settings["bigpost_min_words"].(int) { } 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 mod = 1
} else { } else {
_, err = stmts.incrementUserPosts.Exec(-1, user.ID) _, err = userStmts.incrementPosts.Exec(-1, user.ID)
} }
if err != nil { if err != nil {
return err return err
} }
_, err = stmts.incrementUserScore.Exec(baseScore-mod, user.ID) _, err = userStmts.incrementScore.Exec(baseScore-mod, user.ID)
if err != nil { if err != nil {
return err return err
} }
// TODO: Use a transaction to prevent level desyncs? // 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 return err
} }
@ -303,12 +333,12 @@ func (user *User) Copy() User {
} }
// TODO: Write unit tests for this // TODO: Write unit tests for this
func (user *User) initPerms() { func (user *User) InitPerms() {
if user.TempGroup != 0 { if user.TempGroup != 0 {
user.Group = user.TempGroup user.Group = user.TempGroup
} }
group := gstore.DirtyGet(user.Group) group := Gstore.DirtyGet(user.Group)
if user.IsSuperAdmin { if user.IsSuperAdmin {
user.Perms = AllPerms user.Perms = AllPerms
user.PluginPerms = AllPluginPerms user.PluginPerms = AllPluginPerms
@ -332,7 +362,7 @@ func BcryptCheckPassword(realPassword string, password string, salt string) (err
// Investigate. Do we need the extra salt? // Investigate. Do we need the extra salt?
func BcryptGeneratePassword(password string) (hashedPassword string, salt string, err error) { func BcryptGeneratePassword(password string) (hashedPassword string, salt string, err error) {
salt, err = GenerateSafeString(saltLength) salt, err = GenerateSafeString(SaltLength)
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
@ -353,27 +383,16 @@ func BcryptGeneratePasswordNoSalt(password string) (hash string, err error) {
return string(hashedPassword), nil return string(hashedPassword), nil
} }
// TODO: Move this to *User
func SetPassword(uid int, password string) error { func SetPassword(uid int, password string) error {
hashedPassword, salt, err := GeneratePassword(password) hashedPassword, salt, err := GeneratePassword(password)
if err != nil { if err != nil {
return err return err
} }
_, err = stmts.setPassword.Exec(hashedPassword, salt, uid) _, err = userStmts.setPassword.Exec(hashedPassword, salt, uid)
return err 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 // TODO: Write units tests for this
func wordsToScore(wcount int, topic bool) (score int) { func wordsToScore(wcount int, topic bool) (score int) {
if topic { if topic {
@ -382,7 +401,7 @@ func wordsToScore(wcount int, topic bool) (score int) {
score = 1 score = 1
} }
settings := settingBox.Load().(SettingBox) settings := SettingBox.Load().(SettingMap)
if wcount >= settings["megapost_min_words"].(int) { if wcount >= settings["megapost_min_words"].(int) {
score += 4 score += 4
} else if wcount >= settings["bigpost_min_words"].(int) { } 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 // 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: ""} return &User{ID: 0, Name: ""}
} }
// TODO: Write unit tests for this // TODO: Write unit tests for this
func buildProfileURL(slug string, uid int) string { func BuildProfileURL(slug string, uid int) string {
if slug == "" { if slug == "" {
return "/user/" + strconv.Itoa(uid) return "/user/" + strconv.Itoa(uid)
} }

View File

@ -8,15 +8,17 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"../query_gen/lib"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
// TODO: Add the watchdog goroutine // TODO: Add the watchdog goroutine
// TODO: Add some sort of update method // TODO: Add some sort of update method
var users UserStore var Users UserStore
var errAccountExists = errors.New("this username is already in use") var ErrAccountExists = errors.New("this username is already in use")
type UserStore interface { type UserStore interface {
DirtyGet(id int) *User
Get(id int) (*User, error) Get(id int) (*User, error)
Exists(id int) bool Exists(id int) bool
//BulkGet(ids []int) ([]*User, error) //BulkGet(ids []int) ([]*User, error)
@ -86,6 +88,25 @@ func (mus *MemoryUserStore) CacheGetUnsafe(id int) (*User, error) {
return item, ErrNoRows 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) { func (mus *MemoryUserStore) Get(id int) (*User, error) {
mus.RLock() mus.RLock()
user, ok := mus.items[id] 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 // We probably don't need this, but it might be useful in case of bugs in BulkCascadeGetMap
if sidList == "" { 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("This data is sampled later in the BulkCascadeGetMap function, so it might miss the cached IDs")
log.Print("idCount", idCount) log.Print("idCount", idCount)
log.Print("ids", ids) log.Print("ids", ids)
@ -298,10 +319,10 @@ func (mus *MemoryUserStore) Create(username string, password string, email strin
// Is this username already taken..? // Is this username already taken..?
err := mus.usernameExists.QueryRow(username).Scan(&username) err := mus.usernameExists.QueryRow(username).Scan(&username)
if err != ErrNoRows { if err != ErrNoRows {
return 0, errAccountExists return 0, ErrAccountExists
} }
salt, err := GenerateSafeString(saltLength) salt, err := GenerateSafeString(SaltLength)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -370,6 +391,17 @@ func NewSQLUserStore() (*SQLUserStore, error) {
}, acc.FirstError() }, 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) { func (mus *SQLUserStore) Get(id int) (*User, error) {
user := &User{ID: id, Loggedin: true} 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) 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..? // Is this username already taken..?
err := mus.usernameExists.QueryRow(username).Scan(&username) err := mus.usernameExists.QueryRow(username).Scan(&username)
if err != ErrNoRows { if err != ErrNoRows {
return 0, errAccountExists return 0, ErrAccountExists
} }
salt, err := GenerateSafeString(saltLength) salt, err := GenerateSafeString(SaltLength)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View File

@ -12,12 +12,13 @@ import (
"errors" "errors"
"fmt" "fmt"
"math" "math"
"net/smtp"
"os" "os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"unicode" "unicode"
"../query_gen/lib"
) )
// Version stores a Gosora version // Version stores a Gosora version
@ -53,7 +54,7 @@ func GenerateSafeString(length int) (string, error) {
} }
// TODO: Write a test for this // TODO: Write a test for this
func relativeTimeFromString(in string) (string, error) { func RelativeTimeFromString(in string) (string, error) {
if in == "" { if in == "" {
return "", nil return "", nil
} }
@ -63,11 +64,11 @@ func relativeTimeFromString(in string) (string, error) {
return "", err return "", err
} }
return relativeTime(t), nil return RelativeTime(t), nil
} }
// TODO: Write a test for this // TODO: Write a test for this
func relativeTime(t time.Time) string { func RelativeTime(t time.Time) string {
diff := time.Since(t) diff := time.Since(t)
hours := diff.Hours() hours := diff.Hours()
seconds := diff.Seconds() seconds := diff.Seconds()
@ -105,36 +106,36 @@ func relativeTime(t time.Time) string {
} }
// TODO: Write a test for this // TODO: Write a test for this
func convertByteUnit(bytes float64) (float64, string) { func ConvertByteUnit(bytes float64) (float64, string) {
switch { switch {
case bytes >= float64(petabyte): case bytes >= float64(Petabyte):
return bytes / float64(petabyte), "PB" return bytes / float64(Petabyte), "PB"
case bytes >= float64(terabyte): case bytes >= float64(Terabyte):
return bytes / float64(terabyte), "TB" return bytes / float64(Terabyte), "TB"
case bytes >= float64(gigabyte): case bytes >= float64(Gigabyte):
return bytes / float64(gigabyte), "GB" return bytes / float64(Gigabyte), "GB"
case bytes >= float64(megabyte): case bytes >= float64(Megabyte):
return bytes / float64(megabyte), "MB" return bytes / float64(Megabyte), "MB"
case bytes >= float64(kilobyte): case bytes >= float64(Kilobyte):
return bytes / float64(kilobyte), "KB" return bytes / float64(Kilobyte), "KB"
default: default:
return bytes, " bytes" return bytes, " bytes"
} }
} }
// TODO: Write a test for this // TODO: Write a test for this
func convertByteInUnit(bytes float64, unit string) (count float64) { func ConvertByteInUnit(bytes float64, unit string) (count float64) {
switch unit { switch unit {
case "PB": case "PB":
count = bytes / float64(petabyte) count = bytes / float64(Petabyte)
case "TB": case "TB":
count = bytes / float64(terabyte) count = bytes / float64(Terabyte)
case "GB": case "GB":
count = bytes / float64(gigabyte) count = bytes / float64(Gigabyte)
case "MB": case "MB":
count = bytes / float64(megabyte) count = bytes / float64(Megabyte)
case "KB": case "KB":
count = bytes / float64(kilobyte) count = bytes / float64(Kilobyte)
default: default:
count = 0.1 count = 0.1
} }
@ -146,7 +147,7 @@ func convertByteInUnit(bytes float64, unit string) (count float64) {
} }
// TODO: Write a test for this // TODO: Write a test for this
func convertUnit(num int) (int, string) { func ConvertUnit(num int) (int, string) {
switch { switch {
case num >= 1000000000000: case num >= 1000000000000:
return num / 1000000000000, "T" return num / 1000000000000, "T"
@ -162,7 +163,7 @@ func convertUnit(num int) (int, string) {
} }
// TODO: Write a test for this // TODO: Write a test for this
func convertFriendlyUnit(num int) (int, string) { func ConvertFriendlyUnit(num int) (int, string) {
switch { switch {
case num >= 1000000000000000: case num >= 1000000000000000:
return 0, " quadrillion" 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.TrimSpace(name)
name = strings.Replace(name, " ", " ", -1) name = strings.Replace(name, " ", " ", -1)
@ -199,58 +200,8 @@ func nameToSlug(name string) (slug string) {
return slug 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 // TODO: Write a test for this
func weakPassword(password string) error { func WeakPassword(password string) error {
if len(password) < 8 { if len(password) < 8 {
return errors.New("your password needs to be at-least eight characters long") 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 // TODO: Write a test for this
func wordCount(input string) (count int) { func WordCount(input string) (count int) {
input = strings.TrimSpace(input) input = strings.TrimSpace(input)
if input == "" { if input == "" {
return 0 return 0
@ -355,7 +306,7 @@ func wordCount(input string) (count int) {
} }
// TODO: Write a test for this // TODO: Write a test for this
func getLevel(score int) (level int) { func GetLevel(score int) (level int) {
var base float64 = 25 var base float64 = 25
var current, prev float64 var current, prev float64
var expFactor = 2.8 var expFactor = 2.8
@ -376,7 +327,7 @@ func getLevel(score int) (level int) {
} }
// TODO: Write a test for this // TODO: Write a test for this
func getLevelScore(getLevel int) (score int) { func GetLevelScore(getLevel int) (score int) {
var base float64 = 25 var base float64 = 25
var current, prev float64 var current, prev float64
var level int var level int
@ -398,7 +349,7 @@ func getLevelScore(getLevel int) (score int) {
} }
// TODO: Write a test for this // TODO: Write a test for this
func getLevels(maxLevel int) []float64 { func GetLevels(maxLevel int) []float64 {
var base float64 = 25 var base float64 = 25
var current, prev float64 // = 0 var current, prev float64 // = 0
var expFactor = 2.8 var expFactor = 2.8
@ -417,7 +368,7 @@ func getLevels(maxLevel int) []float64 {
return out return out
} }
func buildSlug(slug string, id int) string { func BuildSlug(slug string, id int) string {
if slug == "" { if slug == "" {
return strconv.Itoa(id) return strconv.Itoa(id)
} }
@ -425,13 +376,21 @@ func buildSlug(slug string, id int) string {
} }
// TODO: Make a store for this? // TODO: Make a store for this?
func addModLog(action string, elementID int, elementType string, ipaddress string, actorID int) (err error) { func AddModLog(action string, elementID int, elementType string, ipaddress string, actorID int) (err error) {
_, err = stmts.addModlogEntry.Exec(action, elementID, elementType, ipaddress, actorID) 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 return err
} }
// TODO: Make a store for this? // TODO: Make a store for this?
func addAdminLog(action string, elementID string, elementType int, ipaddress string, actorID int) (err error) { func AddAdminLog(action string, elementID string, elementType int, ipaddress string, actorID int) (err error) {
_, err = stmts.addAdminlogEntry.Exec(action, elementID, elementType, ipaddress, actorID) 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 return err
} }

View File

@ -1,14 +1,13 @@
/* Copyright Azareal 2017 - 2018 */ /* Copyright Azareal 2017 - 2018 */
package main package common
import "log" import "log"
import "bytes" import "bytes"
import "sync" import "sync"
import "encoding/json" import "encoding/json"
import "../query_gen/lib"
//import "html/template" var Docks WidgetDocks
var docks WidgetDocks
var widgetUpdateMutex sync.RWMutex var widgetUpdateMutex sync.RWMutex
type WidgetDocks struct { type WidgetDocks struct {
@ -41,8 +40,12 @@ type NameTextPair struct {
} }
// TODO: Make a store for this? // TODO: Make a store for this?
func initWidgets() error { func InitWidgets() error {
rows, err := stmts.getWidgets.Query() 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 { if err != nil {
return err return err
} }
@ -71,7 +74,7 @@ func initWidgets() error {
} }
var b bytes.Buffer var b bytes.Buffer
err = templates.ExecuteTemplate(&b, "widget_simple.html", tmp) err = Templates.ExecuteTemplate(&b, "widget_simple.html", tmp)
if err != nil { if err != nil {
return err return err
} }
@ -92,13 +95,13 @@ func initWidgets() error {
} }
widgetUpdateMutex.Lock() widgetUpdateMutex.Lock()
docks.LeftSidebar = leftWidgets Docks.LeftSidebar = leftWidgets
docks.RightSidebar = rightWidgets Docks.RightSidebar = rightWidgets
widgetUpdateMutex.Unlock() widgetUpdateMutex.Unlock()
if dev.SuperDebug { if Dev.SuperDebug {
log.Print("docks.LeftSidebar", docks.LeftSidebar) log.Print("Docks.LeftSidebar", Docks.LeftSidebar)
log.Print("docks.RightSidebar", docks.RightSidebar) log.Print("Docks.RightSidebar", Docks.RightSidebar)
} }
return nil return nil

50
common/word_filters.go Normal file
View File

@ -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)
}

View File

@ -1,8 +1,11 @@
package main package main
import "log" import (
"database/sql"
"log"
import "database/sql" "./common"
)
var stmts *Stmts var stmts *Stmts
@ -15,7 +18,7 @@ var ErrNoRows = sql.ErrNoRows
var _initDatabase func() error var _initDatabase func() error
func initDatabase() (err error) { func InitDatabase() (err error) {
stmts = &Stmts{Mocks: false} stmts = &Stmts{Mocks: false}
// Engine specific code // Engine specific code
@ -25,70 +28,69 @@ func initDatabase() (err error) {
} }
globs = &Globs{stmts} globs = &Globs{stmts}
log.Print("Loading the usergroups.") err = common.DbInits.Run()
gstore, err = NewMemoryGroupStore()
if err != nil { if err != nil {
return err return err
} }
err = gstore.LoadGroups()
log.Print("Loading the usergroups.")
common.Gstore, err = common.NewMemoryGroupStore()
if err != nil { if err != nil {
return err 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 // 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") log.Print("Initialising the user and topic stores")
if config.CacheTopicUser == CACHE_STATIC { if common.Config.CacheTopicUser == common.CACHE_STATIC {
users, err = NewMemoryUserStore(config.UserCacheCapacity) common.Users, err = common.NewMemoryUserStore(common.Config.UserCacheCapacity)
if err != nil { common.Topics, err2 = common.NewMemoryTopicStore(common.Config.TopicCacheCapacity)
return err
}
topics, err = NewMemoryTopicStore(config.TopicCacheCapacity)
if err != nil {
return err
}
} else { } else {
users, err = NewSQLUserStore() common.Users, err = common.NewSQLUserStore()
if err != nil { common.Topics, err2 = common.NewSQLTopicStore()
return err
}
topics, err = NewSQLTopicStore()
if err != nil {
return err
}
} }
log.Print("Loading the forums.")
fstore, err = NewMemoryForumStore()
if err != nil { if err != nil {
return err 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 { if err != nil {
return err return err
} }
log.Print("Loading the forum permissions.") log.Print("Loading the forum permissions.")
fpstore, err = NewMemoryForumPermsStore() common.Fpstore, err = common.NewMemoryForumPermsStore()
if err != nil { if err != nil {
return err return err
} }
err = fpstore.Init() err = common.Fpstore.Init()
if err != nil { if err != nil {
return err return err
} }
log.Print("Loading the settings.") log.Print("Loading the settings.")
err = LoadSettings() err = common.LoadSettings()
if err != nil { if err != nil {
return err return err
} }
log.Print("Loading the plugins.") log.Print("Loading the plugins.")
err = initExtend() err = common.InitExtend()
if err != nil { if err != nil {
return err return err
} }
log.Print("Loading the themes.") log.Print("Loading the themes.")
return LoadThemeActiveStatus() return common.Themes.LoadActiveStatus()
} }

View File

@ -14,6 +14,9 @@ import (
"../../../common" "../../../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 ListStmt *sql.Stmt
var MemberListStmt *sql.Stmt var MemberListStmt *sql.Stmt
var MemberListJoinStmt *sql.Stmt var MemberListJoinStmt *sql.Stmt
@ -45,15 +48,15 @@ type Guild struct {
MainForumID int MainForumID int
MainForum *common.Forum MainForum *common.Forum
Forums []*common.Forum Forums []*common.Forum
ExtData ExtData ExtData common.ExtData
} }
type Page struct { type Page struct {
Title string Title string
CurrentUser User CurrentUser common.User
Header *common.HeaderVars Header *common.HeaderVars
ItemList []*TopicsRow ItemList []*common.TopicsRow
Forum *commmon.Forum Forum *common.Forum
Guild *Guild Guild *Guild
Page int Page int
LastPage int LastPage int
@ -62,16 +65,16 @@ type Page struct {
// ListPage is a page struct for constructing a list of every guild // ListPage is a page struct for constructing a list of every guild
type ListPage struct { type ListPage struct {
Title string Title string
CurrentUser User CurrentUser common.User
Header *HeaderVars Header *common.HeaderVars
GuildList []*Guild GuildList []*Guild
} }
type MemberListPage struct { type MemberListPage struct {
Title string Title string
CurrentUser User CurrentUser common.User
Header *HeaderVars Header *common.HeaderVars
ItemList []GuildMember ItemList []Member
Guild *Guild Guild *Guild
Page int Page int
LastPage int LastPage int
@ -86,15 +89,15 @@ type Member struct {
JoinedAt string JoinedAt string
Offline bool // TODO: Need to track the online states of members when WebSockets are enabled 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{ var guildList = []*Guild{
&Guild{ &Guild{
ID: 1, ID: 1,
Name: "lol", Name: "lol",
Link: guildsBuildGuildURL(nameToSlug("lol"), 1), Link: BuildGuildURL(common.NameToSlug("lol"), 1),
Desc: "A group for people who like to laugh", Desc: "A group for people who like to laugh",
Active: true, Active: true,
MemberCount: 1, MemberCount: 1,
@ -102,38 +105,38 @@ func PrebuildTmplList(user *User, headerVars *HeaderVars) CTmpl {
CreatedAt: "date", CreatedAt: "date",
LastUpdateTime: "date", LastUpdateTime: "date",
MainForumID: 1, MainForumID: 1,
MainForum: fstore.DirtyGet(1), MainForum: common.Fstore.DirtyGet(1),
Forums: []*Forum{fstore.DirtyGet(1)}, Forums: []*common.Forum{common.Fstore.DirtyGet(1)},
}, },
} }
listPage := ListPage{"Guild List", user, headerVars, guildList} 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 // TODO: Do this properly via the widget system
func CommonAreaWidgets(headerVars *HeaderVars) { func CommonAreaWidgets(headerVars *common.HeaderVars) {
// TODO: Hot Groups? Featured Groups? Official Groups? // TODO: Hot Groups? Featured Groups? Official Groups?
var b bytes.Buffer var b bytes.Buffer
var menu = WidgetMenu{"Guilds", []WidgetMenuItem{ var menu = common.WidgetMenu{"Guilds", []common.WidgetMenuItem{
WidgetMenuItem{"Create Guild", "/guild/create/", false}, 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 { if err != nil {
LogError(err) common.LogError(err)
return return
} }
if themes[headerVars.ThemeName].Sidebars == "left" { if common.Themes[headerVars.ThemeName].Sidebars == "left" {
headerVars.Widgets.LeftSidebar = template.HTML(string(b.Bytes())) 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())) headerVars.Widgets.RightSidebar = template.HTML(string(b.Bytes()))
} }
} }
// TODO: Do this properly via the widget system // TODO: Do this properly via the widget system
// TODO: Make a better more customisable group 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 return false // Disabled until the next commit
/*var b bytes.Buffer /*var b bytes.Buffer
@ -144,7 +147,7 @@ func GuildWidgets(headerVars *HeaderVars, guildItem *Guild) (success bool) {
err := templates.ExecuteTemplate(&b, "widget_menu.html", menu) err := templates.ExecuteTemplate(&b, "widget_menu.html", menu)
if err != nil { if err != nil {
LogError(err) common.LogError(err)
return false return false
} }
@ -162,16 +165,16 @@ func GuildWidgets(headerVars *HeaderVars, guildItem *Guild) (success bool) {
Custom Pages Custom Pages
*/ */
func routeGuildList(w http.ResponseWriter, r *http.Request, user User) RouteError { func RouteGuildList(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
headerVars, ferr := UserCheck(w, r, &user) headerVars, ferr := common.UserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
guildsCommonAreaWidgets(headerVars) CommonAreaWidgets(headerVars)
rows, err := guildsListStmt.Query() rows, err := ListStmt.Query()
if err != nil && err != ErrNoRows { if err != nil && err != common.ErrNoRows {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
defer rows.Close() defer rows.Close()
@ -180,31 +183,31 @@ func routeGuildList(w http.ResponseWriter, r *http.Request, user User) RouteErro
guildItem := &Guild{ID: 0} 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) 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 { 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) guildList = append(guildList, guildItem)
} }
err = rows.Err() err = rows.Err()
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
pi := GuildListPage{"Guild List", user, headerVars, guildList} pi := ListPage{"Guild List", user, headerVars, guildList}
err = RunThemeTemplate(headerVars.ThemeName, "guilds_guild_list", pi, w) err = common.RunThemeTemplate(headerVars.ThemeName, "guilds_guild_list", pi, w)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
return nil return nil
} }
func GetGuild(guildID int) (guildItem *Guild, err error) { func GetGuild(guildID int) (guildItem *Guild, err error) {
guildItem = &Guild{ID: guildID} 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 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... // SEO URLs...
halves := strings.Split(r.URL.Path[len("/guild/"):], ".") halves := strings.Split(r.URL.Path[len("/guild/"):], ".")
if len(halves) < 2 { 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]) guildID, err := strconv.Atoi(halves[1])
if err != nil { 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 { if err != nil {
return LocalError("Bad guild", w, r, user) return common.LocalError("Bad guild", w, r, user)
} }
if !guildItem.Active { if !guildItem.Active {
return NotFound(w, r) return common.NotFound(w, r)
} }
return nil
// TODO: Re-implement this
// Re-route the request to routeForums // Re-route the request to routeForums
var ctx = context.WithValue(r.Context(), "guilds_current_guild", guildItem) //var ctx = context.WithValue(r.Context(), "guilds_current_guild", guildItem)
return routeForum(w, r.WithContext(ctx), user, strconv.Itoa(guildItem.MainForumID)) //return routeForum(w, r.WithContext(ctx), user, strconv.Itoa(guildItem.MainForumID))
} }
func CreateGuild(w http.ResponseWriter, r *http.Request, user User) RouteError { func RouteCreateGuild(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
headerVars, ferr := UserCheck(w, r, &user) headerVars, ferr := common.UserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
// TODO: Add an approval queue mode for group creation // TODO: Add an approval queue mode for group creation
if !user.Loggedin || !user.PluginPerms["CreateGuild"] { 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} pi := common.Page{"Create Guild", user, headerVars, tList, nil}
err := templates.ExecuteTemplate(w, "guilds_create_guild.html", pi) err := common.Templates.ExecuteTemplate(w, "guilds_create_guild.html", pi)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
return nil 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 // TODO: Add an approval queue mode for group creation
if !user.Loggedin || !user.PluginPerms["CreateGuild"] { if !user.Loggedin || !user.PluginPerms["CreateGuild"] {
return NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
var guildActive = true var guildActive = true
@ -271,37 +277,37 @@ func CreateGuildSubmit(w http.ResponseWriter, r *http.Request, user User) RouteE
} }
// Create the backing forum // Create the backing forum
fid, err := fstore.Create(guildName, "", true, "") fid, err := common.Fstore.Create(guildName, "", true, "")
if err != nil { 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 { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
lastID, err := res.LastInsertId() lastID, err := res.LastInsertId()
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
// Add the main backing forum to the forum list // Add the main backing forum to the forum list
err = guildsAttachForum(int(lastID), fid) err = AttachForum(int(lastID), fid)
if err != nil { 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 { 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 return nil
} }
func MemberList(w http.ResponseWriter, r *http.Request, user User) RouteError { func RouteMemberList(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
headerVars, ferr := UserCheck(w, r, &user) headerVars, ferr := common.UserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
@ -313,40 +319,40 @@ func MemberList(w http.ResponseWriter, r *http.Request, user User) RouteError {
} }
guildID, err := strconv.Atoi(halves[1]) guildID, err := strconv.Atoi(halves[1])
if err != nil { 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 guildItem = &Guild{ID: guildID}
var mainForum int // Unused 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 { 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) rows, err := MemberListJoinStmt.Query(guildID)
if err != nil && err != ErrNoRows { if err != nil && err != common.ErrNoRows {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
var guildMembers []GuildMember var guildMembers []Member
for rows.Next() { 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) err := rows.Scan(&guildMember.User.ID, &guildMember.Rank, &guildMember.PostCount, &guildMember.JoinedAt, &guildMember.User.Name, &guildMember.User.Avatar)
if err != nil { 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 != "" {
if guildMember.User.Avatar[0] == '.' { if guildMember.User.Avatar[0] == '.' {
guildMember.User.Avatar = "/uploads/avatar_" + strconv.Itoa(guildMember.User.ID) + guildMember.User.Avatar guildMember.User.Avatar = "/uploads/avatar_" + strconv.Itoa(guildMember.User.ID) + guildMember.User.Avatar
} }
} else { } 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 { if guildItem.Owner == guildMember.User.ID {
guildMember.RankString = "Owner" guildMember.RankString = "Owner"
} else { } else {
@ -363,31 +369,31 @@ func MemberList(w http.ResponseWriter, r *http.Request, user User) RouteError {
} }
err = rows.Err() err = rows.Err()
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
rows.Close() 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! // A plugin with plugins. Pluginception!
if preRenderHooks["pre_render_guilds_member_list"] != nil { if common.PreRenderHooks["pre_render_guilds_member_list"] != nil {
if runPreRenderHook("pre_render_guilds_member_list", w, r, &user, &pi) { if common.RunPreRenderHook("pre_render_guilds_member_list", w, r, &user, &pi) {
return nil return nil
} }
} }
err = RunThemeTemplate(headerVars.ThemeName, "guilds_member_list", pi, w) err = common.RunThemeTemplate(headerVars.ThemeName, "guilds_member_list", pi, w)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
return nil return nil
} }
func AttachForum(guildID int, fid int) error { func AttachForum(guildID int, fid int) error {
_, err := guildsAttachForumStmt.Exec(guildID, fid) _, err := AttachForumStmt.Exec(guildID, fid)
return err return err
} }
func UnattachForum(fid int) error { func UnattachForum(fid int) error {
_, err := guildsAttachForumStmt.Exec(fid) _, err := AttachForumStmt.Exec(fid)
return err return err
} }
@ -403,16 +409,16 @@ func BuildGuildURL(slug string, id int) string {
*/ */
// TODO: Prebuild this template // TODO: Prebuild this template
func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) { func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *common.User, data interface{}) (halt bool) {
pi := data.(*ForumPage) pi := data.(*common.ForumPage)
if pi.Header.ExtData.items != nil { if pi.Header.ExtData.Items != nil {
if guildData, ok := pi.Header.ExtData.items["guilds_current_group"]; ok { if guildData, ok := pi.Header.ExtData.Items["guilds_current_group"]; ok {
guildItem := guildData.(*Guild) guildItem := guildData.(*Guild)
guildpi := GuildPage{pi.Title, pi.CurrentUser, pi.Header, pi.ItemList, pi.Forum, guildItem, pi.Page, pi.LastPage} guildpi := Page{pi.Title, pi.CurrentUser, pi.Header, pi.ItemList, pi.Forum, guildItem, pi.Page, pi.LastPage}
err := templates.ExecuteTemplate(w, "guilds_view_guild.html", guildpi) err := common.Templates.ExecuteTemplate(w, "guilds_view_guild.html", guildpi)
if err != nil { if err != nil {
LogError(err) common.LogError(err)
return false return false
} }
return true return true
@ -422,10 +428,10 @@ func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *User, data
} }
func TrowAssign(args ...interface{}) interface{} { func TrowAssign(args ...interface{}) interface{} {
var forum = args[1].(*Forum) var forum = args[1].(*common.Forum)
if forum.ParentType == "guild" { if forum.ParentType == "guild" {
var topicItem = args[0].(*TopicsRow) var topicItem = args[0].(*common.TopicsRow)
topicItem.ForumLink = "/guild/" + strings.TrimPrefix(topicItem.ForumLink, getForumURLPrefix()) topicItem.ForumLink = "/guild/" + strings.TrimPrefix(topicItem.ForumLink, common.GetForumURLPrefix())
} }
return nil 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 // 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{} { func TopicCreatePreLoop(args ...interface{}) interface{} {
var fid = args[2].(int) var fid = args[2].(int)
if fstore.DirtyGet(fid).ParentType == "guild" { if common.Fstore.DirtyGet(fid).ParentType == "guild" {
var strictmode = args[5].(*bool) var strictmode = args[5].(*bool)
*strictmode = true *strictmode = true
} }
@ -443,27 +449,27 @@ func TopicCreatePreLoop(args ...interface{}) interface{} {
// TODO: Add privacy options // TODO: Add privacy options
// TODO: Add support for multiple boards and add per-board simplified permissions // TODO: Add support for multiple boards and add per-board simplified permissions
// TODO: Take isJs into account for routes which expect JSON responses // 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 r = args[1].(*http.Request)
var fid = args[3].(*int) var fid = args[3].(*int)
var forum = fstore.DirtyGet(*fid) var forum = common.Fstore.DirtyGet(*fid)
if forum.ParentType == "guild" { if forum.ParentType == "guild" {
var err error var err error
var w = args[0].(http.ResponseWriter) var w = args[0].(http.ResponseWriter)
guildItem, ok := r.Context().Value("guilds_current_group").(*Guild) guildItem, ok := r.Context().Value("guilds_current_group").(*Guild)
if !ok { if !ok {
guildItem, err = guildsGetGuild(forum.ParentID) guildItem, err = GetGuild(forum.ParentID)
if err != nil { 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 { 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)) 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 rank int
var posts int var posts int
var joinedAt string var joinedAt string
@ -472,32 +478,32 @@ func ForumCheck(args ...interface{}) (skip bool, rerr RouteError) {
// Clear the default group permissions // Clear the default group permissions
// TODO: Do this more efficiently, doing it quick and dirty for now to get this out quickly // 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 user.Perms.ViewTopic = true
err = guildsGetMemberStmt.QueryRow(guildItem.ID, user.ID).Scan(&rank, &posts, &joinedAt) err = GetMemberStmt.QueryRow(guildItem.ID, user.ID).Scan(&rank, &posts, &joinedAt)
if err != nil && err != ErrNoRows { if err != nil && err != common.ErrNoRows {
return true, InternalError(err, w, r) return true, common.InternalError(err, w, r)
} else if err != nil { } else if err != nil {
// TODO: Should we let admins / guests into public groups? // 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: 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! // TODO: How does this even work? Refactor it along with the rest of this plugin!
if rank < 0 { 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! // Basic permissions for members, more complicated permissions coming in the next commit!
if guildItem.Owner == user.ID { if guildItem.Owner == user.ID {
overrideForumPerms(&user.Perms, true) common.OverrideForumPerms(&user.Perms, true)
} else if rank == 0 { } else if rank == 0 {
user.Perms.LikeItem = true user.Perms.LikeItem = true
user.Perms.CreateTopic = true user.Perms.CreateTopic = true
user.Perms.CreateReply = true user.Perms.CreateReply = true
} else { } else {
overrideForumPerms(&user.Perms, true) common.OverrideForumPerms(&user.Perms, true)
} }
return true, nil return true, nil
} }
@ -509,28 +515,28 @@ func ForumCheck(args ...interface{}) (skip bool, rerr RouteError) {
func Widgets(args ...interface{}) interface{} { func Widgets(args ...interface{}) interface{} {
var zone = args[0].(string) var zone = args[0].(string)
var headerVars = args[2].(*HeaderVars) var headerVars = args[2].(*common.HeaderVars)
var request = args[3].(*http.Request) var request = args[3].(*http.Request)
if zone != "view_forum" { if zone != "view_forum" {
return false return false
} }
var forum = args[1].(*Forum) var forum = args[1].(*common.Forum)
if forum.ParentType == "guild" { if forum.ParentType == "guild" {
// This is why I hate using contexts, all the daisy chains and interface casts x.x // 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) guildItem, ok := request.Context().Value("guilds_current_group").(*Guild)
if !ok { 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 return false
} }
if headerVars.ExtData.items == nil { if headerVars.ExtData.Items == nil {
headerVars.ExtData.items = make(map[string]interface{}) 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 return false
} }

View File

@ -5,6 +5,7 @@ package main
import "log" import "log"
import "database/sql" import "database/sql"
import "./common"
// nolint // nolint
type Stmts struct { type Stmts struct {
@ -12,21 +13,14 @@ type Stmts struct {
getSettings *sql.Stmt getSettings *sql.Stmt
getSetting *sql.Stmt getSetting *sql.Stmt
getFullSetting *sql.Stmt getFullSetting *sql.Stmt
getFullSettings *sql.Stmt
getPlugins *sql.Stmt
getThemes *sql.Stmt
getWidgets *sql.Stmt
isPluginActive *sql.Stmt isPluginActive *sql.Stmt
getUsersOffset *sql.Stmt getUsersOffset *sql.Stmt
getWordFilters *sql.Stmt
isThemeDefault *sql.Stmt isThemeDefault *sql.Stmt
getModlogs *sql.Stmt getModlogs *sql.Stmt
getModlogsOffset *sql.Stmt getModlogsOffset *sql.Stmt
getReplyTID *sql.Stmt getReplyTID *sql.Stmt
getTopicFID *sql.Stmt getTopicFID *sql.Stmt
getUserReplyUID *sql.Stmt getUserReplyUID *sql.Stmt
hasLikedTopic *sql.Stmt
hasLikedReply *sql.Stmt
getUserName *sql.Stmt getUserName *sql.Stmt
getEmailsByUser *sql.Stmt getEmailsByUser *sql.Stmt
getTopicBasic *sql.Stmt getTopicBasic *sql.Stmt
@ -34,20 +28,14 @@ type Stmts struct {
forumEntryExists *sql.Stmt forumEntryExists *sql.Stmt
groupEntryExists *sql.Stmt groupEntryExists *sql.Stmt
getForumTopicsOffset *sql.Stmt getForumTopicsOffset *sql.Stmt
getExpiredScheduledGroups *sql.Stmt
getSync *sql.Stmt
getAttachment *sql.Stmt getAttachment *sql.Stmt
getTopicRepliesOffset *sql.Stmt getTopicRepliesOffset *sql.Stmt
getTopicList *sql.Stmt getTopicList *sql.Stmt
getTopicUser *sql.Stmt
getTopicByReply *sql.Stmt
getTopicReplies *sql.Stmt getTopicReplies *sql.Stmt
getForumTopics *sql.Stmt getForumTopics *sql.Stmt
getProfileReplies *sql.Stmt getProfileReplies *sql.Stmt
getWatchers *sql.Stmt getWatchers *sql.Stmt
createReport *sql.Stmt createReport *sql.Stmt
createActionReply *sql.Stmt
createLike *sql.Stmt
addActivity *sql.Stmt addActivity *sql.Stmt
notifyOne *sql.Stmt notifyOne *sql.Stmt
addEmail *sql.Stmt addEmail *sql.Stmt
@ -55,57 +43,27 @@ type Stmts struct {
addForumPermsToForum *sql.Stmt addForumPermsToForum *sql.Stmt
addPlugin *sql.Stmt addPlugin *sql.Stmt
addTheme *sql.Stmt addTheme *sql.Stmt
addModlogEntry *sql.Stmt
addAdminlogEntry *sql.Stmt
addAttachment *sql.Stmt addAttachment *sql.Stmt
createWordFilter *sql.Stmt createWordFilter *sql.Stmt
addRepliesToTopic *sql.Stmt
removeRepliesFromTopic *sql.Stmt
addLikesToTopic *sql.Stmt
addLikesToReply *sql.Stmt
editTopic *sql.Stmt
editReply *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 editProfileReply *sql.Stmt
updateForum *sql.Stmt
updateSetting *sql.Stmt updateSetting *sql.Stmt
updatePlugin *sql.Stmt updatePlugin *sql.Stmt
updatePluginInstall *sql.Stmt updatePluginInstall *sql.Stmt
updateTheme *sql.Stmt updateTheme *sql.Stmt
updateForum *sql.Stmt
updateUser *sql.Stmt updateUser *sql.Stmt
updateUserGroup *sql.Stmt
updateGroupPerms *sql.Stmt updateGroupPerms *sql.Stmt
updateGroupRank *sql.Stmt
updateGroup *sql.Stmt updateGroup *sql.Stmt
updateEmail *sql.Stmt updateEmail *sql.Stmt
verifyEmail *sql.Stmt verifyEmail *sql.Stmt
setTempGroup *sql.Stmt setTempGroup *sql.Stmt
updateWordFilter *sql.Stmt updateWordFilter *sql.Stmt
bumpSync *sql.Stmt bumpSync *sql.Stmt
deleteUser *sql.Stmt
deleteTopic *sql.Stmt
deleteReply *sql.Stmt
deleteProfileReply *sql.Stmt deleteProfileReply *sql.Stmt
deleteActivityStreamMatch *sql.Stmt deleteActivityStreamMatch *sql.Stmt
deleteWordFilter *sql.Stmt deleteWordFilter *sql.Stmt
reportExists *sql.Stmt reportExists *sql.Stmt
groupCount *sql.Stmt
modlogCount *sql.Stmt modlogCount *sql.Stmt
notifyWatchers *sql.Stmt notifyWatchers *sql.Stmt
@ -124,7 +82,7 @@ type Stmts struct {
// nolint // nolint
func _gen_mssql() (err error) { func _gen_mssql() (err error) {
if dev.DebugMode { if common.Dev.DebugMode {
log.Print("Building the generated statements") log.Print("Building the generated statements")
} }
@ -156,34 +114,6 @@ func _gen_mssql() (err error) {
return err 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.") log.Print("Preparing isPluginActive statement.")
stmts.isPluginActive, err = db.Prepare("SELECT [active] FROM [plugins] WHERE [uname] = ?1") stmts.isPluginActive, err = db.Prepare("SELECT [active] FROM [plugins] WHERE [uname] = ?1")
if err != nil { if err != nil {
@ -198,13 +128,6 @@ func _gen_mssql() (err error) {
return err 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.") log.Print("Preparing isThemeDefault statement.")
stmts.isThemeDefault, err = db.Prepare("SELECT [default] FROM [themes] WHERE [uname] = ?1") stmts.isThemeDefault, err = db.Prepare("SELECT [default] FROM [themes] WHERE [uname] = ?1")
if err != nil { if err != nil {
@ -247,20 +170,6 @@ func _gen_mssql() (err error) {
return err 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.") log.Print("Preparing getUserName statement.")
stmts.getUserName, err = db.Prepare("SELECT [name] FROM [users] WHERE [uid] = ?1") stmts.getUserName, err = db.Prepare("SELECT [name] FROM [users] WHERE [uid] = ?1")
if err != nil { if err != nil {
@ -310,20 +219,6 @@ func _gen_mssql() (err error) {
return err 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.") 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") 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 { if err != nil {
@ -345,20 +240,6 @@ func _gen_mssql() (err error) {
return err 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.") 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") 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 { if err != nil {
@ -394,20 +275,6 @@ func _gen_mssql() (err error) {
return err 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.") log.Print("Preparing addActivity statement.")
stmts.addActivity, err = db.Prepare("INSERT INTO [activity_stream] ([actor],[targetUser],[event],[elementType],[elementID]) VALUES (?,?,?,?,?)") stmts.addActivity, err = db.Prepare("INSERT INTO [activity_stream] ([actor],[targetUser],[event],[elementType],[elementID]) VALUES (?,?,?,?,?)")
if err != nil { if err != nil {
@ -457,20 +324,6 @@ func _gen_mssql() (err error) {
return err 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.") log.Print("Preparing addAttachment statement.")
stmts.addAttachment, err = db.Prepare("INSERT INTO [attachments] ([sectionID],[sectionTable],[originID],[originTable],[uploadedBy],[path]) VALUES (?,?,?,?,?,?)") stmts.addAttachment, err = db.Prepare("INSERT INTO [attachments] ([sectionID],[sectionTable],[originID],[originTable],[uploadedBy],[path]) VALUES (?,?,?,?,?,?)")
if err != nil { if err != nil {
@ -485,41 +338,6 @@ func _gen_mssql() (err error) {
return err 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.") log.Print("Preparing editReply statement.")
stmts.editReply, err = db.Prepare("UPDATE [replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?") stmts.editReply, err = db.Prepare("UPDATE [replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?")
if err != nil { if err != nil {
@ -527,125 +345,6 @@ func _gen_mssql() (err error) {
return err 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.") log.Print("Preparing editProfileReply statement.")
stmts.editProfileReply, err = db.Prepare("UPDATE [users_replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?") stmts.editProfileReply, err = db.Prepare("UPDATE [users_replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?")
if err != nil { if err != nil {
@ -653,13 +352,6 @@ func _gen_mssql() (err error) {
return err return err
} }
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE [forums] SET [name] = ?,[desc] = ?,[active] = ?,[preset] = ? WHERE [fid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [forums] SET [name] = ?,[desc] = ?,[active] = ?,[preset] = ? WHERE [fid] = ?")
return err
}
log.Print("Preparing updateSetting statement.") log.Print("Preparing updateSetting statement.")
stmts.updateSetting, err = db.Prepare("UPDATE [settings] SET [content] = ? WHERE [name] = ?") stmts.updateSetting, err = db.Prepare("UPDATE [settings] SET [content] = ? WHERE [name] = ?")
if err != nil { if err != nil {
@ -688,6 +380,13 @@ func _gen_mssql() (err error) {
return err return err
} }
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE [forums] SET [name] = ?,[desc] = ?,[active] = ?,[preset] = ? WHERE [fid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [forums] SET [name] = ?,[desc] = ?,[active] = ?,[preset] = ? WHERE [fid] = ?")
return err
}
log.Print("Preparing updateUser statement.") log.Print("Preparing updateUser statement.")
stmts.updateUser, err = db.Prepare("UPDATE [users] SET [name] = ?,[email] = ?,[group] = ? WHERE [uid] = ?") stmts.updateUser, err = db.Prepare("UPDATE [users] SET [name] = ?,[email] = ?,[group] = ? WHERE [uid] = ?")
if err != nil { if err != nil {
@ -695,13 +394,6 @@ func _gen_mssql() (err error) {
return err 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.") log.Print("Preparing updateGroupPerms statement.")
stmts.updateGroupPerms, err = db.Prepare("UPDATE [users_groups] SET [permissions] = ? WHERE [gid] = ?") stmts.updateGroupPerms, err = db.Prepare("UPDATE [users_groups] SET [permissions] = ? WHERE [gid] = ?")
if err != nil { if err != nil {
@ -709,13 +401,6 @@ func _gen_mssql() (err error) {
return err 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.") log.Print("Preparing updateGroup statement.")
stmts.updateGroup, err = db.Prepare("UPDATE [users_groups] SET [name] = ?,[tag] = ? WHERE [gid] = ?") stmts.updateGroup, err = db.Prepare("UPDATE [users_groups] SET [name] = ?,[tag] = ? WHERE [gid] = ?")
if err != nil { if err != nil {
@ -758,27 +443,6 @@ func _gen_mssql() (err error) {
return err 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.") log.Print("Preparing deleteProfileReply statement.")
stmts.deleteProfileReply, err = db.Prepare("DELETE FROM [users_replies] WHERE [rid] = ?") stmts.deleteProfileReply, err = db.Prepare("DELETE FROM [users_replies] WHERE [rid] = ?")
if err != nil { if err != nil {
@ -807,13 +471,6 @@ func _gen_mssql() (err error) {
return err 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.") log.Print("Preparing modlogCount statement.")
stmts.modlogCount, err = db.Prepare("SELECT COUNT(*) AS [count] FROM [moderation_logs]") stmts.modlogCount, err = db.Prepare("SELECT COUNT(*) AS [count] FROM [moderation_logs]")
if err != nil { if err != nil {

View File

@ -6,6 +6,7 @@ package main
import "log" import "log"
import "database/sql" import "database/sql"
import "./common"
//import "./query_gen/lib" //import "./query_gen/lib"
// nolint // nolint
@ -14,21 +15,14 @@ type Stmts struct {
getSettings *sql.Stmt getSettings *sql.Stmt
getSetting *sql.Stmt getSetting *sql.Stmt
getFullSetting *sql.Stmt getFullSetting *sql.Stmt
getFullSettings *sql.Stmt
getPlugins *sql.Stmt
getThemes *sql.Stmt
getWidgets *sql.Stmt
isPluginActive *sql.Stmt isPluginActive *sql.Stmt
getUsersOffset *sql.Stmt getUsersOffset *sql.Stmt
getWordFilters *sql.Stmt
isThemeDefault *sql.Stmt isThemeDefault *sql.Stmt
getModlogs *sql.Stmt getModlogs *sql.Stmt
getModlogsOffset *sql.Stmt getModlogsOffset *sql.Stmt
getReplyTID *sql.Stmt getReplyTID *sql.Stmt
getTopicFID *sql.Stmt getTopicFID *sql.Stmt
getUserReplyUID *sql.Stmt getUserReplyUID *sql.Stmt
hasLikedTopic *sql.Stmt
hasLikedReply *sql.Stmt
getUserName *sql.Stmt getUserName *sql.Stmt
getEmailsByUser *sql.Stmt getEmailsByUser *sql.Stmt
getTopicBasic *sql.Stmt getTopicBasic *sql.Stmt
@ -36,20 +30,14 @@ type Stmts struct {
forumEntryExists *sql.Stmt forumEntryExists *sql.Stmt
groupEntryExists *sql.Stmt groupEntryExists *sql.Stmt
getForumTopicsOffset *sql.Stmt getForumTopicsOffset *sql.Stmt
getExpiredScheduledGroups *sql.Stmt
getSync *sql.Stmt
getAttachment *sql.Stmt getAttachment *sql.Stmt
getTopicRepliesOffset *sql.Stmt getTopicRepliesOffset *sql.Stmt
getTopicList *sql.Stmt getTopicList *sql.Stmt
getTopicUser *sql.Stmt
getTopicByReply *sql.Stmt
getTopicReplies *sql.Stmt getTopicReplies *sql.Stmt
getForumTopics *sql.Stmt getForumTopics *sql.Stmt
getProfileReplies *sql.Stmt getProfileReplies *sql.Stmt
getWatchers *sql.Stmt getWatchers *sql.Stmt
createReport *sql.Stmt createReport *sql.Stmt
createActionReply *sql.Stmt
createLike *sql.Stmt
addActivity *sql.Stmt addActivity *sql.Stmt
notifyOne *sql.Stmt notifyOne *sql.Stmt
addEmail *sql.Stmt addEmail *sql.Stmt
@ -57,57 +45,27 @@ type Stmts struct {
addForumPermsToForum *sql.Stmt addForumPermsToForum *sql.Stmt
addPlugin *sql.Stmt addPlugin *sql.Stmt
addTheme *sql.Stmt addTheme *sql.Stmt
addModlogEntry *sql.Stmt
addAdminlogEntry *sql.Stmt
addAttachment *sql.Stmt addAttachment *sql.Stmt
createWordFilter *sql.Stmt createWordFilter *sql.Stmt
addRepliesToTopic *sql.Stmt
removeRepliesFromTopic *sql.Stmt
addLikesToTopic *sql.Stmt
addLikesToReply *sql.Stmt
editTopic *sql.Stmt
editReply *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 editProfileReply *sql.Stmt
updateForum *sql.Stmt
updateSetting *sql.Stmt updateSetting *sql.Stmt
updatePlugin *sql.Stmt updatePlugin *sql.Stmt
updatePluginInstall *sql.Stmt updatePluginInstall *sql.Stmt
updateTheme *sql.Stmt updateTheme *sql.Stmt
updateForum *sql.Stmt
updateUser *sql.Stmt updateUser *sql.Stmt
updateUserGroup *sql.Stmt
updateGroupPerms *sql.Stmt updateGroupPerms *sql.Stmt
updateGroupRank *sql.Stmt
updateGroup *sql.Stmt updateGroup *sql.Stmt
updateEmail *sql.Stmt updateEmail *sql.Stmt
verifyEmail *sql.Stmt verifyEmail *sql.Stmt
setTempGroup *sql.Stmt setTempGroup *sql.Stmt
updateWordFilter *sql.Stmt updateWordFilter *sql.Stmt
bumpSync *sql.Stmt bumpSync *sql.Stmt
deleteUser *sql.Stmt
deleteTopic *sql.Stmt
deleteReply *sql.Stmt
deleteProfileReply *sql.Stmt deleteProfileReply *sql.Stmt
deleteActivityStreamMatch *sql.Stmt deleteActivityStreamMatch *sql.Stmt
deleteWordFilter *sql.Stmt deleteWordFilter *sql.Stmt
reportExists *sql.Stmt reportExists *sql.Stmt
groupCount *sql.Stmt
modlogCount *sql.Stmt modlogCount *sql.Stmt
notifyWatchers *sql.Stmt notifyWatchers *sql.Stmt
@ -126,7 +84,7 @@ type Stmts struct {
// nolint // nolint
func _gen_mysql() (err error) { func _gen_mysql() (err error) {
if dev.DebugMode { if common.Dev.DebugMode {
log.Print("Building the generated statements") log.Print("Building the generated statements")
} }
@ -154,30 +112,6 @@ func _gen_mysql() (err error) {
return err 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.") log.Print("Preparing isPluginActive statement.")
stmts.isPluginActive, err = db.Prepare("SELECT `active` FROM `plugins` WHERE `uname` = ?") stmts.isPluginActive, err = db.Prepare("SELECT `active` FROM `plugins` WHERE `uname` = ?")
if err != nil { if err != nil {
@ -190,12 +124,6 @@ func _gen_mysql() (err error) {
return err 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.") log.Print("Preparing isThemeDefault statement.")
stmts.isThemeDefault, err = db.Prepare("SELECT `default` FROM `themes` WHERE `uname` = ?") stmts.isThemeDefault, err = db.Prepare("SELECT `default` FROM `themes` WHERE `uname` = ?")
if err != nil { if err != nil {
@ -232,18 +160,6 @@ func _gen_mysql() (err error) {
return err 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.") log.Print("Preparing getUserName statement.")
stmts.getUserName, err = db.Prepare("SELECT `name` FROM `users` WHERE `uid` = ?") stmts.getUserName, err = db.Prepare("SELECT `name` FROM `users` WHERE `uid` = ?")
if err != nil { if err != nil {
@ -286,18 +202,6 @@ func _gen_mysql() (err error) {
return err 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.") 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` = ?") stmts.getAttachment, err = db.Prepare("SELECT `sectionID`,`sectionTable`,`originID`,`originTable`,`uploadedBy`,`path` FROM `attachments` WHERE `path` = ? AND `sectionID` = ? AND `sectionTable` = ?")
if err != nil { if err != nil {
@ -316,18 +220,6 @@ func _gen_mysql() (err error) {
return err 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.") 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` = ?") 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 { if err != nil {
@ -358,18 +250,6 @@ func _gen_mysql() (err error) {
return err 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.") log.Print("Preparing addActivity statement.")
stmts.addActivity, err = db.Prepare("INSERT INTO `activity_stream`(`actor`,`targetUser`,`event`,`elementType`,`elementID`) VALUES (?,?,?,?,?)") stmts.addActivity, err = db.Prepare("INSERT INTO `activity_stream`(`actor`,`targetUser`,`event`,`elementType`,`elementID`) VALUES (?,?,?,?,?)")
if err != nil { if err != nil {
@ -412,18 +292,6 @@ func _gen_mysql() (err error) {
return err 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.") log.Print("Preparing addAttachment statement.")
stmts.addAttachment, err = db.Prepare("INSERT INTO `attachments`(`sectionID`,`sectionTable`,`originID`,`originTable`,`uploadedBy`,`path`) VALUES (?,?,?,?,?,?)") stmts.addAttachment, err = db.Prepare("INSERT INTO `attachments`(`sectionID`,`sectionTable`,`originID`,`originTable`,`uploadedBy`,`path`) VALUES (?,?,?,?,?,?)")
if err != nil { if err != nil {
@ -436,156 +304,18 @@ func _gen_mysql() (err error) {
return err 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.") log.Print("Preparing editReply statement.")
stmts.editReply, err = db.Prepare("UPDATE `replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?") stmts.editReply, err = db.Prepare("UPDATE `replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?")
if err != nil { if err != nil {
return err 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.") log.Print("Preparing editProfileReply statement.")
stmts.editProfileReply, err = db.Prepare("UPDATE `users_replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?") stmts.editProfileReply, err = db.Prepare("UPDATE `users_replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?")
if err != nil { if err != nil {
return err return err
} }
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE `forums` SET `name` = ?,`desc` = ?,`active` = ?,`preset` = ? WHERE `fid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateSetting statement.") log.Print("Preparing updateSetting statement.")
stmts.updateSetting, err = db.Prepare("UPDATE `settings` SET `content` = ? WHERE `name` = ?") stmts.updateSetting, err = db.Prepare("UPDATE `settings` SET `content` = ? WHERE `name` = ?")
if err != nil { if err != nil {
@ -610,30 +340,24 @@ func _gen_mysql() (err error) {
return err return err
} }
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE `forums` SET `name` = ?,`desc` = ?,`active` = ?,`preset` = ? WHERE `fid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateUser statement.") log.Print("Preparing updateUser statement.")
stmts.updateUser, err = db.Prepare("UPDATE `users` SET `name` = ?,`email` = ?,`group` = ? WHERE `uid` = ?") stmts.updateUser, err = db.Prepare("UPDATE `users` SET `name` = ?,`email` = ?,`group` = ? WHERE `uid` = ?")
if err != nil { if err != nil {
return err 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.") log.Print("Preparing updateGroupPerms statement.")
stmts.updateGroupPerms, err = db.Prepare("UPDATE `users_groups` SET `permissions` = ? WHERE `gid` = ?") stmts.updateGroupPerms, err = db.Prepare("UPDATE `users_groups` SET `permissions` = ? WHERE `gid` = ?")
if err != nil { if err != nil {
return err 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.") log.Print("Preparing updateGroup statement.")
stmts.updateGroup, err = db.Prepare("UPDATE `users_groups` SET `name` = ?,`tag` = ? WHERE `gid` = ?") stmts.updateGroup, err = db.Prepare("UPDATE `users_groups` SET `name` = ?,`tag` = ? WHERE `gid` = ?")
if err != nil { if err != nil {
@ -670,24 +394,6 @@ func _gen_mysql() (err error) {
return err 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.") log.Print("Preparing deleteProfileReply statement.")
stmts.deleteProfileReply, err = db.Prepare("DELETE FROM `users_replies` WHERE `rid` = ?") stmts.deleteProfileReply, err = db.Prepare("DELETE FROM `users_replies` WHERE `rid` = ?")
if err != nil { if err != nil {
@ -712,12 +418,6 @@ func _gen_mysql() (err error) {
return err 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.") log.Print("Preparing modlogCount statement.")
stmts.modlogCount, err = db.Prepare("SELECT COUNT(*) AS `count` FROM `moderation_logs`") stmts.modlogCount, err = db.Prepare("SELECT COUNT(*) AS `count` FROM `moderation_logs`")
if err != nil { if err != nil {

View File

@ -5,42 +5,19 @@ package main
import "log" import "log"
import "database/sql" import "database/sql"
import "./common"
// nolint // nolint
type Stmts struct { type Stmts struct {
addRepliesToTopic *sql.Stmt
removeRepliesFromTopic *sql.Stmt
addLikesToTopic *sql.Stmt
addLikesToReply *sql.Stmt
editTopic *sql.Stmt
editReply *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 editProfileReply *sql.Stmt
updateForum *sql.Stmt
updateSetting *sql.Stmt updateSetting *sql.Stmt
updatePlugin *sql.Stmt updatePlugin *sql.Stmt
updatePluginInstall *sql.Stmt updatePluginInstall *sql.Stmt
updateTheme *sql.Stmt updateTheme *sql.Stmt
updateForum *sql.Stmt
updateUser *sql.Stmt updateUser *sql.Stmt
updateUserGroup *sql.Stmt
updateGroupPerms *sql.Stmt updateGroupPerms *sql.Stmt
updateGroupRank *sql.Stmt
updateGroup *sql.Stmt updateGroup *sql.Stmt
updateEmail *sql.Stmt updateEmail *sql.Stmt
verifyEmail *sql.Stmt verifyEmail *sql.Stmt
@ -63,160 +40,22 @@ type Stmts struct {
// nolint // nolint
func _gen_pgsql() (err error) { func _gen_pgsql() (err error) {
if dev.DebugMode { if common.Dev.DebugMode {
log.Print("Building the generated statements") 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.") log.Print("Preparing editReply statement.")
stmts.editReply, err = db.Prepare("UPDATE `replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?") stmts.editReply, err = db.Prepare("UPDATE `replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?")
if err != nil { if err != nil {
return err 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.") log.Print("Preparing editProfileReply statement.")
stmts.editProfileReply, err = db.Prepare("UPDATE `users_replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?") stmts.editProfileReply, err = db.Prepare("UPDATE `users_replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?")
if err != nil { if err != nil {
return err return err
} }
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE `forums` SET `name` = ?,`desc` = ?,`active` = ?,`preset` = ? WHERE `fid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateSetting statement.") log.Print("Preparing updateSetting statement.")
stmts.updateSetting, err = db.Prepare("UPDATE `settings` SET `content` = ? WHERE `name` = ?") stmts.updateSetting, err = db.Prepare("UPDATE `settings` SET `content` = ? WHERE `name` = ?")
if err != nil { if err != nil {
@ -241,30 +80,24 @@ func _gen_pgsql() (err error) {
return err return err
} }
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE `forums` SET `name` = ?,`desc` = ?,`active` = ?,`preset` = ? WHERE `fid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateUser statement.") log.Print("Preparing updateUser statement.")
stmts.updateUser, err = db.Prepare("UPDATE `users` SET `name` = ?,`email` = ?,`group` = ? WHERE `uid` = ?") stmts.updateUser, err = db.Prepare("UPDATE `users` SET `name` = ?,`email` = ?,`group` = ? WHERE `uid` = ?")
if err != nil { if err != nil {
return err 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.") log.Print("Preparing updateGroupPerms statement.")
stmts.updateGroupPerms, err = db.Prepare("UPDATE `users_groups` SET `permissions` = ? WHERE `gid` = ?") stmts.updateGroupPerms, err = db.Prepare("UPDATE `users_groups` SET `permissions` = ? WHERE `gid` = ?")
if err != nil { if err != nil {
return err 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.") log.Print("Preparing updateGroup statement.")
stmts.updateGroup, err = db.Prepare("UPDATE `users_groups` SET `name` = ?,`tag` = ? WHERE `gid` = ?") stmts.updateGroup, err = db.Prepare("UPDATE `users_groups` SET `name` = ?,`tag` = ? WHERE `gid` = ?")
if err != nil { if err != nil {

View File

@ -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. */ /* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main package main
import "log" import (
import "strings" "log"
import "sync" "strings"
import "errors" "sync"
import "net/http" "errors"
"net/http"
"./common"
)
var ErrNoRoute = errors.New("That route doesn't exist.") var ErrNoRoute = errors.New("That route doesn't exist.")
type GenRouter struct { type GenRouter struct {
UploadHandler func(http.ResponseWriter, *http.Request) 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 sync.RWMutex
} }
@ -20,26 +24,26 @@ type GenRouter struct {
func NewGenRouter(uploads http.Handler) *GenRouter { func NewGenRouter(uploads http.Handler) *GenRouter {
return &GenRouter{ return &GenRouter{
UploadHandler: http.StripPrefix("/uploads/",uploads).ServeHTTP, 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() { if err.Handled() {
return return
} }
if err.Type() == "system" { if err.Type() == "system" {
InternalErrorJSQ(err,w,r,err.Json()) common.InternalErrorJSQ(err, w, r, err.JSON())
return 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) 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.Lock()
router.extra_routes[pattern] = handle router.extra_routes[pattern] = handle
router.Unlock() router.Unlock()
@ -52,7 +56,7 @@ func (router *GenRouter) RemoveFunc(pattern string) error {
router.Unlock() router.Unlock()
return ErrNoRoute return ErrNoRoute
} }
delete(router.extra_routes,pattern) delete(router.extra_routes, pattern)
router.Unlock() router.Unlock()
return nil 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] 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("before routeStatic")
log.Print("prefix: ", prefix) log.Print("prefix: ", prefix)
log.Print("req.URL.Path: ", req.URL.Path) 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" { if prefix == "/static" {
req.URL.Path += extra_data req.URL.Path += extra_data
routeStatic(w,req) routeStatic(w, req)
return return
} }
if dev.SuperDebug { if common.Dev.SuperDebug {
log.Print("before PreRoute") log.Print("before PreRoute")
} }
// Deal with the session stuff, etc. // Deal with the session stuff, etc.
user, ok := PreRoute(w,req) user, ok := common.PreRoute(w, req)
if !ok { if !ok {
return return
} }
if dev.SuperDebug { if common.Dev.SuperDebug {
log.Print("after PreRoute") log.Print("after PreRoute")
} }
var err RouteError var err common.RouteError
switch(prefix) { switch(prefix) {
case "/api": case "/api":
err = routeAPI(w,req,user) 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) router.handleError(err,w,req,user)
} }
case "/report": case "/report":
err = MemberOnly(w,req,user) err = common.MemberOnly(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
} }
err = NoBanned(w,req,user) err = common.NoBanned(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
} }
err = NoSessionMismatch(w,req,user) err = common.NoSessionMismatch(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -164,7 +168,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
case "/topics": case "/topics":
switch(req.URL.Path) { switch(req.URL.Path) {
case "/topics/create/": case "/topics/create/":
err = MemberOnly(w,req,user) err = common.MemberOnly(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -178,7 +182,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
} }
case "/panel": case "/panel":
err = SuperModOnly(w,req,user) err = common.SuperModOnly(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -260,7 +264,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
case "/user": case "/user":
switch(req.URL.Path) { switch(req.URL.Path) {
case "/user/edit/critical/": case "/user/edit/critical/":
err = MemberOnly(w,req,user) err = common.MemberOnly(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -268,13 +272,13 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
err = routeAccountEditCritical(w,req,user) err = routeAccountEditCritical(w,req,user)
case "/user/edit/critical/submit/": case "/user/edit/critical/submit/":
err = NoSessionMismatch(w,req,user) err = common.NoSessionMismatch(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
} }
err = MemberOnly(w,req,user) err = common.MemberOnly(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -282,7 +286,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
err = routeAccountEditCriticalSubmit(w,req,user) err = routeAccountEditCriticalSubmit(w,req,user)
case "/user/edit/avatar/": case "/user/edit/avatar/":
err = MemberOnly(w,req,user) err = common.MemberOnly(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -290,7 +294,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
err = routeAccountEditAvatar(w,req,user) err = routeAccountEditAvatar(w,req,user)
case "/user/edit/avatar/submit/": case "/user/edit/avatar/submit/":
err = MemberOnly(w,req,user) err = common.MemberOnly(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -298,7 +302,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
err = routeAccountEditAvatarSubmit(w,req,user) err = routeAccountEditAvatarSubmit(w,req,user)
case "/user/edit/username/": case "/user/edit/username/":
err = MemberOnly(w,req,user) err = common.MemberOnly(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -306,7 +310,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
err = routeAccountEditUsername(w,req,user) err = routeAccountEditUsername(w,req,user)
case "/user/edit/username/submit/": case "/user/edit/username/submit/":
err = MemberOnly(w,req,user) err = common.MemberOnly(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -314,7 +318,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
err = routeAccountEditUsernameSubmit(w,req,user) err = routeAccountEditUsernameSubmit(w,req,user)
case "/user/edit/email/": case "/user/edit/email/":
err = MemberOnly(w,req,user) err = common.MemberOnly(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -322,7 +326,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
err = routeAccountEditEmail(w,req,user) err = routeAccountEditEmail(w,req,user)
case "/user/edit/token/": case "/user/edit/token/":
err = MemberOnly(w,req,user) err = common.MemberOnly(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -337,7 +341,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
} }
case "/users": case "/users":
err = MemberOnly(w,req,user) err = common.MemberOnly(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -345,7 +349,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
switch(req.URL.Path) { switch(req.URL.Path) {
case "/users/ban/submit/": case "/users/ban/submit/":
err = NoSessionMismatch(w,req,user) err = common.NoSessionMismatch(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -353,7 +357,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
err = routeBanSubmit(w,req,user) err = routeBanSubmit(w,req,user)
case "/users/unban/": case "/users/unban/":
err = NoSessionMismatch(w,req,user) err = common.NoSessionMismatch(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -361,7 +365,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
err = routeUnban(w,req,user) err = routeUnban(w,req,user)
case "/users/activate/": case "/users/activate/":
err = NoSessionMismatch(w,req,user) err = common.NoSessionMismatch(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -376,7 +380,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
case "/uploads": case "/uploads":
if extra_data == "" { if extra_data == "" {
NotFound(w,req) common.NotFound(w,req)
return return
} }
req.URL.Path += extra_data req.URL.Path += extra_data
@ -395,10 +399,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
if extra_data != "" { if extra_data != "" {
NotFound(w,req) common.NotFound(w,req)
return return
} }
config.DefaultRoute(w,req,user) common.Config.DefaultRoute(w,req,user)
default: default:
// A fallback for the routes which haven't been converted to the new router yet or plugins // A fallback for the routes which haven't been converted to the new router yet or plugins
router.RLock() router.RLock()
@ -413,6 +417,6 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
return return
} }
NotFound(w,req) common.NotFound(w,req)
} }
} }

View File

@ -14,6 +14,7 @@ import (
"testing" "testing"
"time" "time"
"./common"
"./install/install" "./install/install"
//"runtime/pprof" //"runtime/pprof"
//_ "github.com/go-sql-driver/mysql" //_ "github.com/go-sql-driver/mysql"
@ -46,28 +47,28 @@ func ResetTables() (err error) {
} }
func gloinit() (err error) { func gloinit() (err error) {
dev.DebugMode = false common.Dev.DebugMode = false
//nogrouplog = true //nogrouplog = true
startTime = time.Now() startTime = time.Now()
err = processConfig() err = common.ProcessConfig()
if err != nil { if err != nil {
return err return err
} }
err = initThemes() err = common.InitThemes()
if err != nil { if err != nil {
return err return err
} }
switchToTestDB() common.SwitchToTestDB()
var ok bool var ok bool
installAdapter, ok = install.Lookup(dbAdapter) installAdapter, ok = install.Lookup(dbAdapter)
if !ok { if !ok {
return errors.New("We couldn't find the adapter '" + dbAdapter + "'") 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() err = ResetTables()
if err != nil { if err != nil {

View File

@ -97,67 +97,69 @@ func main() {
configContents := []byte(`package main configContents := []byte(`package main
import "./common"
func init() { func init() {
// Site Info // Site Info
site.ShortName = "` + siteShortName + `" // This should be less than three letters to fit in the navbar common.Site.ShortName = "` + siteShortName + `" // This should be less than three letters to fit in the navbar
site.Name = "` + siteName + `" common.Site.Name = "` + siteName + `"
site.Email = "" common.Site.Email = ""
site.URL = "` + siteURL + `" common.Site.URL = "` + siteURL + `"
site.Port = "` + serverPort + `" common.Site.Port = "` + serverPort + `"
site.EnableSsl = false common.Site.EnableSsl = false
site.EnableEmails = false common.Site.EnableEmails = false
site.HasProxy = false // Cloudflare counts as this, if it's sitting in the middle common.Site.HasProxy = false // Cloudflare counts as this, if it's sitting in the middle
config.SslPrivkey = "" common.Config.SslPrivkey = ""
config.SslFullchain = "" common.Config.SslFullchain = ""
site.Language = "english" common.Site.Language = "english"
// Database details // Database details
dbConfig.Host = "` + adap.DBHost() + `" common.DbConfig.Host = "` + adap.DBHost() + `"
dbConfig.Username = "` + adap.DBUsername() + `" common.DbConfig.Username = "` + adap.DBUsername() + `"
dbConfig.Password = "` + adap.DBPassword() + `" common.DbConfig.Password = "` + adap.DBPassword() + `"
dbConfig.Dbname = "` + adap.DBName() + `" common.DbConfig.Dbname = "` + adap.DBName() + `"
dbConfig.Port = "` + adap.DBPort() + `" // You probably won't need to change this common.DbConfig.Port = "` + adap.DBPort() + `" // You probably won't need to change this
// Test Database details // Test Database details
dbConfig.TestHost = "" common.DbConfig.TestHost = ""
dbConfig.TestUsername = "" common.DbConfig.TestUsername = ""
dbConfig.TestPassword = "" common.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. 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.
dbConfig.TestPort = "" common.DbConfig.TestPort = ""
// Limiters // Limiters
config.MaxRequestSize = 5 * megabyte common.Config.MaxRequestSize = 5 * common.Megabyte
// Caching // Caching
config.CacheTopicUser = CACHE_STATIC common.Config.CacheTopicUser = common.CACHE_STATIC
config.UserCacheCapacity = 120 // The max number of users held in memory common.Config.UserCacheCapacity = 120 // The max number of users held in memory
config.TopicCacheCapacity = 200 // The max number of topics held in memory common.Config.TopicCacheCapacity = 200 // The max number of topics held in memory
// Email // Email
config.SMTPServer = "" common.Config.SMTPServer = ""
config.SMTPUsername = "" common.Config.SMTPUsername = ""
config.SMTPPassword = "" common.Config.SMTPPassword = ""
config.SMTPPort = "25" common.Config.SMTPPort = "25"
// Misc // Misc
config.DefaultRoute = routeTopics common.Config.DefaultRoute = routeTopics
config.DefaultGroup = 3 // Should be a setting in the database common.Config.DefaultGroup = 3 // Should be a setting in the database
config.ActivationGroup = 5 // Should be a setting in the database common.Config.ActivationGroup = 5 // Should be a setting in the database
config.StaffCSS = "staff_post" common.Config.StaffCSS = "staff_post"
config.DefaultForum = 2 common.Config.DefaultForum = 2
config.MinifyTemplates = true common.Config.MinifyTemplates = true
config.MultiServer = false // Experimental: Enable Cross-Server Synchronisation and several other features 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" //common.Config.Noavatar = "https://api.adorable.io/avatars/{width}/{id}@{site_url}.png"
config.Noavatar = "https://api.adorable.io/avatars/285/{id}@{site_url}.png" common.Config.Noavatar = "https://api.adorable.io/avatars/285/{id}@{site_url}.png"
config.ItemsPerPage = 25 common.Config.ItemsPerPage = 25
// Developer flags // Developer flags
dev.DebugMode = true common.Dev.DebugMode = true
//dev.SuperDebug = true //common.Dev.SuperDebug = true
//dev.TemplateDebug = true //common.Dev.TemplateDebug = true
//dev.Profiling = true //common.Dev.Profiling = true
//dev.TestDB = true //common.Dev.TestDB = true
} }
`) `)

116
main.go
View File

@ -14,65 +14,12 @@ import (
"os" "os"
"time" "time"
//"runtime/pprof" //"runtime/pprof"
"./common"
) )
var version = Version{Major: 0, Minor: 1, Patch: 0, Tag: "dev"} var version = common.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 router *GenRouter var router *GenRouter
var startTime time.Time 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) var logWriter = io.MultiWriter(os.Stderr)
// TODO: Wrap the globals in here so we can pass pointers to them to subpackages // TODO: Wrap the globals in here so we can pass pointers to them to subpackages
@ -128,58 +75,61 @@ func main() {
startTime = time.Now() startTime = time.Now()
log.Print("Processing configuration data") log.Print("Processing configuration data")
err = processConfig() err = common.ProcessConfig()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
err = initThemes() err = common.InitThemes()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
err = initDatabase() err = InitDatabase()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
rstore, err = NewSQLReplyStore() common.Rstore, err = common.NewSQLReplyStore()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
prstore, err = NewSQLProfileReplyStore() common.Prstore, err = common.NewSQLProfileReplyStore()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
initTemplates() common.InitTemplates()
err = initPhrases() err = common.InitPhrases()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Print("Loading the static files.") log.Print("Loading the static files.")
err = initStaticFiles() err = common.StaticFiles.Init()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Print("Initialising the widgets") log.Print("Initialising the widgets")
err = initWidgets() err = common.InitWidgets()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Print("Initialising the authentication system") log.Print("Initialising the authentication system")
auth = NewDefaultAuth() common.Auth, err = common.NewDefaultAuth()
err = LoadWordFilters()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
err = verifyConfig() err = common.LoadWordFilters()
if err != nil {
log.Fatal(err)
}
err = common.VerifyConfig()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -195,18 +145,18 @@ func main() {
//log.Print("Running the second ticker") //log.Print("Running the second ticker")
// TODO: Add a plugin hook here // TODO: Add a plugin hook here
err := handleExpiredScheduledGroups() err := common.HandleExpiredScheduledGroups()
if err != nil { if err != nil {
LogError(err) common.LogError(err)
} }
// TODO: Handle delayed moderation tasks // TODO: Handle delayed moderation tasks
// TODO: Handle the daily clean-up. Move this to a 24 hour task? // TODO: Handle the daily clean-up. Move this to a 24 hour task?
// Sync with the database, if there are any changes // Sync with the database, if there are any changes
err = handleServerSync() err = common.HandleServerSync()
if err != nil { if err != nil {
LogError(err) common.LogError(err)
} }
// TODO: Manage the TopicStore, UserStore, and ForumStore // TODO: Manage the TopicStore, UserStore, and ForumStore
@ -264,7 +214,7 @@ func main() {
router.HandleFunc("/ws/", routeWebsockets) router.HandleFunc("/ws/", routeWebsockets)
log.Print("Initialising the plugins") log.Print("Initialising the plugins")
initPlugins() common.InitPlugins()
defer db.Close() defer db.Close()
@ -274,17 +224,17 @@ func main() {
// TODO: Let users run *both* HTTP and HTTPS // TODO: Let users run *both* HTTP and HTTPS
log.Print("Initialising the HTTP server") log.Print("Initialising the HTTP server")
if !site.EnableSsl { if !common.Site.EnableSsl {
if site.Port == "" { if common.Site.Port == "" {
site.Port = "80" common.Site.Port = "80"
} }
log.Print("Listening on port " + site.Port) log.Print("Listening on port " + common.Site.Port)
err = http.ListenAndServe(":"+site.Port, router) err = http.ListenAndServe(":"+common.Site.Port, router)
} else { } else {
if site.Port == "" { if common.Site.Port == "" {
site.Port = "443" 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 // We should also run the server on port 80
// TODO: Redirect to port 443 // TODO: Redirect to port 443
go func() { go func() {
@ -295,8 +245,8 @@ func main() {
} }
}() }()
} }
log.Print("Listening on port " + site.Port) log.Printf("Listening on port %s", common.Site.Port)
err = http.ListenAndServeTLS(":"+site.Port, config.SslFullchain, config.SslPrivkey, router) err = http.ListenAndServeTLS(":"+common.Site.Port, common.Config.SslFullchain, common.Config.SslPrivkey, router)
} }
// Why did the server stop? // Why did the server stop?

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,8 @@ import (
"strconv" "strconv"
"testing" "testing"
"time" "time"
"./common"
) )
func recordMustExist(t *testing.T, err error, errmsg string, args ...interface{}) { func recordMustExist(t *testing.T, err error, errmsg string, args ...interface{}) {
@ -47,22 +49,22 @@ func TestUserStore(t *testing.T) {
userStoreTest(t, 3) userStoreTest(t, 3)
} }
func userStoreTest(t *testing.T, newUserID int) { 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 // Go doesn't have short-circuiting, so this'll allow us to do one liner tests
if !hasCache { if !hasCache {
ucache = &NullUserStore{} ucache = &NullUserStore{}
} }
expect(t, (!hasCache || ucache.Length() == 0), fmt.Sprintf("The initial ucache length should be zero, not %d", ucache.Length())) 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") 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())) 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") 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())) 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") 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)) 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.IsMod, "Admin should be a mod")
expect(t, !user.IsBanned, "Admin should not be banned") 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)) recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't exist", newUserID))
if hasCache { 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? // 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 var userList map[int]*User
userList, _ = users.BulkGetMap([]int{-1}) userList, _ = common.Users.BulkGetMap([]int{-1})
if len(userList) > 0 { if len(userList) > 0 {
t.Error("There shouldn't be any results for UID #-1") 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") 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 { if len(userList) > 0 {
t.Error("There shouldn't be any results for UID #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") 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 { if len(userList) == 0 {
t.Error("The returned map is empty for UID #1") t.Error("The returned map is empty for UID #1")
} else if len(userList) > 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(-1), "UID #-1 shouldn't exist")
expect(t, !users.Exists(0), "UID #0 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, !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())) 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 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) expectNilErr(t, err)
expect(t, uid == newUserID, fmt.Sprintf("The UID of the new user should be %d", newUserID)) 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) recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
if user.ID != newUserID { if user.ID != newUserID {
t.Errorf("The UID of the user record should be %d", 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) 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) 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)) 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) 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) recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
if user.ID != newUserID { if user.ID != newUserID {
t.Errorf("The UID of the user record should be %d", 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) 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) recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") 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) expectNilErr(t, err)
expect(t, user.Group == config.DefaultGroup, "Someone's mutated this pointer elsewhere") 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) recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
var user2 *User = getDummyUser() var user2 *User = getDummyUser()
@ -293,7 +295,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectNilErr(t, err) expectNilErr(t, err)
expect(t, user.Group == 1, "Someone's mutated this pointer elsewhere") 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) recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
user2 = getDummyUser() user2 = getDummyUser()
@ -316,7 +318,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectNilErr(t, err) expectNilErr(t, err)
expect(t, user.Group == 2, "Someone's mutated this pointer elsewhere") 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) recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
user2 = getDummyUser() user2 = getDummyUser()
@ -340,7 +342,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectNilErr(t, err) expectNilErr(t, err)
expect(t, user.Group == 3, "Someone's mutated this pointer elsewhere") 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) recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
user2 = getDummyUser() user2 = getDummyUser()
@ -363,7 +365,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectNilErr(t, err) expectNilErr(t, err)
expect(t, user.Group == 4, "Someone's mutated this pointer elsewhere") 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) recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
user2 = getDummyUser() user2 = getDummyUser()
@ -386,7 +388,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectNilErr(t, err) expectNilErr(t, err)
expect(t, user.Group == 5, "Someone's mutated this pointer elsewhere") 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) recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d") expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
user2 = getDummyUser() 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) 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) recordMustNotExist(t, err, "UID #%d shouldn't exist", newUserID)
// TODO: Add tests for the Cache* methods // TODO: Add tests for the Cache* methods
@ -515,13 +517,13 @@ func topicStoreTest(t *testing.T) {
var topic *Topic var topic *Topic
var err error var err error
_, err = topics.Get(-1) _, err = common.Topics.Get(-1)
recordMustNotExist(t, err, "TID #-1 shouldn't exist") 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") 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") recordMustExist(t, err, "Couldn't find TID #1")
if topic.ID != 1 { if topic.ID != 1 {
@ -530,22 +532,22 @@ func topicStoreTest(t *testing.T) {
// TODO: Add BulkGetMap() to the TopicStore // TODO: Add BulkGetMap() to the TopicStore
ok := topics.Exists(-1) ok := common.Topics.Exists(-1)
if ok { if ok {
t.Error("TID #-1 shouldn't exist") t.Error("TID #-1 shouldn't exist")
} }
ok = topics.Exists(0) ok = common.Topics.Exists(0)
if ok { if ok {
t.Error("TID #0 shouldn't exist") t.Error("TID #0 shouldn't exist")
} }
ok = topics.Exists(1) ok = common.Topics.Exists(1)
if !ok { if !ok {
t.Error("TID #1 should exist") t.Error("TID #1 should exist")
} }
count := topics.GlobalCount() count := common.Topics.GlobalCount()
if count <= 0 { if count <= 0 {
t.Error("The number of topics should be bigger than zero") t.Error("The number of topics should be bigger than zero")
t.Error("count", count) t.Error("count", count)
@ -620,11 +622,11 @@ func TestGroupStore(t *testing.T) {
initPlugins() initPlugins()
} }
_, err := gstore.Get(-1) _, err := common.Gstore.Get(-1)
recordMustNotExist(t, err, "GID #-1 shouldn't exist") recordMustNotExist(t, err, "GID #-1 shouldn't exist")
// TODO: Refactor the group store to remove GID #0 // 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") recordMustExist(t, err, "Couldn't find GID #0")
if group.ID != 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)) 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") recordMustExist(t, err, "Couldn't find GID #1")
if group.ID != 1 { if group.ID != 1 {
t.Errorf("group.ID doesn't not match the requested GID. Got '%d' instead.'", group.ID) 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") expect(t, !ok, "GID #-1 shouldn't exist")
// 0 aka Unknown, for system posts and other oddities // 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") expect(t, ok, "GID #0 should exist")
ok = gstore.Exists(1) ok = common.Gstore.Exists(1)
expect(t, ok, "GID #1 should exist") expect(t, ok, "GID #1 should exist")
var isAdmin = true var isAdmin = true
var isMod = true var isMod = true
var isBanned = false 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) 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) expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID") expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, group.IsAdmin, "This should be an admin group") expect(t, group.IsAdmin, "This should be an admin group")
@ -666,11 +668,11 @@ func TestGroupStore(t *testing.T) {
isAdmin = false isAdmin = false
isMod = true isMod = true
isBanned = 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) 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) expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID") expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, !group.IsAdmin, "This should not be an admin group") 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) err = group.ChangeRank(false, false, true)
expectNilErr(t, err) expectNilErr(t, err)
group, err = gstore.Get(gid) group, err = common.Gstore.Get(gid)
expectNilErr(t, err) expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID") expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, !group.IsAdmin, "This shouldn't be an admin group") 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) err = group.ChangeRank(true, true, true)
expectNilErr(t, err) expectNilErr(t, err)
group, err = gstore.Get(gid) group, err = common.Gstore.Get(gid)
expectNilErr(t, err) expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID") expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, group.IsAdmin, "This should be an admin group") 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) err = group.ChangeRank(false, true, true)
expectNilErr(t, err) expectNilErr(t, err)
group, err = gstore.Get(gid) group, err = common.Gstore.Get(gid)
expectNilErr(t, err) expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID") expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, !group.IsAdmin, "This shouldn't be an admin group") 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") expect(t, !group.IsBanned, "This shouldn't be a ban group")
// Make sure the data is static // 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) expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID") expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, !group.IsAdmin, "This shouldn't be an admin group") expect(t, !group.IsAdmin, "This shouldn't be an admin group")
@ -731,13 +733,13 @@ func TestReplyStore(t *testing.T) {
initPlugins() initPlugins()
} }
_, err := rstore.Get(-1) _, err := common.Rstore.Get(-1)
recordMustNotExist(t, err, "RID #-1 shouldn't exist") 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") recordMustNotExist(t, err, "RID #0 shouldn't exist")
reply, err := rstore.Get(1) reply, err := common.Rstore.Get(1)
expectNilErr(t, err) 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.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)) 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.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)) 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") recordMustNotExist(t, err, "RID #2 shouldn't exist")
// TODO: Test Create and Get // TODO: Test Create and Get
//Create(tid int, content string, ipaddress string, fid int, uid int) (id int, err error) //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) expectNilErr(t, err)
rid, err := rstore.Create(topic, "Fofofo", "::1", 1) rid, err := common.Rstore.Create(topic, "Fofofo", "::1", 1)
expectNilErr(t, err) expectNilErr(t, err)
expect(t, rid == 2, fmt.Sprintf("The next reply ID should be 2 not %d", rid)) 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) 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.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)) 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() initPlugins()
} }
_, err := prstore.Get(-1) _, err := common.Prstore.Get(-1)
recordMustNotExist(t, err, "PRID #-1 shouldn't exist") 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") 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") recordMustNotExist(t, err, "PRID #1 shouldn't exist")
var profileID = 1 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, err == nil, "Unable to create a profile reply")
expect(t, prid == 1, "The first profile reply should have an ID of 1") 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, 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.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)) 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 { for _, item := range msgList {
t.Log("Testing string '" + item.Msg + "'") t.Log("Testing string '" + item.Msg + "'")
res = nameToSlug(item.Msg) res = common.NameToSlug(item.Msg)
if res != item.Expects { if res != item.Expects {
t.Error("Bad output:", "'"+res+"'") t.Error("Bad output:", "'"+res+"'")
t.Error("Expected:", item.Expects) t.Error("Expected:", item.Expects)
@ -846,7 +848,7 @@ func TestAuth(t *testing.T) {
realPassword = "Madame Cassandra's Mystic Orb" realPassword = "Madame Cassandra's Mystic Orb"
t.Log("Set realPassword to '" + realPassword + "'") t.Log("Set realPassword to '" + realPassword + "'")
t.Log("Hashing the real password") t.Log("Hashing the real password")
hashedPassword, err = BcryptGeneratePasswordNoSalt(realPassword) hashedPassword, err = common.BcryptGeneratePasswordNoSalt(realPassword)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -854,7 +856,7 @@ func TestAuth(t *testing.T) {
password = realPassword password = realPassword
t.Log("Testing password '" + password + "'") t.Log("Testing password '" + password + "'")
t.Log("Testing salt '" + salt + "'") t.Log("Testing salt '" + salt + "'")
err = CheckPassword(hashedPassword, password, salt) err = common.CheckPassword(hashedPassword, password, salt)
if err == ErrMismatchedHashAndPassword { if err == ErrMismatchedHashAndPassword {
t.Error("The two don't match") t.Error("The two don't match")
} else if err == ErrPasswordTooLong { } else if err == ErrPasswordTooLong {
@ -866,7 +868,7 @@ func TestAuth(t *testing.T) {
password = "hahaha" password = "hahaha"
t.Log("Testing password '" + password + "'") t.Log("Testing password '" + password + "'")
t.Log("Testing salt '" + salt + "'") t.Log("Testing salt '" + salt + "'")
err = CheckPassword(hashedPassword, password, salt) err = common.CheckPassword(hashedPassword, password, salt)
if err == ErrPasswordTooLong { if err == ErrPasswordTooLong {
t.Error("CheckPassword thinks the password is too long") t.Error("CheckPassword thinks the password is too long")
} else if err == nil { } else if err == nil {
@ -876,7 +878,7 @@ func TestAuth(t *testing.T) {
password = "Madame Cassandra's Mystic" password = "Madame Cassandra's Mystic"
t.Log("Testing password '" + password + "'") t.Log("Testing password '" + password + "'")
t.Log("Testing salt '" + salt + "'") t.Log("Testing salt '" + salt + "'")
err = CheckPassword(hashedPassword, password, salt) err = common.CheckPassword(hashedPassword, password, salt)
if err == ErrPasswordTooLong { if err == ErrPasswordTooLong {
t.Error("CheckPassword thinks the password is too long") t.Error("CheckPassword thinks the password is too long")
} else if err == nil { } else if err == nil {

View File

@ -9,48 +9,50 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"time" "time"
"./common"
) )
// TODO: Update the stats after edits so that we don't under or over decrement stats during deletes // 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 // 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() err := r.ParseForm()
if err != nil { if err != nil {
return PreError("Bad Form", w, r) return common.PreError("Bad Form", w, r)
} }
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
tid, err := strconv.Atoi(r.URL.Path[len("/topic/edit/submit/"):]) tid, err := strconv.Atoi(r.URL.Path[len("/topic/edit/submit/"):])
if err != nil { 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 { 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 { } 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 // 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.EditTopic { 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") topicName := r.PostFormValue("topic_name")
topicContent := html.EscapeString(r.PostFormValue("topic_content")) topicContent := html.EscapeString(r.PostFormValue("topic_content"))
err = topic.Update(topicName, topicContent) err = topic.Update(topicName, topicContent)
if err != nil { 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 { if err != nil && err != ErrNoRows {
return InternalErrorJSQ(err, w, r, isJs) return common.InternalErrorJSQ(err, w, r, isJs)
} }
if !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: 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 // 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 // TODO: Move this to some sort of middleware
var tids []int var tids []int
var isJs = false var isJs = false
if r.Header.Get("Content-type") == "application/json" { if r.Header.Get("Content-type") == "application/json" {
if r.Body == nil { 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) //log.Print("r.Body: ", r.Body)
err := json.NewDecoder(r.Body).Decode(&tids) err := json.NewDecoder(r.Body).Decode(&tids)
if err != nil { if err != nil {
//log.Print("parse err: ", err) //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 isJs = true
} else { } else {
tid, err := strconv.Atoi(r.URL.Path[len("/topic/delete/submit/"):]) tid, err := strconv.Atoi(r.URL.Path[len("/topic/delete/submit/"):])
if err != nil { 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) tids = append(tids, tid)
} }
if len(tids) == 0 { 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 { for _, tid := range tids {
topic, err := topics.Get(tid) topic, err := common.Topics.Get(tid)
if err == ErrNoRows { 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 { } 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 // 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.DeleteTopic { 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 // We might be able to handle this err better
err = topic.Delete() err = topic.Delete()
if err != nil { 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 { 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 // ? - 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) /*_, err = stmts.createActionReply.Exec(tid,"delete",ipaddress,user.ID)
if err != nil { 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) http.Redirect(w, r, "/", http.StatusSeeOther)
return nil 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/"):]) tid, err := strconv.Atoi(r.URL.Path[len("/topic/stick/submit/"):])
if err != nil { 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 { 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 { } else if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
// TODO: Add hooks to make use of headerLite // 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.PinTopic { if !user.Perms.ViewTopic || !user.Perms.PinTopic {
return NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
err = topic.Stick() err = topic.Stick()
if err != nil { 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 { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
err = topic.CreateActionReply("stick", user.LastIP, user) err = topic.CreateActionReply("stick", user.LastIP, user)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
return nil 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/"):]) tid, err := strconv.Atoi(r.URL.Path[len("/topic/unstick/submit/"):])
if err != nil { 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 { 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 { } else if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
// TODO: Add hooks to make use of headerLite // 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.PinTopic { if !user.Perms.ViewTopic || !user.Perms.PinTopic {
return NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
err = topic.Unstick() err = topic.Unstick()
if err != nil { 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 { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
err = topic.CreateActionReply("unstick", user.LastIP, user) err = topic.CreateActionReply("unstick", user.LastIP, user)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
return nil 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 // TODO: Move this to some sort of middleware
var tids []int var tids []int
var isJs = false var isJs = false
if r.Header.Get("Content-type") == "application/json" { if r.Header.Get("Content-type") == "application/json" {
if r.Body == nil { 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) err := json.NewDecoder(r.Body).Decode(&tids)
if err != nil { 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 isJs = true
} else { } else {
tid, err := strconv.Atoi(r.URL.Path[len("/topic/lock/submit/"):]) tid, err := strconv.Atoi(r.URL.Path[len("/topic/lock/submit/"):])
if err != nil { 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) tids = append(tids, tid)
} }
if len(tids) == 0 { 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 { for _, tid := range tids {
topic, err := topics.Get(tid) topic, err := common.Topics.Get(tid)
if err == ErrNoRows { 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 { } 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 // 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.CloseTopic { if !user.Perms.ViewTopic || !user.Perms.CloseTopic {
return NoPermissionsJSQ(w, r, user, isJs) return common.NoPermissionsJSQ(w, r, user, isJs)
} }
err = topic.Lock() err = topic.Lock()
if err != nil { 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 { if err != nil {
return InternalErrorJSQ(err, w, r, isJs) return common.InternalErrorJSQ(err, w, r, isJs)
} }
err = topic.CreateActionReply("lock", user.LastIP, user) err = topic.CreateActionReply("lock", user.LastIP, user)
if err != nil { 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 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/"):]) tid, err := strconv.Atoi(r.URL.Path[len("/topic/unlock/submit/"):])
if err != nil { 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 { 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 { } else if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
// TODO: Add hooks to make use of headerLite // 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.CloseTopic { if !user.Perms.ViewTopic || !user.Perms.CloseTopic {
return NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
err = topic.Unlock() err = topic.Unlock()
if err != nil { 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 { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
err = topic.CreateActionReply("unlock", user.LastIP, user) err = topic.CreateActionReply("unlock", user.LastIP, user)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) 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: 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 // 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() err := r.ParseForm()
if err != nil { if err != nil {
return PreError("Bad Form", w, r) return common.PreError("Bad Form", w, r)
} }
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
rid, err := strconv.Atoi(r.URL.Path[len("/reply/edit/submit/"):]) rid, err := strconv.Atoi(r.URL.Path[len("/reply/edit/submit/"):])
if err != nil { 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.. // Get the Reply ID..
var tid int var tid int
err = stmts.getReplyTID.QueryRow(rid).Scan(&tid) err = stmts.getReplyTID.QueryRow(rid).Scan(&tid)
if err != nil { if err != nil {
return InternalErrorJSQ(err, w, r, isJs) return common.InternalErrorJSQ(err, w, r, isJs)
} }
var fid int var fid int
err = stmts.getTopicFID.QueryRow(tid).Scan(&fid) err = stmts.getTopicFID.QueryRow(tid).Scan(&fid)
if err == ErrNoRows { 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 { } 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 // TODO: Add hooks to make use of headerLite
_, ferr := SimpleForumUserCheck(w, r, &user, fid) _, ferr := common.SimpleForumUserCheck(w, r, &user, fid)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.EditReply { 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"))) content := html.EscapeString(common.PreparseMessage(r.PostFormValue("edit_item")))
_, err = stmts.editReply.Exec(content, parseMessage(content, fid, "forums"), rid) _, err = stmts.editReply.Exec(content, common.ParseMessage(content, fid, "forums"), rid)
if err != nil { if err != nil {
return InternalErrorJSQ(err, w, r, isJs) return common.InternalErrorJSQ(err, w, r, isJs)
} }
if !isJs { if !isJs {
@ -364,99 +366,99 @@ func routeReplyEditSubmit(w http.ResponseWriter, r *http.Request, user User) Rou
// TODO: Refactor this // TODO: Refactor this
// TODO: Disable stat updates in posts handled by plugin_guilds // 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() err := r.ParseForm()
if err != nil { if err != nil {
return PreError("Bad Form", w, r) return common.PreError("Bad Form", w, r)
} }
isJs := (r.PostFormValue("isJs") == "1") isJs := (r.PostFormValue("isJs") == "1")
rid, err := strconv.Atoi(r.URL.Path[len("/reply/delete/submit/"):]) rid, err := strconv.Atoi(r.URL.Path[len("/reply/delete/submit/"):])
if err != nil { 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 { 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 { } else if err != nil {
return InternalErrorJSQ(err, w, r, isJs) return common.InternalErrorJSQ(err, w, r, isJs)
} }
var fid int var fid int
err = stmts.getTopicFID.QueryRow(reply.ParentID).Scan(&fid) err = stmts.getTopicFID.QueryRow(reply.ParentID).Scan(&fid)
if err == ErrNoRows { 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 { } 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 // TODO: Add hooks to make use of headerLite
_, ferr := SimpleForumUserCheck(w, r, &user, fid) _, ferr := common.SimpleForumUserCheck(w, r, &user, fid)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.DeleteReply { if !user.Perms.ViewTopic || !user.Perms.DeleteReply {
return NoPermissionsJSQ(w, r, user, isJs) return common.NoPermissionsJSQ(w, r, user, isJs)
} }
err = reply.Delete() err = reply.Delete()
if err != nil { 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 { if !isJs {
//http.Redirect(w,r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther) //http.Redirect(w,r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther)
} else { } else {
w.Write(successJSONBytes) w.Write(successJSONBytes)
} }
replyCreator, err := users.Get(reply.CreatedBy) replyCreator, err := common.Users.Get(reply.CreatedBy)
if err == nil { if err == nil {
wcount := wordCount(reply.Content) wcount := common.WordCount(reply.Content)
err = replyCreator.decreasePostStats(wcount, false) err = replyCreator.DecreasePostStats(wcount, false)
if err != nil { if err != nil {
return InternalErrorJSQ(err, w, r, isJs) return common.InternalErrorJSQ(err, w, r, isJs)
} }
} else if err != ErrNoRows { } 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 { if err != nil {
return InternalErrorJSQ(err, w, r, isJs) return common.InternalErrorJSQ(err, w, r, isJs)
} }
return nil 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() err := r.ParseForm()
if err != nil { if err != nil {
return LocalError("Bad Form", w, r, user) return common.LocalError("Bad Form", w, r, user)
} }
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/edit/submit/"):]) rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/edit/submit/"):])
if err != nil { 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.. // Get the Reply ID..
var uid int var uid int
err = stmts.getUserReplyUID.QueryRow(rid).Scan(&uid) err = stmts.getUserReplyUID.QueryRow(rid).Scan(&uid)
if err != nil { if err != nil {
return InternalErrorJSQ(err, w, r, isJs) return common.InternalErrorJSQ(err, w, r, isJs)
} }
if user.ID != uid && !user.Perms.EditReply { 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"))) content := html.EscapeString(common.PreparseMessage(r.PostFormValue("edit_item")))
_, err = stmts.editProfileReply.Exec(content, parseMessage(content, 0, ""), rid) _, err = stmts.editProfileReply.Exec(content, common.ParseMessage(content, 0, ""), rid)
if err != nil { if err != nil {
return InternalErrorJSQ(err, w, r, isJs) return common.InternalErrorJSQ(err, w, r, isJs)
} }
if !isJs { if !isJs {
@ -467,35 +469,35 @@ func routeProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user Us
return nil 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() err := r.ParseForm()
if err != nil { if err != nil {
return LocalError("Bad Form", w, r, user) return common.LocalError("Bad Form", w, r, user)
} }
isJs := (r.PostFormValue("isJs") == "1") isJs := (r.PostFormValue("isJs") == "1")
rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/delete/submit/"):]) rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/delete/submit/"):])
if err != nil { 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 var uid int
err = stmts.getUserReplyUID.QueryRow(rid).Scan(&uid) err = stmts.getUserReplyUID.QueryRow(rid).Scan(&uid)
if err == ErrNoRows { 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 { } else if err != nil {
return InternalErrorJSQ(err, w, r, isJs) return common.InternalErrorJSQ(err, w, r, isJs)
} }
if user.ID != uid && !user.Perms.DeleteReply { 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) _, err = stmts.deleteProfileReply.Exec(rid)
if err != nil { 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 { if !isJs {
//http.Redirect(w,r, "/user/" + strconv.Itoa(uid), http.StatusSeeOther) //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 return nil
} }
func routeIps(w http.ResponseWriter, r *http.Request, user User) RouteError { func routeIps(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
headerVars, ferr := UserCheck(w, r, &user) headerVars, ferr := common.UserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewIPs { if !user.Perms.ViewIPs {
return NoPermissions(w, r, user) return common.NoPermissions(w, r, user)
} }
var ip = r.FormValue("ip") 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) rows, err := stmts.findUsersByIPUsers.Query(ip)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
err := rows.Scan(&uid) err := rows.Scan(&uid)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
reqUserList[uid] = true reqUserList[uid] = true
} }
err = rows.Err() err = rows.Err()
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
rows2, err := stmts.findUsersByIPTopics.Query(ip) rows2, err := stmts.findUsersByIPTopics.Query(ip)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
defer rows2.Close() defer rows2.Close()
for rows2.Next() { for rows2.Next() {
err := rows2.Scan(&uid) err := rows2.Scan(&uid)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
reqUserList[uid] = true reqUserList[uid] = true
} }
err = rows2.Err() err = rows2.Err()
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
rows3, err := stmts.findUsersByIPReplies.Query(ip) rows3, err := stmts.findUsersByIPReplies.Query(ip)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
defer rows3.Close() defer rows3.Close()
for rows3.Next() { for rows3.Next() {
err := rows3.Scan(&uid) err := rows3.Scan(&uid)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
reqUserList[uid] = true reqUserList[uid] = true
} }
err = rows3.Err() err = rows3.Err()
if err != nil { 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 // 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? // 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 { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
pi := IPSearchPage{"IP Search", user, headerVars, userList, ip} pi := common.IPSearchPage{"IP Search", user, headerVars, userList, ip}
if preRenderHooks["pre_render_ips"] != nil { if common.PreRenderHooks["pre_render_ips"] != nil {
if runPreRenderHook("pre_render_ips", w, r, &user, &pi) { if common.RunPreRenderHook("pre_render_ips", w, r, &user, &pi) {
return nil return nil
} }
} }
err = templates.ExecuteTemplate(w, "ip-search.html", pi) err = common.Templates.ExecuteTemplate(w, "ip-search.html", pi)
if err != nil { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
return nil 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 { 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/"):]) uid, err := strconv.Atoi(r.URL.Path[len("/users/ban/submit/"):])
if err != nil { 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 { /*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 { 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 { } 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? // TODO: Is there a difference between IsMod and IsSuperMod? Should we delete the redundant one?
if targetUser.IsSuperAdmin || targetUser.IsAdmin || targetUser.IsMod { 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 { 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 { 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")) durationDays, err := strconv.Atoi(r.FormValue("ban-duration-days"))
if err != nil { 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")) durationWeeks, err := strconv.Atoi(r.FormValue("ban-duration-weeks"))
if err != nil { 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")) durationMonths, err := strconv.Atoi(r.FormValue("ban-duration-months"))
if err != nil { 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 var duration time.Duration
@ -650,95 +652,95 @@ func routeBanSubmit(w http.ResponseWriter, r *http.Request, user User) RouteErro
duration, _ = time.ParseDuration("0") duration, _ = time.ParseDuration("0")
} else { } else {
var seconds int var seconds int
seconds += durationDays * day seconds += durationDays * common.Day
seconds += durationWeeks * week seconds += durationWeeks * common.Week
seconds += durationMonths * month seconds += durationMonths * common.Month
duration, _ = time.ParseDuration(strconv.Itoa(seconds) + "s") duration, _ = time.ParseDuration(strconv.Itoa(seconds) + "s")
} }
err = targetUser.Ban(duration, user.ID) err = targetUser.Ban(duration, user.ID)
if err == ErrNoRows { 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 { } 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 { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther) http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther)
return nil 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 { 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/"):]) uid, err := strconv.Atoi(r.URL.Path[len("/users/unban/"):])
if err != nil { 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 { 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 { } else if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
if !targetUser.IsBanned { 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() err = targetUser.Unban()
if err == ErrNoTempGroup { if err == common.ErrNoTempGroup {
return LocalError("The user you're trying to unban is not banned", w, r, user) return common.LocalError("The user you're trying to unban is not banned", w, r, user)
} else if err == ErrNoRows { } 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 { } 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 { if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther) http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther)
return nil 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 { 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/"):]) uid, err := strconv.Atoi(r.URL.Path[len("/users/activate/"):])
if err != nil { 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 { 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 { } else if err != nil {
return InternalError(err, w, r) return common.InternalError(err, w, r)
} }
if targetUser.Active { 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() err = targetUser.Activate()
if err != nil { 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 { 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) http.Redirect(w, r, "/user/"+strconv.Itoa(targetUser.ID), http.StatusSeeOther)
return nil return nil

View File

@ -8,12 +8,16 @@
*/ */
package main package main
import "log" import (
"database/sql"
"log"
//import "time" //import "time"
import "database/sql"
import _ "github.com/go-sql-driver/mysql" "./common"
import "./query_gen/lib" "./query_gen/lib"
_ "github.com/go-sql-driver/mysql"
)
var dbCollation = "utf8mb4_general_ci" var dbCollation = "utf8mb4_general_ci"
@ -24,13 +28,13 @@ func init() {
func initMySQL() (err error) { func initMySQL() (err error) {
var _dbpassword string var _dbpassword string
if dbConfig.Password != "" { if common.DbConfig.Password != "" {
_dbpassword = ":" + dbConfig.Password _dbpassword = ":" + common.DbConfig.Password
} }
// TODO: Move this bit to the query gen lib // TODO: Move this bit to the query gen lib
// Open the database connection // 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 { if err != nil {
return err return err
} }

File diff suppressed because it is too large Load Diff

View File

@ -10,9 +10,11 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"time" "time"
"./common"
) )
var random *rand.Rand var bbcodeRandom *rand.Rand
var bbcodeInvalidNumber []byte var bbcodeInvalidNumber []byte
var bbcodeNoNegative []byte var bbcodeNoNegative []byte
var bbcodeMissingTag []byte var bbcodeMissingTag []byte
@ -27,12 +29,12 @@ var bbcodeQuotes *regexp.Regexp
var bbcodeCode *regexp.Regexp var bbcodeCode *regexp.Regexp
func init() { 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 { func initBbcode() error {
//plugins["bbcode"].AddHook("parse_assign", bbcode_parse_without_code) //plugins["bbcode"].AddHook("parse_assign", bbcode_parse_without_code)
plugins["bbcode"].AddHook("parse_assign", bbcodeFullParse) common.Plugins["bbcode"].AddHook("parse_assign", bbcodeFullParse)
bbcodeInvalidNumber = []byte("<span style='color: red;'>[Invalid Number]</span>") bbcodeInvalidNumber = []byte("<span style='color: red;'>[Invalid Number]</span>")
bbcodeNoNegative = []byte("<span style='color: red;'>[No Negative Numbers]</span>") bbcodeNoNegative = []byte("<span style='color: red;'>[No Negative Numbers]</span>")
@ -48,13 +50,12 @@ func initBbcode() error {
bbcodeQuotes = regexp.MustCompile(`\[quote\](.*)\[/quote\]`) bbcodeQuotes = regexp.MustCompile(`\[quote\](.*)\[/quote\]`)
bbcodeCode = regexp.MustCompile(`\[code\](.*)\[/code\]`) bbcodeCode = regexp.MustCompile(`\[code\](.*)\[/code\]`)
random = rand.New(rand.NewSource(time.Now().UnixNano())) bbcodeRandom = rand.New(rand.NewSource(time.Now().UnixNano()))
return nil return nil
} }
func deactivateBbcode() { func deactivateBbcode() {
//plugins["bbcode"].RemoveHook("parse_assign", bbcode_parse_without_code) common.Plugins["bbcode"].RemoveHook("parse_assign", bbcodeFullParse)
plugins["bbcode"].RemoveHook("parse_assign", bbcodeFullParse)
} }
func bbcodeRegexParse(msg string) string { func bbcodeRegexParse(msg string) string {
@ -213,7 +214,7 @@ func bbcodeFullParse(msg string) string {
var complexBbc bool var complexBbc bool
msgbytes := []byte(msg) msgbytes := []byte(msg)
msgbytes = append(msgbytes, spaceGap...) msgbytes = append(msgbytes, common.SpaceGap...)
//log.Print("BBCode Simple Pre:","`"+string(msgbytes)+"`") //log.Print("BBCode Simple Pre:","`"+string(msgbytes)+"`")
//log.Print("----") //log.Print("----")
@ -306,7 +307,7 @@ func bbcodeFullParse(msg string) string {
if hasS { if hasS {
msgbytes = append(bytes.TrimSpace(msgbytes), closeStrike...) msgbytes = append(bytes.TrimSpace(msgbytes), closeStrike...)
} }
msgbytes = append(msgbytes, spaceGap...) msgbytes = append(msgbytes, common.SpaceGap...)
} }
if complexBbc { if complexBbc {
@ -357,21 +358,21 @@ func bbcodeParseURL(i int, start int, lastTag int, msgbytes []byte, outbytes []b
start = i + 5 start = i + 5
outbytes = append(outbytes, msgbytes[lastTag:i]...) outbytes = append(outbytes, msgbytes[lastTag:i]...)
i = start i = start
i += partialURLBytesLen(msgbytes[start:]) i += common.PartialURLBytesLen(msgbytes[start:])
//log.Print("Partial Bytes: ", string(msgbytes[start:])) //log.Print("Partial Bytes: ", string(msgbytes[start:]))
//log.Print("-----") //log.Print("-----")
if !bytes.Equal(msgbytes[i:i+6], []byte("[/url]")) { if !bytes.Equal(msgbytes[i:i+6], []byte("[/url]")) {
//log.Print("Invalid Bytes: ", string(msgbytes[i:i+6])) //log.Print("Invalid Bytes: ", string(msgbytes[i:i+6]))
//log.Print("-----") //log.Print("-----")
outbytes = append(outbytes, invalidURL...) outbytes = append(outbytes, common.InvalidURL...)
return i, start, lastTag, outbytes return i, start, lastTag, outbytes
} }
outbytes = append(outbytes, urlOpen...) outbytes = append(outbytes, common.UrlOpen...)
outbytes = append(outbytes, msgbytes[start:i]...) outbytes = append(outbytes, msgbytes[start:i]...)
outbytes = append(outbytes, urlOpen2...) outbytes = append(outbytes, common.UrlOpen2...)
outbytes = append(outbytes, msgbytes[start:i]...) outbytes = append(outbytes, msgbytes[start:i]...)
outbytes = append(outbytes, urlClose...) outbytes = append(outbytes, common.UrlClose...)
i += 6 i += 6
lastTag = i lastTag = i
@ -411,7 +412,7 @@ func bbcodeParseRand(i int, start int, lastTag int, msgbytes []byte, outbytes []
if number == 0 { if number == 0 {
dat = []byte("0") dat = []byte("0")
} else { } else {
dat = []byte(strconv.FormatInt((random.Int63n(number)), 10)) dat = []byte(strconv.FormatInt((bbcodeRandom.Int63n(number)), 10))
} }
outbytes = append(outbytes, dat...) outbytes = append(outbytes, dat...)

View File

@ -3,6 +3,7 @@ package main
import ( import (
//"fmt" //"fmt"
"./common"
"./extend/guilds/lib" "./extend/guilds/lib"
"./query_gen/lib" "./query_gen/lib"
) )
@ -11,75 +12,58 @@ import (
// TODO: Add a plugin interface instead of having a bunch of argument to AddPlugin? // TODO: Add a plugin interface instead of having a bunch of argument to AddPlugin?
func init() { 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? // 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) { func initGuilds() (err error) {
plugins["guilds"].AddHook("intercept_build_widgets", guilds.Widgets) common.Plugins["guilds"].AddHook("intercept_build_widgets", guilds.Widgets)
plugins["guilds"].AddHook("trow_assign", guilds.TrowAssign) common.Plugins["guilds"].AddHook("trow_assign", guilds.TrowAssign)
plugins["guilds"].AddHook("topic_create_pre_loop", guilds.TopicCreatePreLoop) common.Plugins["guilds"].AddHook("topic_create_pre_loop", guilds.TopicCreatePreLoop)
plugins["guilds"].AddHook("pre_render_view_forum", guilds.PreRenderViewForum) common.Plugins["guilds"].AddHook("pre_render_view_forum", guilds.PreRenderViewForum)
plugins["guilds"].AddHook("simple_forum_check_pre_perms", guilds.ForumCheck) common.Plugins["guilds"].AddHook("simple_forum_check_pre_perms", guilds.ForumCheck)
plugins["guilds"].AddHook("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? // TODO: Auto-grant this perm to admins upon installation?
registerPluginPerm("CreateGuild") common.RegisterPluginPerm("CreateGuild")
router.HandleFunc("/guilds/", guilds.GuildList) router.HandleFunc("/guilds/", guilds.RouteGuildList)
router.HandleFunc("/guild/", guilds.ViewGuild) router.HandleFunc("/guild/", guilds.MiddleViewGuild)
router.HandleFunc("/guild/create/", guilds.CreateGuild) router.HandleFunc("/guild/create/", guilds.RouteCreateGuild)
router.HandleFunc("/guild/create/submit/", guilds.CreateGuildSubmit) router.HandleFunc("/guild/create/submit/", guilds.RouteCreateGuildSubmit)
router.HandleFunc("/guild/members/", guilds.MemberList) router.HandleFunc("/guild/members/", guilds.RouteMemberList)
guilds.ListStmt, err = qgen.Builder.SimpleSelect("guilds", "guildID, name, desc, active, privacy, joinable, owner, memberCount, createdAt, lastUpdateTime", "", "", "") acc := qgen.Builder.Accumulator()
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
}
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() { func deactivateGuilds() {
plugins["guilds"].RemoveHook("intercept_build_widgets", guilds.Widgets) common.Plugins["guilds"].RemoveHook("intercept_build_widgets", guilds.Widgets)
plugins["guilds"].RemoveHook("trow_assign", guilds.TrowAssign) common.Plugins["guilds"].RemoveHook("trow_assign", guilds.TrowAssign)
plugins["guilds"].RemoveHook("topic_create_pre_loop", guilds.TopicCreatePreLoop) common.Plugins["guilds"].RemoveHook("topic_create_pre_loop", guilds.TopicCreatePreLoop)
plugins["guilds"].RemoveHook("pre_render_view_forum", guilds.PreRenderViewForum) common.Plugins["guilds"].RemoveHook("pre_render_view_forum", guilds.PreRenderViewForum)
plugins["guilds"].RemoveHook("simple_forum_check_pre_perms", guilds.ForumCheck) common.Plugins["guilds"].RemoveHook("simple_forum_check_pre_perms", guilds.ForumCheck)
plugins["guilds"].RemoveHook("forum_check_pre_perms", guilds.ForumCheck) common.Plugins["guilds"].RemoveHook("forum_check_pre_perms", guilds.ForumCheck)
deregisterPluginPerm("CreateGuild") common.DeregisterPluginPerm("CreateGuild")
_ = router.RemoveFunc("/guilds/") _ = router.RemoveFunc("/guilds/")
_ = router.RemoveFunc("/guild/") _ = router.RemoveFunc("/guild/")
_ = router.RemoveFunc("/guild/create/") _ = router.RemoveFunc("/guild/create/")

View File

@ -1,22 +1,24 @@
package main package main
import "./common"
func init() { 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 // init_heythere is separate from init() as we don't want the plugin to run if the plugin is disabled
func initHeythere() error { func initHeythere() error {
plugins["heythere"].AddHook("topic_reply_row_assign", heythereReply) common.Plugins["heythere"].AddHook("topic_reply_row_assign", heythereReply)
return nil return nil
} }
func deactivateHeythere() { func deactivateHeythere() {
plugins["heythere"].RemoveHook("topic_reply_row_assign", heythereReply) common.Plugins["heythere"].RemoveHook("topic_reply_row_assign", heythereReply)
} }
func heythereReply(data ...interface{}) interface{} { func heythereReply(data ...interface{}) interface{} {
currentUser := data[0].(*TopicPage).CurrentUser currentUser := data[0].(*common.TopicPage).CurrentUser
reply := data[1].(*ReplyUser) reply := data[1].(*common.ReplyUser)
reply.Content = "Hey there, " + currentUser.Name + "!" reply.Content = "Hey there, " + currentUser.Name + "!"
reply.ContentHtml = "Hey there, " + currentUser.Name + "!" reply.ContentHtml = "Hey there, " + currentUser.Name + "!"
reply.Tag = "Auto" reply.Tag = "Auto"

View File

@ -4,6 +4,8 @@ package main
import ( import (
"log" "log"
"strings" "strings"
"./common"
) )
var markdownMaxDepth = 25 // How deep the parser will go when parsing Markdown strings var markdownMaxDepth = 25 // How deep the parser will go when parsing Markdown strings
@ -19,11 +21,11 @@ var markdownStrikeTagOpen []byte
var markdownStrikeTagClose []byte var markdownStrikeTagClose []byte
func init() { 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 { func initMarkdown() error {
plugins["markdown"].AddHook("parse_assign", markdownParse) common.Plugins["markdown"].AddHook("parse_assign", markdownParse)
markdownUnclosedElement = []byte("<span style='color: red;'>[Unclosed Element]</span>") markdownUnclosedElement = []byte("<span style='color: red;'>[Unclosed Element]</span>")
@ -39,7 +41,7 @@ func initMarkdown() error {
} }
func deactivateMarkdown() { 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. // An adapter for the parser, so that the parser can call itself recursively.

View File

@ -1,5 +1,7 @@
package main package main
import "./common"
func init() { 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. 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. 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 } func initSkeleton() error { return nil }

View File

@ -37,6 +37,10 @@ func (build *builder) GetAdapter() DB_Adapter {
return build.adapter return build.adapter
} }
func (build *builder) Begin() (*sql.Tx, error) {
return build.conn.Begin()
}
func (build *builder) Tx(handler func(*TransactionBuilder) error) error { func (build *builder) Tx(handler func(*TransactionBuilder) error) error {
tx, err := build.conn.Begin() tx, err := build.conn.Begin()
if err != nil { if err != nil {
@ -50,101 +54,60 @@ func (build *builder) Tx(handler func(*TransactionBuilder) error) error {
return tx.Commit() return tx.Commit()
} }
func (build *builder) SimpleSelect(table string, columns string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) { func (build *builder) prepare(res string, err error) (*sql.Stmt, error) {
res, err := build.adapter.SimpleSelect("_builder", table, columns, where, orderby, limit)
if err != nil { if err != nil {
return stmt, err return nil, err
} }
return build.conn.Prepare(res) 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) { func (build *builder) SimpleCount(table string, where string, limit string) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleCount("_builder", table, where, limit) return build.prepare(build.adapter.SimpleCount("_builder", table, where, limit))
if err != nil {
return stmt, err
}
return build.conn.Prepare(res)
} }
func (build *builder) SimpleLeftJoin(table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) { 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) return build.prepare(build.adapter.SimpleLeftJoin("_builder", table1, table2, columns, joiners, where, orderby, limit))
if err != nil {
return stmt, err
}
return build.conn.Prepare(res)
} }
func (build *builder) SimpleInnerJoin(table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) { 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) return build.prepare(build.adapter.SimpleInnerJoin("_builder", table1, table2, columns, joiners, where, orderby, limit))
if err != nil {
return stmt, err
}
return build.conn.Prepare(res)
} }
func (build *builder) CreateTable(table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (stmt *sql.Stmt, err error) { 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) return build.prepare(build.adapter.CreateTable("_builder", table, charset, collation, columns, keys))
if err != nil {
return stmt, err
}
return build.conn.Prepare(res)
} }
func (build *builder) SimpleInsert(table string, columns string, fields string) (stmt *sql.Stmt, err error) { func (build *builder) SimpleInsert(table string, columns string, fields string) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleInsert("_builder", table, columns, fields) return build.prepare(build.adapter.SimpleInsert("_builder", table, columns, fields))
if err != nil {
return stmt, err
}
return build.conn.Prepare(res)
} }
func (build *builder) SimpleInsertSelect(ins DB_Insert, sel DB_Select) (stmt *sql.Stmt, err error) { func (build *builder) SimpleInsertSelect(ins DB_Insert, sel DB_Select) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleInsertSelect("_builder", ins, sel) return build.prepare(build.adapter.SimpleInsertSelect("_builder", ins, sel))
if err != nil {
return stmt, err
}
return build.conn.Prepare(res)
} }
func (build *builder) SimpleInsertLeftJoin(ins DB_Insert, sel DB_Join) (stmt *sql.Stmt, err error) { func (build *builder) SimpleInsertLeftJoin(ins DB_Insert, sel DB_Join) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleInsertLeftJoin("_builder", ins, sel) return build.prepare(build.adapter.SimpleInsertLeftJoin("_builder", ins, sel))
if err != nil {
return stmt, err
}
return build.conn.Prepare(res)
} }
func (build *builder) SimpleInsertInnerJoin(ins DB_Insert, sel DB_Join) (stmt *sql.Stmt, err error) { func (build *builder) SimpleInsertInnerJoin(ins DB_Insert, sel DB_Join) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleInsertInnerJoin("_builder", ins, sel) return build.prepare(build.adapter.SimpleInsertInnerJoin("_builder", ins, sel))
if err != nil {
return stmt, err
}
return build.conn.Prepare(res)
} }
func (build *builder) SimpleUpdate(table string, set string, where string) (stmt *sql.Stmt, err error) { func (build *builder) SimpleUpdate(table string, set string, where string) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleUpdate("_builder", table, set, where) return build.prepare(build.adapter.SimpleUpdate("_builder", table, set, where))
if err != nil {
return stmt, err
}
return build.conn.Prepare(res)
} }
func (build *builder) SimpleDelete(table string, where string) (stmt *sql.Stmt, err error) { func (build *builder) SimpleDelete(table string, where string) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleDelete("_builder", table, where) return build.prepare(build.adapter.SimpleDelete("_builder", table, where))
if err != nil {
return stmt, err
}
return build.conn.Prepare(res)
} }
// I don't know why you need this, but here it is x.x // 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) { func (build *builder) Purge(table string) (stmt *sql.Stmt, err error) {
res, err := build.adapter.Purge("_builder", table) return build.prepare(build.adapter.Purge("_builder", table))
if err != nil {
return stmt, err
}
return build.conn.Prepare(res)
} }
// These ones support transactions // These ones support transactions

View File

@ -1098,6 +1098,7 @@ package main
import "log" import "log"
import "database/sql" import "database/sql"
import "./common"
// nolint // nolint
type Stmts struct { type Stmts struct {
@ -1117,7 +1118,7 @@ type Stmts struct {
// nolint // nolint
func _gen_mssql() (err error) { func _gen_mssql() (err error) {
if dev.DebugMode { if common.Dev.DebugMode {
log.Print("Building the generated statements") log.Print("Building the generated statements")
} }
` + body + ` ` + body + `

View File

@ -590,6 +590,7 @@ package main
import "log" import "log"
import "database/sql" import "database/sql"
import "./common"
//import "./query_gen/lib" //import "./query_gen/lib"
// nolint // nolint
@ -610,7 +611,7 @@ type Stmts struct {
// nolint // nolint
func _gen_mysql() (err error) { func _gen_mysql() (err error) {
if dev.DebugMode { if common.Dev.DebugMode {
log.Print("Building the generated statements") log.Print("Building the generated statements")
} }
` + body + ` ` + body + `

View File

@ -346,6 +346,7 @@ package main
import "log" import "log"
import "database/sql" import "database/sql"
import "./common"
// nolint // nolint
type Stmts struct { type Stmts struct {
@ -365,7 +366,7 @@ type Stmts struct {
// nolint // nolint
func _gen_pgsql() (err error) { func _gen_pgsql() (err error) {
if dev.DebugMode { if common.Dev.DebugMode {
log.Print("Building the generated statements") log.Print("Building the generated statements")
} }
` + body + ` ` + body + `

View File

@ -230,20 +230,12 @@ func writeSelects(adapter qgen.DB_Adapter) error {
adapter.SimpleSelect("getFullSetting", "settings", "name, type, constraints", "name = ?", "", "") 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("isPluginActive", "plugins", "active", "uname = ?", "", "")
//adapter.SimpleSelect("isPluginInstalled","plugins","installed","uname = ?","","") //adapter.SimpleSelect("isPluginInstalled","plugins","installed","uname = ?","","")
adapter.SimpleSelect("getUsersOffset", "users", "uid, name, group, active, is_super_admin, avatar", "", "uid ASC", "?,?") 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("isThemeDefault", "themes", "default", "uname = ?", "", "")
adapter.SimpleSelect("getModlogs", "moderation_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "", "", "") 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("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("getUserName", "users", "name", "uid = ?", "", "")
adapter.SimpleSelect("getEmailsByUser", "emails", "email, validated, token", "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("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 = ?", "", "") adapter.SimpleSelect("getAttachment", "attachments", "sectionID, sectionTable, originID, originTable, uploadedBy, path", "path = ? AND sectionID = ? AND sectionTable = ?", "", "")
return nil 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", "") 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("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", "") 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 { 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("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("addActivity", "activity_stream", "actor, targetUser, event, elementType, elementID", "?,?,?,?,?")
adapter.SimpleInsert("notifyOne", "activity_stream_matches", "watcher, asid", "?,?") 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("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("addAttachment", "attachments", "sectionID, sectionTable, originID, originTable, uploadedBy, path", "?,?,?,?,?,?")
adapter.SimpleInsert("createWordFilter", "word_filters", "find, replacement", "?,?") 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 { 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("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("editProfileReply", "users_replies", "content = ?, parsed_content = ?", "rid = ?")
adapter.SimpleUpdate("updateForum", "forums", "name = ?, desc = ?, active = ?, preset = ?", "fid = ?")
adapter.SimpleUpdate("updateSetting", "settings", "content = ?", "name = ?") adapter.SimpleUpdate("updateSetting", "settings", "content = ?", "name = ?")
adapter.SimpleUpdate("updatePlugin", "plugins", "active = ?", "uname = ?") 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("updateTheme", "themes", "default = ?", "uname = ?")
adapter.SimpleUpdate("updateForum", "forums", "name = ?, desc = ?, active = ?, preset = ?", "fid = ?")
adapter.SimpleUpdate("updateUser", "users", "name = ?, email = ?, group = ?", "uid = ?") adapter.SimpleUpdate("updateUser", "users", "name = ?, email = ?, group = ?", "uid = ?")
adapter.SimpleUpdate("updateUserGroup", "users", "group = ?", "uid = ?")
adapter.SimpleUpdate("updateGroupPerms", "users_groups", "permissions = ?", "gid = ?") 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("updateGroup", "users_groups", "name = ?, tag = ?", "gid = ?")
adapter.SimpleUpdate("updateEmail", "emails", "email = ?, uid = ?, validated = ?, token = ?", "email = ?") 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 { 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("deleteProfileReply", "users_replies", "rid = ?")
//adapter.SimpleDelete("deleteForumPermsByForum", "forums_permissions", "fid = ?") //adapter.SimpleDelete("deleteForumPermsByForum", "forums_permissions", "fid = ?")
@ -466,8 +383,6 @@ func writeDeletes(adapter qgen.DB_Adapter) error {
func writeSimpleCounts(adapter qgen.DB_Adapter) error { func writeSimpleCounts(adapter qgen.DB_Adapter) error {
adapter.SimpleCount("reportExists", "topics", "data = ? AND data != '' AND parentID = 1", "") adapter.SimpleCount("reportExists", "topics", "data = ? AND data != '' AND parentID = 1", "")
adapter.SimpleCount("groupCount", "users_groups", "", "")
adapter.SimpleCount("modlogCount", "moderation_logs", "", "") adapter.SimpleCount("modlogCount", "moderation_logs", "", "")
return nil return nil

View File

@ -2,9 +2,13 @@
package main package main
//import "fmt" //import "fmt"
import "strings" import (
import "sync" "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 // 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 // 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 return
} }
//log.Print("req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/')]",req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/')]) //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)
} }

View File

@ -32,7 +32,7 @@ func main() {
out += "\n\t\t\t\t\t" + runnable.Contents out += "\n\t\t\t\t\t" + runnable.Contents
} else { } else {
out += ` out += `
err = ` + runnable.Contents + `(w,req,user) err = common.` + runnable.Contents + `(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -65,7 +65,7 @@ func main() {
out += "\t\t\t" + runnable.Contents out += "\t\t\t" + runnable.Contents
} else { } else {
out += ` out += `
err = ` + runnable.Contents + `(w,req,user) err = common.` + runnable.Contents + `(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -89,7 +89,7 @@ func main() {
out += "\n\t\t\t\t\t" + runnable.Contents out += "\n\t\t\t\t\t" + runnable.Contents
} else { } else {
out += ` out += `
err = ` + runnable.Contents + `(w,req,user) err = common.` + runnable.Contents + `(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -113,7 +113,7 @@ func main() {
out += "\n\t\t\t\t\t" + runnable.Contents out += "\n\t\t\t\t\t" + runnable.Contents
} else { } else {
out += ` out += `
err = ` + runnable.Contents + `(w,req,user) err = common.` + runnable.Contents + `(w,req,user)
if err != nil { if err != nil {
router.handleError(err,w,req,user) router.handleError(err,w,req,user)
return return
@ -137,17 +137,21 @@ func main() {
fileData += `package main fileData += `package main
import "log" import (
import "strings" "log"
import "sync" "strings"
import "errors" "sync"
import "net/http" "errors"
"net/http"
"./common"
)
var ErrNoRoute = errors.New("That route doesn't exist.") var ErrNoRoute = errors.New("That route doesn't exist.")
type GenRouter struct { type GenRouter struct {
UploadHandler func(http.ResponseWriter, *http.Request) 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 sync.RWMutex
} }
@ -155,26 +159,26 @@ type GenRouter struct {
func NewGenRouter(uploads http.Handler) *GenRouter { func NewGenRouter(uploads http.Handler) *GenRouter {
return &GenRouter{ return &GenRouter{
UploadHandler: http.StripPrefix("/uploads/",uploads).ServeHTTP, 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() { if err.Handled() {
return return
} }
if err.Type() == "system" { if err.Type() == "system" {
InternalErrorJSQ(err,w,r,err.Json()) common.InternalErrorJSQ(err, w, r, err.JSON())
return 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) 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.Lock()
router.extra_routes[pattern] = handle router.extra_routes[pattern] = handle
router.Unlock() router.Unlock()
@ -187,7 +191,7 @@ func (router *GenRouter) RemoveFunc(pattern string) error {
router.Unlock() router.Unlock()
return ErrNoRoute return ErrNoRoute
} }
delete(router.extra_routes,pattern) delete(router.extra_routes, pattern)
router.Unlock() router.Unlock()
return nil 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] 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("before routeStatic")
log.Print("prefix: ", prefix) log.Print("prefix: ", prefix)
log.Print("req.URL.Path: ", req.URL.Path) 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" { if prefix == "/static" {
req.URL.Path += extra_data req.URL.Path += extra_data
routeStatic(w,req) routeStatic(w, req)
return return
} }
if dev.SuperDebug { if common.Dev.SuperDebug {
log.Print("before PreRoute") log.Print("before PreRoute")
} }
// Deal with the session stuff, etc. // Deal with the session stuff, etc.
user, ok := PreRoute(w,req) user, ok := common.PreRoute(w, req)
if !ok { if !ok {
return return
} }
if dev.SuperDebug { if common.Dev.SuperDebug {
log.Print("after PreRoute") log.Print("after PreRoute")
} }
var err RouteError var err common.RouteError
switch(prefix) {` + out + ` switch(prefix) {` + out + `
case "/uploads": case "/uploads":
if extra_data == "" { if extra_data == "" {
NotFound(w,req) common.NotFound(w,req)
return return
} }
req.URL.Path += extra_data req.URL.Path += extra_data
@ -261,10 +265,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
if extra_data != "" { if extra_data != "" {
NotFound(w,req) common.NotFound(w,req)
return return
} }
config.DefaultRoute(w,req,user) common.Config.DefaultRoute(w,req,user)
default: default:
// A fallback for the routes which haven't been converted to the new router yet or plugins // A fallback for the routes which haven't been converted to the new router yet or plugins
router.RLock() router.RLock()
@ -279,7 +283,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
return return
} }
NotFound(w,req) common.NotFound(w,req)
} }
} }
` `

474
routes.go

File diff suppressed because it is too large Load Diff

View File

@ -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
}

View File

@ -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
}

File diff suppressed because it is too large Load Diff

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -18,6 +18,7 @@ import (
"sync" "sync"
"time" "time"
"./common"
"github.com/Azareal/gopsutil/cpu" "github.com/Azareal/gopsutil/cpu"
"github.com/Azareal/gopsutil/mem" "github.com/Azareal/gopsutil/mem"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
@ -25,7 +26,7 @@ import (
type WSUser struct { type WSUser struct {
conn *websocket.Conn conn *websocket.Conn
User *User User *common.User
} }
type WSHub struct { 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? // 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) conn, err := wsUpgrader.Upgrade(w, r, nil)
if err != nil { if err != nil {
return nil return nil
} }
userptr, err := users.Get(user.ID) userptr, err := common.Users.Get(user.ID)
if err != nil && err != ErrStoreCapacityOverflow { if err != nil && err != common.ErrStoreCapacityOverflow {
return nil return nil
} }
@ -341,9 +342,9 @@ AdminStatLoop:
onlineUsersColour = "stat_red" onlineUsersColour = "stat_red"
} }
totonline, totunit = convertFriendlyUnit(totonline) totonline, totunit = common.ConvertFriendlyUnit(totonline)
uonline, uunit = convertFriendlyUnit(uonline) uonline, uunit = common.ConvertFriendlyUnit(uonline)
gonline, gunit = convertFriendlyUnit(gonline) gonline, gunit = common.ConvertFriendlyUnit(gonline)
} }
if cpuerr != nil { if cpuerr != nil {
@ -364,8 +365,8 @@ AdminStatLoop:
if ramerr != nil { if ramerr != nil {
ramstr = "Unknown" ramstr = "Unknown"
} else { } else {
totalCount, totalUnit := convertByteUnit(float64(memres.Total)) totalCount, totalUnit := common.ConvertByteUnit(float64(memres.Total))
usedCount := convertByteInUnit(float64(memres.Total-memres.Available), totalUnit) 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 // 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 var totstr string

View File

@ -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)
}