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

View File

@ -4,18 +4,17 @@
* Copyright Azareal 2017 - 2018
*
*/
package main
package common
import "log"
import "errors"
import "strconv"
import "net/http"
import "database/sql"
import "./query_gen/lib"
import "golang.org/x/crypto/bcrypt"
import "../query_gen/lib"
var auth Auth
var Auth AuthInt
// ErrMismatchedHashAndPassword is thrown whenever a hash doesn't match it's unhashed password
var ErrMismatchedHashAndPassword = bcrypt.ErrMismatchedHashAndPassword
@ -27,8 +26,8 @@ var ErrWrongPassword = errors.New("That's not the correct password.")
var ErrSecretError = errors.New("There was a glitch in the system. Please contact your local administrator.")
var ErrNoUserByName = errors.New("We couldn't find an account with that username.")
// Auth is the main authentication interface.
type Auth interface {
// AuthInt is the main authentication interface.
type AuthInt interface {
Authenticate(username string, password string) (uid int, err error)
Logout(w http.ResponseWriter, uid int)
ForceLogout(uid int) error
@ -40,24 +39,19 @@ type Auth interface {
// DefaultAuth is the default authenticator used by Gosora, may be swapped with an alternate authenticator in some situations. E.g. To support LDAP.
type DefaultAuth struct {
login *sql.Stmt
logout *sql.Stmt
login *sql.Stmt
logout *sql.Stmt
updateSession *sql.Stmt
}
// NewDefaultAuth is a factory for spitting out DefaultAuths
func NewDefaultAuth() *DefaultAuth {
loginStmt, err := qgen.Builder.SimpleSelect("users", "uid, password, salt", "name = ?", "", "")
if err != nil {
log.Fatal(err)
}
logoutStmt, err := qgen.Builder.SimpleUpdate("users", "session = ''", "uid = ?")
if err != nil {
log.Fatal(err)
}
func NewDefaultAuth() (*DefaultAuth, error) {
acc := qgen.Builder.Accumulator()
return &DefaultAuth{
login: loginStmt,
logout: logoutStmt,
}
login: acc.SimpleSelect("users", "uid, password, salt", "name = ?", "", ""),
logout: acc.SimpleUpdate("users", "session = ''", "uid = ?"),
updateSession: acc.SimpleUpdate("users", "session = ?", "uid = ?"),
}, acc.FirstError()
}
// Authenticate checks if a specific username and password is valid and returns the UID for the corresponding user, if so. Otherwise, a user safe error.
@ -97,7 +91,7 @@ func (auth *DefaultAuth) ForceLogout(uid int) error {
}
// Flush the user out of the cache
ucache, ok := users.(UserCache)
ucache, ok := Users.(UserCache)
if ok {
ucache.CacheRemove(uid)
}
@ -107,18 +101,18 @@ func (auth *DefaultAuth) ForceLogout(uid int) error {
// Logout logs you out of the computer you requested the logout for, but not the other computers you're logged in with
func (auth *DefaultAuth) Logout(w http.ResponseWriter, _ int) {
cookie := http.Cookie{Name: "uid", Value: "", Path: "/", MaxAge: year}
cookie := http.Cookie{Name: "uid", Value: "", Path: "/", MaxAge: Year}
http.SetCookie(w, &cookie)
cookie = http.Cookie{Name: "session", Value: "", Path: "/", MaxAge: year}
cookie = http.Cookie{Name: "session", Value: "", Path: "/", MaxAge: Year}
http.SetCookie(w, &cookie)
}
// TODO: Set the cookie domain
// SetCookies sets the two cookies required for the current user to be recognised as a specific user in future requests
func (auth *DefaultAuth) SetCookies(w http.ResponseWriter, uid int, session string) {
cookie := http.Cookie{Name: "uid", Value: strconv.Itoa(uid), Path: "/", MaxAge: year}
cookie := http.Cookie{Name: "uid", Value: strconv.Itoa(uid), Path: "/", MaxAge: Year}
http.SetCookie(w, &cookie)
cookie = http.Cookie{Name: "session", Value: session, Path: "/", MaxAge: year}
cookie = http.Cookie{Name: "session", Value: session, Path: "/", MaxAge: Year}
http.SetCookie(w, &cookie)
}
@ -144,20 +138,20 @@ func (auth *DefaultAuth) GetCookies(r *http.Request) (uid int, session string, e
func (auth *DefaultAuth) SessionCheck(w http.ResponseWriter, r *http.Request) (user *User, halt bool) {
uid, session, err := auth.GetCookies(r)
if err != nil {
return &guestUser, false
return &GuestUser, false
}
// Is this session valid..?
user, err = users.Get(uid)
user, err = Users.Get(uid)
if err == ErrNoRows {
return &guestUser, false
return &GuestUser, false
} else if err != nil {
InternalError(err, w, r)
return &guestUser, true
return &GuestUser, true
}
if user.Session == "" || session != user.Session {
return &guestUser, false
return &GuestUser, false
}
return user, false
@ -165,18 +159,18 @@ func (auth *DefaultAuth) SessionCheck(w http.ResponseWriter, r *http.Request) (u
// CreateSession generates a new session to allow a remote client to stay logged in as a specific user
func (auth *DefaultAuth) CreateSession(uid int) (session string, err error) {
session, err = GenerateSafeString(sessionLength)
session, err = GenerateSafeString(SessionLength)
if err != nil {
return "", err
}
_, err = stmts.updateSession.Exec(session, uid)
_, err = auth.updateSession.Exec(session, uid)
if err != nil {
return "", err
}
// Flush the user data from the cache
ucache, ok := users.(UserCache)
ucache, ok := Users.(UserCache)
if ok {
ucache.CacheRemove(uid)
}

View File

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

View File

@ -2,5 +2,78 @@ package common
import "database/sql"
// nolint I don't want to write comments for each of these o.o
const Hour int = 60 * 60
const Day int = Hour * 24
const Week int = Day * 7
const Month int = Day * 30
const Year int = Day * 365
const Kilobyte int = 1024
const Megabyte int = Kilobyte * 1024
const Gigabyte int = Megabyte * 1024
const Terabyte int = Gigabyte * 1024
const Petabyte int = Terabyte * 1024
const SaltLength int = 32
const SessionLength int = 80
var TmplPtrMap = make(map[string]interface{})
// ErrNoRows is an alias of sql.ErrNoRows, just in case we end up with non-database/sql datastores
var ErrNoRows = sql.ErrNoRows
// ? - Make this more customisable?
var ExternalSites = map[string]string{
"YT": "https://www.youtube.com/",
}
type StringList []string
// ? - Should we allow users to upload .php or .go files? It could cause security issues. We could store them with a mangled extension to render them inert
// TODO: Let admins manage this from the Control Panel
var AllowedFileExts = StringList{
"png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp", "apng", // images
"txt", "xml", "json", "yaml", "toml", "ini", "md", "html", "rtf", "js", "py", "rb", "css", "scss", "less", "eqcss", "pcss", "java", "ts", "cs", "c", "cc", "cpp", "cxx", "C", "c++", "h", "hh", "hpp", "hxx", "h++", "rs", "rlib", "htaccess", "gitignore", // text
"mp3", "mp4", "avi", "wmv", "webm", // video
"otf", "woff2", "woff", "ttf", "eot", // fonts
}
var ImageFileExts = StringList{
"png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp", "apng",
}
var ArchiveFileExts = StringList{
"bz2", "zip", "gz", "7z", "tar", "cab",
}
var ExecutableFileExts = StringList{
"exe", "jar", "phar", "shar", "iso",
}
// TODO: Write a test for this
func (slice StringList) Contains(needle string) bool {
for _, item := range slice {
if item == needle {
return true
}
}
return false
}
type DBInits []func() error
var DbInits DBInits
func (inits DBInits) Run() error {
for _, init := range inits {
err := init()
if err != nil {
return err
}
}
return nil
}
func (inits DBInits) Add(init ...func() error) {
inits = append(inits, init...)
}

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() string
Error() string
Json() bool
JSON() bool
Handled() bool
}
@ -49,7 +49,7 @@ func (err *RouteErrorImpl) Error() string {
}
// Respond with JSON?
func (err *RouteErrorImpl) Json() bool {
func (err *RouteErrorImpl) JSON() bool {
return err.json
}
@ -86,7 +86,7 @@ func InternalError(err error, w http.ResponseWriter, r *http.Request) RouteError
// TODO: Centralise the user struct somewhere else
user := User{0, "guest", "Guest", "", 0, false, false, false, false, false, false, GuestPerms, nil, "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0}
pi := Page{"Internal Server Error", user, DefaultHeaderVar(), tList, "A problem has occurred in the system."}
err = templates.ExecuteTemplate(w, "error.html", pi)
err = Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
log.Print(err)
}
@ -119,33 +119,16 @@ func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) RouteErr
return HandledRouteError()
}
// ? - Where is this used? Should we use it more?
// LoginRequired is an error shown to the end-user when they try to access an area which requires them to login
func LoginRequired(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(401)
pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You need to login to do that."}
if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
return HandledRouteError()
}
func PreError(errmsg string, w http.ResponseWriter, r *http.Request) RouteError {
w.WriteHeader(500)
user := User{ID: 0, Group: 6, Perms: GuestPerms}
pi := Page{"Error", user, DefaultHeaderVar(), tList, errmsg}
if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := templates.ExecuteTemplate(w, "error.html", pi)
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
@ -169,12 +152,12 @@ func PreErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, isJs boo
func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(500)
pi := Page{"Local Error", user, DefaultHeaderVar(), tList, errmsg}
if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := templates.ExecuteTemplate(w, "error.html", pi)
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
@ -200,12 +183,12 @@ func NoPermissions(w http.ResponseWriter, r *http.Request, user User) RouteError
w.WriteHeader(403)
pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You don't have permission to do that."}
// TODO: What to do about this hook?
if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := templates.ExecuteTemplate(w, "error.html", pi)
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
@ -229,12 +212,12 @@ func NoPermissionsJS(w http.ResponseWriter, r *http.Request, user User) RouteErr
func Banned(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(403)
pi := Page{"Banned", user, DefaultHeaderVar(), tList, "You have been banned from this site."}
if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := templates.ExecuteTemplate(w, "error.html", pi)
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
@ -258,21 +241,33 @@ func BannedJS(w http.ResponseWriter, r *http.Request, user User) RouteError {
// nolint
func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) RouteError {
w.WriteHeader(401)
if !isJs {
pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You need to login to do that."}
if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
} else {
_, _ = w.Write([]byte(`{"errmsg":"You need to login to do that."}`))
return LoginRequired(w, r, user)
}
return LoginRequiredJS(w, r, user)
}
// ? - Where is this used? Should we use it more?
// LoginRequired is an error shown to the end-user when they try to access an area which requires them to login
func LoginRequired(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(401)
pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You need to login to do that."}
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
return HandledRouteError()
}
// nolint
func LoginRequiredJS(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(401)
_, _ = w.Write([]byte(`{"errmsg":"You need to login to do that."}`))
return HandledRouteError()
}
@ -281,12 +276,12 @@ func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bo
func SecurityError(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(403)
pi := Page{"Security Error", user, DefaultHeaderVar(), tList, "There was a security issue with your request."}
if preRenderHooks["pre_render_security_error"] != nil {
if runPreRenderHook("pre_render_security_error", w, r, &user, &pi) {
if PreRenderHooks["pre_render_security_error"] != nil {
if RunPreRenderHook("pre_render_security_error", w, r, &user, &pi) {
return nil
}
}
err := templates.ExecuteTemplate(w, "error.html", pi)
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
@ -301,7 +296,7 @@ func NotFound(w http.ResponseWriter, r *http.Request) RouteError {
// TODO: Centralise the user struct somewhere else
user := User{0, "guest", "Guest", "", 0, false, false, false, false, false, false, GuestPerms, nil, "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0}
pi := Page{"Not Found", user, DefaultHeaderVar(), tList, "The requested page doesn't exist."}
err := templates.ExecuteTemplate(w, "error.html", pi)
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
@ -312,12 +307,12 @@ func NotFound(w http.ResponseWriter, r *http.Request) RouteError {
func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(errcode)
pi := Page{errtitle, user, DefaultHeaderVar(), tList, errmsg}
if preRenderHooks["pre_render_error"] != nil {
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := templates.ExecuteTemplate(w, "error.html", pi)
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}

View File

@ -18,13 +18,13 @@ type PluginList map[string]*Plugin
var Plugins PluginList = make(map[string]*Plugin)
// Hooks with a single argument. Is this redundant? Might be useful for inlining, as variadics aren't inlined? Are closures even inlined to begin with?
var hooks = map[string][]func(interface{}) interface{}{
var Hooks = map[string][]func(interface{}) interface{}{
"forums_frow_assign": nil,
"topic_create_frow_assign": nil,
}
// Hooks with a variable number of arguments
var vhooks = map[string]func(...interface{}) interface{}{
var Vhooks = map[string]func(...interface{}) interface{}{
"intercept_build_widgets": nil,
"forum_trow_assign": nil,
"topics_topic_row_assign": nil,
@ -35,7 +35,7 @@ var vhooks = map[string]func(...interface{}) interface{}{
}
// Hooks with a variable number of arguments and return values for skipping the parent function and propagating an error upwards
var vhookSkippable = map[string]func(...interface{}) (bool, RouteError){
var VhookSkippable = map[string]func(...interface{}) (bool, RouteError){
"simple_forum_check_pre_perms": nil,
"forum_check_pre_perms": nil,
}
@ -65,13 +65,13 @@ var messageHooks = map[string][]func(Message, PageInt, ...interface{}) interface
}
// Hooks which take in and spit out a string. This is usually used for parser components
var sshooks = map[string][]func(string) string{
var Sshooks = map[string][]func(string) string{
"preparse_preassign": nil,
"parse_assign": nil,
}
// The hooks which run before the template is rendered for a route
var preRenderHooks = map[string][]func(http.ResponseWriter, *http.Request, *User, interface{}) bool{
var PreRenderHooks = map[string][]func(http.ResponseWriter, *http.Request, *User, interface{}) bool{
"pre_render": nil,
"pre_render_forum_list": nil,
@ -137,7 +137,7 @@ type Plugin struct {
Data interface{} // Usually used for hosting the VMs / reusable elements of non-native plugins
}
func initExtend() (err error) {
func InitExtend() (err error) {
err = InitPluginLangs()
if err != nil {
return err
@ -145,7 +145,7 @@ func initExtend() (err error) {
return Plugins.Load()
}
// LoadPlugins polls the database to see which plugins have been activated and which have been installed
// Load polls the database to see which plugins have been activated and which have been installed
func (plugins PluginList) Load() error {
getPlugins, err := qgen.Builder.SimpleSelect("plugins", "uname, active, installed", "", "", "")
if err != nil {
@ -206,37 +206,37 @@ func NewPlugin(uname string, name string, author string, url string, settings st
func (plugin *Plugin) AddHook(name string, handler interface{}) {
switch h := handler.(type) {
case func(interface{}) interface{}:
if len(hooks[name]) == 0 {
if len(Hooks[name]) == 0 {
var hookSlice []func(interface{}) interface{}
hookSlice = append(hookSlice, h)
hooks[name] = hookSlice
Hooks[name] = hookSlice
} else {
hooks[name] = append(hooks[name], h)
Hooks[name] = append(Hooks[name], h)
}
plugin.Hooks[name] = len(hooks[name])
plugin.Hooks[name] = len(Hooks[name])
case func(string) string:
if len(sshooks[name]) == 0 {
if len(Sshooks[name]) == 0 {
var hookSlice []func(string) string
hookSlice = append(hookSlice, h)
sshooks[name] = hookSlice
Sshooks[name] = hookSlice
} else {
sshooks[name] = append(sshooks[name], h)
Sshooks[name] = append(Sshooks[name], h)
}
plugin.Hooks[name] = len(sshooks[name])
plugin.Hooks[name] = len(Sshooks[name])
case func(http.ResponseWriter, *http.Request, *User, interface{}) bool:
if len(preRenderHooks[name]) == 0 {
if len(PreRenderHooks[name]) == 0 {
var hookSlice []func(http.ResponseWriter, *http.Request, *User, interface{}) bool
hookSlice = append(hookSlice, h)
preRenderHooks[name] = hookSlice
PreRenderHooks[name] = hookSlice
} else {
preRenderHooks[name] = append(preRenderHooks[name], h)
PreRenderHooks[name] = append(PreRenderHooks[name], h)
}
plugin.Hooks[name] = len(preRenderHooks[name])
plugin.Hooks[name] = len(PreRenderHooks[name])
case func(...interface{}) interface{}:
vhooks[name] = h
Vhooks[name] = h
plugin.Hooks[name] = 0
case func(...interface{}) (bool, RouteError):
vhookSkippable[name] = h
VhookSkippable[name] = h
plugin.Hooks[name] = 0
default:
panic("I don't recognise this kind of handler!") // Should this be an error for the plugin instead of a panic()?
@ -248,35 +248,35 @@ func (plugin *Plugin) RemoveHook(name string, handler interface{}) {
switch handler.(type) {
case func(interface{}) interface{}:
key := plugin.Hooks[name]
hook := hooks[name]
hook := Hooks[name]
if len(hook) == 1 {
hook = []func(interface{}) interface{}{}
} else {
hook = append(hook[:key], hook[key+1:]...)
}
hooks[name] = hook
Hooks[name] = hook
case func(string) string:
key := plugin.Hooks[name]
hook := sshooks[name]
hook := Sshooks[name]
if len(hook) == 1 {
hook = []func(string) string{}
} else {
hook = append(hook[:key], hook[key+1:]...)
}
sshooks[name] = hook
Sshooks[name] = hook
case func(http.ResponseWriter, *http.Request, *User, interface{}) bool:
key := plugin.Hooks[name]
hook := preRenderHooks[name]
hook := PreRenderHooks[name]
if len(hook) == 1 {
hook = []func(http.ResponseWriter, *http.Request, *User, interface{}) bool{}
} else {
hook = append(hook[:key], hook[key+1:]...)
}
preRenderHooks[name] = hook
PreRenderHooks[name] = hook
case func(...interface{}) interface{}:
delete(vhooks, name)
delete(Vhooks, name)
case func(...interface{}) (bool, RouteError):
delete(vhookSkippable, name)
delete(VhookSkippable, name)
default:
panic("I don't recognise this kind of handler!") // Should this be an error for the plugin instead of a panic()?
}
@ -285,18 +285,18 @@ func (plugin *Plugin) RemoveHook(name string, handler interface{}) {
var pluginsInited = false
func initPlugins() {
func InitPlugins() {
for name, body := range Plugins {
log.Print("Added plugin " + name)
log.Printf("Added plugin %s", name)
if body.Active {
log.Print("Initialised plugin " + name)
log.Printf("Initialised plugin %s", name)
if Plugins[name].Init != nil {
err := Plugins[name].Init()
if err != nil {
log.Print(err)
}
} else {
log.Print("Plugin " + name + " doesn't have an initialiser.")
log.Printf("Plugin %s doesn't have an initialiser.", name)
}
}
}
@ -304,49 +304,49 @@ func initPlugins() {
}
// ? - Are the following functions racey?
func runHook(name string, data interface{}) interface{} {
for _, hook := range hooks[name] {
func RunHook(name string, data interface{}) interface{} {
for _, hook := range Hooks[name] {
data = hook(data)
}
return data
}
func runHookNoreturn(name string, data interface{}) {
for _, hook := range hooks[name] {
func RunHookNoreturn(name string, data interface{}) {
for _, hook := range Hooks[name] {
_ = hook(data)
}
}
func runVhook(name string, data ...interface{}) interface{} {
return vhooks[name](data...)
func RunVhook(name string, data ...interface{}) interface{} {
return Vhooks[name](data...)
}
func runVhookSkippable(name string, data ...interface{}) (bool, RouteError) {
return vhookSkippable[name](data...)
func RunVhookSkippable(name string, data ...interface{}) (bool, RouteError) {
return VhookSkippable[name](data...)
}
func runVhookNoreturn(name string, data ...interface{}) {
_ = vhooks[name](data...)
func RunVhookNoreturn(name string, data ...interface{}) {
_ = Vhooks[name](data...)
}
// Trying to get a teeny bit of type-safety where-ever possible, especially for such a critical set of hooks
func runSshook(name string, data string) string {
for _, hook := range sshooks[name] {
func RunSshook(name string, data string) string {
for _, hook := range Sshooks[name] {
data = hook(data)
}
return data
}
func runPreRenderHook(name string, w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) {
func RunPreRenderHook(name string, w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) {
// This hook runs on ALL pre_render hooks
for _, hook := range preRenderHooks["pre_render"] {
for _, hook := range PreRenderHooks["pre_render"] {
if hook(w, r, user, data) {
return true
}
}
// The actual pre_render hook
for _, hook := range preRenderHooks[name] {
for _, hook := range PreRenderHooks[name] {
if hook(w, r, user, data) {
return true
}

View File

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

View File

@ -2,12 +2,15 @@ package common
//import "fmt"
import (
"database/sql"
"strconv"
"strings"
"../query_gen/lib"
_ "github.com/go-sql-driver/mysql"
)
// TODO: Do we really need this?
type ForumAdmin struct {
ID int
Name string
@ -44,11 +47,25 @@ type ForumSimple struct {
Preset string
}
type ForumStmts struct {
update *sql.Stmt
}
var forumStmts ForumStmts
func init() {
DbInits.Add(func() error {
acc := qgen.Builder.Accumulator()
forumStmts = ForumStmts{
update: acc.SimpleUpdate("forums", "name = ?, desc = ?, active = ?, preset = ?", "fid = ?"),
}
return acc.FirstError()
})
}
// Copy gives you a non-pointer concurrency safe copy of the forum
func (forum *Forum) Copy() (fcopy Forum) {
//forum.LastLock.RLock()
fcopy = *forum
//forum.LastLock.RUnlock()
return fcopy
}
@ -58,17 +75,17 @@ func (forum *Forum) Update(name string, desc string, active bool, preset string)
name = forum.Name
}
preset = strings.TrimSpace(preset)
_, err := stmts.updateForum.Exec(name, desc, active, preset, forum.ID)
_, err := forumStmts.update.Exec(name, desc, active, preset, forum.ID)
if err != nil {
return err
}
if forum.Preset != preset || preset == "custom" || preset == "" {
err = permmapToQuery(presetToPermmap(preset), forum.ID)
err = PermmapToQuery(PresetToPermmap(preset), forum.ID)
if err != nil {
return err
}
}
_ = fstore.Reload(forum.ID)
_ = Fstore.Reload(forum.ID)
return nil
}
@ -91,13 +108,13 @@ func makeDummyForum(fid int, link string, name string, desc string, active bool,
return &Forum{ID: fid, Link: link, Name: name, Desc: desc, Active: active, Preset: preset, ParentID: parentID, ParentType: parentType, TopicCount: topicCount}
}
func buildForumURL(slug string, fid int) string {
func BuildForumURL(slug string, fid int) string {
if slug == "" {
return "/forum/" + strconv.Itoa(fid)
}
return "/forum/" + slug + "." + strconv.Itoa(fid)
}
func getForumURLPrefix() string {
func GetForumURLPrefix() string {
return "/forum/"
}

View File

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

View File

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

View File

@ -1,5 +1,8 @@
package common
import "database/sql"
import "../query_gen/lib"
var blankGroup = Group{ID: 0, Name: ""}
type GroupAdmin struct {
@ -27,13 +30,29 @@ type Group struct {
CanSee []int // The IDs of the forums this group can see
}
type GroupStmts struct {
updateGroupRank *sql.Stmt
}
var groupStmts GroupStmts
func init() {
DbInits.Add(func() error {
acc := qgen.Builder.Accumulator()
groupStmts = GroupStmts{
updateGroupRank: acc.SimpleUpdate("users_groups", "is_admin = ?, is_mod = ?, is_banned = ?", "gid = ?"),
}
return acc.FirstError()
})
}
func (group *Group) ChangeRank(isAdmin bool, isMod bool, isBanned bool) (err error) {
_, err = stmts.updateGroupRank.Exec(isAdmin, isMod, isBanned, group.ID)
_, err = groupStmts.updateGroupRank.Exec(isAdmin, isMod, isBanned, group.ID)
if err != nil {
return err
}
gstore.Reload(group.ID)
Gstore.Reload(group.ID)
return nil
}

View File

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

View File

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

View File

@ -11,7 +11,7 @@ type HeaderVars struct {
Scripts []string
Stylesheets []string
Widgets PageWidgets
Site *Site
Site *site
Settings map[string]interface{}
Themes map[string]Theme // TODO: Use a slice containing every theme instead of the main map for speed
ThemeName string
@ -21,7 +21,7 @@ type HeaderVars struct {
// TODO: Add this to routes which don't use templates. E.g. Json APIs.
type HeaderLite struct {
Site *Site
Site *site
Settings SettingMap
ExtData ExtData
}
@ -34,7 +34,7 @@ type PageWidgets struct {
// TODO: Add a ExtDataHolder interface with methods for manipulating the contents?
// ? - Could we use a sync.Map instead?
type ExtData struct {
items map[string]interface{} // Key: pluginname
Items map[string]interface{} // Key: pluginname
sync.RWMutex
}
@ -226,7 +226,7 @@ type PanelEditGroupPermsPage struct {
GlobalPerms []NameLangToggle
}
type backupItem struct {
type BackupItem struct {
SQLURL string
// TODO: Add an easier to parse format here for Gosora to be able to more easily reimport portions of the dump and to strip unnecessary data (e.g. table defs and parsed post data)
@ -239,10 +239,10 @@ type PanelBackupPage struct {
CurrentUser User
Header *HeaderVars
Stats PanelStats
Backups []backupItem
Backups []BackupItem
}
type logItem struct {
type LogItem struct {
Action template.HTML
IPAddress string
DoneAt string
@ -253,7 +253,7 @@ type PanelLogsPage struct {
CurrentUser User
Header *HeaderVars
Stats PanelStats
Logs []logItem
Logs []LogItem
PageList []int
Page int
LastPage int
@ -282,5 +282,5 @@ type AreYouSure struct {
// This is mostly for errors.go, please create *HeaderVars on the spot instead of relying on this or the atomic store underlying it, if possible
// TODO: Write a test for this
func DefaultHeaderVar() *HeaderVars {
return &HeaderVars{Site: site, ThemeName: fallbackTheme}
return &HeaderVars{Site: Site, ThemeName: fallbackTheme}
}

View File

@ -1,4 +1,4 @@
package main
package common
import (
//"fmt"
@ -9,19 +9,19 @@ import (
"strings"
)
var spaceGap = []byte(" ")
var SpaceGap = []byte(" ")
var httpProtBytes = []byte("http://")
var invalidURL = []byte("<span style='color: red;'>[Invalid URL]</span>")
var invalidTopic = []byte("<span style='color: red;'>[Invalid Topic]</span>")
var invalidProfile = []byte("<span style='color: red;'>[Invalid Profile]</span>")
var invalidForum = []byte("<span style='color: red;'>[Invalid Forum]</span>")
var InvalidURL = []byte("<span style='color: red;'>[Invalid URL]</span>")
var InvalidTopic = []byte("<span style='color: red;'>[Invalid Topic]</span>")
var InvalidProfile = []byte("<span style='color: red;'>[Invalid Profile]</span>")
var InvalidForum = []byte("<span style='color: red;'>[Invalid Forum]</span>")
var unknownMedia = []byte("<span style='color: red;'>[Unknown Media]</span>")
var urlOpen = []byte("<a href='")
var urlOpen2 = []byte("'>")
var UrlOpen = []byte("<a href='")
var UrlOpen2 = []byte("'>")
var bytesSinglequote = []byte("'")
var bytesGreaterthan = []byte(">")
var urlMention = []byte(" class='mention'")
var urlClose = []byte("</a>")
var UrlClose = []byte("</a>")
var imageOpen = []byte("<a href=\"")
var imageOpen2 = []byte("\"><img src='")
var imageClose = []byte("' class='postImage' /></a>")
@ -164,16 +164,16 @@ func shortcodeToUnicode(msg string) string {
return msg
}
func preparseMessage(msg string) string {
if sshooks["preparse_preassign"] != nil {
msg = runSshook("preparse_preassign", msg)
func PreparseMessage(msg string) string {
if Sshooks["preparse_preassign"] != nil {
msg = RunSshook("preparse_preassign", msg)
}
return shortcodeToUnicode(msg)
}
// TODO: Write a test for this
// TODO: We need a lot more hooks here. E.g. To add custom media types and handlers.
func parseMessage(msg string, sectionID int, sectionType string /*, user User*/) string {
func ParseMessage(msg string, sectionID int, sectionType string /*, user User*/) string {
msg = strings.Replace(msg, ":)", "😀", -1)
msg = strings.Replace(msg, ":(", "😞", -1)
msg = strings.Replace(msg, ":D", "😃", -1)
@ -185,7 +185,7 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
//msg = url_reg.ReplaceAllString(msg,"<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
wordFilters := wordFilterBox.Load().(WordFilterBox)
wordFilters := WordFilterBox.Load().(WordFilterMap)
for _, filter := range wordFilters {
msg = strings.Replace(msg, filter.Find, filter.Replacement, -1)
}
@ -194,7 +194,7 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
//log.Print("Parser Loop!")
var msgbytes = []byte(msg)
var outbytes []byte
msgbytes = append(msgbytes, spaceGap...)
msgbytes = append(msgbytes, SpaceGap...)
//log.Printf("string(msgbytes) %+v\n", `"`+string(msgbytes)+`"`)
var lastItem = 0
var i = 0
@ -215,23 +215,23 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
outbytes = append(outbytes, msgbytes[lastItem:i]...)
i += 5
start := i
tid, intLen := coerceIntBytes(msgbytes[start:])
tid, intLen := CoerceIntBytes(msgbytes[start:])
i += intLen
topic, err := topics.Get(tid)
if err != nil || !fstore.Exists(topic.ParentID) {
outbytes = append(outbytes, invalidTopic...)
topic, err := Topics.Get(tid)
if err != nil || !Fstore.Exists(topic.ParentID) {
outbytes = append(outbytes, InvalidTopic...)
lastItem = i
continue
}
outbytes = append(outbytes, urlOpen...)
var urlBit = []byte(buildTopicURL("", tid))
outbytes = append(outbytes, UrlOpen...)
var urlBit = []byte(BuildTopicURL("", tid))
outbytes = append(outbytes, urlBit...)
outbytes = append(outbytes, urlOpen2...)
outbytes = append(outbytes, UrlOpen2...)
var tidBit = []byte("#tid-" + strconv.Itoa(tid))
outbytes = append(outbytes, tidBit...)
outbytes = append(outbytes, urlClose...)
outbytes = append(outbytes, UrlClose...)
lastItem = i
//log.Print("string(msgbytes): ",string(msgbytes))
@ -244,44 +244,46 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
outbytes = append(outbytes, msgbytes[lastItem:i]...)
i += 5
start := i
rid, intLen := coerceIntBytes(msgbytes[start:])
rid, intLen := CoerceIntBytes(msgbytes[start:])
i += intLen
topic, err := getTopicByReply(rid)
if err != nil || !fstore.Exists(topic.ParentID) {
outbytes = append(outbytes, invalidTopic...)
reply := BlankReply()
reply.ID = rid
topic, err := reply.Topic()
if err != nil || !Fstore.Exists(topic.ParentID) {
outbytes = append(outbytes, InvalidTopic...)
lastItem = i
continue
}
outbytes = append(outbytes, urlOpen...)
var urlBit = []byte(buildTopicURL("", topic.ID))
outbytes = append(outbytes, UrlOpen...)
var urlBit = []byte(BuildTopicURL("", topic.ID))
outbytes = append(outbytes, urlBit...)
outbytes = append(outbytes, urlOpen2...)
outbytes = append(outbytes, UrlOpen2...)
var ridBit = []byte("#rid-" + strconv.Itoa(rid))
outbytes = append(outbytes, ridBit...)
outbytes = append(outbytes, urlClose...)
outbytes = append(outbytes, UrlClose...)
lastItem = i
} else if bytes.Equal(msgbytes[i+1:i+5], []byte("fid-")) {
outbytes = append(outbytes, msgbytes[lastItem:i]...)
i += 5
start := i
fid, intLen := coerceIntBytes(msgbytes[start:])
fid, intLen := CoerceIntBytes(msgbytes[start:])
i += intLen
if !fstore.Exists(fid) {
outbytes = append(outbytes, invalidForum...)
if !Fstore.Exists(fid) {
outbytes = append(outbytes, InvalidForum...)
lastItem = i
continue
}
outbytes = append(outbytes, urlOpen...)
var urlBit = []byte(buildForumURL("", fid))
outbytes = append(outbytes, UrlOpen...)
var urlBit = []byte(BuildForumURL("", fid))
outbytes = append(outbytes, urlBit...)
outbytes = append(outbytes, urlOpen2...)
outbytes = append(outbytes, UrlOpen2...)
var fidBit = []byte("#fid-" + strconv.Itoa(fid))
outbytes = append(outbytes, fidBit...)
outbytes = append(outbytes, urlClose...)
outbytes = append(outbytes, UrlClose...)
lastItem = i
} else {
// TODO: Forum Shortcode Link
@ -291,17 +293,17 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
outbytes = append(outbytes, msgbytes[lastItem:i]...)
i++
start := i
uid, intLen := coerceIntBytes(msgbytes[start:])
uid, intLen := CoerceIntBytes(msgbytes[start:])
i += intLen
menUser, err := users.Get(uid)
menUser, err := Users.Get(uid)
if err != nil {
outbytes = append(outbytes, invalidProfile...)
outbytes = append(outbytes, InvalidProfile...)
lastItem = i
continue
}
outbytes = append(outbytes, urlOpen...)
outbytes = append(outbytes, UrlOpen...)
var urlBit = []byte(menUser.Link)
outbytes = append(outbytes, urlBit...)
outbytes = append(outbytes, bytesSinglequote...)
@ -309,7 +311,7 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
outbytes = append(outbytes, bytesGreaterthan...)
var uidBit = []byte("@" + menUser.Name)
outbytes = append(outbytes, uidBit...)
outbytes = append(outbytes, urlClose...)
outbytes = append(outbytes, UrlClose...)
lastItem = i
//log.Print(string(msgbytes))
@ -338,21 +340,21 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
//log.Print("Normal URL")
outbytes = append(outbytes, msgbytes[lastItem:i]...)
urlLen := partialURLBytesLen(msgbytes[i:])
urlLen := PartialURLBytesLen(msgbytes[i:])
if msgbytes[i+urlLen] > 32 { // space and invisibles
//log.Print("INVALID URL")
//log.Print("msgbytes[i+urlLen]: ", msgbytes[i+urlLen])
//log.Print("string(msgbytes[i+urlLen]): ", string(msgbytes[i+urlLen]))
//log.Print("msgbytes[i:i+urlLen]: ", msgbytes[i:i+urlLen])
//log.Print("string(msgbytes[i:i+urlLen]): ", string(msgbytes[i:i+urlLen]))
outbytes = append(outbytes, invalidURL...)
outbytes = append(outbytes, InvalidURL...)
i += urlLen
continue
}
media, ok := parseMediaBytes(msgbytes[i : i+urlLen])
if !ok {
outbytes = append(outbytes, invalidURL...)
outbytes = append(outbytes, InvalidURL...)
i += urlLen
continue
}
@ -386,23 +388,23 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
continue
}
outbytes = append(outbytes, urlOpen...)
outbytes = append(outbytes, UrlOpen...)
outbytes = append(outbytes, msgbytes[i:i+urlLen]...)
outbytes = append(outbytes, urlOpen2...)
outbytes = append(outbytes, UrlOpen2...)
outbytes = append(outbytes, msgbytes[i:i+urlLen]...)
outbytes = append(outbytes, urlClose...)
outbytes = append(outbytes, UrlClose...)
i += urlLen
lastItem = i
} else if msgbytes[i] == '/' && msgbytes[i+1] == '/' {
outbytes = append(outbytes, msgbytes[lastItem:i]...)
urlLen := partialURLBytesLen(msgbytes[i:])
urlLen := PartialURLBytesLen(msgbytes[i:])
if msgbytes[i+urlLen] > 32 { // space and invisibles
//log.Print("INVALID URL")
//log.Print("msgbytes[i+urlLen]: ", msgbytes[i+urlLen])
//log.Print("string(msgbytes[i+urlLen]): ", string(msgbytes[i+urlLen]))
//log.Print("msgbytes[i:i+urlLen]: ", msgbytes[i:i+urlLen])
//log.Print("string(msgbytes[i:i+urlLen]): ", string(msgbytes[i:i+urlLen]))
outbytes = append(outbytes, invalidURL...)
outbytes = append(outbytes, InvalidURL...)
i += urlLen
continue
}
@ -412,7 +414,7 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
//log.Print("string(msgbytes[i:i+urlLen]): ", string(msgbytes[i:i+urlLen]))
media, ok := parseMediaBytes(msgbytes[i : i+urlLen])
if !ok {
outbytes = append(outbytes, invalidURL...)
outbytes = append(outbytes, InvalidURL...)
i += urlLen
continue
}
@ -446,11 +448,11 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
continue
}
outbytes = append(outbytes, urlOpen...)
outbytes = append(outbytes, UrlOpen...)
outbytes = append(outbytes, msgbytes[i:i+urlLen]...)
outbytes = append(outbytes, urlOpen2...)
outbytes = append(outbytes, UrlOpen2...)
outbytes = append(outbytes, msgbytes[i:i+urlLen]...)
outbytes = append(outbytes, urlClose...)
outbytes = append(outbytes, UrlClose...)
i += urlLen
lastItem = i
}
@ -474,25 +476,12 @@ func parseMessage(msg string, sectionID int, sectionType string /*, user User*/)
//log.Print("msg",`"`+msg+`"`)
msg = strings.Replace(msg, "\n", "<br>", -1)
if sshooks["parse_assign"] != nil {
msg = runSshook("parse_assign", msg)
if Sshooks["parse_assign"] != nil {
msg = RunSshook("parse_assign", msg)
}
return msg
}
// TODO: Write a test for this
/*func regexParseMessage(msg string) string {
msg = strings.Replace(msg, ":)", "😀", -1)
msg = strings.Replace(msg, ":D", "😃", -1)
msg = strings.Replace(msg, ":P", "😛", -1)
msg = urlReg.ReplaceAllString(msg, "<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
// ftp://, http://, https:// git://, //, mailto: (not a URL, just here for length comparison purposes)
// TODO: Write a test for this
@ -541,7 +530,7 @@ func validatedURLBytes(data []byte) (url []byte) {
// ? - There should only be one : and that's only if the URL is on a non-standard port. Same for ?s.
for ; datalen > i; i++ {
if data[i] != '\\' && data[i] != '_' && data[i] != ':' && data[i] != '?' && data[i] != '&' && data[i] != '=' && data[i] != ';' && data[i] != '@' && !(data[i] > 44 && data[i] < 58) && !(data[i] > 64 && data[i] < 91) && !(data[i] > 96 && data[i] < 123) {
return invalidURL
return InvalidURL
}
}
@ -550,7 +539,7 @@ func validatedURLBytes(data []byte) (url []byte) {
}
// TODO: Write a test for this
func partialURLBytes(data []byte) (url []byte) {
func PartialURLBytes(data []byte) (url []byte) {
datalen := len(data)
i := 0
end := datalen - 1
@ -579,7 +568,7 @@ func partialURLBytes(data []byte) (url []byte) {
}
// TODO: Write a test for this
func partialURLBytesLen(data []byte) int {
func PartialURLBytesLen(data []byte) int {
datalen := len(data)
i := 0
@ -632,13 +621,12 @@ func parseMediaBytes(data []byte) (media MediaEmbed, ok bool) {
query := url.Query()
//log.Printf("query %+v\n", query)
var samesite = hostname == "localhost" || hostname == site.URL
var samesite = hostname == "localhost" || hostname == Site.URL
if samesite {
//log.Print("samesite")
hostname = strings.Split(site.URL, ":")[0]
hostname = strings.Split(Site.URL, ":")[0]
// ?- Test this as I'm not sure it'll do what it should. If someone's running SSL on port 80 or non-SSL on port 443 then... Well... They're in far worse trouble than this...
port = site.Port
if scheme == "" && site.EnableSsl {
port = Site.Port
if scheme == "" && Site.EnableSsl {
scheme = "https"
}
}
@ -684,7 +672,7 @@ func parseMediaBytes(data []byte) (media MediaEmbed, ok bool) {
extarr := strings.Split(lastFrag, ".")
if len(extarr) >= 2 {
ext := extarr[len(extarr)-1]
if imageFileExts.Contains(ext) {
if ImageFileExts.Contains(ext) {
media.Type = "image"
var sport string
if port != "443" && port != "80" {
@ -704,7 +692,7 @@ func parseURL(data []byte) (*url.URL, error) {
}
// TODO: Write a test for this
func coerceIntBytes(data []byte) (res int, length int) {
func CoerceIntBytes(data []byte) (res int, length int) {
if !(data[0] > 47 && data[0] < 58) {
return 0, 1
}
@ -728,7 +716,7 @@ func coerceIntBytes(data []byte) (res int, length int) {
}
// TODO: Write tests for this
func paginate(count int, perPage int, maxPages int) []int {
func Paginate(count int, perPage int, maxPages int) []int {
if count < perPage {
return []int{1}
}
@ -745,7 +733,7 @@ func paginate(count int, perPage int, maxPages int) []int {
}
// TODO: Write tests for this
func pageOffset(count int, page int, perPage int) (int, int, int) {
func PageOffset(count int, page int, perPage int) (int, int, int) {
var offset int
lastPage := (count / perPage) + 1
if page > 1 {

View File

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

View File

@ -4,7 +4,7 @@
* Copyright Azareal 2017 - 2018
*
*/
package main
package common
import (
"encoding/json"
@ -20,7 +20,7 @@ import (
// TODO: Let the admin edit phrases from inside the Control Panel? How should we persist these? Should we create a copy of the langpack or edit the primaries? Use the changeLangpack mutex for this?
// nolint Be quiet megacheck, this *is* used
var currentLangPack atomic.Value
var langpackCount int // TODO: Use atomics for this
var langPackCount int // TODO: Use atomics for this
// TODO: We'll be implementing the level phrases in the software proper very very soon!
type LevelPhrases struct {
@ -44,10 +44,9 @@ type LanguagePack struct {
}
// TODO: Add the ability to edit language JSON files from the Control Panel and automatically scan the files for changes
////var langpacks = map[string]*LanguagePack
var langpacks sync.Map // nolint it is used
var langPacks sync.Map // nolint it is used
func initPhrases() error {
func InitPhrases() error {
log.Print("Loading the language packs")
err := filepath.Walk("./langs", func(path string, f os.FileInfo, err error) error {
if f.IsDir() {
@ -61,8 +60,8 @@ func initPhrases() error {
var ext = filepath.Ext("/langs/" + path)
if ext != ".json" {
if dev.DebugMode {
log.Print("Found a " + ext + "in /langs/")
if Dev.DebugMode {
log.Printf("Found a '%s' in /langs/", ext)
}
return nil
}
@ -74,8 +73,8 @@ func initPhrases() error {
}
log.Print("Adding the '" + langPack.Name + "' language pack")
langpacks.Store(langPack.Name, &langPack)
langpackCount++
langPacks.Store(langPack.Name, &langPack)
langPackCount++
return nil
})
@ -83,13 +82,13 @@ func initPhrases() error {
if err != nil {
return err
}
if langpackCount == 0 {
if langPackCount == 0 {
return errors.New("You don't have any language packs")
}
langPack, ok := langpacks.Load(site.Language)
langPack, ok := langPacks.Load(Site.Language)
if !ok {
return errors.New("Couldn't find the " + site.Language + " language pack")
return errors.New("Couldn't find the " + Site.Language + " language pack")
}
currentLangPack.Store(langPack)
return nil
@ -167,7 +166,7 @@ func DeletePhrase() {
// TODO: Use atomics to store the pointer of the current active langpack?
// nolint
func ChangeLanguagePack(name string) (exists bool) {
pack, ok := langpacks.Load(name)
pack, ok := langPacks.Load(name)
if !ok {
return false
}

View File

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

View File

@ -2,9 +2,11 @@ package common
import (
"database/sql"
"../query_gen/lib"
)
var prstore ProfileReplyStore
var Prstore ProfileReplyStore
type ProfileReplyStore interface {
Get(id int) (*Reply, error)
@ -33,7 +35,7 @@ func (store *SQLProfileReplyStore) Get(id int) (*Reply, error) {
}
func (store *SQLProfileReplyStore) Create(profileID int, content string, createdBy int, ipaddress string) (id int, err error) {
res, err := store.create.Exec(profileID, content, parseMessage(content, 0, ""), createdBy, ipaddress)
res, err := store.create.Exec(profileID, content, ParseMessage(content, 0, ""), createdBy, ipaddress)
if err != nil {
return 0, err
}

View File

@ -7,8 +7,11 @@
package common
import (
"database/sql"
"errors"
"time"
"../query_gen/lib"
)
type ReplyUser struct {
@ -56,12 +59,37 @@ type Reply struct {
}
var ErrAlreadyLiked = errors.New("You already liked this!")
var replyStmts ReplyStmts
type ReplyStmts struct {
isLiked *sql.Stmt
createLike *sql.Stmt
delete *sql.Stmt
addLikesToReply *sql.Stmt
removeRepliesFromTopic *sql.Stmt
getParent *sql.Stmt
}
func init() {
DbInits.Add(func() error {
acc := qgen.Builder.Accumulator()
replyStmts = ReplyStmts{
isLiked: acc.SimpleSelect("likes", "targetItem", "sentBy = ? and targetItem = ? and targetType = 'replies'", "", ""),
createLike: acc.SimpleInsert("likes", "weight, targetItem, targetType, sentBy", "?,?,?,?"),
delete: acc.SimpleDelete("replies", "rid = ?"),
addLikesToReply: acc.SimpleUpdate("replies", "likeCount = likeCount + ?", "rid = ?"),
removeRepliesFromTopic: acc.SimpleUpdate("topics", "postCount = postCount - ?", "tid = ?"),
getParent: acc.SimpleLeftJoin("replies", "topics", "topics.tid, topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, topics.data", "replies.tid = topics.tid", "rid = ?", "", ""),
}
return acc.FirstError()
})
}
// TODO: Write tests for this
// TODO: Wrap these queries in a transaction to make sure the state is consistent
func (reply *Reply) Like(uid int) (err error) {
var rid int // unused, just here to avoid mutating reply.ID
err = stmts.hasLikedReply.QueryRow(uid, reply.ID).Scan(&rid)
err = replyStmts.isLiked.QueryRow(uid, reply.ID).Scan(&rid)
if err != nil && err != ErrNoRows {
return err
} else if err != ErrNoRows {
@ -69,29 +97,41 @@ func (reply *Reply) Like(uid int) (err error) {
}
score := 1
_, err = stmts.createLike.Exec(score, reply.ID, "replies", uid)
_, err = replyStmts.createLike.Exec(score, reply.ID, "replies", uid)
if err != nil {
return err
}
_, err = stmts.addLikesToReply.Exec(1, reply.ID)
_, err = replyStmts.addLikesToReply.Exec(1, reply.ID)
return err
}
// TODO: Write tests for this
func (reply *Reply) Delete() error {
_, err := stmts.deleteReply.Exec(reply.ID)
_, err := replyStmts.delete.Exec(reply.ID)
if err != nil {
return err
}
_, err = stmts.removeRepliesFromTopic.Exec(1, reply.ParentID)
tcache, ok := topics.(TopicCache)
// TODO: Move this bit to *Topic
_, err = replyStmts.removeRepliesFromTopic.Exec(1, reply.ParentID)
tcache, ok := Topics.(TopicCache)
if ok {
tcache.CacheRemove(reply.ParentID)
}
return err
}
func (reply *Reply) Topic() (*Topic, error) {
topic := Topic{ID: 0}
err := replyStmts.getParent.QueryRow(reply.ID).Scan(&topic.ID, &topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
topic.Link = BuildTopicURL(NameToSlug(topic.Title), topic.ID)
return &topic, err
}
// Copy gives you a non-pointer concurrency safe copy of the reply
func (reply *Reply) Copy() Reply {
return *reply
}
func BlankReply() *Reply {
return &Reply{ID: 0}
}

View File

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

View File

@ -1,4 +1,4 @@
package main
package common
import (
"html"
@ -7,8 +7,6 @@ import (
"net"
"net/http"
"strings"
"./common"
)
// nolint
@ -16,28 +14,28 @@ var PreRoute func(http.ResponseWriter, *http.Request) (User, bool) = preRoute
// TODO: Come up with a better middleware solution
// nolint We need these types so people can tell what they are without scrolling to the bottom of the file
var PanelUserCheck func(http.ResponseWriter, *http.Request, *User) (*common.HeaderVars, common.PanelStats, RouteError) = panelUserCheck
var SimplePanelUserCheck func(http.ResponseWriter, *http.Request, *User) (*common.HeaderLite, RouteError) = simplePanelUserCheck
var SimpleForumUserCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *common.HeaderLite, err RouteError) = simpleForumUserCheck
var ForumUserCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *common.HeaderVars, err RouteError) = forumUserCheck
var MemberCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, err RouteError) = memberCheck
var UserCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, err RouteError) = userCheck
var UserCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, err RouteError) = userCheck
var PanelUserCheck func(http.ResponseWriter, *http.Request, *User) (*HeaderVars, PanelStats, RouteError) = panelUserCheck
var SimplePanelUserCheck func(http.ResponseWriter, *http.Request, *User) (*HeaderLite, RouteError) = simplePanelUserCheck
var SimpleForumUserCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *HeaderLite, err RouteError) = simpleForumUserCheck
var ForumUserCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *HeaderVars, err RouteError) = forumUserCheck
var MemberCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, err RouteError) = memberCheck
var SimpleUserCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, err RouteError) = simpleUserCheck
var UserCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, err RouteError) = userCheck
// TODO: Support for left sidebars and sidebars on both sides
// http.Request is for context.Context middleware. Mostly for plugin_guilds right now
func BuildWidgets(zone string, data interface{}, headerVars *common.HeaderVars, r *http.Request) {
if vhooks["intercept_build_widgets"] != nil {
if runVhook("intercept_build_widgets", zone, data, headerVars, r).(bool) {
func BuildWidgets(zone string, data interface{}, headerVars *HeaderVars, r *http.Request) {
if Vhooks["intercept_build_widgets"] != nil {
if RunVhook("intercept_build_widgets", zone, data, headerVars, r).(bool) {
return
}
}
//log.Print("themes[headerVars.ThemeName].Sidebars",themes[headerVars.ThemeName].Sidebars)
if themes[headerVars.ThemeName].Sidebars == "right" {
if len(docks.RightSidebar) != 0 {
//log.Print("Themes[headerVars.ThemeName].Sidebars", Themes[headerVars.ThemeName].Sidebars)
if Themes[headerVars.ThemeName].Sidebars == "right" {
if len(Docks.RightSidebar) != 0 {
var sbody string
for _, widget := range docks.RightSidebar {
for _, widget := range Docks.RightSidebar {
if widget.Enabled {
if widget.Location == "global" || widget.Location == zone {
sbody += widget.Body
@ -49,21 +47,21 @@ func BuildWidgets(zone string, data interface{}, headerVars *common.HeaderVars,
}
}
func simpleForumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *common.HeaderLite, rerr RouteError) {
if !fstore.Exists(fid) {
func simpleForumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *HeaderLite, rerr RouteError) {
if !Fstore.Exists(fid) {
return nil, PreError("The target forum doesn't exist.", w, r)
}
// Is there a better way of doing the skip AND the success flag on this hook like multiple returns?
if vhookSkippable["simple_forum_check_pre_perms"] != nil {
if VhookSkippable["simple_forum_check_pre_perms"] != nil {
var skip bool
skip, rerr = runVhookSkippable("simple_forum_check_pre_perms", w, r, user, &fid, &headerLite)
skip, rerr = RunVhookSkippable("simple_forum_check_pre_perms", w, r, user, &fid, &headerLite)
if skip || rerr != nil {
return headerLite, rerr
}
}
fperms, err := fpstore.Get(fid, user.Group)
fperms, err := Fpstore.Get(fid, user.Group)
if err != nil {
// TODO: Refactor this
log.Printf("Unable to get the forum perms for Group #%d for User #%d", user.Group, user.ID)
@ -73,24 +71,24 @@ func simpleForumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fi
return headerLite, nil
}
func forumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *common.HeaderVars, rerr RouteError) {
func forumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *HeaderVars, rerr RouteError) {
headerVars, rerr = UserCheck(w, r, user)
if rerr != nil {
return headerVars, rerr
}
if !fstore.Exists(fid) {
if !Fstore.Exists(fid) {
return headerVars, NotFound(w, r)
}
if vhookSkippable["forum_check_pre_perms"] != nil {
if VhookSkippable["forum_check_pre_perms"] != nil {
var skip bool
skip, rerr = runVhookSkippable("forum_check_pre_perms", w, r, user, &fid, &headerVars)
skip, rerr = RunVhookSkippable("forum_check_pre_perms", w, r, user, &fid, &headerVars)
if skip || rerr != nil {
return headerVars, rerr
}
}
fperms, err := fpstore.Get(fid, user.Group)
fperms, err := Fpstore.Get(fid, user.Group)
if err != nil {
// TODO: Refactor this
log.Printf("Unable to get the forum perms for Group #%d for User #%d", user.Group, user.ID)
@ -126,29 +124,29 @@ func cascadeForumPerms(fperms ForumPerms, user *User) {
// Even if they have the right permissions, the control panel is only open to supermods+. There are many areas without subpermissions which assume that the current user is a supermod+ and admins are extremely unlikely to give these permissions to someone who isn't at-least a supermod to begin with
// TODO: Do a panel specific theme?
func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, stats common.PanelStats, rerr RouteError) {
var themeName = defaultThemeBox.Load().(string)
func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, stats PanelStats, rerr RouteError) {
var themeName = DefaultThemeBox.Load().(string)
cookie, err := r.Cookie("current_theme")
if err == nil {
cookie := html.EscapeString(cookie.Value)
theme, ok := themes[cookie]
theme, ok := Themes[cookie]
if ok && !theme.HideFromThemes {
themeName = cookie
}
}
headerVars = &HeaderVars{
Site: site,
Settings: settingBox.Load().(SettingBox),
Themes: themes,
Site: Site,
Settings: SettingBox.Load().(SettingMap),
Themes: Themes,
ThemeName: themeName,
}
// TODO: We should probably initialise headerVars.ExtData
headerVars.Stylesheets = append(headerVars.Stylesheets, headerVars.ThemeName+"/panel.css")
if len(themes[headerVars.ThemeName].Resources) > 0 {
rlist := themes[headerVars.ThemeName].Resources
if len(Themes[headerVars.ThemeName].Resources) > 0 {
rlist := Themes[headerVars.ThemeName].Resources
for _, resource := range rlist {
if resource.Location == "global" || resource.Location == "panel" {
extarr := strings.Split(resource.Name, ".")
@ -162,16 +160,12 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerV
}
}
err = stmts.groupCount.QueryRow().Scan(&stats.Groups)
if err != nil {
return headerVars, stats, InternalError(err, w, r)
}
stats.Users = users.GlobalCount()
stats.Forums = fstore.GlobalCount() // TODO: Stop it from showing the blanked forums
stats.Users = Users.GlobalCount()
stats.Groups = Gstore.GlobalCount()
stats.Forums = Fstore.GlobalCount() // TODO: Stop it from showing the blanked forums
stats.Settings = len(headerVars.Settings)
stats.WordFilters = len(wordFilterBox.Load().(WordFilterBox))
stats.Themes = len(themes)
stats.WordFilters = len(WordFilterBox.Load().(WordFilterMap))
stats.Themes = len(Themes)
stats.Reports = 0 // TODO: Do the report count. Only show open threads?
pusher, ok := w.(http.Pusher)
@ -188,15 +182,15 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerV
return headerVars, stats, nil
}
func simplePanelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerLite *common.HeaderLite, rerr RouteError) {
func simplePanelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, rerr RouteError) {
return &HeaderLite{
Site: site,
Settings: settingBox.Load().(SettingBox),
Site: Site,
Settings: SettingBox.Load().(SettingMap),
}, nil
}
// TODO: Add this to the member routes
func memberCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, rerr RouteError) {
func memberCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, rerr RouteError) {
headerVars, rerr = UserCheck(w, r, user)
if !user.Loggedin {
return headerVars, NoPermissions(w, r, *user)
@ -205,31 +199,31 @@ func memberCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars
}
// SimpleUserCheck is back from the grave, yay :D
func simpleUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerLite *common.HeaderLite, rerr RouteError) {
func simpleUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, rerr RouteError) {
headerLite = &HeaderLite{
Site: site,
Settings: settingBox.Load().(SettingBox),
Site: Site,
Settings: SettingBox.Load().(SettingMap),
}
return headerLite, nil
}
// TODO: Add the ability for admins to restrict certain themes to certain groups?
func userCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *common.HeaderVars, rerr RouteError) {
var themeName = defaultThemeBox.Load().(string)
func userCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, rerr RouteError) {
var themeName = DefaultThemeBox.Load().(string)
cookie, err := r.Cookie("current_theme")
if err == nil {
cookie := html.EscapeString(cookie.Value)
theme, ok := themes[cookie]
theme, ok := Themes[cookie]
if ok && !theme.HideFromThemes {
themeName = cookie
}
}
headerVars = &HeaderVars{
Site: site,
Settings: settingBox.Load().(SettingBox),
Themes: themes,
Site: Site,
Settings: SettingBox.Load().(SettingMap),
Themes: Themes,
ThemeName: themeName,
}
@ -237,8 +231,8 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *
headerVars.NoticeList = append(headerVars.NoticeList, "Your account has been suspended. Some of your permissions may have been revoked.")
}
if len(themes[headerVars.ThemeName].Resources) > 0 {
rlist := themes[headerVars.ThemeName].Resources
if len(Themes[headerVars.ThemeName].Resources) > 0 {
rlist := Themes[headerVars.ThemeName].Resources
for _, resource := range rlist {
if resource.Location == "global" || resource.Location == "frontend" {
extarr := strings.Split(resource.Name, ".")
@ -266,27 +260,28 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *
}
func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) {
user, halt := auth.SessionCheck(w, r)
user, halt := Auth.SessionCheck(w, r)
if halt {
return *user, false
}
if user == &guestUser {
if user == &GuestUser {
return *user, true
}
var usercpy = *user
var usercpy *User
*usercpy = *user
// TODO: WIP. Refactor this to eliminate the unnecessary query
host, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
PreError("Bad IP", w, r)
return usercpy, false
return *usercpy, false
}
if host != usercpy.LastIP {
_, err = stmts.updateLastIP.Exec(host, usercpy.ID)
err = usercpy.UpdateIP(host)
if err != nil {
InternalError(err, w, r)
return usercpy, false
return *usercpy, false
}
usercpy.LastIP = host
}
@ -296,7 +291,7 @@ func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) {
//h.Set("X-XSS-Protection", "1")
// TODO: Set the content policy header
return usercpy, true
return *usercpy, true
}
// SuperModeOnly makes sure that only super mods or higher can access the panel routes

View File

@ -3,6 +3,7 @@ package common
import "strconv"
import "strings"
import "sync/atomic"
import "../query_gen/lib"
// SettingMap is a map type specifically for holding the various settings admins set to toggle features on and off or to otherwise alter Gosora's behaviour from the Control Panel
type SettingMap map[string]interface{}
@ -27,7 +28,12 @@ func init() {
}
func LoadSettings() error {
rows, err := stmts.getFullSettings.Query()
// TODO: Stop doing this inline
getFullSettings, err := qgen.Builder.SimpleSelect("settings", "name, content, type, constraints", "", "", "")
if err != nil {
return err
}
rows, err := getFullSettings.Query()
if err != nil {
return err
}

View File

@ -6,24 +6,31 @@ import (
"strings"
)
var site = &Site{Name: "Magical Fairy Land", Language: "english"}
var dbConfig = DBConfig{Host: "localhost"}
var config Config
var dev DevConfig
// Site holds the basic settings which should be tweaked when setting up a site, we might move them to the settings table at some point
var Site = &site{Name: "Magical Fairy Land", Language: "english"}
type Site struct {
// DbConfig holds the database configuration
var DbConfig = dbConfig{Host: "localhost"}
// Config holds the more technical settings
var Config config
// Dev holds build flags and other things which should only be modified during developers or to gather additional test data
var Dev devConfig
type site struct {
ShortName string
Name string // ? - Move this into the settings table? Should we make a second version of this for the abbreviation shown in the navbar?
Email string // ? - Move this into the settings table?
Name string
Email string
URL string
Port string
EnableSsl bool
EnableEmails bool
HasProxy bool
Language string // ? - Move this into the settings table?
Language string
}
type DBConfig struct {
type dbConfig struct {
// Production database
Host string
Username string
@ -39,7 +46,7 @@ type DBConfig struct {
TestPort string
}
type Config struct {
type config struct {
SslPrivkey string
SslFullchain string
@ -65,7 +72,7 @@ type Config struct {
ItemsPerPage int // ? - Move this into the settings table?
}
type DevConfig struct {
type devConfig struct {
DebugMode bool
SuperDebug bool
TemplateDebug bool
@ -73,35 +80,35 @@ type DevConfig struct {
TestDB bool
}
func processConfig() error {
config.Noavatar = strings.Replace(config.Noavatar, "{site_url}", site.URL, -1)
if site.Port != "80" && site.Port != "443" {
site.URL = strings.TrimSuffix(site.URL, "/")
site.URL = strings.TrimSuffix(site.URL, "\\")
site.URL = strings.TrimSuffix(site.URL, ":")
site.URL = site.URL + ":" + site.Port
func ProcessConfig() error {
Config.Noavatar = strings.Replace(Config.Noavatar, "{site_url}", Site.URL, -1)
if Site.Port != "80" && Site.Port != "443" {
Site.URL = strings.TrimSuffix(Site.URL, "/")
Site.URL = strings.TrimSuffix(Site.URL, "\\")
Site.URL = strings.TrimSuffix(Site.URL, ":")
Site.URL = Site.URL + ":" + Site.Port
}
// We need this in here rather than verifyConfig as switchToTestDB() currently overwrites the values it verifies
if dbConfig.TestDbname == dbConfig.Dbname {
if DbConfig.TestDbname == DbConfig.Dbname {
return errors.New("Your test database can't have the same name as your production database")
}
if dev.TestDB {
switchToTestDB()
if Dev.TestDB {
SwitchToTestDB()
}
return nil
}
func verifyConfig() error {
if !fstore.Exists(config.DefaultForum) {
func VerifyConfig() error {
if !Fstore.Exists(Config.DefaultForum) {
return errors.New("Invalid default forum")
}
return nil
}
func switchToTestDB() {
dbConfig.Host = dbConfig.TestHost
dbConfig.Username = dbConfig.TestUsername
dbConfig.Password = dbConfig.TestPassword
dbConfig.Dbname = dbConfig.TestDbname
dbConfig.Port = dbConfig.TestPort
func SwitchToTestDB() {
DbConfig.Host = DbConfig.TestHost
DbConfig.Username = DbConfig.TestUsername
DbConfig.Password = DbConfig.TestPassword
DbConfig.Dbname = DbConfig.TestDbname
DbConfig.Port = DbConfig.TestPort
}

View File

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

View File

@ -5,10 +5,12 @@ import (
"log"
"net/http"
"time"
"./templates"
)
var templates = template.New("")
var prebuildTmplList []func(*User, *HeaderVars) CTmpl
var Templates = template.New("")
var PrebuildTmplList []func(User, *HeaderVars) CTmpl
type CTmpl struct {
Name string
@ -20,11 +22,11 @@ type CTmpl struct {
// nolint
func interpreted_topic_template(pi TopicPage, w http.ResponseWriter) error {
mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap["topic"]
mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["topic"]
if !ok {
mapping = "topic"
}
return templates.ExecuteTemplate(w, mapping+".html", pi)
return Templates.ExecuteTemplate(w, mapping+".html", pi)
}
// nolint
@ -33,64 +35,66 @@ var template_topic_alt_handle func(TopicPage, http.ResponseWriter) error = inter
// nolint
var template_topics_handle func(TopicsPage, http.ResponseWriter) error = func(pi TopicsPage, w http.ResponseWriter) error {
mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap["topics"]
mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["topics"]
if !ok {
mapping = "topics"
}
return templates.ExecuteTemplate(w, mapping+".html", pi)
return Templates.ExecuteTemplate(w, mapping+".html", pi)
}
// nolint
var template_forum_handle func(ForumPage, http.ResponseWriter) error = func(pi ForumPage, w http.ResponseWriter) error {
mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap["forum"]
mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["forum"]
if !ok {
mapping = "forum"
}
return templates.ExecuteTemplate(w, mapping+".html", pi)
return Templates.ExecuteTemplate(w, mapping+".html", pi)
}
// nolint
var template_forums_handle func(ForumsPage, http.ResponseWriter) error = func(pi ForumsPage, w http.ResponseWriter) error {
mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap["forums"]
mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["forums"]
if !ok {
mapping = "forums"
}
return templates.ExecuteTemplate(w, mapping+".html", pi)
return Templates.ExecuteTemplate(w, mapping+".html", pi)
}
// nolint
var template_profile_handle func(ProfilePage, http.ResponseWriter) error = func(pi ProfilePage, w http.ResponseWriter) error {
mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap["profile"]
mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["profile"]
if !ok {
mapping = "profile"
}
return templates.ExecuteTemplate(w, mapping+".html", pi)
return Templates.ExecuteTemplate(w, mapping+".html", pi)
}
// nolint
var template_create_topic_handle func(CreateTopicPage, http.ResponseWriter) error = func(pi CreateTopicPage, w http.ResponseWriter) error {
mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap["create-topic"]
mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["create-topic"]
if !ok {
mapping = "create-topic"
}
return templates.ExecuteTemplate(w, mapping+".html", pi)
return Templates.ExecuteTemplate(w, mapping+".html", pi)
}
// ? - Add template hooks?
func compileTemplates() error {
var c CTemplateSet
var c tmpl.CTemplateSet
c.Minify(Config.MinifyTemplates)
c.SuperDebug(Dev.TemplateDebug)
// Schemas to train the template compiler on what to expect
// TODO: Add support for interface{}s
user := User{62, buildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0}
user := User{62, BuildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0}
// TODO: Do a more accurate level calculation for this?
user2 := User{1, buildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", "", "", "", "", 58, 1000, "127.0.0.1", 0}
user3 := User{2, buildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", "", "", "", "", 42, 900, "::1", 0}
user2 := User{1, BuildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", "", "", "", "", 58, 1000, "127.0.0.1", 0}
user3 := User{2, BuildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", "", "", "", "", 42, 900, "::1", 0}
headerVars := &HeaderVars{
Site: site,
Settings: settingBox.Load().(SettingBox),
Themes: themes,
ThemeName: defaultThemeBox.Load().(string),
Site: Site,
Settings: SettingBox.Load().(SettingMap),
Themes: Themes,
ThemeName: DefaultThemeBox.Load().(string),
NoticeList: []string{"test"},
Stylesheets: []string{"panel"},
Scripts: []string{"whatever"},
@ -102,31 +106,31 @@ func compileTemplates() error {
log.Print("Compiling the templates")
var now = time.Now()
topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, now, relativeTime(now), now, relativeTime(now), 0, "", "127.0.0.1", 0, 1, "classname", "weird-data", buildProfileURL("fake-user", 62), "Fake User", config.DefaultGroup, "", 0, "", "", "", "", "", 58, false}
topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, now, RelativeTime(now), now, RelativeTime(now), 0, "", "127.0.0.1", 0, 1, "classname", "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, "", 0, "", "", "", "", "", 58, false}
var replyList []ReplyUser
replyList = append(replyList, ReplyUser{0, 0, "Yo!", "Yo!", 0, "alice", "Alice", config.DefaultGroup, now, relativeTime(now), 0, 0, "", "", 0, "", "", "", "", 0, "127.0.0.1", false, 1, "", ""})
replyList = append(replyList, ReplyUser{0, 0, "Yo!", "Yo!", 0, "alice", "Alice", Config.DefaultGroup, now, RelativeTime(now), 0, 0, "", "", 0, "", "", "", "", 0, "127.0.0.1", false, 1, "", ""})
var varList = make(map[string]VarItem)
var varList = make(map[string]tmpl.VarItem)
tpage := TopicPage{"Title", user, headerVars, replyList, topic, 1, 1}
topicIDTmpl, err := c.compileTemplate("topic.html", "templates/", "TopicPage", tpage, varList)
topicIDTmpl, err := c.Compile("topic.html", "templates/", "TopicPage", tpage, varList)
if err != nil {
return err
}
topicIDAltTmpl, err := c.compileTemplate("topic_alt.html", "templates/", "TopicPage", tpage, varList)
topicIDAltTmpl, err := c.Compile("topic_alt.html", "templates/", "TopicPage", tpage, varList)
if err != nil {
return err
}
varList = make(map[string]VarItem)
varList = make(map[string]tmpl.VarItem)
ppage := ProfilePage{"User 526", user, headerVars, replyList, user}
profileTmpl, err := c.compileTemplate("profile.html", "templates/", "ProfilePage", ppage, varList)
profileTmpl, err := c.Compile("profile.html", "templates/", "ProfilePage", ppage, varList)
if err != nil {
return err
}
// TODO: Use a dummy forum list to avoid o(n) problems
var forumList []Forum
forums, err := fstore.GetAll()
forums, err := Fstore.GetAll()
if err != nil {
return err
}
@ -135,17 +139,17 @@ func compileTemplates() error {
//log.Printf("*forum %+v\n", *forum)
forumList = append(forumList, *forum)
}
varList = make(map[string]VarItem)
varList = make(map[string]tmpl.VarItem)
forumsPage := ForumsPage{"Forum List", user, headerVars, forumList}
forumsTmpl, err := c.compileTemplate("forums.html", "templates/", "ForumsPage", forumsPage, varList)
forumsTmpl, err := c.Compile("forums.html", "templates/", "ForumsPage", forumsPage, varList)
if err != nil {
return err
}
var topicsList []*TopicsRow
topicsList = append(topicsList, &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, "Date", time.Now(), "Date", user3.ID, 1, "", "127.0.0.1", 0, 1, "classname", "", &user2, "", 0, &user3, "General", "/forum/general.2"})
topicsPage := TopicsPage{"Topic List", user, headerVars, topicsList, forumList, config.DefaultForum}
topicsTmpl, err := c.compileTemplate("topics.html", "templates/", "TopicsPage", topicsPage, varList)
topicsPage := TopicsPage{"Topic List", user, headerVars, topicsList, forumList, Config.DefaultForum}
topicsTmpl, err := c.Compile("topics.html", "templates/", "TopicsPage", topicsPage, varList)
if err != nil {
return err
}
@ -154,20 +158,20 @@ func compileTemplates() error {
//topicList = append(topicList,TopicUser{1,"topic-title","Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"classname","","admin-fred","Admin Fred",config.DefaultGroup,"",0,"","","","",58,false})
forumItem := makeDummyForum(1, "general-forum.1", "General Forum", "Where the general stuff happens", true, "all", 0, "", 0)
forumPage := ForumPage{"General Forum", user, headerVars, topicsList, forumItem, 1, 1}
forumTmpl, err := c.compileTemplate("forum.html", "templates/", "ForumPage", forumPage, varList)
forumTmpl, err := c.Compile("forum.html", "templates/", "ForumPage", forumPage, varList)
if err != nil {
return err
}
// Let plugins register their own templates
for _, tmplfunc := range prebuildTmplList {
tmpl := tmplfunc(user, headerVars)
varList = make(map[string]VarItem)
compiledTmpl, err := c.compileTemplate(tmpl.Filename, tmpl.Path, tmpl.StructName, tmpl.Data, varList)
for _, tmplfunc := range PrebuildTmplList {
tmplItem := tmplfunc(user, headerVars)
varList = make(map[string]tmpl.VarItem)
compiledTmpl, err := c.Compile(tmplItem.Filename, tmplItem.Path, tmplItem.StructName, tmplItem.Data, varList)
if err != nil {
return err
}
go writeTemplate(tmpl.Name, compiledTmpl)
go writeTemplate(tmplItem.Name, compiledTmpl)
}
log.Print("Writing the templates")
@ -194,8 +198,8 @@ func writeTemplate(name string, content string) {
}
}
func initTemplates() {
if dev.DebugMode {
func InitTemplates() {
if Dev.DebugMode {
log.Print("Initialising the template system")
}
compileTemplates()
@ -259,10 +263,10 @@ func initTemplates() {
}
// The interpreted templates...
if dev.DebugMode {
if Dev.DebugMode {
log.Print("Loading the template files...")
}
templates.Funcs(fmap)
template.Must(templates.ParseGlob("templates/*"))
template.Must(templates.ParseGlob("pages/*"))
Templates.Funcs(fmap)
template.Must(Templates.ParseGlob("templates/*"))
template.Must(Templates.ParseGlob("pages/*"))
}

View File

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

View File

@ -17,13 +17,15 @@ import (
"sync"
"sync/atomic"
"text/template"
"../query_gen/lib"
)
type ThemeList map[string]Theme
//var themes ThemeList = make(map[string]Theme)
var Themes ThemeList = make(map[string]Theme)
var DefaultThemeBox atomic.Value
var changeDefaultThemeMutex sync.Mutex
var ChangeDefaultThemeMutex sync.Mutex
// TODO: Use this when the default theme doesn't exist
var fallbackTheme = "shadow"
@ -73,14 +75,19 @@ type ThemeResource struct {
}
func init() {
defaultThemeBox.Store(fallbackTheme)
DefaultThemeBox.Store(fallbackTheme)
}
// TODO: Make the initThemes and LoadThemes functions less confusing
// ? - Delete themes which no longer exist in the themes folder from the database?
func LoadThemeActiveStatus() error {
changeDefaultThemeMutex.Lock()
rows, err := stmts.getThemes.Query()
func (themes ThemeList) LoadActiveStatus() error {
getThemes, err := qgen.Builder.SimpleSelect("themes", "uname, default", "", "", "")
if err != nil {
return err
}
ChangeDefaultThemeMutex.Lock()
rows, err := getThemes.Query()
if err != nil {
return err
}
@ -103,8 +110,8 @@ func LoadThemeActiveStatus() error {
if defaultThemeSwitch {
log.Print("Loading the default theme '" + theme.Name + "'")
theme.Active = true
defaultThemeBox.Store(theme.Name)
mapThemeTemplates(theme)
DefaultThemeBox.Store(theme.Name)
MapThemeTemplates(theme)
} else {
log.Print("Loading the theme '" + theme.Name + "'")
theme.Active = false
@ -112,11 +119,11 @@ func LoadThemeActiveStatus() error {
themes[uname] = theme
}
changeDefaultThemeMutex.Unlock()
ChangeDefaultThemeMutex.Unlock()
return rows.Err()
}
func initThemes() error {
func InitThemes() error {
themeFiles, err := ioutil.ReadDir("./themes")
if err != nil {
return err
@ -156,10 +163,10 @@ func initThemes() error {
}
if theme.FullImage != "" {
if dev.DebugMode {
if Dev.DebugMode {
log.Print("Adding theme image")
}
err = addStaticFile("./themes/"+themeName+"/"+theme.FullImage, "./themes/"+themeName)
err = StaticFiles.Add("./themes/"+themeName+"/"+theme.FullImage, "./themes/"+themeName)
if err != nil {
return err
}
@ -170,7 +177,7 @@ func initThemes() error {
if theme.Templates != nil {
for _, themeTmpl := range theme.Templates {
theme.TemplatesMap[themeTmpl.Name] = themeTmpl.Source
theme.TmplPtr[themeTmpl.Name] = tmplPtrMap["o_"+themeTmpl.Source]
theme.TmplPtr[themeTmpl.Name] = TmplPtrMap["o_"+themeTmpl.Source]
}
}
@ -178,20 +185,20 @@ func initThemes() error {
template.Must(theme.ResourceTemplates.ParseGlob("./themes/" + theme.Name + "/public/*.css"))
// It should be safe for us to load the files for all the themes in memory, as-long as the admin hasn't setup a ridiculous number of themes
err = addThemeStaticFiles(theme)
err = AddThemeStaticFiles(theme)
if err != nil {
return err
}
themes[theme.Name] = theme
Themes[theme.Name] = theme
}
return nil
}
func addThemeStaticFiles(theme Theme) error {
func AddThemeStaticFiles(theme Theme) error {
// TODO: Use a function instead of a closure to make this more testable? What about a function call inside the closure to take the theme variable into account?
return filepath.Walk("./themes/"+theme.Name+"/public", func(path string, f os.FileInfo, err error) error {
if dev.DebugMode {
if Dev.DebugMode {
log.Print("Attempting to add static file '" + path + "' for default theme '" + theme.Name + "'")
}
if err != nil {
@ -224,16 +231,16 @@ func addThemeStaticFiles(theme Theme) error {
path = strings.TrimPrefix(path, "themes/"+theme.Name+"/public")
gzipData := compressBytesGzip(data)
staticFiles["/static/"+theme.Name+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}
StaticFiles["/static/"+theme.Name+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}
if dev.DebugMode {
if Dev.DebugMode {
log.Print("Added the '/" + theme.Name + path + "' static file for theme " + theme.Name + ".")
}
return nil
})
}
func mapThemeTemplates(theme Theme) {
func MapThemeTemplates(theme Theme) {
if theme.Templates != nil {
for _, themeTmpl := range theme.Templates {
if themeTmpl.Name == "" {
@ -245,11 +252,11 @@ func mapThemeTemplates(theme Theme) {
// `go generate` is one possibility for letting plugins inject custom page structs, but it would simply add another step of compilation. It might be simpler than the current build process from the perspective of the administrator?
destTmplPtr, ok := tmplPtrMap[themeTmpl.Name]
destTmplPtr, ok := TmplPtrMap[themeTmpl.Name]
if !ok {
return
}
sourceTmplPtr, ok := tmplPtrMap[themeTmpl.Source]
sourceTmplPtr, ok := TmplPtrMap[themeTmpl.Source]
if !ok {
log.Fatal("The source template doesn't exist!")
}
@ -325,20 +332,20 @@ func mapThemeTemplates(theme Theme) {
}
}
func resetTemplateOverrides() {
func ResetTemplateOverrides() {
log.Print("Resetting the template overrides")
for name := range overridenTemplates {
log.Print("Resetting '" + name + "' template override")
originPointer, ok := tmplPtrMap["o_"+name]
originPointer, ok := TmplPtrMap["o_"+name]
if !ok {
//log.Fatal("The origin template doesn't exist!")
log.Print("The origin template doesn't exist!")
return
}
destTmplPtr, ok := tmplPtrMap[name]
destTmplPtr, ok := TmplPtrMap[name]
if !ok {
//log.Fatal("The destination template doesn't exist!")
log.Print("The destination template doesn't exist!")
@ -447,11 +454,11 @@ func RunThemeTemplate(theme string, template string, pi interface{}, w http.Resp
case func(Page, http.ResponseWriter) error:
return tmplO(pi.(Page), w)
case string:
mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap[template]
mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap[template]
if !ok {
mapping = template
}
return templates.ExecuteTemplate(w, mapping+".html", pi)
return Templates.ExecuteTemplate(w, mapping+".html", pi)
default:
log.Print("theme ", theme)
log.Print("template ", template)
@ -474,11 +481,11 @@ func RunThemeTemplate(theme string, template string, pi interface{}, w http.Resp
// GetThemeTemplate attempts to get the template for a specific theme, otherwise it falls back on the default template pointer, which if absent will fallback onto the template interpreter
func GetThemeTemplate(theme string, template string) interface{} {
tmpl, ok := themes[theme].TmplPtr[template]
tmpl, ok := Themes[theme].TmplPtr[template]
if ok {
return tmpl
}
tmpl, ok = tmplPtrMap[template]
tmpl, ok = TmplPtrMap[template]
if ok {
return tmpl
}
@ -487,19 +494,19 @@ func GetThemeTemplate(theme string, template string) interface{} {
// CreateThemeTemplate creates a theme template on the current default theme
func CreateThemeTemplate(theme string, name string) {
themes[theme].TmplPtr[name] = func(pi Page, w http.ResponseWriter) error {
mapping, ok := themes[defaultThemeBox.Load().(string)].TemplatesMap[name]
Themes[theme].TmplPtr[name] = func(pi Page, w http.ResponseWriter) error {
mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap[name]
if !ok {
mapping = name
}
return templates.ExecuteTemplate(w, mapping+".html", pi)
return Templates.ExecuteTemplate(w, mapping+".html", pi)
}
}
func GetDefaultThemeName() string {
return defaultThemeBox.Load().(string)
return DefaultThemeBox.Load().(string)
}
func SetDefaultThemeName(name string) {
defaultThemeBox.Store(name)
DefaultThemeBox.Store(name)
}

View File

@ -6,12 +6,14 @@
*/
package common
//import "fmt"
import (
"database/sql"
"html"
"html/template"
"strconv"
"time"
"../query_gen/lib"
)
// This is also in reply.go
@ -105,10 +107,49 @@ type TopicsRow struct {
ForumLink string
}
type TopicStmts struct {
addRepliesToTopic *sql.Stmt
lock *sql.Stmt
unlock *sql.Stmt
stick *sql.Stmt
unstick *sql.Stmt
hasLikedTopic *sql.Stmt
createLike *sql.Stmt
addLikesToTopic *sql.Stmt
delete *sql.Stmt
edit *sql.Stmt
createActionReply *sql.Stmt
getTopicUser *sql.Stmt // TODO: Can we get rid of this?
}
var topicStmts TopicStmts
func init() {
DbInits.Add(func() error {
acc := qgen.Builder.Accumulator()
topicStmts = TopicStmts{
addRepliesToTopic: acc.SimpleUpdate("topics", "postCount = postCount + ?, lastReplyBy = ?, lastReplyAt = UTC_TIMESTAMP()", "tid = ?"),
lock: acc.SimpleUpdate("topics", "is_closed = 1", "tid = ?"),
unlock: acc.SimpleUpdate("topics", "is_closed = 0", "tid = ?"),
stick: acc.SimpleUpdate("topics", "sticky = 1", "tid = ?"),
unstick: acc.SimpleUpdate("topics", "sticky = 0", "tid = ?"),
hasLikedTopic: acc.SimpleSelect("likes", "targetItem", "sentBy = ? and targetItem = ? and targetType = 'topics'", "", ""),
createLike: acc.SimpleInsert("likes", "weight, targetItem, targetType, sentBy", "?,?,?,?"),
addLikesToTopic: acc.SimpleUpdate("topics", "likeCount = likeCount + ?", "tid = ?"),
delete: acc.SimpleDelete("topics", "tid = ?"),
edit: acc.SimpleUpdate("topics", "title = ?, content = ?, parsed_content = ?", "tid = ?"),
createActionReply: acc.SimpleInsert("replies", "tid, actionType, ipaddress, createdBy, createdAt, lastUpdated, content, parsed_content", "?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'',''"),
getTopicUser: acc.SimpleLeftJoin("topics", "users", "topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level", "topics.createdBy = users.uid", "tid = ?", "", ""),
}
return acc.FirstError()
})
}
// Flush the topic out of the cache
// ? - We do a CacheRemove() here instead of mutating the pointer to avoid creating a race condition
func (topic *Topic) cacheRemove() {
tcache, ok := topics.(TopicCache)
tcache, ok := Topics.(TopicCache)
if ok {
tcache.CacheRemove(topic.ID)
}
@ -116,32 +157,32 @@ func (topic *Topic) cacheRemove() {
// TODO: Write a test for this
func (topic *Topic) AddReply(uid int) (err error) {
_, err = stmts.addRepliesToTopic.Exec(1, uid, topic.ID)
_, err = topicStmts.addRepliesToTopic.Exec(1, uid, topic.ID)
topic.cacheRemove()
return err
}
func (topic *Topic) Lock() (err error) {
_, err = stmts.lockTopic.Exec(topic.ID)
_, err = topicStmts.lock.Exec(topic.ID)
topic.cacheRemove()
return err
}
func (topic *Topic) Unlock() (err error) {
_, err = stmts.unlockTopic.Exec(topic.ID)
_, err = topicStmts.unlock.Exec(topic.ID)
topic.cacheRemove()
return err
}
// TODO: We might want more consistent terminology rather than using stick in some places and pin in others. If you don't understand the difference, there is none, they are one and the same.
func (topic *Topic) Stick() (err error) {
_, err = stmts.stickTopic.Exec(topic.ID)
_, err = topicStmts.stick.Exec(topic.ID)
topic.cacheRemove()
return err
}
func (topic *Topic) Unstick() (err error) {
_, err = stmts.unstickTopic.Exec(topic.ID)
_, err = topicStmts.unstick.Exec(topic.ID)
topic.cacheRemove()
return err
}
@ -150,19 +191,19 @@ func (topic *Topic) Unstick() (err error) {
// TODO: Use a transaction for this
func (topic *Topic) Like(score int, uid int) (err error) {
var tid int // Unused
err = stmts.hasLikedTopic.QueryRow(uid, topic.ID).Scan(&tid)
err = topicStmts.hasLikedTopic.QueryRow(uid, topic.ID).Scan(&tid)
if err != nil && err != ErrNoRows {
return err
} else if err != ErrNoRows {
return ErrAlreadyLiked
}
_, err = stmts.createLike.Exec(score, tid, "topics", uid)
_, err = topicStmts.createLike.Exec(score, tid, "topics", uid)
if err != nil {
return err
}
_, err = stmts.addLikesToTopic.Exec(1, tid)
_, err = topicStmts.addLikesToTopic.Exec(1, tid)
topic.cacheRemove()
return err
}
@ -174,10 +215,10 @@ func (topic *Topic) Unlike(uid int) error {
// TODO: Use a transaction here
func (topic *Topic) Delete() error {
topicCreator, err := users.Get(topic.CreatedBy)
topicCreator, err := Users.Get(topic.CreatedBy)
if err == nil {
wcount := wordCount(topic.Content)
err = topicCreator.decreasePostStats(wcount, true)
wcount := WordCount(topic.Content)
err = topicCreator.DecreasePostStats(wcount, true)
if err != nil {
return err
}
@ -185,31 +226,31 @@ func (topic *Topic) Delete() error {
return err
}
err = fstore.RemoveTopic(topic.ParentID)
err = Fstore.RemoveTopic(topic.ParentID)
if err != nil && err != ErrNoRows {
return err
}
_, err = stmts.deleteTopic.Exec(topic.ID)
_, err = topicStmts.delete.Exec(topic.ID)
topic.cacheRemove()
return err
}
func (topic *Topic) Update(name string, content string) error {
content = preparseMessage(content)
parsed_content := parseMessage(html.EscapeString(content), topic.ParentID, "forums")
_, err := stmts.editTopic.Exec(name, content, parsed_content, topic.ID)
content = PreparseMessage(content)
parsedContent := ParseMessage(html.EscapeString(content), topic.ParentID, "forums")
_, err := topicStmts.edit.Exec(name, content, parsedContent, topic.ID)
topic.cacheRemove()
return err
}
// TODO: Have this go through the ReplyStore?
func (topic *Topic) CreateActionReply(action string, ipaddress string, user User) (err error) {
_, err = stmts.createActionReply.Exec(topic.ID, action, ipaddress, user.ID)
_, err = topicStmts.createActionReply.Exec(topic.ID, action, ipaddress, user.ID)
if err != nil {
return err
}
_, err = stmts.addRepliesToTopic.Exec(1, user.ID, topic.ID)
_, err = topicStmts.addRepliesToTopic.Exec(1, user.ID, topic.ID)
topic.cacheRemove()
// ? - Update the last topic cache for the parent forum?
return err
@ -221,13 +262,13 @@ func (topic *Topic) Copy() Topic {
}
// TODO: Refactor the caller to take a Topic and a User rather than a combined TopicUser
func getTopicUser(tid int) (TopicUser, error) {
tcache, tok := topics.(TopicCache)
ucache, uok := users.(UserCache)
func GetTopicUser(tid int) (TopicUser, error) {
tcache, tok := Topics.(TopicCache)
ucache, uok := Users.(UserCache)
if tok && uok {
topic, err := tcache.CacheGet(tid)
if err == nil {
user, err := users.Get(topic.CreatedBy)
user, err := Users.Get(topic.CreatedBy)
if err != nil {
return TopicUser{ID: tid}, err
}
@ -235,11 +276,11 @@ func getTopicUser(tid int) (TopicUser, error) {
// We might be better off just passing separate topic and user structs to the caller?
return copyTopicToTopicUser(topic, user), nil
} else if ucache.Length() < ucache.GetCapacity() {
topic, err = topics.Get(tid)
topic, err = Topics.Get(tid)
if err != nil {
return TopicUser{ID: tid}, err
}
user, err := users.Get(topic.CreatedBy)
user, err := Users.Get(topic.CreatedBy)
if err != nil {
return TopicUser{ID: tid}, err
}
@ -248,14 +289,14 @@ func getTopicUser(tid int) (TopicUser, error) {
}
tu := TopicUser{ID: tid}
err := stmts.getTopicUser.QueryRow(tid).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
tu.Link = buildTopicURL(nameToSlug(tu.Title), tu.ID)
tu.UserLink = buildProfileURL(nameToSlug(tu.CreatedByName), tu.CreatedBy)
tu.Tag = gstore.DirtyGet(tu.Group).Tag
err := topicStmts.getTopicUser.QueryRow(tid).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
tu.Link = BuildTopicURL(NameToSlug(tu.Title), tu.ID)
tu.UserLink = BuildProfileURL(NameToSlug(tu.CreatedByName), tu.CreatedBy)
tu.Tag = Gstore.DirtyGet(tu.Group).Tag
if tok {
theTopic := Topic{ID: tu.ID, Link: tu.Link, Title: tu.Title, Content: tu.Content, CreatedBy: tu.CreatedBy, IsClosed: tu.IsClosed, Sticky: tu.Sticky, CreatedAt: tu.CreatedAt, LastReplyAt: tu.LastReplyAt, ParentID: tu.ParentID, IPAddress: tu.IPAddress, PostCount: tu.PostCount, LikeCount: tu.LikeCount}
//log.Printf("the_topic: %+v\n", theTopic)
//log.Printf("theTopic: %+v\n", theTopic)
_ = tcache.CacheAdd(&theTopic)
}
return tu, err
@ -289,18 +330,11 @@ func copyTopicToTopicUser(topic *Topic, user *User) (tu TopicUser) {
}
// For use in tests and for generating blank topics for forums which don't have a last poster
func getDummyTopic() *Topic {
func BlankTopic() *Topic {
return &Topic{ID: 0, Title: ""}
}
func getTopicByReply(rid int) (*Topic, error) {
topic := Topic{ID: 0}
err := stmts.getTopicByReply.QueryRow(rid).Scan(&topic.ID, &topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
topic.Link = buildTopicURL(nameToSlug(topic.Title), topic.ID)
return &topic, err
}
func buildTopicURL(slug string, tid int) string {
func BuildTopicURL(slug string, tid int) string {
if slug == "" {
return "/topic/" + strconv.Itoa(tid)
}

View File

@ -20,11 +20,12 @@ import (
// TODO: Add BulkGetMap
// TODO: Add some sort of update method
// ? - Should we add stick, lock, unstick, and unlock methods? These might be better on the Topics not the TopicStore
var topics TopicStore
var Topics TopicStore
var ErrNoTitle = errors.New("This message is missing a title")
var ErrNoBody = errors.New("This message is missing a body")
type TopicStore interface {
DirtyGet(id int) *Topic
Get(id int) (*Topic, error)
BypassGet(id int) (*Topic, error)
Exists(id int) bool
@ -93,6 +94,24 @@ func (mts *MemoryTopicStore) CacheGetUnsafe(id int) (*Topic, error) {
return item, ErrNoRows
}
func (mts *MemoryTopicStore) DirtyGet(id int) *Topic {
mts.RLock()
topic, ok := mts.items[id]
mts.RUnlock()
if ok {
return topic
}
topic = &Topic{ID: id}
err := mts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
if err == nil {
topic.Link = BuildTopicURL(NameToSlug(topic.Title), id)
_ = mts.CacheAdd(topic)
return topic
}
return BlankTopic()
}
func (mts *MemoryTopicStore) Get(id int) (*Topic, error) {
mts.RLock()
topic, ok := mts.items[id]
@ -104,7 +123,7 @@ func (mts *MemoryTopicStore) Get(id int) (*Topic, error) {
topic = &Topic{ID: id}
err := mts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
if err == nil {
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
topic.Link = BuildTopicURL(NameToSlug(topic.Title), id)
_ = mts.CacheAdd(topic)
}
return topic, err
@ -114,7 +133,7 @@ func (mts *MemoryTopicStore) Get(id int) (*Topic, error) {
func (mts *MemoryTopicStore) BypassGet(id int) (*Topic, error) {
topic := &Topic{ID: id}
err := mts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
topic.Link = BuildTopicURL(NameToSlug(topic.Title), id)
return topic, err
}
@ -122,7 +141,7 @@ func (mts *MemoryTopicStore) Reload(id int) error {
topic := &Topic{ID: id}
err := mts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
if err == nil {
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
topic.Link = BuildTopicURL(NameToSlug(topic.Title), id)
_ = mts.CacheSet(topic)
} else {
_ = mts.CacheRemove(id)
@ -141,12 +160,12 @@ func (mts *MemoryTopicStore) Create(fid int, topicName string, content string, u
}
content = strings.TrimSpace(content)
parsedContent := parseMessage(content, fid, "forums")
parsedContent := ParseMessage(content, fid, "forums")
if strings.TrimSpace(parsedContent) == "" {
return 0, ErrNoBody
}
wcount := wordCount(content)
wcount := WordCount(content)
// TODO: Move this statement into the topic store
res, err := mts.create.Exec(fid, topicName, content, parsedContent, uid, ipaddress, wcount, uid)
if err != nil {
@ -158,8 +177,7 @@ func (mts *MemoryTopicStore) Create(fid int, topicName string, content string, u
return 0, err
}
err = fstore.AddTopic(int(lastID), uid, fid)
return int(lastID), err
return int(lastID), Fstore.AddTopic(int(lastID), uid, fid)
}
func (mts *MemoryTopicStore) CacheSet(item *Topic) error {
@ -268,10 +286,20 @@ func NewSQLTopicStore() (*SQLTopicStore, error) {
}, acc.FirstError()
}
func (sts *SQLTopicStore) DirtyGet(id int) *Topic {
topic := &Topic{ID: id}
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
topic.Link = BuildTopicURL(NameToSlug(topic.Title), id)
if err != nil {
return BlankTopic()
}
return topic
}
func (sts *SQLTopicStore) Get(id int) (*Topic, error) {
topic := Topic{ID: id}
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
topic.Link = BuildTopicURL(NameToSlug(topic.Title), id)
return &topic, err
}
@ -279,7 +307,7 @@ func (sts *SQLTopicStore) Get(id int) (*Topic, error) {
func (sts *SQLTopicStore) BypassGet(id int) (*Topic, error) {
topic := &Topic{ID: id}
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
topic.Link = BuildTopicURL(NameToSlug(topic.Title), id)
return topic, err
}
@ -294,12 +322,12 @@ func (sts *SQLTopicStore) Create(fid int, topicName string, content string, uid
}
content = strings.TrimSpace(content)
parsedContent := parseMessage(content, fid, "forums")
parsedContent := ParseMessage(content, fid, "forums")
if strings.TrimSpace(parsedContent) == "" {
return 0, ErrNoBody
}
wcount := wordCount(content)
wcount := WordCount(content)
// TODO: Move this statement into the topic store
res, err := sts.create.Exec(fid, topicName, content, parsedContent, uid, ipaddress, wcount, uid)
if err != nil {
@ -311,8 +339,7 @@ func (sts *SQLTopicStore) Create(fid int, topicName string, content string, uid
return 0, err
}
err = fstore.AddTopic(int(lastID), uid, fid)
return int(lastID), err
return int(lastID), Fstore.AddTopic(int(lastID), uid, fid)
}
// ? - What're we going to do about this?

View File

@ -15,12 +15,14 @@ import (
"strings"
"time"
"../query_gen/lib"
"golang.org/x/crypto/bcrypt"
)
// TODO: Replace any literals with this
var BanGroup = 4
// GuestUser is an instance of user which holds guest data to avoid having to initialise a guest every time
var GuestUser = User{ID: 0, Link: "#", Group: 6, Perms: GuestPerms}
//func(real_password string, password string, salt string) (err error)
@ -57,12 +59,48 @@ type User struct {
TempGroup int
}
type Email struct {
UserID int
Email string
Validated bool
Primary bool
Token string
type UserStmts struct {
activate *sql.Stmt
changeGroup *sql.Stmt
delete *sql.Stmt
setAvatar *sql.Stmt
setUsername *sql.Stmt
updateGroup *sql.Stmt
incrementTopics *sql.Stmt
updateLevel *sql.Stmt
incrementScore *sql.Stmt
incrementPosts *sql.Stmt
incrementBigposts *sql.Stmt
incrementMegaposts *sql.Stmt
updateLastIP *sql.Stmt
setPassword *sql.Stmt
}
var userStmts UserStmts
func init() {
DbInits.Add(func() error {
acc := qgen.Builder.Accumulator()
userStmts = UserStmts{
activate: acc.SimpleUpdate("users", "active = 1", "uid = ?"),
changeGroup: acc.SimpleUpdate("users", "group = ?", "uid = ?"),
delete: acc.SimpleDelete("users", "uid = ?"),
setAvatar: acc.SimpleUpdate("users", "avatar = ?", "uid = ?"),
setUsername: acc.SimpleUpdate("users", "name = ?", "uid = ?"),
updateGroup: acc.SimpleUpdate("users", "group = ?", "uid = ?"),
incrementTopics: acc.SimpleUpdate("users", "topics = topics + ?", "uid = ?"),
updateLevel: acc.SimpleUpdate("users", "level = ?", "uid = ?"),
incrementScore: acc.SimpleUpdate("users", "score = score + ?", "uid = ?"),
incrementPosts: acc.SimpleUpdate("users", "posts = posts + ?", "uid = ?"),
incrementBigposts: acc.SimpleUpdate("users", "posts = posts + ?, bigposts = bigposts + ?", "uid = ?"),
incrementMegaposts: acc.SimpleUpdate("users", "posts = posts + ?, bigposts = bigposts + ?, megaposts = megaposts + ?", "uid = ?"),
updateLastIP: acc.SimpleUpdate("users", "last_ip = ?", "uid = ?"),
setPassword: acc.SimpleUpdate("users", "password = ?, salt = ?", "uid = ?"),
}
return acc.FirstError()
})
}
func (user *User) Init() {
@ -71,15 +109,22 @@ func (user *User) Init() {
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + user.Avatar
}
} else {
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
user.Avatar = strings.Replace(Config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
}
user.Link = BuildProfileURL(NameToSlug(user.Name), user.ID)
user.Tag = Gstore.DirtyGet(user.Group).Tag
user.InitPerms()
}
func (user *User) CacheRemove() {
ucache, ok := Users.(UserCache)
if ok {
ucache.CacheRemove(user.ID)
}
user.Link = buildProfileURL(nameToSlug(user.Name), user.ID)
user.Tag = gstore.DirtyGet(user.Group).Tag
user.initPerms()
}
func (user *User) Ban(duration time.Duration, issuedBy int) error {
return user.ScheduleGroupUpdate(banGroup, issuedBy, duration)
return user.ScheduleGroupUpdate(BanGroup, issuedBy, duration)
}
func (user *User) Unban() error {
@ -112,7 +157,7 @@ func (user *User) ScheduleGroupUpdate(gid int, issuedBy int, duration time.Durat
}
revertAt := time.Now().Add(duration)
tx, err := db.Begin()
tx, err := qgen.Builder.Begin()
if err != nil {
return err
}
@ -138,15 +183,12 @@ func (user *User) ScheduleGroupUpdate(gid int, issuedBy int, duration time.Durat
}
err = tx.Commit()
ucache, ok := users.(UserCache)
if ok {
ucache.CacheRemove(user.ID)
}
user.CacheRemove()
return err
}
func (user *User) RevertGroupUpdate() error {
tx, err := db.Begin()
tx, err := qgen.Builder.Begin()
if err != nil {
return err
}
@ -163,25 +205,19 @@ func (user *User) RevertGroupUpdate() error {
}
err = tx.Commit()
ucache, ok := users.(UserCache)
if ok {
ucache.CacheRemove(user.ID)
}
user.CacheRemove()
return err
}
// TODO: Use a transaction here
// ? - Add a Deactivate method? Not really needed, if someone's been bad you could do a ban, I guess it might be useful, if someone says that email x isn't actually owned by the user in question?
func (user *User) Activate() (err error) {
_, err = stmts.activateUser.Exec(user.ID)
_, err = userStmts.activate.Exec(user.ID)
if err != nil {
return err
}
_, err = stmts.changeGroup.Exec(config.DefaultGroup, user.ID)
ucache, ok := users.(UserCache)
if ok {
ucache.CacheRemove(user.ID)
}
_, err = userStmts.changeGroup.Exec(Config.DefaultGroup, user.ID)
user.CacheRemove()
return err
}
@ -189,111 +225,105 @@ func (user *User) Activate() (err error) {
// TODO: Delete this user's content too?
// TODO: Expose this to the admin?
func (user *User) Delete() error {
_, err := stmts.deleteUser.Exec(user.ID)
_, err := userStmts.delete.Exec(user.ID)
if err != nil {
return err
}
ucache, ok := users.(UserCache)
if ok {
ucache.CacheRemove(user.ID)
}
user.CacheRemove()
return err
}
func (user *User) ChangeName(username string) (err error) {
_, err = stmts.setUsername.Exec(username, user.ID)
ucache, ok := users.(UserCache)
if ok {
ucache.CacheRemove(user.ID)
}
_, err = userStmts.setUsername.Exec(username, user.ID)
user.CacheRemove()
return err
}
func (user *User) ChangeAvatar(avatar string) (err error) {
_, err = stmts.setAvatar.Exec(avatar, user.ID)
ucache, ok := users.(UserCache)
if ok {
ucache.CacheRemove(user.ID)
}
_, err = userStmts.setAvatar.Exec(avatar, user.ID)
user.CacheRemove()
return err
}
func (user *User) ChangeGroup(group int) (err error) {
_, err = stmts.updateUserGroup.Exec(group, user.ID)
ucache, ok := users.(UserCache)
if ok {
ucache.CacheRemove(user.ID)
}
_, err = userStmts.updateGroup.Exec(group, user.ID)
user.CacheRemove()
return err
}
func (user *User) increasePostStats(wcount int, topic bool) (err error) {
// ! Only updates the database not the *User for safety reasons
func (user *User) UpdateIP(host string) error {
_, err := userStmts.updateLastIP.Exec(host, user.ID)
return err
}
func (user *User) IncreasePostStats(wcount int, topic bool) (err error) {
var mod int
baseScore := 1
if topic {
_, err = stmts.incrementUserTopics.Exec(1, user.ID)
_, err = userStmts.incrementTopics.Exec(1, user.ID)
if err != nil {
return err
}
baseScore = 2
}
settings := settingBox.Load().(SettingBox)
settings := SettingBox.Load().(SettingMap)
if wcount >= settings["megapost_min_words"].(int) {
_, err = stmts.incrementUserMegaposts.Exec(1, 1, 1, user.ID)
_, err = userStmts.incrementMegaposts.Exec(1, 1, 1, user.ID)
mod = 4
} else if wcount >= settings["bigpost_min_words"].(int) {
_, err = stmts.incrementUserBigposts.Exec(1, 1, user.ID)
_, err = userStmts.incrementBigposts.Exec(1, 1, user.ID)
mod = 1
} else {
_, err = stmts.incrementUserPosts.Exec(1, user.ID)
_, err = userStmts.incrementPosts.Exec(1, user.ID)
}
if err != nil {
return err
}
_, err = stmts.incrementUserScore.Exec(baseScore+mod, user.ID)
_, err = userStmts.incrementScore.Exec(baseScore+mod, user.ID)
if err != nil {
return err
}
//log.Print(user.Score + base_score + mod)
//log.Print(getLevel(user.Score + base_score + mod))
// TODO: Use a transaction to prevent level desyncs?
_, err = stmts.updateUserLevel.Exec(getLevel(user.Score+baseScore+mod), user.ID)
_, err = userStmts.updateLevel.Exec(GetLevel(user.Score+baseScore+mod), user.ID)
return err
}
func (user *User) decreasePostStats(wcount int, topic bool) (err error) {
func (user *User) DecreasePostStats(wcount int, topic bool) (err error) {
var mod int
baseScore := -1
if topic {
_, err = stmts.incrementUserTopics.Exec(-1, user.ID)
_, err = userStmts.incrementTopics.Exec(-1, user.ID)
if err != nil {
return err
}
baseScore = -2
}
settings := settingBox.Load().(SettingBox)
settings := SettingBox.Load().(SettingMap)
if wcount >= settings["megapost_min_words"].(int) {
_, err = stmts.incrementUserMegaposts.Exec(-1, -1, -1, user.ID)
_, err = userStmts.incrementMegaposts.Exec(-1, -1, -1, user.ID)
mod = 4
} else if wcount >= settings["bigpost_min_words"].(int) {
_, err = stmts.incrementUserBigposts.Exec(-1, -1, user.ID)
_, err = userStmts.incrementBigposts.Exec(-1, -1, user.ID)
mod = 1
} else {
_, err = stmts.incrementUserPosts.Exec(-1, user.ID)
_, err = userStmts.incrementPosts.Exec(-1, user.ID)
}
if err != nil {
return err
}
_, err = stmts.incrementUserScore.Exec(baseScore-mod, user.ID)
_, err = userStmts.incrementScore.Exec(baseScore-mod, user.ID)
if err != nil {
return err
}
// TODO: Use a transaction to prevent level desyncs?
_, err = stmts.updateUserLevel.Exec(getLevel(user.Score-baseScore-mod), user.ID)
_, err = userStmts.updateLevel.Exec(GetLevel(user.Score-baseScore-mod), user.ID)
return err
}
@ -303,12 +333,12 @@ func (user *User) Copy() User {
}
// TODO: Write unit tests for this
func (user *User) initPerms() {
func (user *User) InitPerms() {
if user.TempGroup != 0 {
user.Group = user.TempGroup
}
group := gstore.DirtyGet(user.Group)
group := Gstore.DirtyGet(user.Group)
if user.IsSuperAdmin {
user.Perms = AllPerms
user.PluginPerms = AllPluginPerms
@ -332,7 +362,7 @@ func BcryptCheckPassword(realPassword string, password string, salt string) (err
// Investigate. Do we need the extra salt?
func BcryptGeneratePassword(password string) (hashedPassword string, salt string, err error) {
salt, err = GenerateSafeString(saltLength)
salt, err = GenerateSafeString(SaltLength)
if err != nil {
return "", "", err
}
@ -353,27 +383,16 @@ func BcryptGeneratePasswordNoSalt(password string) (hash string, err error) {
return string(hashedPassword), nil
}
// TODO: Move this to *User
func SetPassword(uid int, password string) error {
hashedPassword, salt, err := GeneratePassword(password)
if err != nil {
return err
}
_, err = stmts.setPassword.Exec(hashedPassword, salt, uid)
_, err = userStmts.setPassword.Exec(hashedPassword, salt, uid)
return err
}
func SendValidationEmail(username string, email string, token string) bool {
var schema = "http"
if site.EnableSsl {
schema += "s"
}
// TODO: Move these to the phrase system
subject := "Validate Your Email @ " + site.Name
msg := "Dear " + username + ", following your registration on our forums, we ask you to validate your email, so that we can confirm that this email actually belongs to you.\n\nClick on the following link to do so. " + schema + "://" + site.URL + "/user/edit/token/" + token + "\n\nIf you haven't created an account here, then please feel free to ignore this email.\nWe're sorry for the inconvenience this may have caused."
return SendEmail(email, subject, msg)
}
// TODO: Write units tests for this
func wordsToScore(wcount int, topic bool) (score int) {
if topic {
@ -382,7 +401,7 @@ func wordsToScore(wcount int, topic bool) (score int) {
score = 1
}
settings := settingBox.Load().(SettingBox)
settings := SettingBox.Load().(SettingMap)
if wcount >= settings["megapost_min_words"].(int) {
score += 4
} else if wcount >= settings["bigpost_min_words"].(int) {
@ -392,12 +411,12 @@ func wordsToScore(wcount int, topic bool) (score int) {
}
// For use in tests and to help generate dummy users for forums which don't have last posters
func getDummyUser() *User {
func BlankUser() *User {
return &User{ID: 0, Name: ""}
}
// TODO: Write unit tests for this
func buildProfileURL(slug string, uid int) string {
func BuildProfileURL(slug string, uid int) string {
if slug == "" {
return "/user/" + strconv.Itoa(uid)
}

View File

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

View File

@ -12,12 +12,13 @@ import (
"errors"
"fmt"
"math"
"net/smtp"
"os"
"strconv"
"strings"
"time"
"unicode"
"../query_gen/lib"
)
// Version stores a Gosora version
@ -53,7 +54,7 @@ func GenerateSafeString(length int) (string, error) {
}
// TODO: Write a test for this
func relativeTimeFromString(in string) (string, error) {
func RelativeTimeFromString(in string) (string, error) {
if in == "" {
return "", nil
}
@ -63,11 +64,11 @@ func relativeTimeFromString(in string) (string, error) {
return "", err
}
return relativeTime(t), nil
return RelativeTime(t), nil
}
// TODO: Write a test for this
func relativeTime(t time.Time) string {
func RelativeTime(t time.Time) string {
diff := time.Since(t)
hours := diff.Hours()
seconds := diff.Seconds()
@ -105,36 +106,36 @@ func relativeTime(t time.Time) string {
}
// TODO: Write a test for this
func convertByteUnit(bytes float64) (float64, string) {
func ConvertByteUnit(bytes float64) (float64, string) {
switch {
case bytes >= float64(petabyte):
return bytes / float64(petabyte), "PB"
case bytes >= float64(terabyte):
return bytes / float64(terabyte), "TB"
case bytes >= float64(gigabyte):
return bytes / float64(gigabyte), "GB"
case bytes >= float64(megabyte):
return bytes / float64(megabyte), "MB"
case bytes >= float64(kilobyte):
return bytes / float64(kilobyte), "KB"
case bytes >= float64(Petabyte):
return bytes / float64(Petabyte), "PB"
case bytes >= float64(Terabyte):
return bytes / float64(Terabyte), "TB"
case bytes >= float64(Gigabyte):
return bytes / float64(Gigabyte), "GB"
case bytes >= float64(Megabyte):
return bytes / float64(Megabyte), "MB"
case bytes >= float64(Kilobyte):
return bytes / float64(Kilobyte), "KB"
default:
return bytes, " bytes"
}
}
// TODO: Write a test for this
func convertByteInUnit(bytes float64, unit string) (count float64) {
func ConvertByteInUnit(bytes float64, unit string) (count float64) {
switch unit {
case "PB":
count = bytes / float64(petabyte)
count = bytes / float64(Petabyte)
case "TB":
count = bytes / float64(terabyte)
count = bytes / float64(Terabyte)
case "GB":
count = bytes / float64(gigabyte)
count = bytes / float64(Gigabyte)
case "MB":
count = bytes / float64(megabyte)
count = bytes / float64(Megabyte)
case "KB":
count = bytes / float64(kilobyte)
count = bytes / float64(Kilobyte)
default:
count = 0.1
}
@ -146,7 +147,7 @@ func convertByteInUnit(bytes float64, unit string) (count float64) {
}
// TODO: Write a test for this
func convertUnit(num int) (int, string) {
func ConvertUnit(num int) (int, string) {
switch {
case num >= 1000000000000:
return num / 1000000000000, "T"
@ -162,7 +163,7 @@ func convertUnit(num int) (int, string) {
}
// TODO: Write a test for this
func convertFriendlyUnit(num int) (int, string) {
func ConvertFriendlyUnit(num int) (int, string) {
switch {
case num >= 1000000000000000:
return 0, " quadrillion"
@ -179,7 +180,7 @@ func convertFriendlyUnit(num int) (int, string) {
}
}
func nameToSlug(name string) (slug string) {
func NameToSlug(name string) (slug string) {
name = strings.TrimSpace(name)
name = strings.Replace(name, " ", " ", -1)
@ -199,58 +200,8 @@ func nameToSlug(name string) (slug string) {
return slug
}
// TODO: Refactor this
func SendEmail(email string, subject string, msg string) bool {
// This hook is useful for plugin_sendmail or for testing tools. Possibly to hook it into some sort of mail server?
if vhooks["email_send_intercept"] != nil {
return vhooks["email_send_intercept"](email, subject, msg).(bool)
}
body := "Subject: " + subject + "\n\n" + msg + "\n"
con, err := smtp.Dial(config.SMTPServer + ":" + config.SMTPPort)
if err != nil {
return false
}
if config.SMTPUsername != "" {
auth := smtp.PlainAuth("", config.SMTPUsername, config.SMTPPassword, config.SMTPServer)
err = con.Auth(auth)
if err != nil {
return false
}
}
err = con.Mail(site.Email)
if err != nil {
return false
}
err = con.Rcpt(email)
if err != nil {
return false
}
emailData, err := con.Data()
if err != nil {
return false
}
_, err = fmt.Fprintf(emailData, body)
if err != nil {
return false
}
err = emailData.Close()
if err != nil {
return false
}
err = con.Quit()
if err != nil {
return false
}
return true
}
// TODO: Write a test for this
func weakPassword(password string) error {
func WeakPassword(password string) error {
if len(password) < 8 {
return errors.New("your password needs to be at-least eight characters long")
}
@ -335,7 +286,7 @@ func Stripslashes(text string) string {
}
// TODO: Write a test for this
func wordCount(input string) (count int) {
func WordCount(input string) (count int) {
input = strings.TrimSpace(input)
if input == "" {
return 0
@ -355,7 +306,7 @@ func wordCount(input string) (count int) {
}
// TODO: Write a test for this
func getLevel(score int) (level int) {
func GetLevel(score int) (level int) {
var base float64 = 25
var current, prev float64
var expFactor = 2.8
@ -376,7 +327,7 @@ func getLevel(score int) (level int) {
}
// TODO: Write a test for this
func getLevelScore(getLevel int) (score int) {
func GetLevelScore(getLevel int) (score int) {
var base float64 = 25
var current, prev float64
var level int
@ -398,7 +349,7 @@ func getLevelScore(getLevel int) (score int) {
}
// TODO: Write a test for this
func getLevels(maxLevel int) []float64 {
func GetLevels(maxLevel int) []float64 {
var base float64 = 25
var current, prev float64 // = 0
var expFactor = 2.8
@ -417,7 +368,7 @@ func getLevels(maxLevel int) []float64 {
return out
}
func buildSlug(slug string, id int) string {
func BuildSlug(slug string, id int) string {
if slug == "" {
return strconv.Itoa(id)
}
@ -425,13 +376,21 @@ func buildSlug(slug string, id int) string {
}
// TODO: Make a store for this?
func addModLog(action string, elementID int, elementType string, ipaddress string, actorID int) (err error) {
_, err = stmts.addModlogEntry.Exec(action, elementID, elementType, ipaddress, actorID)
func AddModLog(action string, elementID int, elementType string, ipaddress string, actorID int) (err error) {
addModLogEntry, err := qgen.Builder.SimpleInsert("moderation_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "?,?,?,?,?,UTC_TIMESTAMP()")
if err != nil {
return err
}
_, err = addModLogEntry.Exec(action, elementID, elementType, ipaddress, actorID)
return err
}
// TODO: Make a store for this?
func addAdminLog(action string, elementID string, elementType int, ipaddress string, actorID int) (err error) {
_, err = stmts.addAdminlogEntry.Exec(action, elementID, elementType, ipaddress, actorID)
func AddAdminLog(action string, elementID string, elementType int, ipaddress string, actorID int) (err error) {
addAdminLogEntry, err := qgen.Builder.SimpleInsert("administration_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "?,?,?,?,?,UTC_TIMESTAMP()")
if err != nil {
return err
}
_, err = addAdminLogEntry.Exec(action, elementID, elementType, ipaddress, actorID)
return err
}

View File

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

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
import "log"
import (
"database/sql"
"log"
import "database/sql"
"./common"
)
var stmts *Stmts
@ -15,7 +18,7 @@ var ErrNoRows = sql.ErrNoRows
var _initDatabase func() error
func initDatabase() (err error) {
func InitDatabase() (err error) {
stmts = &Stmts{Mocks: false}
// Engine specific code
@ -25,70 +28,69 @@ func initDatabase() (err error) {
}
globs = &Globs{stmts}
log.Print("Loading the usergroups.")
gstore, err = NewMemoryGroupStore()
err = common.DbInits.Run()
if err != nil {
return err
}
err = gstore.LoadGroups()
log.Print("Loading the usergroups.")
common.Gstore, err = common.NewMemoryGroupStore()
if err != nil {
return err
}
err2 := common.Gstore.LoadGroups()
if err2 != nil {
return err2
}
// We have to put this here, otherwise LoadForums() won't be able to get the last poster data when building it's forums
log.Print("Initialising the user and topic stores")
if config.CacheTopicUser == CACHE_STATIC {
users, err = NewMemoryUserStore(config.UserCacheCapacity)
if err != nil {
return err
}
topics, err = NewMemoryTopicStore(config.TopicCacheCapacity)
if err != nil {
return err
}
if common.Config.CacheTopicUser == common.CACHE_STATIC {
common.Users, err = common.NewMemoryUserStore(common.Config.UserCacheCapacity)
common.Topics, err2 = common.NewMemoryTopicStore(common.Config.TopicCacheCapacity)
} else {
users, err = NewSQLUserStore()
if err != nil {
return err
}
topics, err = NewSQLTopicStore()
if err != nil {
return err
}
common.Users, err = common.NewSQLUserStore()
common.Topics, err2 = common.NewSQLTopicStore()
}
log.Print("Loading the forums.")
fstore, err = NewMemoryForumStore()
if err != nil {
return err
}
err = fstore.LoadForums()
if err2 != nil {
return err2
}
log.Print("Loading the forums.")
common.Fstore, err = common.NewMemoryForumStore()
if err != nil {
return err
}
err = common.Fstore.LoadForums()
if err != nil {
return err
}
log.Print("Loading the forum permissions.")
fpstore, err = NewMemoryForumPermsStore()
common.Fpstore, err = common.NewMemoryForumPermsStore()
if err != nil {
return err
}
err = fpstore.Init()
err = common.Fpstore.Init()
if err != nil {
return err
}
log.Print("Loading the settings.")
err = LoadSettings()
err = common.LoadSettings()
if err != nil {
return err
}
log.Print("Loading the plugins.")
err = initExtend()
err = common.InitExtend()
if err != nil {
return err
}
log.Print("Loading the themes.")
return LoadThemeActiveStatus()
return common.Themes.LoadActiveStatus()
}

View File

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

View File

@ -5,6 +5,7 @@ package main
import "log"
import "database/sql"
import "./common"
// nolint
type Stmts struct {
@ -12,21 +13,14 @@ type Stmts struct {
getSettings *sql.Stmt
getSetting *sql.Stmt
getFullSetting *sql.Stmt
getFullSettings *sql.Stmt
getPlugins *sql.Stmt
getThemes *sql.Stmt
getWidgets *sql.Stmt
isPluginActive *sql.Stmt
getUsersOffset *sql.Stmt
getWordFilters *sql.Stmt
isThemeDefault *sql.Stmt
getModlogs *sql.Stmt
getModlogsOffset *sql.Stmt
getReplyTID *sql.Stmt
getTopicFID *sql.Stmt
getUserReplyUID *sql.Stmt
hasLikedTopic *sql.Stmt
hasLikedReply *sql.Stmt
getUserName *sql.Stmt
getEmailsByUser *sql.Stmt
getTopicBasic *sql.Stmt
@ -34,20 +28,14 @@ type Stmts struct {
forumEntryExists *sql.Stmt
groupEntryExists *sql.Stmt
getForumTopicsOffset *sql.Stmt
getExpiredScheduledGroups *sql.Stmt
getSync *sql.Stmt
getAttachment *sql.Stmt
getTopicRepliesOffset *sql.Stmt
getTopicList *sql.Stmt
getTopicUser *sql.Stmt
getTopicByReply *sql.Stmt
getTopicReplies *sql.Stmt
getForumTopics *sql.Stmt
getProfileReplies *sql.Stmt
getWatchers *sql.Stmt
createReport *sql.Stmt
createActionReply *sql.Stmt
createLike *sql.Stmt
addActivity *sql.Stmt
notifyOne *sql.Stmt
addEmail *sql.Stmt
@ -55,57 +43,27 @@ type Stmts struct {
addForumPermsToForum *sql.Stmt
addPlugin *sql.Stmt
addTheme *sql.Stmt
addModlogEntry *sql.Stmt
addAdminlogEntry *sql.Stmt
addAttachment *sql.Stmt
createWordFilter *sql.Stmt
addRepliesToTopic *sql.Stmt
removeRepliesFromTopic *sql.Stmt
addLikesToTopic *sql.Stmt
addLikesToReply *sql.Stmt
editTopic *sql.Stmt
editReply *sql.Stmt
stickTopic *sql.Stmt
unstickTopic *sql.Stmt
lockTopic *sql.Stmt
unlockTopic *sql.Stmt
updateLastIP *sql.Stmt
updateSession *sql.Stmt
setPassword *sql.Stmt
setAvatar *sql.Stmt
setUsername *sql.Stmt
changeGroup *sql.Stmt
activateUser *sql.Stmt
updateUserLevel *sql.Stmt
incrementUserScore *sql.Stmt
incrementUserPosts *sql.Stmt
incrementUserBigposts *sql.Stmt
incrementUserMegaposts *sql.Stmt
incrementUserTopics *sql.Stmt
editProfileReply *sql.Stmt
updateForum *sql.Stmt
updateSetting *sql.Stmt
updatePlugin *sql.Stmt
updatePluginInstall *sql.Stmt
updateTheme *sql.Stmt
updateForum *sql.Stmt
updateUser *sql.Stmt
updateUserGroup *sql.Stmt
updateGroupPerms *sql.Stmt
updateGroupRank *sql.Stmt
updateGroup *sql.Stmt
updateEmail *sql.Stmt
verifyEmail *sql.Stmt
setTempGroup *sql.Stmt
updateWordFilter *sql.Stmt
bumpSync *sql.Stmt
deleteUser *sql.Stmt
deleteTopic *sql.Stmt
deleteReply *sql.Stmt
deleteProfileReply *sql.Stmt
deleteActivityStreamMatch *sql.Stmt
deleteWordFilter *sql.Stmt
reportExists *sql.Stmt
groupCount *sql.Stmt
modlogCount *sql.Stmt
notifyWatchers *sql.Stmt
@ -124,7 +82,7 @@ type Stmts struct {
// nolint
func _gen_mssql() (err error) {
if dev.DebugMode {
if common.Dev.DebugMode {
log.Print("Building the generated statements")
}
@ -156,34 +114,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing getFullSettings statement.")
stmts.getFullSettings, err = db.Prepare("SELECT [name],[content],[type],[constraints] FROM [settings]")
if err != nil {
log.Print("Bad Query: ","SELECT [name],[content],[type],[constraints] FROM [settings]")
return err
}
log.Print("Preparing getPlugins statement.")
stmts.getPlugins, err = db.Prepare("SELECT [uname],[active],[installed] FROM [plugins]")
if err != nil {
log.Print("Bad Query: ","SELECT [uname],[active],[installed] FROM [plugins]")
return err
}
log.Print("Preparing getThemes statement.")
stmts.getThemes, err = db.Prepare("SELECT [uname],[default] FROM [themes]")
if err != nil {
log.Print("Bad Query: ","SELECT [uname],[default] FROM [themes]")
return err
}
log.Print("Preparing getWidgets statement.")
stmts.getWidgets, err = db.Prepare("SELECT [position],[side],[type],[active],[location],[data] FROM [widgets] ORDER BY position ASC")
if err != nil {
log.Print("Bad Query: ","SELECT [position],[side],[type],[active],[location],[data] FROM [widgets] ORDER BY position ASC")
return err
}
log.Print("Preparing isPluginActive statement.")
stmts.isPluginActive, err = db.Prepare("SELECT [active] FROM [plugins] WHERE [uname] = ?1")
if err != nil {
@ -198,13 +128,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing getWordFilters statement.")
stmts.getWordFilters, err = db.Prepare("SELECT [wfid],[find],[replacement] FROM [word_filters]")
if err != nil {
log.Print("Bad Query: ","SELECT [wfid],[find],[replacement] FROM [word_filters]")
return err
}
log.Print("Preparing isThemeDefault statement.")
stmts.isThemeDefault, err = db.Prepare("SELECT [default] FROM [themes] WHERE [uname] = ?1")
if err != nil {
@ -247,20 +170,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing hasLikedTopic statement.")
stmts.hasLikedTopic, err = db.Prepare("SELECT [targetItem] FROM [likes] WHERE [sentBy] = ?1 AND [targetItem] = ?2 AND [targetType] = 'topics'")
if err != nil {
log.Print("Bad Query: ","SELECT [targetItem] FROM [likes] WHERE [sentBy] = ?1 AND [targetItem] = ?2 AND [targetType] = 'topics'")
return err
}
log.Print("Preparing hasLikedReply statement.")
stmts.hasLikedReply, err = db.Prepare("SELECT [targetItem] FROM [likes] WHERE [sentBy] = ?1 AND [targetItem] = ?2 AND [targetType] = 'replies'")
if err != nil {
log.Print("Bad Query: ","SELECT [targetItem] FROM [likes] WHERE [sentBy] = ?1 AND [targetItem] = ?2 AND [targetType] = 'replies'")
return err
}
log.Print("Preparing getUserName statement.")
stmts.getUserName, err = db.Prepare("SELECT [name] FROM [users] WHERE [uid] = ?1")
if err != nil {
@ -310,20 +219,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing getExpiredScheduledGroups statement.")
stmts.getExpiredScheduledGroups, err = db.Prepare("SELECT [uid] FROM [users_groups_scheduler] WHERE GETDATE() > [revert_at] AND [temporary] = 1")
if err != nil {
log.Print("Bad Query: ","SELECT [uid] FROM [users_groups_scheduler] WHERE GETDATE() > [revert_at] AND [temporary] = 1")
return err
}
log.Print("Preparing getSync statement.")
stmts.getSync, err = db.Prepare("SELECT [last_update] FROM [sync]")
if err != nil {
log.Print("Bad Query: ","SELECT [last_update] FROM [sync]")
return err
}
log.Print("Preparing getAttachment statement.")
stmts.getAttachment, err = db.Prepare("SELECT [sectionID],[sectionTable],[originID],[originTable],[uploadedBy],[path] FROM [attachments] WHERE [path] = ?1 AND [sectionID] = ?2 AND [sectionTable] = ?3")
if err != nil {
@ -345,20 +240,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing getTopicUser statement.")
stmts.getTopicUser, err = db.Prepare("SELECT [topics].[title],[topics].[content],[topics].[createdBy],[topics].[createdAt],[topics].[is_closed],[topics].[sticky],[topics].[parentID],[topics].[ipaddress],[topics].[postCount],[topics].[likeCount],[users].[name],[users].[avatar],[users].[group],[users].[url_prefix],[users].[url_name],[users].[level] FROM [topics] LEFT JOIN [users] ON [topics].[createdBy] = [users].[uid] WHERE [tid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [topics].[title],[topics].[content],[topics].[createdBy],[topics].[createdAt],[topics].[is_closed],[topics].[sticky],[topics].[parentID],[topics].[ipaddress],[topics].[postCount],[topics].[likeCount],[users].[name],[users].[avatar],[users].[group],[users].[url_prefix],[users].[url_name],[users].[level] FROM [topics] LEFT JOIN [users] ON [topics].[createdBy] = [users].[uid] WHERE [tid] = ?1")
return err
}
log.Print("Preparing getTopicByReply statement.")
stmts.getTopicByReply, err = db.Prepare("SELECT [topics].[tid],[topics].[title],[topics].[content],[topics].[createdBy],[topics].[createdAt],[topics].[is_closed],[topics].[sticky],[topics].[parentID],[topics].[ipaddress],[topics].[postCount],[topics].[likeCount],[topics].[data] FROM [replies] LEFT JOIN [topics] ON [replies].[tid] = [topics].[tid] WHERE [rid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [topics].[tid],[topics].[title],[topics].[content],[topics].[createdBy],[topics].[createdAt],[topics].[is_closed],[topics].[sticky],[topics].[parentID],[topics].[ipaddress],[topics].[postCount],[topics].[likeCount],[topics].[data] FROM [replies] LEFT JOIN [topics] ON [replies].[tid] = [topics].[tid] WHERE [rid] = ?1")
return err
}
log.Print("Preparing getTopicReplies statement.")
stmts.getTopicReplies, err = db.Prepare("SELECT [replies].[rid],[replies].[content],[replies].[createdBy],[replies].[createdAt],[replies].[lastEdit],[replies].[lastEditBy],[users].[avatar],[users].[name],[users].[group],[users].[url_prefix],[users].[url_name],[users].[level],[replies].[ipaddress] FROM [replies] LEFT JOIN [users] ON [replies].[createdBy] = [users].[uid] WHERE [tid] = ?1")
if err != nil {
@ -394,20 +275,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing createActionReply statement.")
stmts.createActionReply, err = db.Prepare("INSERT INTO [replies] ([tid],[actionType],[ipaddress],[createdBy],[createdAt],[lastUpdated],[content],[parsed_content]) VALUES (?,?,?,?,GETUTCDATE(),GETUTCDATE(),'','')")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [replies] ([tid],[actionType],[ipaddress],[createdBy],[createdAt],[lastUpdated],[content],[parsed_content]) VALUES (?,?,?,?,GETUTCDATE(),GETUTCDATE(),'','')")
return err
}
log.Print("Preparing createLike statement.")
stmts.createLike, err = db.Prepare("INSERT INTO [likes] ([weight],[targetItem],[targetType],[sentBy]) VALUES (?,?,?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [likes] ([weight],[targetItem],[targetType],[sentBy]) VALUES (?,?,?,?)")
return err
}
log.Print("Preparing addActivity statement.")
stmts.addActivity, err = db.Prepare("INSERT INTO [activity_stream] ([actor],[targetUser],[event],[elementType],[elementID]) VALUES (?,?,?,?,?)")
if err != nil {
@ -457,20 +324,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing addModlogEntry statement.")
stmts.addModlogEntry, err = db.Prepare("INSERT INTO [moderation_logs] ([action],[elementID],[elementType],[ipaddress],[actorID],[doneAt]) VALUES (?,?,?,?,?,GETUTCDATE())")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [moderation_logs] ([action],[elementID],[elementType],[ipaddress],[actorID],[doneAt]) VALUES (?,?,?,?,?,GETUTCDATE())")
return err
}
log.Print("Preparing addAdminlogEntry statement.")
stmts.addAdminlogEntry, err = db.Prepare("INSERT INTO [administration_logs] ([action],[elementID],[elementType],[ipaddress],[actorID],[doneAt]) VALUES (?,?,?,?,?,GETUTCDATE())")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [administration_logs] ([action],[elementID],[elementType],[ipaddress],[actorID],[doneAt]) VALUES (?,?,?,?,?,GETUTCDATE())")
return err
}
log.Print("Preparing addAttachment statement.")
stmts.addAttachment, err = db.Prepare("INSERT INTO [attachments] ([sectionID],[sectionTable],[originID],[originTable],[uploadedBy],[path]) VALUES (?,?,?,?,?,?)")
if err != nil {
@ -485,41 +338,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing addRepliesToTopic statement.")
stmts.addRepliesToTopic, err = db.Prepare("UPDATE [topics] SET [postCount] = [postCount] + ?,[lastReplyBy] = ?,[lastReplyAt] = GETUTCDATE() WHERE [tid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [topics] SET [postCount] = [postCount] + ?,[lastReplyBy] = ?,[lastReplyAt] = GETUTCDATE() WHERE [tid] = ?")
return err
}
log.Print("Preparing removeRepliesFromTopic statement.")
stmts.removeRepliesFromTopic, err = db.Prepare("UPDATE [topics] SET [postCount] = [postCount] - ? WHERE [tid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [topics] SET [postCount] = [postCount] - ? WHERE [tid] = ?")
return err
}
log.Print("Preparing addLikesToTopic statement.")
stmts.addLikesToTopic, err = db.Prepare("UPDATE [topics] SET [likeCount] = [likeCount] + ? WHERE [tid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [topics] SET [likeCount] = [likeCount] + ? WHERE [tid] = ?")
return err
}
log.Print("Preparing addLikesToReply statement.")
stmts.addLikesToReply, err = db.Prepare("UPDATE [replies] SET [likeCount] = [likeCount] + ? WHERE [rid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [replies] SET [likeCount] = [likeCount] + ? WHERE [rid] = ?")
return err
}
log.Print("Preparing editTopic statement.")
stmts.editTopic, err = db.Prepare("UPDATE [topics] SET [title] = ?,[content] = ?,[parsed_content] = ? WHERE [tid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [topics] SET [title] = ?,[content] = ?,[parsed_content] = ? WHERE [tid] = ?")
return err
}
log.Print("Preparing editReply statement.")
stmts.editReply, err = db.Prepare("UPDATE [replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?")
if err != nil {
@ -527,125 +345,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing stickTopic statement.")
stmts.stickTopic, err = db.Prepare("UPDATE [topics] SET [sticky] = 1 WHERE [tid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [topics] SET [sticky] = 1 WHERE [tid] = ?")
return err
}
log.Print("Preparing unstickTopic statement.")
stmts.unstickTopic, err = db.Prepare("UPDATE [topics] SET [sticky] = 0 WHERE [tid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [topics] SET [sticky] = 0 WHERE [tid] = ?")
return err
}
log.Print("Preparing lockTopic statement.")
stmts.lockTopic, err = db.Prepare("UPDATE [topics] SET [is_closed] = 1 WHERE [tid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [topics] SET [is_closed] = 1 WHERE [tid] = ?")
return err
}
log.Print("Preparing unlockTopic statement.")
stmts.unlockTopic, err = db.Prepare("UPDATE [topics] SET [is_closed] = 0 WHERE [tid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [topics] SET [is_closed] = 0 WHERE [tid] = ?")
return err
}
log.Print("Preparing updateLastIP statement.")
stmts.updateLastIP, err = db.Prepare("UPDATE [users] SET [last_ip] = ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [last_ip] = ? WHERE [uid] = ?")
return err
}
log.Print("Preparing updateSession statement.")
stmts.updateSession, err = db.Prepare("UPDATE [users] SET [session] = ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [session] = ? WHERE [uid] = ?")
return err
}
log.Print("Preparing setPassword statement.")
stmts.setPassword, err = db.Prepare("UPDATE [users] SET [password] = ?,[salt] = ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [password] = ?,[salt] = ? WHERE [uid] = ?")
return err
}
log.Print("Preparing setAvatar statement.")
stmts.setAvatar, err = db.Prepare("UPDATE [users] SET [avatar] = ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [avatar] = ? WHERE [uid] = ?")
return err
}
log.Print("Preparing setUsername statement.")
stmts.setUsername, err = db.Prepare("UPDATE [users] SET [name] = ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [name] = ? WHERE [uid] = ?")
return err
}
log.Print("Preparing changeGroup statement.")
stmts.changeGroup, err = db.Prepare("UPDATE [users] SET [group] = ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [group] = ? WHERE [uid] = ?")
return err
}
log.Print("Preparing activateUser statement.")
stmts.activateUser, err = db.Prepare("UPDATE [users] SET [active] = 1 WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [active] = 1 WHERE [uid] = ?")
return err
}
log.Print("Preparing updateUserLevel statement.")
stmts.updateUserLevel, err = db.Prepare("UPDATE [users] SET [level] = ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [level] = ? WHERE [uid] = ?")
return err
}
log.Print("Preparing incrementUserScore statement.")
stmts.incrementUserScore, err = db.Prepare("UPDATE [users] SET [score] = [score] + ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [score] = [score] + ? WHERE [uid] = ?")
return err
}
log.Print("Preparing incrementUserPosts statement.")
stmts.incrementUserPosts, err = db.Prepare("UPDATE [users] SET [posts] = [posts] + ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [posts] = [posts] + ? WHERE [uid] = ?")
return err
}
log.Print("Preparing incrementUserBigposts statement.")
stmts.incrementUserBigposts, err = db.Prepare("UPDATE [users] SET [posts] = [posts] + ?,[bigposts] = [bigposts] + ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [posts] = [posts] + ?,[bigposts] = [bigposts] + ? WHERE [uid] = ?")
return err
}
log.Print("Preparing incrementUserMegaposts statement.")
stmts.incrementUserMegaposts, err = db.Prepare("UPDATE [users] SET [posts] = [posts] + ?,[bigposts] = [bigposts] + ?,[megaposts] = [megaposts] + ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [posts] = [posts] + ?,[bigposts] = [bigposts] + ?,[megaposts] = [megaposts] + ? WHERE [uid] = ?")
return err
}
log.Print("Preparing incrementUserTopics statement.")
stmts.incrementUserTopics, err = db.Prepare("UPDATE [users] SET [topics] = [topics] + ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [topics] = [topics] + ? WHERE [uid] = ?")
return err
}
log.Print("Preparing editProfileReply statement.")
stmts.editProfileReply, err = db.Prepare("UPDATE [users_replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?")
if err != nil {
@ -653,13 +352,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE [forums] SET [name] = ?,[desc] = ?,[active] = ?,[preset] = ? WHERE [fid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [forums] SET [name] = ?,[desc] = ?,[active] = ?,[preset] = ? WHERE [fid] = ?")
return err
}
log.Print("Preparing updateSetting statement.")
stmts.updateSetting, err = db.Prepare("UPDATE [settings] SET [content] = ? WHERE [name] = ?")
if err != nil {
@ -688,6 +380,13 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE [forums] SET [name] = ?,[desc] = ?,[active] = ?,[preset] = ? WHERE [fid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [forums] SET [name] = ?,[desc] = ?,[active] = ?,[preset] = ? WHERE [fid] = ?")
return err
}
log.Print("Preparing updateUser statement.")
stmts.updateUser, err = db.Prepare("UPDATE [users] SET [name] = ?,[email] = ?,[group] = ? WHERE [uid] = ?")
if err != nil {
@ -695,13 +394,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing updateUserGroup statement.")
stmts.updateUserGroup, err = db.Prepare("UPDATE [users] SET [group] = ? WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users] SET [group] = ? WHERE [uid] = ?")
return err
}
log.Print("Preparing updateGroupPerms statement.")
stmts.updateGroupPerms, err = db.Prepare("UPDATE [users_groups] SET [permissions] = ? WHERE [gid] = ?")
if err != nil {
@ -709,13 +401,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing updateGroupRank statement.")
stmts.updateGroupRank, err = db.Prepare("UPDATE [users_groups] SET [is_admin] = ?,[is_mod] = ?,[is_banned] = ? WHERE [gid] = ?")
if err != nil {
log.Print("Bad Query: ","UPDATE [users_groups] SET [is_admin] = ?,[is_mod] = ?,[is_banned] = ? WHERE [gid] = ?")
return err
}
log.Print("Preparing updateGroup statement.")
stmts.updateGroup, err = db.Prepare("UPDATE [users_groups] SET [name] = ?,[tag] = ? WHERE [gid] = ?")
if err != nil {
@ -758,27 +443,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing deleteUser statement.")
stmts.deleteUser, err = db.Prepare("DELETE FROM [users] WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","DELETE FROM [users] WHERE [uid] = ?")
return err
}
log.Print("Preparing deleteTopic statement.")
stmts.deleteTopic, err = db.Prepare("DELETE FROM [topics] WHERE [tid] = ?")
if err != nil {
log.Print("Bad Query: ","DELETE FROM [topics] WHERE [tid] = ?")
return err
}
log.Print("Preparing deleteReply statement.")
stmts.deleteReply, err = db.Prepare("DELETE FROM [replies] WHERE [rid] = ?")
if err != nil {
log.Print("Bad Query: ","DELETE FROM [replies] WHERE [rid] = ?")
return err
}
log.Print("Preparing deleteProfileReply statement.")
stmts.deleteProfileReply, err = db.Prepare("DELETE FROM [users_replies] WHERE [rid] = ?")
if err != nil {
@ -807,13 +471,6 @@ func _gen_mssql() (err error) {
return err
}
log.Print("Preparing groupCount statement.")
stmts.groupCount, err = db.Prepare("SELECT COUNT(*) AS [count] FROM [users_groups]")
if err != nil {
log.Print("Bad Query: ","SELECT COUNT(*) AS [count] FROM [users_groups]")
return err
}
log.Print("Preparing modlogCount statement.")
stmts.modlogCount, err = db.Prepare("SELECT COUNT(*) AS [count] FROM [moderation_logs]")
if err != nil {

View File

@ -6,6 +6,7 @@ package main
import "log"
import "database/sql"
import "./common"
//import "./query_gen/lib"
// nolint
@ -14,21 +15,14 @@ type Stmts struct {
getSettings *sql.Stmt
getSetting *sql.Stmt
getFullSetting *sql.Stmt
getFullSettings *sql.Stmt
getPlugins *sql.Stmt
getThemes *sql.Stmt
getWidgets *sql.Stmt
isPluginActive *sql.Stmt
getUsersOffset *sql.Stmt
getWordFilters *sql.Stmt
isThemeDefault *sql.Stmt
getModlogs *sql.Stmt
getModlogsOffset *sql.Stmt
getReplyTID *sql.Stmt
getTopicFID *sql.Stmt
getUserReplyUID *sql.Stmt
hasLikedTopic *sql.Stmt
hasLikedReply *sql.Stmt
getUserName *sql.Stmt
getEmailsByUser *sql.Stmt
getTopicBasic *sql.Stmt
@ -36,20 +30,14 @@ type Stmts struct {
forumEntryExists *sql.Stmt
groupEntryExists *sql.Stmt
getForumTopicsOffset *sql.Stmt
getExpiredScheduledGroups *sql.Stmt
getSync *sql.Stmt
getAttachment *sql.Stmt
getTopicRepliesOffset *sql.Stmt
getTopicList *sql.Stmt
getTopicUser *sql.Stmt
getTopicByReply *sql.Stmt
getTopicReplies *sql.Stmt
getForumTopics *sql.Stmt
getProfileReplies *sql.Stmt
getWatchers *sql.Stmt
createReport *sql.Stmt
createActionReply *sql.Stmt
createLike *sql.Stmt
addActivity *sql.Stmt
notifyOne *sql.Stmt
addEmail *sql.Stmt
@ -57,57 +45,27 @@ type Stmts struct {
addForumPermsToForum *sql.Stmt
addPlugin *sql.Stmt
addTheme *sql.Stmt
addModlogEntry *sql.Stmt
addAdminlogEntry *sql.Stmt
addAttachment *sql.Stmt
createWordFilter *sql.Stmt
addRepliesToTopic *sql.Stmt
removeRepliesFromTopic *sql.Stmt
addLikesToTopic *sql.Stmt
addLikesToReply *sql.Stmt
editTopic *sql.Stmt
editReply *sql.Stmt
stickTopic *sql.Stmt
unstickTopic *sql.Stmt
lockTopic *sql.Stmt
unlockTopic *sql.Stmt
updateLastIP *sql.Stmt
updateSession *sql.Stmt
setPassword *sql.Stmt
setAvatar *sql.Stmt
setUsername *sql.Stmt
changeGroup *sql.Stmt
activateUser *sql.Stmt
updateUserLevel *sql.Stmt
incrementUserScore *sql.Stmt
incrementUserPosts *sql.Stmt
incrementUserBigposts *sql.Stmt
incrementUserMegaposts *sql.Stmt
incrementUserTopics *sql.Stmt
editProfileReply *sql.Stmt
updateForum *sql.Stmt
updateSetting *sql.Stmt
updatePlugin *sql.Stmt
updatePluginInstall *sql.Stmt
updateTheme *sql.Stmt
updateForum *sql.Stmt
updateUser *sql.Stmt
updateUserGroup *sql.Stmt
updateGroupPerms *sql.Stmt
updateGroupRank *sql.Stmt
updateGroup *sql.Stmt
updateEmail *sql.Stmt
verifyEmail *sql.Stmt
setTempGroup *sql.Stmt
updateWordFilter *sql.Stmt
bumpSync *sql.Stmt
deleteUser *sql.Stmt
deleteTopic *sql.Stmt
deleteReply *sql.Stmt
deleteProfileReply *sql.Stmt
deleteActivityStreamMatch *sql.Stmt
deleteWordFilter *sql.Stmt
reportExists *sql.Stmt
groupCount *sql.Stmt
modlogCount *sql.Stmt
notifyWatchers *sql.Stmt
@ -126,7 +84,7 @@ type Stmts struct {
// nolint
func _gen_mysql() (err error) {
if dev.DebugMode {
if common.Dev.DebugMode {
log.Print("Building the generated statements")
}
@ -154,30 +112,6 @@ func _gen_mysql() (err error) {
return err
}
log.Print("Preparing getFullSettings statement.")
stmts.getFullSettings, err = db.Prepare("SELECT `name`,`content`,`type`,`constraints` FROM `settings`")
if err != nil {
return err
}
log.Print("Preparing getPlugins statement.")
stmts.getPlugins, err = db.Prepare("SELECT `uname`,`active`,`installed` FROM `plugins`")
if err != nil {
return err
}
log.Print("Preparing getThemes statement.")
stmts.getThemes, err = db.Prepare("SELECT `uname`,`default` FROM `themes`")
if err != nil {
return err
}
log.Print("Preparing getWidgets statement.")
stmts.getWidgets, err = db.Prepare("SELECT `position`,`side`,`type`,`active`,`location`,`data` FROM `widgets` ORDER BY position ASC")
if err != nil {
return err
}
log.Print("Preparing isPluginActive statement.")
stmts.isPluginActive, err = db.Prepare("SELECT `active` FROM `plugins` WHERE `uname` = ?")
if err != nil {
@ -190,12 +124,6 @@ func _gen_mysql() (err error) {
return err
}
log.Print("Preparing getWordFilters statement.")
stmts.getWordFilters, err = db.Prepare("SELECT `wfid`,`find`,`replacement` FROM `word_filters`")
if err != nil {
return err
}
log.Print("Preparing isThemeDefault statement.")
stmts.isThemeDefault, err = db.Prepare("SELECT `default` FROM `themes` WHERE `uname` = ?")
if err != nil {
@ -232,18 +160,6 @@ func _gen_mysql() (err error) {
return err
}
log.Print("Preparing hasLikedTopic statement.")
stmts.hasLikedTopic, err = db.Prepare("SELECT `targetItem` FROM `likes` WHERE `sentBy` = ? AND `targetItem` = ? AND `targetType` = 'topics'")
if err != nil {
return err
}
log.Print("Preparing hasLikedReply statement.")
stmts.hasLikedReply, err = db.Prepare("SELECT `targetItem` FROM `likes` WHERE `sentBy` = ? AND `targetItem` = ? AND `targetType` = 'replies'")
if err != nil {
return err
}
log.Print("Preparing getUserName statement.")
stmts.getUserName, err = db.Prepare("SELECT `name` FROM `users` WHERE `uid` = ?")
if err != nil {
@ -286,18 +202,6 @@ func _gen_mysql() (err error) {
return err
}
log.Print("Preparing getExpiredScheduledGroups statement.")
stmts.getExpiredScheduledGroups, err = db.Prepare("SELECT `uid` FROM `users_groups_scheduler` WHERE UTC_TIMESTAMP() > `revert_at` AND `temporary` = 1")
if err != nil {
return err
}
log.Print("Preparing getSync statement.")
stmts.getSync, err = db.Prepare("SELECT `last_update` FROM `sync`")
if err != nil {
return err
}
log.Print("Preparing getAttachment statement.")
stmts.getAttachment, err = db.Prepare("SELECT `sectionID`,`sectionTable`,`originID`,`originTable`,`uploadedBy`,`path` FROM `attachments` WHERE `path` = ? AND `sectionID` = ? AND `sectionTable` = ?")
if err != nil {
@ -316,18 +220,6 @@ func _gen_mysql() (err error) {
return err
}
log.Print("Preparing getTopicUser statement.")
stmts.getTopicUser, err = db.Prepare("SELECT `topics`.`title`, `topics`.`content`, `topics`.`createdBy`, `topics`.`createdAt`, `topics`.`is_closed`, `topics`.`sticky`, `topics`.`parentID`, `topics`.`ipaddress`, `topics`.`postCount`, `topics`.`likeCount`, `users`.`name`, `users`.`avatar`, `users`.`group`, `users`.`url_prefix`, `users`.`url_name`, `users`.`level` FROM `topics` LEFT JOIN `users` ON `topics`.`createdBy` = `users`.`uid` WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing getTopicByReply statement.")
stmts.getTopicByReply, err = db.Prepare("SELECT `topics`.`tid`, `topics`.`title`, `topics`.`content`, `topics`.`createdBy`, `topics`.`createdAt`, `topics`.`is_closed`, `topics`.`sticky`, `topics`.`parentID`, `topics`.`ipaddress`, `topics`.`postCount`, `topics`.`likeCount`, `topics`.`data` FROM `replies` LEFT JOIN `topics` ON `replies`.`tid` = `topics`.`tid` WHERE `rid` = ?")
if err != nil {
return err
}
log.Print("Preparing getTopicReplies statement.")
stmts.getTopicReplies, err = db.Prepare("SELECT `replies`.`rid`, `replies`.`content`, `replies`.`createdBy`, `replies`.`createdAt`, `replies`.`lastEdit`, `replies`.`lastEditBy`, `users`.`avatar`, `users`.`name`, `users`.`group`, `users`.`url_prefix`, `users`.`url_name`, `users`.`level`, `replies`.`ipaddress` FROM `replies` LEFT JOIN `users` ON `replies`.`createdBy` = `users`.`uid` WHERE `tid` = ?")
if err != nil {
@ -358,18 +250,6 @@ func _gen_mysql() (err error) {
return err
}
log.Print("Preparing createActionReply statement.")
stmts.createActionReply, err = db.Prepare("INSERT INTO `replies`(`tid`,`actionType`,`ipaddress`,`createdBy`,`createdAt`,`lastUpdated`,`content`,`parsed_content`) VALUES (?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'','')")
if err != nil {
return err
}
log.Print("Preparing createLike statement.")
stmts.createLike, err = db.Prepare("INSERT INTO `likes`(`weight`,`targetItem`,`targetType`,`sentBy`) VALUES (?,?,?,?)")
if err != nil {
return err
}
log.Print("Preparing addActivity statement.")
stmts.addActivity, err = db.Prepare("INSERT INTO `activity_stream`(`actor`,`targetUser`,`event`,`elementType`,`elementID`) VALUES (?,?,?,?,?)")
if err != nil {
@ -412,18 +292,6 @@ func _gen_mysql() (err error) {
return err
}
log.Print("Preparing addModlogEntry statement.")
stmts.addModlogEntry, err = db.Prepare("INSERT INTO `moderation_logs`(`action`,`elementID`,`elementType`,`ipaddress`,`actorID`,`doneAt`) VALUES (?,?,?,?,?,UTC_TIMESTAMP())")
if err != nil {
return err
}
log.Print("Preparing addAdminlogEntry statement.")
stmts.addAdminlogEntry, err = db.Prepare("INSERT INTO `administration_logs`(`action`,`elementID`,`elementType`,`ipaddress`,`actorID`,`doneAt`) VALUES (?,?,?,?,?,UTC_TIMESTAMP())")
if err != nil {
return err
}
log.Print("Preparing addAttachment statement.")
stmts.addAttachment, err = db.Prepare("INSERT INTO `attachments`(`sectionID`,`sectionTable`,`originID`,`originTable`,`uploadedBy`,`path`) VALUES (?,?,?,?,?,?)")
if err != nil {
@ -436,156 +304,18 @@ func _gen_mysql() (err error) {
return err
}
log.Print("Preparing addRepliesToTopic statement.")
stmts.addRepliesToTopic, err = db.Prepare("UPDATE `topics` SET `postCount` = `postCount` + ?,`lastReplyBy` = ?,`lastReplyAt` = UTC_TIMESTAMP() WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing removeRepliesFromTopic statement.")
stmts.removeRepliesFromTopic, err = db.Prepare("UPDATE `topics` SET `postCount` = `postCount` - ? WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing addLikesToTopic statement.")
stmts.addLikesToTopic, err = db.Prepare("UPDATE `topics` SET `likeCount` = `likeCount` + ? WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing addLikesToReply statement.")
stmts.addLikesToReply, err = db.Prepare("UPDATE `replies` SET `likeCount` = `likeCount` + ? WHERE `rid` = ?")
if err != nil {
return err
}
log.Print("Preparing editTopic statement.")
stmts.editTopic, err = db.Prepare("UPDATE `topics` SET `title` = ?,`content` = ?,`parsed_content` = ? WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing editReply statement.")
stmts.editReply, err = db.Prepare("UPDATE `replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?")
if err != nil {
return err
}
log.Print("Preparing stickTopic statement.")
stmts.stickTopic, err = db.Prepare("UPDATE `topics` SET `sticky` = 1 WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing unstickTopic statement.")
stmts.unstickTopic, err = db.Prepare("UPDATE `topics` SET `sticky` = 0 WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing lockTopic statement.")
stmts.lockTopic, err = db.Prepare("UPDATE `topics` SET `is_closed` = 1 WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing unlockTopic statement.")
stmts.unlockTopic, err = db.Prepare("UPDATE `topics` SET `is_closed` = 0 WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateLastIP statement.")
stmts.updateLastIP, err = db.Prepare("UPDATE `users` SET `last_ip` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateSession statement.")
stmts.updateSession, err = db.Prepare("UPDATE `users` SET `session` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing setPassword statement.")
stmts.setPassword, err = db.Prepare("UPDATE `users` SET `password` = ?,`salt` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing setAvatar statement.")
stmts.setAvatar, err = db.Prepare("UPDATE `users` SET `avatar` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing setUsername statement.")
stmts.setUsername, err = db.Prepare("UPDATE `users` SET `name` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing changeGroup statement.")
stmts.changeGroup, err = db.Prepare("UPDATE `users` SET `group` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing activateUser statement.")
stmts.activateUser, err = db.Prepare("UPDATE `users` SET `active` = 1 WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateUserLevel statement.")
stmts.updateUserLevel, err = db.Prepare("UPDATE `users` SET `level` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing incrementUserScore statement.")
stmts.incrementUserScore, err = db.Prepare("UPDATE `users` SET `score` = `score` + ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing incrementUserPosts statement.")
stmts.incrementUserPosts, err = db.Prepare("UPDATE `users` SET `posts` = `posts` + ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing incrementUserBigposts statement.")
stmts.incrementUserBigposts, err = db.Prepare("UPDATE `users` SET `posts` = `posts` + ?,`bigposts` = `bigposts` + ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing incrementUserMegaposts statement.")
stmts.incrementUserMegaposts, err = db.Prepare("UPDATE `users` SET `posts` = `posts` + ?,`bigposts` = `bigposts` + ?,`megaposts` = `megaposts` + ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing incrementUserTopics statement.")
stmts.incrementUserTopics, err = db.Prepare("UPDATE `users` SET `topics` = `topics` + ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing editProfileReply statement.")
stmts.editProfileReply, err = db.Prepare("UPDATE `users_replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE `forums` SET `name` = ?,`desc` = ?,`active` = ?,`preset` = ? WHERE `fid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateSetting statement.")
stmts.updateSetting, err = db.Prepare("UPDATE `settings` SET `content` = ? WHERE `name` = ?")
if err != nil {
@ -610,30 +340,24 @@ func _gen_mysql() (err error) {
return err
}
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE `forums` SET `name` = ?,`desc` = ?,`active` = ?,`preset` = ? WHERE `fid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateUser statement.")
stmts.updateUser, err = db.Prepare("UPDATE `users` SET `name` = ?,`email` = ?,`group` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateUserGroup statement.")
stmts.updateUserGroup, err = db.Prepare("UPDATE `users` SET `group` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateGroupPerms statement.")
stmts.updateGroupPerms, err = db.Prepare("UPDATE `users_groups` SET `permissions` = ? WHERE `gid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateGroupRank statement.")
stmts.updateGroupRank, err = db.Prepare("UPDATE `users_groups` SET `is_admin` = ?,`is_mod` = ?,`is_banned` = ? WHERE `gid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateGroup statement.")
stmts.updateGroup, err = db.Prepare("UPDATE `users_groups` SET `name` = ?,`tag` = ? WHERE `gid` = ?")
if err != nil {
@ -670,24 +394,6 @@ func _gen_mysql() (err error) {
return err
}
log.Print("Preparing deleteUser statement.")
stmts.deleteUser, err = db.Prepare("DELETE FROM `users` WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing deleteTopic statement.")
stmts.deleteTopic, err = db.Prepare("DELETE FROM `topics` WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing deleteReply statement.")
stmts.deleteReply, err = db.Prepare("DELETE FROM `replies` WHERE `rid` = ?")
if err != nil {
return err
}
log.Print("Preparing deleteProfileReply statement.")
stmts.deleteProfileReply, err = db.Prepare("DELETE FROM `users_replies` WHERE `rid` = ?")
if err != nil {
@ -712,12 +418,6 @@ func _gen_mysql() (err error) {
return err
}
log.Print("Preparing groupCount statement.")
stmts.groupCount, err = db.Prepare("SELECT COUNT(*) AS `count` FROM `users_groups`")
if err != nil {
return err
}
log.Print("Preparing modlogCount statement.")
stmts.modlogCount, err = db.Prepare("SELECT COUNT(*) AS `count` FROM `moderation_logs`")
if err != nil {

View File

@ -5,42 +5,19 @@ package main
import "log"
import "database/sql"
import "./common"
// nolint
type Stmts struct {
addRepliesToTopic *sql.Stmt
removeRepliesFromTopic *sql.Stmt
addLikesToTopic *sql.Stmt
addLikesToReply *sql.Stmt
editTopic *sql.Stmt
editReply *sql.Stmt
stickTopic *sql.Stmt
unstickTopic *sql.Stmt
lockTopic *sql.Stmt
unlockTopic *sql.Stmt
updateLastIP *sql.Stmt
updateSession *sql.Stmt
setPassword *sql.Stmt
setAvatar *sql.Stmt
setUsername *sql.Stmt
changeGroup *sql.Stmt
activateUser *sql.Stmt
updateUserLevel *sql.Stmt
incrementUserScore *sql.Stmt
incrementUserPosts *sql.Stmt
incrementUserBigposts *sql.Stmt
incrementUserMegaposts *sql.Stmt
incrementUserTopics *sql.Stmt
editProfileReply *sql.Stmt
updateForum *sql.Stmt
updateSetting *sql.Stmt
updatePlugin *sql.Stmt
updatePluginInstall *sql.Stmt
updateTheme *sql.Stmt
updateForum *sql.Stmt
updateUser *sql.Stmt
updateUserGroup *sql.Stmt
updateGroupPerms *sql.Stmt
updateGroupRank *sql.Stmt
updateGroup *sql.Stmt
updateEmail *sql.Stmt
verifyEmail *sql.Stmt
@ -63,160 +40,22 @@ type Stmts struct {
// nolint
func _gen_pgsql() (err error) {
if dev.DebugMode {
if common.Dev.DebugMode {
log.Print("Building the generated statements")
}
log.Print("Preparing addRepliesToTopic statement.")
stmts.addRepliesToTopic, err = db.Prepare("UPDATE `topics` SET `postCount` = `postCount` + ?,`lastReplyBy` = ?,`lastReplyAt` = LOCALTIMESTAMP() WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing removeRepliesFromTopic statement.")
stmts.removeRepliesFromTopic, err = db.Prepare("UPDATE `topics` SET `postCount` = `postCount` - ? WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing addLikesToTopic statement.")
stmts.addLikesToTopic, err = db.Prepare("UPDATE `topics` SET `likeCount` = `likeCount` + ? WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing addLikesToReply statement.")
stmts.addLikesToReply, err = db.Prepare("UPDATE `replies` SET `likeCount` = `likeCount` + ? WHERE `rid` = ?")
if err != nil {
return err
}
log.Print("Preparing editTopic statement.")
stmts.editTopic, err = db.Prepare("UPDATE `topics` SET `title` = ?,`content` = ?,`parsed_content` = ? WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing editReply statement.")
stmts.editReply, err = db.Prepare("UPDATE `replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?")
if err != nil {
return err
}
log.Print("Preparing stickTopic statement.")
stmts.stickTopic, err = db.Prepare("UPDATE `topics` SET `sticky` = 1 WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing unstickTopic statement.")
stmts.unstickTopic, err = db.Prepare("UPDATE `topics` SET `sticky` = 0 WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing lockTopic statement.")
stmts.lockTopic, err = db.Prepare("UPDATE `topics` SET `is_closed` = 1 WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing unlockTopic statement.")
stmts.unlockTopic, err = db.Prepare("UPDATE `topics` SET `is_closed` = 0 WHERE `tid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateLastIP statement.")
stmts.updateLastIP, err = db.Prepare("UPDATE `users` SET `last_ip` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateSession statement.")
stmts.updateSession, err = db.Prepare("UPDATE `users` SET `session` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing setPassword statement.")
stmts.setPassword, err = db.Prepare("UPDATE `users` SET `password` = ?,`salt` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing setAvatar statement.")
stmts.setAvatar, err = db.Prepare("UPDATE `users` SET `avatar` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing setUsername statement.")
stmts.setUsername, err = db.Prepare("UPDATE `users` SET `name` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing changeGroup statement.")
stmts.changeGroup, err = db.Prepare("UPDATE `users` SET `group` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing activateUser statement.")
stmts.activateUser, err = db.Prepare("UPDATE `users` SET `active` = 1 WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateUserLevel statement.")
stmts.updateUserLevel, err = db.Prepare("UPDATE `users` SET `level` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing incrementUserScore statement.")
stmts.incrementUserScore, err = db.Prepare("UPDATE `users` SET `score` = `score` + ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing incrementUserPosts statement.")
stmts.incrementUserPosts, err = db.Prepare("UPDATE `users` SET `posts` = `posts` + ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing incrementUserBigposts statement.")
stmts.incrementUserBigposts, err = db.Prepare("UPDATE `users` SET `posts` = `posts` + ?,`bigposts` = `bigposts` + ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing incrementUserMegaposts statement.")
stmts.incrementUserMegaposts, err = db.Prepare("UPDATE `users` SET `posts` = `posts` + ?,`bigposts` = `bigposts` + ?,`megaposts` = `megaposts` + ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing incrementUserTopics statement.")
stmts.incrementUserTopics, err = db.Prepare("UPDATE `users` SET `topics` = `topics` + ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing editProfileReply statement.")
stmts.editProfileReply, err = db.Prepare("UPDATE `users_replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE `forums` SET `name` = ?,`desc` = ?,`active` = ?,`preset` = ? WHERE `fid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateSetting statement.")
stmts.updateSetting, err = db.Prepare("UPDATE `settings` SET `content` = ? WHERE `name` = ?")
if err != nil {
@ -241,30 +80,24 @@ func _gen_pgsql() (err error) {
return err
}
log.Print("Preparing updateForum statement.")
stmts.updateForum, err = db.Prepare("UPDATE `forums` SET `name` = ?,`desc` = ?,`active` = ?,`preset` = ? WHERE `fid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateUser statement.")
stmts.updateUser, err = db.Prepare("UPDATE `users` SET `name` = ?,`email` = ?,`group` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateUserGroup statement.")
stmts.updateUserGroup, err = db.Prepare("UPDATE `users` SET `group` = ? WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateGroupPerms statement.")
stmts.updateGroupPerms, err = db.Prepare("UPDATE `users_groups` SET `permissions` = ? WHERE `gid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateGroupRank statement.")
stmts.updateGroupRank, err = db.Prepare("UPDATE `users_groups` SET `is_admin` = ?,`is_mod` = ?,`is_banned` = ? WHERE `gid` = ?")
if err != nil {
return err
}
log.Print("Preparing updateGroup statement.")
stmts.updateGroup, err = db.Prepare("UPDATE `users_groups` SET `name` = ?,`tag` = ? WHERE `gid` = ?")
if err != nil {

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

View File

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

View File

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

116
main.go
View File

@ -14,65 +14,12 @@ import (
"os"
"time"
//"runtime/pprof"
"./common"
)
var version = Version{Major: 0, Minor: 1, Patch: 0, Tag: "dev"}
const hour int = 60 * 60
const day int = hour * 24
const week int = day * 7
const month int = day * 30
const year int = day * 365
const kilobyte int = 1024
const megabyte int = kilobyte * 1024
const gigabyte int = megabyte * 1024
const terabyte int = gigabyte * 1024
const petabyte int = terabyte * 1024
const saltLength int = 32
const sessionLength int = 80
var version = common.Version{Major: 0, Minor: 1, Patch: 0, Tag: "dev"}
var router *GenRouter
var startTime time.Time
// ? - Make this more customisable?
var externalSites = map[string]string{
"YT": "https://www.youtube.com/",
}
type StringList []string
// ? - Should we allow users to upload .php or .go files? It could cause security issues. We could store them with a mangled extension to render them inert
// TODO: Let admins manage this from the Control Panel
var allowedFileExts = StringList{
"png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp", "apng", // images
"txt", "xml", "json", "yaml", "toml", "ini", "md", "html", "rtf", "js", "py", "rb", "css", "scss", "less", "eqcss", "pcss", "java", "ts", "cs", "c", "cc", "cpp", "cxx", "C", "c++", "h", "hh", "hpp", "hxx", "h++", "rs", "rlib", "htaccess", "gitignore", // text
"mp3", "mp4", "avi", "wmv", "webm", // video
"otf", "woff2", "woff", "ttf", "eot", // fonts
}
var imageFileExts = StringList{
"png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp", "apng",
}
var archiveFileExts = StringList{
"bz2", "zip", "gz", "7z", "tar", "cab",
}
var executableFileExts = StringList{
"exe", "jar", "phar", "shar", "iso",
}
// TODO: Write a test for this
func (slice StringList) Contains(needle string) bool {
for _, item := range slice {
if item == needle {
return true
}
}
return false
}
var staticFiles = make(map[string]SFile)
var logWriter = io.MultiWriter(os.Stderr)
// TODO: Wrap the globals in here so we can pass pointers to them to subpackages
@ -128,58 +75,61 @@ func main() {
startTime = time.Now()
log.Print("Processing configuration data")
err = processConfig()
err = common.ProcessConfig()
if err != nil {
log.Fatal(err)
}
err = initThemes()
err = common.InitThemes()
if err != nil {
log.Fatal(err)
}
err = initDatabase()
err = InitDatabase()
if err != nil {
log.Fatal(err)
}
rstore, err = NewSQLReplyStore()
common.Rstore, err = common.NewSQLReplyStore()
if err != nil {
log.Fatal(err)
}
prstore, err = NewSQLProfileReplyStore()
common.Prstore, err = common.NewSQLProfileReplyStore()
if err != nil {
log.Fatal(err)
}
initTemplates()
common.InitTemplates()
err = initPhrases()
err = common.InitPhrases()
if err != nil {
log.Fatal(err)
}
log.Print("Loading the static files.")
err = initStaticFiles()
err = common.StaticFiles.Init()
if err != nil {
log.Fatal(err)
}
log.Print("Initialising the widgets")
err = initWidgets()
err = common.InitWidgets()
if err != nil {
log.Fatal(err)
}
log.Print("Initialising the authentication system")
auth = NewDefaultAuth()
err = LoadWordFilters()
common.Auth, err = common.NewDefaultAuth()
if err != nil {
log.Fatal(err)
}
err = verifyConfig()
err = common.LoadWordFilters()
if err != nil {
log.Fatal(err)
}
err = common.VerifyConfig()
if err != nil {
log.Fatal(err)
}
@ -195,18 +145,18 @@ func main() {
//log.Print("Running the second ticker")
// TODO: Add a plugin hook here
err := handleExpiredScheduledGroups()
err := common.HandleExpiredScheduledGroups()
if err != nil {
LogError(err)
common.LogError(err)
}
// TODO: Handle delayed moderation tasks
// TODO: Handle the daily clean-up. Move this to a 24 hour task?
// Sync with the database, if there are any changes
err = handleServerSync()
err = common.HandleServerSync()
if err != nil {
LogError(err)
common.LogError(err)
}
// TODO: Manage the TopicStore, UserStore, and ForumStore
@ -264,7 +214,7 @@ func main() {
router.HandleFunc("/ws/", routeWebsockets)
log.Print("Initialising the plugins")
initPlugins()
common.InitPlugins()
defer db.Close()
@ -274,17 +224,17 @@ func main() {
// TODO: Let users run *both* HTTP and HTTPS
log.Print("Initialising the HTTP server")
if !site.EnableSsl {
if site.Port == "" {
site.Port = "80"
if !common.Site.EnableSsl {
if common.Site.Port == "" {
common.Site.Port = "80"
}
log.Print("Listening on port " + site.Port)
err = http.ListenAndServe(":"+site.Port, router)
log.Print("Listening on port " + common.Site.Port)
err = http.ListenAndServe(":"+common.Site.Port, router)
} else {
if site.Port == "" {
site.Port = "443"
if common.Site.Port == "" {
common.Site.Port = "443"
}
if site.Port == "80" || site.Port == "443" {
if common.Site.Port == "80" || common.Site.Port == "443" {
// We should also run the server on port 80
// TODO: Redirect to port 443
go func() {
@ -295,8 +245,8 @@ func main() {
}
}()
}
log.Print("Listening on port " + site.Port)
err = http.ListenAndServeTLS(":"+site.Port, config.SslFullchain, config.SslPrivkey, router)
log.Printf("Listening on port %s", common.Site.Port)
err = http.ListenAndServeTLS(":"+common.Site.Port, common.Config.SslFullchain, common.Config.SslPrivkey, router)
}
// Why did the server stop?

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,8 @@ import (
"strconv"
"testing"
"time"
"./common"
)
func recordMustExist(t *testing.T, err error, errmsg string, args ...interface{}) {
@ -47,22 +49,22 @@ func TestUserStore(t *testing.T) {
userStoreTest(t, 3)
}
func userStoreTest(t *testing.T, newUserID int) {
ucache, hasCache := users.(UserCache)
ucache, hasCache := common.Users.(UserCache)
// Go doesn't have short-circuiting, so this'll allow us to do one liner tests
if !hasCache {
ucache = &NullUserStore{}
}
expect(t, (!hasCache || ucache.Length() == 0), fmt.Sprintf("The initial ucache length should be zero, not %d", ucache.Length()))
_, err := users.Get(-1)
_, err := common.Users.Get(-1)
recordMustNotExist(t, err, "UID #-1 shouldn't exist")
expect(t, !hasCache || ucache.Length() == 0, fmt.Sprintf("We found %d items in the user cache and it's supposed to be empty", ucache.Length()))
_, err = users.Get(0)
_, err = common.Users.Get(0)
recordMustNotExist(t, err, "UID #0 shouldn't exist")
expect(t, !hasCache || ucache.Length() == 0, fmt.Sprintf("We found %d items in the user cache and it's supposed to be empty", ucache.Length()))
user, err := users.Get(1)
user, err := common.Users.Get(1)
recordMustExist(t, err, "Couldn't find UID #1")
expect(t, user.ID == 1, fmt.Sprintf("user.ID should be 1. Got '%d' instead.", user.ID))
@ -74,7 +76,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expect(t, user.IsMod, "Admin should be a mod")
expect(t, !user.IsBanned, "Admin should not be banned")
_, err = users.Get(newUserID)
_, err = common.Users.Get(newUserID)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't exist", newUserID))
if hasCache {
@ -103,7 +105,7 @@ func userStoreTest(t *testing.T, newUserID int) {
// TODO: Lock onto the specific error type. Is this even possible without sacrificing the detailed information in the error message?
var userList map[int]*User
userList, _ = users.BulkGetMap([]int{-1})
userList, _ = common.Users.BulkGetMap([]int{-1})
if len(userList) > 0 {
t.Error("There shouldn't be any results for UID #-1")
}
@ -112,7 +114,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
}
userList, _ = users.BulkGetMap([]int{0})
userList, _ = common.Users.BulkGetMap([]int{0})
if len(userList) > 0 {
t.Error("There shouldn't be any results for UID #0")
}
@ -121,7 +123,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
}
userList, _ = users.BulkGetMap([]int{1})
userList, _ = common.Users.BulkGetMap([]int{1})
if len(userList) == 0 {
t.Error("The returned map is empty for UID #1")
} else if len(userList) > 1 {
@ -151,19 +153,19 @@ func userStoreTest(t *testing.T, newUserID int) {
expect(t, !users.Exists(-1), "UID #-1 shouldn't exist")
expect(t, !users.Exists(0), "UID #0 shouldn't exist")
expect(t, users.Exists(1), "UID #1 should exist")
expect(t, common.Users.Exists(1), "UID #1 should exist")
expect(t, !users.Exists(newUserID), fmt.Sprintf("UID #%d shouldn't exist", newUserID))
expect(t, !hasCache || ucache.Length() == 0, fmt.Sprintf("User cache length should be 0, not %d", ucache.Length()))
expectIntToBeX(t, users.GlobalCount(), 1, "The number of users should be one, not %d")
expectIntToBeX(t, common.Users.GlobalCount(), 1, "The number of users should be one, not %d")
var awaitingActivation = 5
uid, err := users.Create("Sam", "ReallyBadPassword", "sam@localhost.loc", awaitingActivation, false)
uid, err := common.Users.Create("Sam", "ReallyBadPassword", "sam@localhost.loc", awaitingActivation, false)
expectNilErr(t, err)
expect(t, uid == newUserID, fmt.Sprintf("The UID of the new user should be %d", newUserID))
expect(t, users.Exists(newUserID), fmt.Sprintf("UID #%d should exist", newUserID))
expect(t, common.Users.Exists(newUserID), fmt.Sprintf("UID #%d should exist", newUserID))
user, err = users.Get(newUserID)
user, err = common.Users.Get(newUserID)
recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
if user.ID != newUserID {
t.Errorf("The UID of the user record should be %d", newUserID)
@ -195,7 +197,7 @@ func userStoreTest(t *testing.T, newUserID int) {
recordMustNotExist(t, err, "UID #%d shouldn't be in the cache", newUserID)
}
user, err = users.Get(newUserID)
user, err = common.Users.Get(newUserID)
recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expect(t, user.ID == newUserID, fmt.Sprintf("The UID of the user record should be %d, not %d", newUserID, user.ID))
@ -221,7 +223,7 @@ func userStoreTest(t *testing.T, newUserID int) {
recordMustNotExist(t, err, "UID #%d shouldn't be in the cache", newUserID)
}
user, err = users.Get(newUserID)
user, err = common.Users.Get(newUserID)
recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
if user.ID != newUserID {
t.Errorf("The UID of the user record should be %d", newUserID)
@ -247,7 +249,7 @@ func userStoreTest(t *testing.T, newUserID int) {
recordMustNotExist(t, err, "UID #%d shouldn't be in the cache", newUserID)
}
user, err = users.Get(newUserID)
user, err = common.Users.Get(newUserID)
recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
@ -270,7 +272,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectNilErr(t, err)
expect(t, user.Group == config.DefaultGroup, "Someone's mutated this pointer elsewhere")
user, err = users.Get(newUserID)
user, err = common.Users.Get(newUserID)
recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
var user2 *User = getDummyUser()
@ -293,7 +295,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectNilErr(t, err)
expect(t, user.Group == 1, "Someone's mutated this pointer elsewhere")
user, err = users.Get(newUserID)
user, err = common.Users.Get(newUserID)
recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
user2 = getDummyUser()
@ -316,7 +318,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectNilErr(t, err)
expect(t, user.Group == 2, "Someone's mutated this pointer elsewhere")
user, err = users.Get(newUserID)
user, err = common.Users.Get(newUserID)
recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
user2 = getDummyUser()
@ -340,7 +342,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectNilErr(t, err)
expect(t, user.Group == 3, "Someone's mutated this pointer elsewhere")
user, err = users.Get(newUserID)
user, err = common.Users.Get(newUserID)
recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
user2 = getDummyUser()
@ -363,7 +365,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectNilErr(t, err)
expect(t, user.Group == 4, "Someone's mutated this pointer elsewhere")
user, err = users.Get(newUserID)
user, err = common.Users.Get(newUserID)
recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
user2 = getDummyUser()
@ -386,7 +388,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectNilErr(t, err)
expect(t, user.Group == 5, "Someone's mutated this pointer elsewhere")
user, err = users.Get(newUserID)
user, err = common.Users.Get(newUserID)
recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectIntToBeX(t, user.ID, newUserID, "The UID of the user record should be %d")
user2 = getDummyUser()
@ -419,7 +421,7 @@ func userStoreTest(t *testing.T, newUserID int) {
recordMustNotExist(t, err, "UID #%d shouldn't be in the cache", newUserID)
}
_, err = users.Get(newUserID)
_, err = common.Users.Get(newUserID)
recordMustNotExist(t, err, "UID #%d shouldn't exist", newUserID)
// TODO: Add tests for the Cache* methods
@ -515,13 +517,13 @@ func topicStoreTest(t *testing.T) {
var topic *Topic
var err error
_, err = topics.Get(-1)
_, err = common.Topics.Get(-1)
recordMustNotExist(t, err, "TID #-1 shouldn't exist")
_, err = topics.Get(0)
_, err = common.Topics.Get(0)
recordMustNotExist(t, err, "TID #0 shouldn't exist")
topic, err = topics.Get(1)
topic, err = common.Topics.Get(1)
recordMustExist(t, err, "Couldn't find TID #1")
if topic.ID != 1 {
@ -530,22 +532,22 @@ func topicStoreTest(t *testing.T) {
// TODO: Add BulkGetMap() to the TopicStore
ok := topics.Exists(-1)
ok := common.Topics.Exists(-1)
if ok {
t.Error("TID #-1 shouldn't exist")
}
ok = topics.Exists(0)
ok = common.Topics.Exists(0)
if ok {
t.Error("TID #0 shouldn't exist")
}
ok = topics.Exists(1)
ok = common.Topics.Exists(1)
if !ok {
t.Error("TID #1 should exist")
}
count := topics.GlobalCount()
count := common.Topics.GlobalCount()
if count <= 0 {
t.Error("The number of topics should be bigger than zero")
t.Error("count", count)
@ -620,11 +622,11 @@ func TestGroupStore(t *testing.T) {
initPlugins()
}
_, err := gstore.Get(-1)
_, err := common.Gstore.Get(-1)
recordMustNotExist(t, err, "GID #-1 shouldn't exist")
// TODO: Refactor the group store to remove GID #0
group, err := gstore.Get(0)
group, err := common.Gstore.Get(0)
recordMustExist(t, err, "Couldn't find GID #0")
if group.ID != 0 {
@ -632,31 +634,31 @@ func TestGroupStore(t *testing.T) {
}
expect(t, group.Name == "Unknown", fmt.Sprintf("GID #0 is named '%s' and not 'Unknown'", group.Name))
group, err = gstore.Get(1)
group, err = common.Gstore.Get(1)
recordMustExist(t, err, "Couldn't find GID #1")
if group.ID != 1 {
t.Errorf("group.ID doesn't not match the requested GID. Got '%d' instead.'", group.ID)
}
ok := gstore.Exists(-1)
ok := common.Gstore.Exists(-1)
expect(t, !ok, "GID #-1 shouldn't exist")
// 0 aka Unknown, for system posts and other oddities
ok = gstore.Exists(0)
ok = common.Gstore.Exists(0)
expect(t, ok, "GID #0 should exist")
ok = gstore.Exists(1)
ok = common.Gstore.Exists(1)
expect(t, ok, "GID #1 should exist")
var isAdmin = true
var isMod = true
var isBanned = false
gid, err := gstore.Create("Testing", "Test", isAdmin, isMod, isBanned)
gid, err := common.Gstore.Create("Testing", "Test", isAdmin, isMod, isBanned)
expectNilErr(t, err)
expect(t, gstore.Exists(gid), "The group we just made doesn't exist")
expect(t, common.Gstore.Exists(gid), "The group we just made doesn't exist")
group, err = gstore.Get(gid)
group, err = common.Gstore.Get(gid)
expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, group.IsAdmin, "This should be an admin group")
@ -666,11 +668,11 @@ func TestGroupStore(t *testing.T) {
isAdmin = false
isMod = true
isBanned = true
gid, err = gstore.Create("Testing 2", "Test", isAdmin, isMod, isBanned)
gid, err = common.Gstore.Create("Testing 2", "Test", isAdmin, isMod, isBanned)
expectNilErr(t, err)
expect(t, gstore.Exists(gid), "The group we just made doesn't exist")
expect(t, common.Gstore.Exists(gid), "The group we just made doesn't exist")
group, err = gstore.Get(gid)
group, err = common.Gstore.Get(gid)
expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, !group.IsAdmin, "This should not be an admin group")
@ -681,7 +683,7 @@ func TestGroupStore(t *testing.T) {
err = group.ChangeRank(false, false, true)
expectNilErr(t, err)
group, err = gstore.Get(gid)
group, err = common.Gstore.Get(gid)
expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, !group.IsAdmin, "This shouldn't be an admin group")
@ -691,7 +693,7 @@ func TestGroupStore(t *testing.T) {
err = group.ChangeRank(true, true, true)
expectNilErr(t, err)
group, err = gstore.Get(gid)
group, err = common.Gstore.Get(gid)
expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, group.IsAdmin, "This should be an admin group")
@ -701,7 +703,7 @@ func TestGroupStore(t *testing.T) {
err = group.ChangeRank(false, true, true)
expectNilErr(t, err)
group, err = gstore.Get(gid)
group, err = common.Gstore.Get(gid)
expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, !group.IsAdmin, "This shouldn't be an admin group")
@ -709,9 +711,9 @@ func TestGroupStore(t *testing.T) {
expect(t, !group.IsBanned, "This shouldn't be a ban group")
// Make sure the data is static
gstore.Reload(gid)
common.Gstore.Reload(gid)
group, err = gstore.Get(gid)
group, err = common.Gstore.Get(gid)
expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, !group.IsAdmin, "This shouldn't be an admin group")
@ -731,13 +733,13 @@ func TestReplyStore(t *testing.T) {
initPlugins()
}
_, err := rstore.Get(-1)
_, err := common.Rstore.Get(-1)
recordMustNotExist(t, err, "RID #-1 shouldn't exist")
_, err = rstore.Get(0)
_, err = common.Rstore.Get(0)
recordMustNotExist(t, err, "RID #0 shouldn't exist")
reply, err := rstore.Get(1)
reply, err := common.Rstore.Get(1)
expectNilErr(t, err)
expect(t, reply.ID == 1, fmt.Sprintf("RID #1 has the wrong ID. It should be 1 not %d", reply.ID))
expect(t, reply.ParentID == 1, fmt.Sprintf("The parent topic of RID #1 should be 1 not %d", reply.ParentID))
@ -745,18 +747,18 @@ func TestReplyStore(t *testing.T) {
expect(t, reply.Content == "A reply!", fmt.Sprintf("The contents of RID #1 should be 'A reply!' not %s", reply.Content))
expect(t, reply.IPAddress == "::1", fmt.Sprintf("The IPAddress of RID#1 should be '::1' not %s", reply.IPAddress))
_, err = rstore.Get(2)
_, err = common.Rstore.Get(2)
recordMustNotExist(t, err, "RID #2 shouldn't exist")
// TODO: Test Create and Get
//Create(tid int, content string, ipaddress string, fid int, uid int) (id int, err error)
topic, err := topics.Get(1)
topic, err := common.Topics.Get(1)
expectNilErr(t, err)
rid, err := rstore.Create(topic, "Fofofo", "::1", 1)
rid, err := common.Rstore.Create(topic, "Fofofo", "::1", 1)
expectNilErr(t, err)
expect(t, rid == 2, fmt.Sprintf("The next reply ID should be 2 not %d", rid))
reply, err = rstore.Get(2)
reply, err = common.Rstore.Get(2)
expectNilErr(t, err)
expect(t, reply.ID == 2, fmt.Sprintf("RID #2 has the wrong ID. It should be 2 not %d", reply.ID))
expect(t, reply.ParentID == 1, fmt.Sprintf("The parent topic of RID #2 should be 1 not %d", reply.ParentID))
@ -773,21 +775,21 @@ func TestProfileReplyStore(t *testing.T) {
initPlugins()
}
_, err := prstore.Get(-1)
_, err := common.Prstore.Get(-1)
recordMustNotExist(t, err, "PRID #-1 shouldn't exist")
_, err = prstore.Get(0)
_, err = common.Prstore.Get(0)
recordMustNotExist(t, err, "PRID #0 shouldn't exist")
_, err = prstore.Get(1)
_, err = common.Prstore.Get(1)
recordMustNotExist(t, err, "PRID #1 shouldn't exist")
var profileID = 1
prid, err := prstore.Create(profileID, "Haha", 1, "::1")
prid, err := common.Prstore.Create(profileID, "Haha", 1, "::1")
expect(t, err == nil, "Unable to create a profile reply")
expect(t, prid == 1, "The first profile reply should have an ID of 1")
profileReply, err := prstore.Get(1)
profileReply, err := common.Prstore.Get(1)
expect(t, err == nil, "PRID #1 should exist")
expect(t, profileReply.ID == 1, fmt.Sprintf("The profile reply should have an ID of 1 not %d", profileReply.ID))
expect(t, profileReply.ParentID == 1, fmt.Sprintf("The parent ID of the profile reply should be 1 not %d", profileReply.ParentID))
@ -826,7 +828,7 @@ func TestSlugs(t *testing.T) {
for _, item := range msgList {
t.Log("Testing string '" + item.Msg + "'")
res = nameToSlug(item.Msg)
res = common.NameToSlug(item.Msg)
if res != item.Expects {
t.Error("Bad output:", "'"+res+"'")
t.Error("Expected:", item.Expects)
@ -846,7 +848,7 @@ func TestAuth(t *testing.T) {
realPassword = "Madame Cassandra's Mystic Orb"
t.Log("Set realPassword to '" + realPassword + "'")
t.Log("Hashing the real password")
hashedPassword, err = BcryptGeneratePasswordNoSalt(realPassword)
hashedPassword, err = common.BcryptGeneratePasswordNoSalt(realPassword)
if err != nil {
t.Error(err)
}
@ -854,7 +856,7 @@ func TestAuth(t *testing.T) {
password = realPassword
t.Log("Testing password '" + password + "'")
t.Log("Testing salt '" + salt + "'")
err = CheckPassword(hashedPassword, password, salt)
err = common.CheckPassword(hashedPassword, password, salt)
if err == ErrMismatchedHashAndPassword {
t.Error("The two don't match")
} else if err == ErrPasswordTooLong {
@ -866,7 +868,7 @@ func TestAuth(t *testing.T) {
password = "hahaha"
t.Log("Testing password '" + password + "'")
t.Log("Testing salt '" + salt + "'")
err = CheckPassword(hashedPassword, password, salt)
err = common.CheckPassword(hashedPassword, password, salt)
if err == ErrPasswordTooLong {
t.Error("CheckPassword thinks the password is too long")
} else if err == nil {
@ -876,7 +878,7 @@ func TestAuth(t *testing.T) {
password = "Madame Cassandra's Mystic"
t.Log("Testing password '" + password + "'")
t.Log("Testing salt '" + salt + "'")
err = CheckPassword(hashedPassword, password, salt)
err = common.CheckPassword(hashedPassword, password, salt)
if err == ErrPasswordTooLong {
t.Error("CheckPassword thinks the password is too long")
} else if err == nil {

View File

@ -9,48 +9,50 @@ import (
"net/http"
"strconv"
"time"
"./common"
)
// TODO: Update the stats after edits so that we don't under or over decrement stats during deletes
// TODO: Disable stat updates in posts handled by plugin_guilds
func routeEditTopic(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeEditTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
err := r.ParseForm()
if err != nil {
return PreError("Bad Form", w, r)
return common.PreError("Bad Form", w, r)
}
isJs := (r.PostFormValue("js") == "1")
tid, err := strconv.Atoi(r.URL.Path[len("/topic/edit/submit/"):])
if err != nil {
return PreErrorJSQ("The provided TopicID is not a valid number.", w, r, isJs)
return common.PreErrorJSQ("The provided TopicID is not a valid number.", w, r, isJs)
}
topic, err := topics.Get(tid)
topic, err := common.Topics.Get(tid)
if err == ErrNoRows {
return PreErrorJSQ("The topic you tried to edit doesn't exist.", w, r, isJs)
return common.PreErrorJSQ("The topic you tried to edit doesn't exist.", w, r, isJs)
} else if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
// TODO: Add hooks to make use of headerLite
_, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID)
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
if ferr != nil {
return ferr
}
if !user.Perms.ViewTopic || !user.Perms.EditTopic {
return NoPermissionsJSQ(w, r, user, isJs)
return common.NoPermissionsJSQ(w, r, user, isJs)
}
topicName := r.PostFormValue("topic_name")
topicContent := html.EscapeString(r.PostFormValue("topic_content"))
err = topic.Update(topicName, topicContent)
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
err = fstore.UpdateLastTopic(topic.ID, user.ID, topic.ParentID)
err = common.Fstore.UpdateLastTopic(topic.ID, user.ID, topic.ParentID)
if err != nil && err != ErrNoRows {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
if !isJs {
@ -63,204 +65,204 @@ func routeEditTopic(w http.ResponseWriter, r *http.Request, user User) RouteErro
// TODO: Add support for soft-deletion and add a permission for hard delete in addition to the usual
// TODO: Disable stat updates in posts handled by plugin_guilds
func routeDeleteTopic(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeDeleteTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
// TODO: Move this to some sort of middleware
var tids []int
var isJs = false
if r.Header.Get("Content-type") == "application/json" {
if r.Body == nil {
return PreErrorJS("No request body", w, r)
return common.PreErrorJS("No request body", w, r)
}
//log.Print("r.Body: ", r.Body)
err := json.NewDecoder(r.Body).Decode(&tids)
if err != nil {
//log.Print("parse err: ", err)
return PreErrorJS("We weren't able to parse your data", w, r)
return common.PreErrorJS("We weren't able to parse your data", w, r)
}
isJs = true
} else {
tid, err := strconv.Atoi(r.URL.Path[len("/topic/delete/submit/"):])
if err != nil {
return PreError("The provided TopicID is not a valid number.", w, r)
return common.PreError("The provided TopicID is not a valid number.", w, r)
}
tids = append(tids, tid)
}
if len(tids) == 0 {
return LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs)
return common.LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs)
}
for _, tid := range tids {
topic, err := topics.Get(tid)
topic, err := common.Topics.Get(tid)
if err == ErrNoRows {
return PreErrorJSQ("The topic you tried to delete doesn't exist.", w, r, isJs)
return common.PreErrorJSQ("The topic you tried to delete doesn't exist.", w, r, isJs)
} else if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
// TODO: Add hooks to make use of headerLite
_, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID)
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
if ferr != nil {
return ferr
}
if !user.Perms.ViewTopic || !user.Perms.DeleteTopic {
return NoPermissionsJSQ(w, r, user, isJs)
return common.NoPermissionsJSQ(w, r, user, isJs)
}
// We might be able to handle this err better
err = topic.Delete()
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
err = addModLog("delete", tid, "topic", user.LastIP, user.ID)
err = common.AddModLog("delete", tid, "topic", user.LastIP, user.ID)
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
// ? - We might need to add soft-delete before we can do an action reply for this
/*_, err = stmts.createActionReply.Exec(tid,"delete",ipaddress,user.ID)
if err != nil {
return InternalErrorJSQ(err,w,r,isJs)
return common.InternalErrorJSQ(err,w,r,isJs)
}*/
log.Printf("Topic #%d was deleted by User #%d", tid, user.ID)
log.Printf("Topic #%d was deleted by common.User #%d", tid, user.ID)
}
http.Redirect(w, r, "/", http.StatusSeeOther)
return nil
}
func routeStickTopic(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeStickTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
tid, err := strconv.Atoi(r.URL.Path[len("/topic/stick/submit/"):])
if err != nil {
return PreError("The provided TopicID is not a valid number.", w, r)
return common.PreError("The provided TopicID is not a valid number.", w, r)
}
topic, err := topics.Get(tid)
topic, err := common.Topics.Get(tid)
if err == ErrNoRows {
return PreError("The topic you tried to pin doesn't exist.", w, r)
return common.PreError("The topic you tried to pin doesn't exist.", w, r)
} else if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
// TODO: Add hooks to make use of headerLite
_, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID)
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
if ferr != nil {
return ferr
}
if !user.Perms.ViewTopic || !user.Perms.PinTopic {
return NoPermissions(w, r, user)
return common.NoPermissions(w, r, user)
}
err = topic.Stick()
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
err = addModLog("stick", tid, "topic", user.LastIP, user.ID)
err = common.AddModLog("stick", tid, "topic", user.LastIP, user.ID)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
err = topic.CreateActionReply("stick", user.LastIP, user)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
return nil
}
func routeUnstickTopic(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeUnstickTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
tid, err := strconv.Atoi(r.URL.Path[len("/topic/unstick/submit/"):])
if err != nil {
return PreError("The provided TopicID is not a valid number.", w, r)
return common.PreError("The provided TopicID is not a valid number.", w, r)
}
topic, err := topics.Get(tid)
topic, err := common.Topics.Get(tid)
if err == ErrNoRows {
return PreError("The topic you tried to unpin doesn't exist.", w, r)
return common.PreError("The topic you tried to unpin doesn't exist.", w, r)
} else if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
// TODO: Add hooks to make use of headerLite
_, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID)
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
if ferr != nil {
return ferr
}
if !user.Perms.ViewTopic || !user.Perms.PinTopic {
return NoPermissions(w, r, user)
return common.NoPermissions(w, r, user)
}
err = topic.Unstick()
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
err = addModLog("unstick", tid, "topic", user.LastIP, user.ID)
err = common.AddModLog("unstick", tid, "topic", user.LastIP, user.ID)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
err = topic.CreateActionReply("unstick", user.LastIP, user)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
return nil
}
func routeLockTopic(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeLockTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
// TODO: Move this to some sort of middleware
var tids []int
var isJs = false
if r.Header.Get("Content-type") == "application/json" {
if r.Body == nil {
return PreErrorJS("No request body", w, r)
return common.PreErrorJS("No request body", w, r)
}
err := json.NewDecoder(r.Body).Decode(&tids)
if err != nil {
return PreErrorJS("We weren't able to parse your data", w, r)
return common.PreErrorJS("We weren't able to parse your data", w, r)
}
isJs = true
} else {
tid, err := strconv.Atoi(r.URL.Path[len("/topic/lock/submit/"):])
if err != nil {
return PreError("The provided TopicID is not a valid number.", w, r)
return common.PreError("The provided TopicID is not a valid number.", w, r)
}
tids = append(tids, tid)
}
if len(tids) == 0 {
return LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs)
return common.LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs)
}
for _, tid := range tids {
topic, err := topics.Get(tid)
topic, err := common.Topics.Get(tid)
if err == ErrNoRows {
return PreErrorJSQ("The topic you tried to lock doesn't exist.", w, r, isJs)
return common.PreErrorJSQ("The topic you tried to lock doesn't exist.", w, r, isJs)
} else if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
// TODO: Add hooks to make use of headerLite
_, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID)
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
if ferr != nil {
return ferr
}
if !user.Perms.ViewTopic || !user.Perms.CloseTopic {
return NoPermissionsJSQ(w, r, user, isJs)
return common.NoPermissionsJSQ(w, r, user, isJs)
}
err = topic.Lock()
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
err = addModLog("lock", tid, "topic", user.LastIP, user.ID)
err = common.AddModLog("lock", tid, "topic", user.LastIP, user.ID)
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
err = topic.CreateActionReply("lock", user.LastIP, user)
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
}
@ -270,40 +272,40 @@ func routeLockTopic(w http.ResponseWriter, r *http.Request, user User) RouteErro
return nil
}
func routeUnlockTopic(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeUnlockTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
tid, err := strconv.Atoi(r.URL.Path[len("/topic/unlock/submit/"):])
if err != nil {
return PreError("The provided TopicID is not a valid number.", w, r)
return common.PreError("The provided TopicID is not a valid number.", w, r)
}
topic, err := topics.Get(tid)
topic, err := common.Topics.Get(tid)
if err == ErrNoRows {
return PreError("The topic you tried to unlock doesn't exist.", w, r)
return common.PreError("The topic you tried to unlock doesn't exist.", w, r)
} else if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
// TODO: Add hooks to make use of headerLite
_, ferr := SimpleForumUserCheck(w, r, &user, topic.ParentID)
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
if ferr != nil {
return ferr
}
if !user.Perms.ViewTopic || !user.Perms.CloseTopic {
return NoPermissions(w, r, user)
return common.NoPermissions(w, r, user)
}
err = topic.Unlock()
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
err = addModLog("unlock", tid, "topic", user.LastIP, user.ID)
err = common.AddModLog("unlock", tid, "topic", user.LastIP, user.ID)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
err = topic.CreateActionReply("unlock", user.LastIP, user)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
@ -312,46 +314,46 @@ func routeUnlockTopic(w http.ResponseWriter, r *http.Request, user User) RouteEr
// TODO: Disable stat updates in posts handled by plugin_guilds
// TODO: Update the stats after edits so that we don't under or over decrement stats during deletes
func routeReplyEditSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
err := r.ParseForm()
if err != nil {
return PreError("Bad Form", w, r)
return common.PreError("Bad Form", w, r)
}
isJs := (r.PostFormValue("js") == "1")
rid, err := strconv.Atoi(r.URL.Path[len("/reply/edit/submit/"):])
if err != nil {
return PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs)
return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs)
}
// Get the Reply ID..
var tid int
err = stmts.getReplyTID.QueryRow(rid).Scan(&tid)
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
var fid int
err = stmts.getTopicFID.QueryRow(tid).Scan(&fid)
if err == ErrNoRows {
return PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs)
return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs)
} else if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
// TODO: Add hooks to make use of headerLite
_, ferr := SimpleForumUserCheck(w, r, &user, fid)
_, ferr := common.SimpleForumUserCheck(w, r, &user, fid)
if ferr != nil {
return ferr
}
if !user.Perms.ViewTopic || !user.Perms.EditReply {
return NoPermissionsJSQ(w, r, user, isJs)
return common.NoPermissionsJSQ(w, r, user, isJs)
}
content := html.EscapeString(preparseMessage(r.PostFormValue("edit_item")))
_, err = stmts.editReply.Exec(content, parseMessage(content, fid, "forums"), rid)
content := html.EscapeString(common.PreparseMessage(r.PostFormValue("edit_item")))
_, err = stmts.editReply.Exec(content, common.ParseMessage(content, fid, "forums"), rid)
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
if !isJs {
@ -364,99 +366,99 @@ func routeReplyEditSubmit(w http.ResponseWriter, r *http.Request, user User) Rou
// TODO: Refactor this
// TODO: Disable stat updates in posts handled by plugin_guilds
func routeReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
err := r.ParseForm()
if err != nil {
return PreError("Bad Form", w, r)
return common.PreError("Bad Form", w, r)
}
isJs := (r.PostFormValue("isJs") == "1")
rid, err := strconv.Atoi(r.URL.Path[len("/reply/delete/submit/"):])
if err != nil {
return PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs)
return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs)
}
reply, err := rstore.Get(rid)
reply, err := common.Rstore.Get(rid)
if err == ErrNoRows {
return PreErrorJSQ("The reply you tried to delete doesn't exist.", w, r, isJs)
return common.PreErrorJSQ("The reply you tried to delete doesn't exist.", w, r, isJs)
} else if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
var fid int
err = stmts.getTopicFID.QueryRow(reply.ParentID).Scan(&fid)
if err == ErrNoRows {
return PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs)
return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs)
} else if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
// TODO: Add hooks to make use of headerLite
_, ferr := SimpleForumUserCheck(w, r, &user, fid)
_, ferr := common.SimpleForumUserCheck(w, r, &user, fid)
if ferr != nil {
return ferr
}
if !user.Perms.ViewTopic || !user.Perms.DeleteReply {
return NoPermissionsJSQ(w, r, user, isJs)
return common.NoPermissionsJSQ(w, r, user, isJs)
}
err = reply.Delete()
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
//log.Printf("Reply #%d was deleted by User #%d", rid, user.ID)
//log.Printf("Reply #%d was deleted by common.User #%d", rid, user.ID)
if !isJs {
//http.Redirect(w,r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther)
} else {
w.Write(successJSONBytes)
}
replyCreator, err := users.Get(reply.CreatedBy)
replyCreator, err := common.Users.Get(reply.CreatedBy)
if err == nil {
wcount := wordCount(reply.Content)
err = replyCreator.decreasePostStats(wcount, false)
wcount := common.WordCount(reply.Content)
err = replyCreator.DecreasePostStats(wcount, false)
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
} else if err != ErrNoRows {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
err = addModLog("delete", reply.ParentID, "reply", user.LastIP, user.ID)
err = common.AddModLog("delete", reply.ParentID, "reply", user.LastIP, user.ID)
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
return nil
}
func routeProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
err := r.ParseForm()
if err != nil {
return LocalError("Bad Form", w, r, user)
return common.LocalError("Bad Form", w, r, user)
}
isJs := (r.PostFormValue("js") == "1")
rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/edit/submit/"):])
if err != nil {
return LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs)
return common.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs)
}
// Get the Reply ID..
var uid int
err = stmts.getUserReplyUID.QueryRow(rid).Scan(&uid)
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
if user.ID != uid && !user.Perms.EditReply {
return NoPermissionsJSQ(w, r, user, isJs)
return common.NoPermissionsJSQ(w, r, user, isJs)
}
content := html.EscapeString(preparseMessage(r.PostFormValue("edit_item")))
_, err = stmts.editProfileReply.Exec(content, parseMessage(content, 0, ""), rid)
content := html.EscapeString(common.PreparseMessage(r.PostFormValue("edit_item")))
_, err = stmts.editProfileReply.Exec(content, common.ParseMessage(content, 0, ""), rid)
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
if !isJs {
@ -467,35 +469,35 @@ func routeProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user Us
return nil
}
func routeProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
err := r.ParseForm()
if err != nil {
return LocalError("Bad Form", w, r, user)
return common.LocalError("Bad Form", w, r, user)
}
isJs := (r.PostFormValue("isJs") == "1")
rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/delete/submit/"):])
if err != nil {
return LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs)
return common.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs)
}
var uid int
err = stmts.getUserReplyUID.QueryRow(rid).Scan(&uid)
if err == ErrNoRows {
return LocalErrorJSQ("The reply you tried to delete doesn't exist.", w, r, user, isJs)
return common.LocalErrorJSQ("The reply you tried to delete doesn't exist.", w, r, user, isJs)
} else if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
if user.ID != uid && !user.Perms.DeleteReply {
return NoPermissionsJSQ(w, r, user, isJs)
return common.NoPermissionsJSQ(w, r, user, isJs)
}
_, err = stmts.deleteProfileReply.Exec(rid)
if err != nil {
return InternalErrorJSQ(err, w, r, isJs)
return common.InternalErrorJSQ(err, w, r, isJs)
}
//log.Printf("The profile post '%d' was deleted by User #%d", rid, user.ID)
//log.Printf("The profile post '%d' was deleted by common.User #%d", rid, user.ID)
if !isJs {
//http.Redirect(w,r, "/user/" + strconv.Itoa(uid), http.StatusSeeOther)
@ -505,13 +507,13 @@ func routeProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user
return nil
}
func routeIps(w http.ResponseWriter, r *http.Request, user User) RouteError {
headerVars, ferr := UserCheck(w, r, &user)
func routeIps(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
headerVars, ferr := common.UserCheck(w, r, &user)
if ferr != nil {
return ferr
}
if !user.Perms.ViewIPs {
return NoPermissions(w, r, user)
return common.NoPermissions(w, r, user)
}
var ip = r.FormValue("ip")
@ -520,56 +522,56 @@ func routeIps(w http.ResponseWriter, r *http.Request, user User) RouteError {
rows, err := stmts.findUsersByIPUsers.Query(ip)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
defer rows.Close()
for rows.Next() {
err := rows.Scan(&uid)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
reqUserList[uid] = true
}
err = rows.Err()
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
rows2, err := stmts.findUsersByIPTopics.Query(ip)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
defer rows2.Close()
for rows2.Next() {
err := rows2.Scan(&uid)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
reqUserList[uid] = true
}
err = rows2.Err()
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
rows3, err := stmts.findUsersByIPReplies.Query(ip)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
defer rows3.Close()
for rows3.Next() {
err := rows3.Scan(&uid)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
reqUserList[uid] = true
}
err = rows3.Err()
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
// Convert the user ID map to a slice, then bulk load the users
@ -581,68 +583,68 @@ func routeIps(w http.ResponseWriter, r *http.Request, user User) RouteError {
}
// TODO: What if a user is deleted via the Control Panel?
userList, err := users.BulkGetMap(idSlice)
userList, err := common.Users.BulkGetMap(idSlice)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
pi := IPSearchPage{"IP Search", user, headerVars, userList, ip}
if preRenderHooks["pre_render_ips"] != nil {
if runPreRenderHook("pre_render_ips", w, r, &user, &pi) {
pi := common.IPSearchPage{"IP Search", user, headerVars, userList, ip}
if common.PreRenderHooks["pre_render_ips"] != nil {
if common.RunPreRenderHook("pre_render_ips", w, r, &user, &pi) {
return nil
}
}
err = templates.ExecuteTemplate(w, "ip-search.html", pi)
err = common.Templates.ExecuteTemplate(w, "ip-search.html", pi)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
return nil
}
func routeBanSubmit(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeBanSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
if !user.Perms.BanUsers {
return NoPermissions(w, r, user)
return common.NoPermissions(w, r, user)
}
uid, err := strconv.Atoi(r.URL.Path[len("/users/ban/submit/"):])
if err != nil {
return LocalError("The provided User ID is not a valid number.", w, r, user)
return common.LocalError("The provided common.User ID is not a valid number.", w, r, user)
}
/*if uid == -2 {
return LocalError("Stop trying to ban Merlin! Ban admin! Bad! No!",w,r,user)
return common.LocalError("Stop trying to ban Merlin! Ban admin! Bad! No!",w,r,user)
}*/
targetUser, err := users.Get(uid)
targetUser, err := common.Users.Get(uid)
if err == ErrNoRows {
return LocalError("The user you're trying to ban no longer exists.", w, r, user)
return common.LocalError("The user you're trying to ban no longer exists.", w, r, user)
} else if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
// TODO: Is there a difference between IsMod and IsSuperMod? Should we delete the redundant one?
if targetUser.IsSuperAdmin || targetUser.IsAdmin || targetUser.IsMod {
return LocalError("You may not ban another staff member.", w, r, user)
return common.LocalError("You may not ban another staff member.", w, r, user)
}
if uid == user.ID {
return LocalError("Why are you trying to ban yourself? Stop that.", w, r, user)
return common.LocalError("Why are you trying to ban yourself? Stop that.", w, r, user)
}
if targetUser.IsBanned {
return LocalError("The user you're trying to unban is already banned.", w, r, user)
return common.LocalError("The user you're trying to unban is already banned.", w, r, user)
}
durationDays, err := strconv.Atoi(r.FormValue("ban-duration-days"))
if err != nil {
return LocalError("You can only use whole numbers for the number of days", w, r, user)
return common.LocalError("You can only use whole numbers for the number of days", w, r, user)
}
durationWeeks, err := strconv.Atoi(r.FormValue("ban-duration-weeks"))
if err != nil {
return LocalError("You can only use whole numbers for the number of weeks", w, r, user)
return common.LocalError("You can only use whole numbers for the number of weeks", w, r, user)
}
durationMonths, err := strconv.Atoi(r.FormValue("ban-duration-months"))
if err != nil {
return LocalError("You can only use whole numbers for the number of months", w, r, user)
return common.LocalError("You can only use whole numbers for the number of months", w, r, user)
}
var duration time.Duration
@ -650,95 +652,95 @@ func routeBanSubmit(w http.ResponseWriter, r *http.Request, user User) RouteErro
duration, _ = time.ParseDuration("0")
} else {
var seconds int
seconds += durationDays * day
seconds += durationWeeks * week
seconds += durationMonths * month
seconds += durationDays * common.Day
seconds += durationWeeks * common.Week
seconds += durationMonths * common.Month
duration, _ = time.ParseDuration(strconv.Itoa(seconds) + "s")
}
err = targetUser.Ban(duration, user.ID)
if err == ErrNoRows {
return LocalError("The user you're trying to ban no longer exists.", w, r, user)
return common.LocalError("The user you're trying to ban no longer exists.", w, r, user)
} else if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
err = addModLog("ban", uid, "user", user.LastIP, user.ID)
err = common.AddModLog("ban", uid, "user", user.LastIP, user.ID)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther)
return nil
}
func routeUnban(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeUnban(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
if !user.Perms.BanUsers {
return NoPermissions(w, r, user)
return common.NoPermissions(w, r, user)
}
uid, err := strconv.Atoi(r.URL.Path[len("/users/unban/"):])
if err != nil {
return LocalError("The provided User ID is not a valid number.", w, r, user)
return common.LocalError("The provided common.User ID is not a valid number.", w, r, user)
}
targetUser, err := users.Get(uid)
targetUser, err := common.Users.Get(uid)
if err == ErrNoRows {
return LocalError("The user you're trying to unban no longer exists.", w, r, user)
return common.LocalError("The user you're trying to unban no longer exists.", w, r, user)
} else if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
if !targetUser.IsBanned {
return LocalError("The user you're trying to unban isn't banned.", w, r, user)
return common.LocalError("The user you're trying to unban isn't banned.", w, r, user)
}
err = targetUser.Unban()
if err == ErrNoTempGroup {
return LocalError("The user you're trying to unban is not banned", w, r, user)
if err == common.ErrNoTempGroup {
return common.LocalError("The user you're trying to unban is not banned", w, r, user)
} else if err == ErrNoRows {
return LocalError("The user you're trying to unban no longer exists.", w, r, user)
return common.LocalError("The user you're trying to unban no longer exists.", w, r, user)
} else if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
err = addModLog("unban", uid, "user", user.LastIP, user.ID)
err = common.AddModLog("unban", uid, "user", user.LastIP, user.ID)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther)
return nil
}
func routeActivate(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeActivate(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
if !user.Perms.ActivateUsers {
return NoPermissions(w, r, user)
return common.NoPermissions(w, r, user)
}
uid, err := strconv.Atoi(r.URL.Path[len("/users/activate/"):])
if err != nil {
return LocalError("The provided User ID is not a valid number.", w, r, user)
return common.LocalError("The provided common.User ID is not a valid number.", w, r, user)
}
targetUser, err := users.Get(uid)
targetUser, err := common.Users.Get(uid)
if err == ErrNoRows {
return LocalError("The account you're trying to activate no longer exists.", w, r, user)
return common.LocalError("The account you're trying to activate no longer exists.", w, r, user)
} else if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
if targetUser.Active {
return LocalError("The account you're trying to activate has already been activated.", w, r, user)
return common.LocalError("The account you're trying to activate has already been activated.", w, r, user)
}
err = targetUser.Activate()
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
err = addModLog("activate", targetUser.ID, "user", user.LastIP, user.ID)
err = common.AddModLog("activate", targetUser.ID, "user", user.LastIP, user.ID)
if err != nil {
return InternalError(err, w, r)
return common.InternalError(err, w, r)
}
http.Redirect(w, r, "/user/"+strconv.Itoa(targetUser.ID), http.StatusSeeOther)
return nil

View File

@ -8,12 +8,16 @@
*/
package main
import "log"
import (
"database/sql"
"log"
//import "time"
import "database/sql"
import _ "github.com/go-sql-driver/mysql"
import "./query_gen/lib"
//import "time"
"./common"
"./query_gen/lib"
_ "github.com/go-sql-driver/mysql"
)
var dbCollation = "utf8mb4_general_ci"
@ -24,13 +28,13 @@ func init() {
func initMySQL() (err error) {
var _dbpassword string
if dbConfig.Password != "" {
_dbpassword = ":" + dbConfig.Password
if common.DbConfig.Password != "" {
_dbpassword = ":" + common.DbConfig.Password
}
// TODO: Move this bit to the query gen lib
// Open the database connection
db, err = sql.Open("mysql", dbConfig.Username+_dbpassword+"@tcp("+dbConfig.Host+":"+dbConfig.Port+")/"+dbConfig.Dbname+"?collation="+dbCollation+"&parseTime=true")
db, err = sql.Open("mysql", common.DbConfig.Username+_dbpassword+"@tcp("+common.DbConfig.Host+":"+common.DbConfig.Port+")/"+common.DbConfig.Dbname+"?collation="+dbCollation+"&parseTime=true")
if err != nil {
return err
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -3,6 +3,7 @@ package main
import (
//"fmt"
"./common"
"./extend/guilds/lib"
"./query_gen/lib"
)
@ -11,75 +12,58 @@ import (
// TODO: Add a plugin interface instead of having a bunch of argument to AddPlugin?
func init() {
plugins["guilds"] = NewPlugin("guilds", "Guilds", "Azareal", "http://github.com/Azareal", "", "", "", initGuilds, nil, deactivateGuilds, installGuilds, nil)
common.Plugins["guilds"] = common.NewPlugin("guilds", "Guilds", "Azareal", "http://github.com/Azareal", "", "", "", initGuilds, nil, deactivateGuilds, installGuilds, nil)
// TODO: Is it possible to avoid doing this when the plugin isn't activated?
prebuildTmplList = append(prebuildTmplList, guilds.PrebuildTmplList)
common.PrebuildTmplList = append(common.PrebuildTmplList, guilds.PrebuildTmplList)
}
func initGuilds() (err error) {
plugins["guilds"].AddHook("intercept_build_widgets", guilds.Widgets)
plugins["guilds"].AddHook("trow_assign", guilds.TrowAssign)
plugins["guilds"].AddHook("topic_create_pre_loop", guilds.TopicCreatePreLoop)
plugins["guilds"].AddHook("pre_render_view_forum", guilds.PreRenderViewForum)
plugins["guilds"].AddHook("simple_forum_check_pre_perms", guilds.ForumCheck)
plugins["guilds"].AddHook("forum_check_pre_perms", guilds.ForumCheck)
common.Plugins["guilds"].AddHook("intercept_build_widgets", guilds.Widgets)
common.Plugins["guilds"].AddHook("trow_assign", guilds.TrowAssign)
common.Plugins["guilds"].AddHook("topic_create_pre_loop", guilds.TopicCreatePreLoop)
common.Plugins["guilds"].AddHook("pre_render_view_forum", guilds.PreRenderViewForum)
common.Plugins["guilds"].AddHook("simple_forum_check_pre_perms", guilds.ForumCheck)
common.Plugins["guilds"].AddHook("forum_check_pre_perms", guilds.ForumCheck)
// TODO: Auto-grant this perm to admins upon installation?
registerPluginPerm("CreateGuild")
router.HandleFunc("/guilds/", guilds.GuildList)
router.HandleFunc("/guild/", guilds.ViewGuild)
router.HandleFunc("/guild/create/", guilds.CreateGuild)
router.HandleFunc("/guild/create/submit/", guilds.CreateGuildSubmit)
router.HandleFunc("/guild/members/", guilds.MemberList)
common.RegisterPluginPerm("CreateGuild")
router.HandleFunc("/guilds/", guilds.RouteGuildList)
router.HandleFunc("/guild/", guilds.MiddleViewGuild)
router.HandleFunc("/guild/create/", guilds.RouteCreateGuild)
router.HandleFunc("/guild/create/submit/", guilds.RouteCreateGuildSubmit)
router.HandleFunc("/guild/members/", guilds.RouteMemberList)
guilds.ListStmt, err = qgen.Builder.SimpleSelect("guilds", "guildID, name, desc, active, privacy, joinable, owner, memberCount, createdAt, lastUpdateTime", "", "", "")
if err != nil {
return err
}
guilds.GetGuildStmt, err = qgen.Builder.SimpleSelect("guilds", "name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime", "guildID = ?", "", "")
if err != nil {
return err
}
guilds.MemberListStmt, err = qgen.Builder.SimpleSelect("guilds_members", "guildID, uid, rank, posts, joinedAt", "", "", "")
if err != nil {
return err
}
guilds.MemberListJoinStmt, err = qgen.Builder.SimpleLeftJoin("guilds_members", "users", "users.uid, guilds_members.rank, guilds_members.posts, guilds_members.joinedAt, users.name, users.avatar", "guilds_members.uid = users.uid", "guilds_members.guildID = ?", "guilds_members.rank DESC, guilds_members.joinedat ASC", "")
if err != nil {
return err
}
guilds.GetMemberStmt, err = qgen.Builder.SimpleSelect("guilds_members", "rank, posts, joinedAt", "guildID = ? AND uid = ?", "", "")
if err != nil {
return err
}
guilds.CreateGuildStmt, err = qgen.Builder.SimpleInsert("guilds", "name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime", "?,?,?,?,1,?,1,?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()")
if err != nil {
return err
}
guilds.AttachForumStmt, err = qgen.Builder.SimpleUpdate("forums", "parentID = ?, parentType = 'guild'", "fid = ?")
if err != nil {
return err
}
guilds.UnattachForumStmt, err = qgen.Builder.SimpleUpdate("forums", "parentID = 0, parentType = ''", "fid = ?")
if err != nil {
return err
}
guilds.AddMemberStmt, err = qgen.Builder.SimpleInsert("guilds_members", "guildID, uid, rank, posts, joinedAt", "?,?,?,0,UTC_TIMESTAMP()")
if err != nil {
return err
}
acc := qgen.Builder.Accumulator()
return nil
guilds.ListStmt = acc.SimpleSelect("guilds", "guildID, name, desc, active, privacy, joinable, owner, memberCount, createdAt, lastUpdateTime", "", "", "")
guilds.GetGuildStmt = acc.SimpleSelect("guilds", "name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime", "guildID = ?", "", "")
guilds.MemberListStmt = acc.SimpleSelect("guilds_members", "guildID, uid, rank, posts, joinedAt", "", "", "")
guilds.MemberListJoinStmt = acc.SimpleLeftJoin("guilds_members", "users", "users.uid, guilds_members.rank, guilds_members.posts, guilds_members.joinedAt, users.name, users.avatar", "guilds_members.uid = users.uid", "guilds_members.guildID = ?", "guilds_members.rank DESC, guilds_members.joinedat ASC", "")
guilds.GetMemberStmt = acc.SimpleSelect("guilds_members", "rank, posts, joinedAt", "guildID = ? AND uid = ?", "", "")
guilds.CreateGuildStmt = acc.SimpleInsert("guilds", "name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime", "?,?,?,?,1,?,1,?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()")
guilds.AttachForumStmt = acc.SimpleUpdate("forums", "parentID = ?, parentType = 'guild'", "fid = ?")
guilds.UnattachForumStmt = acc.SimpleUpdate("forums", "parentID = 0, parentType = ''", "fid = ?")
guilds.AddMemberStmt = acc.SimpleInsert("guilds_members", "guildID, uid, rank, posts, joinedAt", "?,?,?,0,UTC_TIMESTAMP()")
return acc.FirstError()
}
func deactivateGuilds() {
plugins["guilds"].RemoveHook("intercept_build_widgets", guilds.Widgets)
plugins["guilds"].RemoveHook("trow_assign", guilds.TrowAssign)
plugins["guilds"].RemoveHook("topic_create_pre_loop", guilds.TopicCreatePreLoop)
plugins["guilds"].RemoveHook("pre_render_view_forum", guilds.PreRenderViewForum)
plugins["guilds"].RemoveHook("simple_forum_check_pre_perms", guilds.ForumCheck)
plugins["guilds"].RemoveHook("forum_check_pre_perms", guilds.ForumCheck)
deregisterPluginPerm("CreateGuild")
common.Plugins["guilds"].RemoveHook("intercept_build_widgets", guilds.Widgets)
common.Plugins["guilds"].RemoveHook("trow_assign", guilds.TrowAssign)
common.Plugins["guilds"].RemoveHook("topic_create_pre_loop", guilds.TopicCreatePreLoop)
common.Plugins["guilds"].RemoveHook("pre_render_view_forum", guilds.PreRenderViewForum)
common.Plugins["guilds"].RemoveHook("simple_forum_check_pre_perms", guilds.ForumCheck)
common.Plugins["guilds"].RemoveHook("forum_check_pre_perms", guilds.ForumCheck)
common.DeregisterPluginPerm("CreateGuild")
_ = router.RemoveFunc("/guilds/")
_ = router.RemoveFunc("/guild/")
_ = router.RemoveFunc("/guild/create/")

View File

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

View File

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

View File

@ -1,5 +1,7 @@
package main
import "./common"
func init() {
/*
The UName field should match the name in the URL minus plugin_ and the file extension. The same name as the map index. Please choose a unique name which won't clash with any other plugins.
@ -26,7 +28,7 @@ func init() {
That Uninstallation field which is currently unused is for not only deactivating this plugin, but for purging any data associated with it such a new tables or data produced by the end-user.
*/
plugins["skeleton"] = NewPlugin("skeleton", "Skeleton", "Azareal", "", "", "", "", initSkeleton, activateSkeleton, deactivateSkeleton, nil, nil)
common.Plugins["skeleton"] = common.NewPlugin("skeleton", "Skeleton", "Azareal", "", "", "", "", initSkeleton, activateSkeleton, deactivateSkeleton, nil, nil)
}
func initSkeleton() error { return nil }

View File

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

View File

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

View File

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

View File

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

View File

@ -230,20 +230,12 @@ func writeSelects(adapter qgen.DB_Adapter) error {
adapter.SimpleSelect("getFullSetting", "settings", "name, type, constraints", "name = ?", "", "")
adapter.SimpleSelect("getFullSettings", "settings", "name, content, type, constraints", "", "", "")
adapter.SimpleSelect("getThemes", "themes", "uname, default", "", "", "")
adapter.SimpleSelect("getWidgets", "widgets", "position, side, type, active, location, data", "", "position ASC", "")
adapter.SimpleSelect("isPluginActive", "plugins", "active", "uname = ?", "", "")
//adapter.SimpleSelect("isPluginInstalled","plugins","installed","uname = ?","","")
adapter.SimpleSelect("getUsersOffset", "users", "uid, name, group, active, is_super_admin, avatar", "", "uid ASC", "?,?")
adapter.SimpleSelect("getWordFilters", "word_filters", "wfid, find, replacement", "", "", "")
adapter.SimpleSelect("isThemeDefault", "themes", "default", "uname = ?", "", "")
adapter.SimpleSelect("getModlogs", "moderation_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "", "", "")
@ -256,10 +248,6 @@ func writeSelects(adapter qgen.DB_Adapter) error {
adapter.SimpleSelect("getUserReplyUID", "users_replies", "uid", "rid = ?", "", "")
adapter.SimpleSelect("hasLikedTopic", "likes", "targetItem", "sentBy = ? and targetItem = ? and targetType = 'topics'", "", "")
adapter.SimpleSelect("hasLikedReply", "likes", "targetItem", "sentBy = ? and targetItem = ? and targetType = 'replies'", "", "")
adapter.SimpleSelect("getUserName", "users", "name", "uid = ?", "", "")
adapter.SimpleSelect("getEmailsByUser", "emails", "email, validated, token", "uid = ?", "", "")
@ -274,10 +262,6 @@ func writeSelects(adapter qgen.DB_Adapter) error {
adapter.SimpleSelect("getForumTopicsOffset", "topics", "tid, title, content, createdBy, is_closed, sticky, createdAt, lastReplyAt, lastReplyBy, parentID, postCount, likeCount", "parentID = ?", "sticky DESC, lastReplyAt DESC, createdBy DESC", "?,?")
adapter.SimpleSelect("getExpiredScheduledGroups", "users_groups_scheduler", "uid", "UTC_TIMESTAMP() > revert_at AND temporary = 1", "", "")
adapter.SimpleSelect("getSync", "sync", "last_update", "", "", "")
adapter.SimpleSelect("getAttachment", "attachments", "sectionID, sectionTable, originID, originTable, uploadedBy, path", "path = ? AND sectionID = ? AND sectionTable = ?", "", "")
return nil
@ -288,11 +272,6 @@ func writeLeftJoins(adapter qgen.DB_Adapter) error {
adapter.SimpleLeftJoin("getTopicList", "topics", "users", "topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.parentID, users.name, users.avatar", "topics.createdBy = users.uid", "", "topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC", "")
// TODO: Can we get rid of this?
adapter.SimpleLeftJoin("getTopicUser", "topics", "users", "topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level", "topics.createdBy = users.uid", "tid = ?", "", "")
adapter.SimpleLeftJoin("getTopicByReply", "replies", "topics", "topics.tid, topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, topics.data", "replies.tid = topics.tid", "rid = ?", "", "")
adapter.SimpleLeftJoin("getTopicReplies", "replies", "users", "replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress", "replies.createdBy = users.uid", "tid = ?", "", "")
adapter.SimpleLeftJoin("getForumTopics", "topics", "users", "topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, users.name, users.avatar", "topics.createdBy = users.uid", "topics.parentID = ?", "topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy desc", "")
@ -314,10 +293,6 @@ func writeInnerJoins(adapter qgen.DB_Adapter) (err error) {
func writeInserts(adapter qgen.DB_Adapter) error {
adapter.SimpleInsert("createReport", "topics", "title, content, parsed_content, createdAt, lastReplyAt, createdBy, lastReplyBy, data, parentID, css_class", "?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?,1,'report'")
adapter.SimpleInsert("createActionReply", "replies", "tid, actionType, ipaddress, createdBy, createdAt, lastUpdated, content, parsed_content", "?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'',''")
adapter.SimpleInsert("createLike", "likes", "weight, targetItem, targetType, sentBy", "?,?,?,?")
adapter.SimpleInsert("addActivity", "activity_stream", "actor, targetUser, event, elementType, elementID", "?,?,?,?,?")
adapter.SimpleInsert("notifyOne", "activity_stream_matches", "watcher, asid", "?,?")
@ -332,10 +307,6 @@ func writeInserts(adapter qgen.DB_Adapter) error {
adapter.SimpleInsert("addTheme", "themes", "uname, default", "?,?")
adapter.SimpleInsert("addModlogEntry", "moderation_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "?,?,?,?,?,UTC_TIMESTAMP()")
adapter.SimpleInsert("addAdminlogEntry", "administration_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "?,?,?,?,?,UTC_TIMESTAMP()")
adapter.SimpleInsert("addAttachment", "attachments", "sectionID, sectionTable, originID, originTable, uploadedBy, path", "?,?,?,?,?,?")
adapter.SimpleInsert("createWordFilter", "word_filters", "find, replacement", "?,?")
@ -363,56 +334,10 @@ func writeReplaces(adapter qgen.DB_Adapter) (err error) {
}*/
func writeUpdates(adapter qgen.DB_Adapter) error {
adapter.SimpleUpdate("addRepliesToTopic", "topics", "postCount = postCount + ?, lastReplyBy = ?, lastReplyAt = UTC_TIMESTAMP()", "tid = ?")
adapter.SimpleUpdate("removeRepliesFromTopic", "topics", "postCount = postCount - ?", "tid = ?")
adapter.SimpleUpdate("addLikesToTopic", "topics", "likeCount = likeCount + ?", "tid = ?")
adapter.SimpleUpdate("addLikesToReply", "replies", "likeCount = likeCount + ?", "rid = ?")
adapter.SimpleUpdate("editTopic", "topics", "title = ?, content = ?, parsed_content = ?", "tid = ?")
adapter.SimpleUpdate("editReply", "replies", "content = ?, parsed_content = ?", "rid = ?")
adapter.SimpleUpdate("stickTopic", "topics", "sticky = 1", "tid = ?")
adapter.SimpleUpdate("unstickTopic", "topics", "sticky = 0", "tid = ?")
adapter.SimpleUpdate("lockTopic", "topics", "is_closed = 1", "tid = ?")
adapter.SimpleUpdate("unlockTopic", "topics", "is_closed = 0", "tid = ?")
adapter.SimpleUpdate("updateLastIP", "users", "last_ip = ?", "uid = ?")
adapter.SimpleUpdate("updateSession", "users", "session = ?", "uid = ?")
adapter.SimpleUpdate("setPassword", "users", "password = ?, salt = ?", "uid = ?")
adapter.SimpleUpdate("setAvatar", "users", "avatar = ?", "uid = ?")
adapter.SimpleUpdate("setUsername", "users", "name = ?", "uid = ?")
adapter.SimpleUpdate("changeGroup", "users", "group = ?", "uid = ?")
adapter.SimpleUpdate("activateUser", "users", "active = 1", "uid = ?")
adapter.SimpleUpdate("updateUserLevel", "users", "level = ?", "uid = ?")
adapter.SimpleUpdate("incrementUserScore", "users", "score = score + ?", "uid = ?")
adapter.SimpleUpdate("incrementUserPosts", "users", "posts = posts + ?", "uid = ?")
adapter.SimpleUpdate("incrementUserBigposts", "users", "posts = posts + ?, bigposts = bigposts + ?", "uid = ?")
adapter.SimpleUpdate("incrementUserMegaposts", "users", "posts = posts + ?, bigposts = bigposts + ?, megaposts = megaposts + ?", "uid = ?")
adapter.SimpleUpdate("incrementUserTopics", "users", "topics = topics + ?", "uid = ?")
adapter.SimpleUpdate("editProfileReply", "users_replies", "content = ?, parsed_content = ?", "rid = ?")
adapter.SimpleUpdate("updateForum", "forums", "name = ?, desc = ?, active = ?, preset = ?", "fid = ?")
adapter.SimpleUpdate("updateSetting", "settings", "content = ?", "name = ?")
adapter.SimpleUpdate("updatePlugin", "plugins", "active = ?", "uname = ?")
@ -421,14 +346,12 @@ func writeUpdates(adapter qgen.DB_Adapter) error {
adapter.SimpleUpdate("updateTheme", "themes", "default = ?", "uname = ?")
adapter.SimpleUpdate("updateForum", "forums", "name = ?, desc = ?, active = ?, preset = ?", "fid = ?")
adapter.SimpleUpdate("updateUser", "users", "name = ?, email = ?, group = ?", "uid = ?")
adapter.SimpleUpdate("updateUserGroup", "users", "group = ?", "uid = ?")
adapter.SimpleUpdate("updateGroupPerms", "users_groups", "permissions = ?", "gid = ?")
adapter.SimpleUpdate("updateGroupRank", "users_groups", "is_admin = ?, is_mod = ?, is_banned = ?", "gid = ?")
adapter.SimpleUpdate("updateGroup", "users_groups", "name = ?, tag = ?", "gid = ?")
adapter.SimpleUpdate("updateEmail", "emails", "email = ?, uid = ?, validated = ?, token = ?", "email = ?")
@ -445,12 +368,6 @@ func writeUpdates(adapter qgen.DB_Adapter) error {
}
func writeDeletes(adapter qgen.DB_Adapter) error {
adapter.SimpleDelete("deleteUser", "users", "uid = ?")
adapter.SimpleDelete("deleteTopic", "topics", "tid = ?")
adapter.SimpleDelete("deleteReply", "replies", "rid = ?")
adapter.SimpleDelete("deleteProfileReply", "users_replies", "rid = ?")
//adapter.SimpleDelete("deleteForumPermsByForum", "forums_permissions", "fid = ?")
@ -466,8 +383,6 @@ func writeDeletes(adapter qgen.DB_Adapter) error {
func writeSimpleCounts(adapter qgen.DB_Adapter) error {
adapter.SimpleCount("reportExists", "topics", "data = ? AND data != '' AND parentID = 1", "")
adapter.SimpleCount("groupCount", "users_groups", "", "")
adapter.SimpleCount("modlogCount", "moderation_logs", "", "")
return nil

View File

@ -2,9 +2,13 @@
package main
//import "fmt"
import "strings"
import "sync"
import "net/http"
import (
"net/http"
"strings"
"sync"
"./common"
)
// TODO: Support the new handler signatures created by our efforts to move the PreRoute middleware into the generated router
// nolint Stop linting the uselessness of this file, we never know when we might need this file again
@ -59,5 +63,5 @@ func (router *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
//log.Print("req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/')]",req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/')])
NotFound(w, req)
common.NotFound(w, req)
}

View File

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

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"
"time"
"./common"
"github.com/Azareal/gopsutil/cpu"
"github.com/Azareal/gopsutil/mem"
"github.com/gorilla/websocket"
@ -25,7 +26,7 @@ import (
type WSUser struct {
conn *websocket.Conn
User *User
User *common.User
}
type WSHub struct {
@ -164,13 +165,13 @@ func (hub *WSHub) pushAlerts(users []int, asid int, event string, elementType st
}
// TODO: How should we handle errors for this?
func routeWebsockets(w http.ResponseWriter, r *http.Request, user User) RouteError {
func routeWebsockets(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
conn, err := wsUpgrader.Upgrade(w, r, nil)
if err != nil {
return nil
}
userptr, err := users.Get(user.ID)
if err != nil && err != ErrStoreCapacityOverflow {
userptr, err := common.Users.Get(user.ID)
if err != nil && err != common.ErrStoreCapacityOverflow {
return nil
}
@ -341,9 +342,9 @@ AdminStatLoop:
onlineUsersColour = "stat_red"
}
totonline, totunit = convertFriendlyUnit(totonline)
uonline, uunit = convertFriendlyUnit(uonline)
gonline, gunit = convertFriendlyUnit(gonline)
totonline, totunit = common.ConvertFriendlyUnit(totonline)
uonline, uunit = common.ConvertFriendlyUnit(uonline)
gonline, gunit = common.ConvertFriendlyUnit(gonline)
}
if cpuerr != nil {
@ -364,8 +365,8 @@ AdminStatLoop:
if ramerr != nil {
ramstr = "Unknown"
} else {
totalCount, totalUnit := convertByteUnit(float64(memres.Total))
usedCount := convertByteInUnit(float64(memres.Total-memres.Available), totalUnit)
totalCount, totalUnit := common.ConvertByteUnit(float64(memres.Total))
usedCount := common.ConvertByteInUnit(float64(memres.Total-memres.Available), totalUnit)
// Round totals with .9s up, it's how most people see it anyway. Floats are notoriously imprecise, so do it off 0.85
var totstr string

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