Removed the images for Cosmo from /images/, it's very saddening to see it go :(
Moved Reload from the UserStore into the UserCache. Replaced many of the calls to Reload with CacheRemove. Simplified the error functions. Fixed a bug in the errors where they didn't have any CSS. Oops. Added CustomErrorJS(), unused for now, but it may be useful in the future, especially for plugins. Fixed many problems in the themes. Added the Stick(), Unstick(), CreateActionReply(), Lock() and Unlock() methods to *Topic. Renamed ip-search.html to ip-search-results.html Added the Activate() and initPerms methods to *User. Tempra Cursive is hiding from sight for this one commit. Added Font Awesome to /public/, it isn't used yet.
1
.gitignore
vendored
@ -8,6 +8,7 @@ brun.bat
|
||||
uploads/avatar_*
|
||||
uploads/socialgroup_*
|
||||
bin/*
|
||||
out/*
|
||||
*.exe
|
||||
*.exe~
|
||||
*.prof
|
||||
|
15
auth.go
@ -92,10 +92,10 @@ func (auth *DefaultAuth) ForceLogout(uid int) error {
|
||||
return errors.New("There was a glitch in the system. Please contact your local administrator.")
|
||||
}
|
||||
|
||||
// Flush the user out of the cache and reload
|
||||
err = users.Reload(uid)
|
||||
if err != nil {
|
||||
return errors.New("Your account no longer exists.")
|
||||
// Flush the user out of the cache
|
||||
ucache, ok := users.(UserCache)
|
||||
if ok {
|
||||
ucache.CacheRemove(uid)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -167,7 +167,10 @@ func (auth *DefaultAuth) CreateSession(uid int) (session string, err error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Reload the user data
|
||||
_ = users.Reload(uid)
|
||||
// Flush the user data from the cache
|
||||
ucache, ok := users.(UserCache)
|
||||
if ok {
|
||||
ucache.CacheRemove(uid)
|
||||
}
|
||||
return session, nil
|
||||
}
|
||||
|
208
errors.go
@ -1,40 +1,18 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import "log"
|
||||
import "bytes"
|
||||
|
||||
import "sync"
|
||||
import "net/http"
|
||||
import "runtime/debug"
|
||||
|
||||
// TODO: Use the error_buffer variable to construct the system log in the Control Panel. Should we log errors caused by users too? Or just collect statistics on those or do nothing? Intercept recover()? Could we intercept the logger instead here? We might get too much information, if we intercept the logger, maybe make it part of the Debug page?
|
||||
// ? - Should we pass HeaderVars / HeaderLite rather than forcing the errors to pull the global HeaderVars instance?
|
||||
var errorBufferMutex sync.RWMutex
|
||||
var errorBuffer []error
|
||||
|
||||
//var notfoundCountPerSecond int
|
||||
//var nopermsCountPerSecond int
|
||||
var errorInternal []byte
|
||||
var errorNotfound []byte
|
||||
|
||||
func initErrors() error {
|
||||
var b bytes.Buffer
|
||||
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, hvars, tList, "A problem has occurred in the system."}
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
errorInternal = b.Bytes()
|
||||
|
||||
b.Reset()
|
||||
pi = Page{"Not Found", user, hvars, tList, "The requested page doesn't exist."}
|
||||
err = templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
errorNotfound = b.Bytes()
|
||||
return nil
|
||||
}
|
||||
|
||||
// LogError logs internal handler errors which can't be handled with InternalError() as a wrapper for log.Fatal(), we might do more with it in the future
|
||||
func LogError(err error) {
|
||||
@ -47,10 +25,19 @@ func LogError(err error) {
|
||||
}
|
||||
|
||||
// InternalError is the main function for handling internal errors, while simultaneously printing out a page for the end-user to let them know that *something* has gone wrong
|
||||
// ? - Add a user parameter?
|
||||
func InternalError(err error, w http.ResponseWriter) {
|
||||
_, _ = w.Write(errorInternal)
|
||||
log.Print(err)
|
||||
debug.PrintStack()
|
||||
|
||||
// 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, getDefaultHeaderVar(), tList, "A problem has occurred in the system."}
|
||||
err = templates.ExecuteTemplate(w, "error.html", pi)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
errorBufferMutex.Lock()
|
||||
defer errorBufferMutex.Unlock()
|
||||
errorBuffer = append(errorBuffer, err)
|
||||
@ -58,22 +45,17 @@ func InternalError(err error, w http.ResponseWriter) {
|
||||
}
|
||||
|
||||
// InternalErrorJSQ is the JSON "maybe" version of InternalError which can handle both JSON and normal requests
|
||||
// ? - Add a user parameter?
|
||||
func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, isJs bool) {
|
||||
w.WriteHeader(500)
|
||||
if !isJs {
|
||||
_, _ = w.Write(errorInternal)
|
||||
InternalError(err, w)
|
||||
} else {
|
||||
_, _ = w.Write([]byte(`{"errmsg":"A problem has occured in the system."}`))
|
||||
InternalErrorJS(err, w, r)
|
||||
}
|
||||
log.Print(err)
|
||||
debug.PrintStack()
|
||||
errorBufferMutex.Lock()
|
||||
defer errorBufferMutex.Unlock()
|
||||
errorBuffer = append(errorBuffer, err)
|
||||
log.Fatal("")
|
||||
}
|
||||
|
||||
// InternalErrorJS is the JSON version of InternalError on routes we know will only be requested via JSON. E.g. An API.
|
||||
// ? - Add a user parameter?
|
||||
func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(500)
|
||||
_, _ = w.Write([]byte(`{"errmsg":"A problem has occured in the system."}`))
|
||||
@ -87,35 +69,31 @@ func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) {
|
||||
// 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) {
|
||||
w.WriteHeader(401)
|
||||
pi := Page{"Local Error", user, hvars, tList, "You need to login to do that."}
|
||||
pi := Page{"Local Error", user, getDefaultHeaderVar(), tList, "You need to login to do that."}
|
||||
if preRenderHooks["pre_render_error"] != nil {
|
||||
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
err := templates.ExecuteTemplate(w, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
fmt.Fprintln(w, b.String())
|
||||
}
|
||||
|
||||
func PreError(errmsg string, w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(500)
|
||||
user := User{ID: 0, Group: 6, Perms: GuestPerms}
|
||||
pi := Page{"Error", user, hvars, tList, errmsg}
|
||||
pi := Page{"Error", user, getDefaultHeaderVar(), tList, errmsg}
|
||||
if preRenderHooks["pre_render_error"] != nil {
|
||||
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
err := templates.ExecuteTemplate(w, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
fmt.Fprintln(w, b.String())
|
||||
}
|
||||
|
||||
func PreErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) {
|
||||
@ -124,60 +102,33 @@ func PreErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func PreErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, isJs bool) {
|
||||
w.WriteHeader(500)
|
||||
if !isJs {
|
||||
user := User{ID: 0, Group: 6, Perms: GuestPerms}
|
||||
pi := Page{"Local Error", user, hvars, tList, errmsg}
|
||||
if preRenderHooks["pre_render_error"] != nil {
|
||||
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
fmt.Fprintln(w, b.String())
|
||||
PreError(errmsg, w, r)
|
||||
} else {
|
||||
_, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
|
||||
PreErrorJS(errmsg, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// LocalError is an error shown to the end-user when something goes wrong and it's not the software's fault
|
||||
func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(500)
|
||||
pi := Page{"Local Error", user, hvars, tList, errmsg}
|
||||
pi := Page{"Local Error", user, getDefaultHeaderVar(), tList, errmsg}
|
||||
if preRenderHooks["pre_render_error"] != nil {
|
||||
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
err := templates.ExecuteTemplate(w, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
fmt.Fprintln(w, b.String())
|
||||
}
|
||||
|
||||
func LocalErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, user User, isJs bool) {
|
||||
w.WriteHeader(500)
|
||||
if !isJs {
|
||||
pi := Page{"Local Error", user, hvars, tList, errmsg}
|
||||
if preRenderHooks["pre_render_error"] != nil {
|
||||
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
fmt.Fprintln(w, b.String())
|
||||
LocalError(errmsg, w, r, user)
|
||||
} else {
|
||||
_, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
|
||||
LocalErrorJS(errmsg, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,156 +140,135 @@ func LocalErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) {
|
||||
// NoPermissions is an error shown to the end-user when they try to access an area which they aren't authorised to access
|
||||
func NoPermissions(w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(403)
|
||||
pi := Page{"Local Error", user, hvars, tList, "You don't have permission to do that."}
|
||||
pi := Page{"Local Error", user, getDefaultHeaderVar(), tList, "You don't have permission to do that."}
|
||||
if preRenderHooks["pre_render_error"] != nil {
|
||||
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
err := templates.ExecuteTemplate(w, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
errpage := b.String()
|
||||
fmt.Fprintln(w, errpage)
|
||||
}
|
||||
|
||||
func NoPermissionsJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) {
|
||||
w.WriteHeader(403)
|
||||
if !isJs {
|
||||
pi := Page{"Local Error", user, hvars, tList, "You don't have permission to do that."}
|
||||
if preRenderHooks["pre_render_error"] != nil {
|
||||
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
fmt.Fprintln(w, b.String())
|
||||
NoPermissions(w, r, user)
|
||||
} else {
|
||||
_, _ = w.Write([]byte(`{"errmsg":"You don't have permission to do that."}`))
|
||||
NoPermissionsJS(w, r, user)
|
||||
}
|
||||
}
|
||||
|
||||
func NoPermissionsJS(w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(403)
|
||||
_, _ = w.Write([]byte(`{"errmsg":"You don't have permission to do that."}`))
|
||||
}
|
||||
|
||||
// ? - Is this actually used? Should it be used? A ban in Gosora should be more of a permission revocation to stop them posting rather than something which spits up an error page, right?
|
||||
func Banned(w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(403)
|
||||
pi := Page{"Banned", user, hvars, tList, "You have been banned from this site."}
|
||||
pi := Page{"Banned", user, getDefaultHeaderVar(), tList, "You have been banned from this site."}
|
||||
if preRenderHooks["pre_render_error"] != nil {
|
||||
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
err := templates.ExecuteTemplate(w, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
fmt.Fprintln(w, b.String())
|
||||
}
|
||||
|
||||
// nolint
|
||||
// BannedJSQ is the version of the banned error page which handles both JavaScript requests and normal page loads
|
||||
func BannedJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) {
|
||||
w.WriteHeader(403)
|
||||
if !isJs {
|
||||
pi := Page{"Banned", user, hvars, tList, "You have been banned from this site."}
|
||||
if preRenderHooks["pre_render_error"] != nil {
|
||||
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
fmt.Fprintln(w, b.String())
|
||||
Banned(w, r, user)
|
||||
} else {
|
||||
_, _ = w.Write([]byte(`{"errmsg":"You have been banned from this site."}`))
|
||||
BannedJS(w, r, user)
|
||||
}
|
||||
}
|
||||
|
||||
func BannedJS(w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(403)
|
||||
_, _ = w.Write([]byte(`{"errmsg":"You have been banned from this site."}`))
|
||||
}
|
||||
|
||||
// nolint
|
||||
func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) {
|
||||
w.WriteHeader(401)
|
||||
if !isJs {
|
||||
pi := Page{"Local Error", user, hvars, tList, "You need to login to do that."}
|
||||
pi := Page{"Local Error", user, getDefaultHeaderVar(), tList, "You need to login to do that."}
|
||||
if preRenderHooks["pre_render_error"] != nil {
|
||||
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
err := templates.ExecuteTemplate(w, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
fmt.Fprintln(w, b.String())
|
||||
} else {
|
||||
_, _ = w.Write([]byte(`{"errmsg":"You need to login to do that."}`))
|
||||
}
|
||||
}
|
||||
|
||||
// SecurityError is used whenever a session mismatch is found
|
||||
// ? - Should we add JS and JSQ versions of this?
|
||||
func SecurityError(w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(403)
|
||||
pi := Page{"Security Error", user, hvars, tList, "There was a security issue with your request."}
|
||||
pi := Page{"Security Error", user, getDefaultHeaderVar(), 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) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
err := templates.ExecuteTemplate(w, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
fmt.Fprintln(w, b.String())
|
||||
}
|
||||
|
||||
// ? - Add a JSQ and JS version of this?
|
||||
// ? - Add a user parameter?
|
||||
func NotFound(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(404)
|
||||
_, _ = w.Write(errorNotfound)
|
||||
// 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, getDefaultHeaderVar(), tList, "The requested page doesn't exist."}
|
||||
err := templates.ExecuteTemplate(w, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// nolint
|
||||
func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(errcode)
|
||||
pi := Page{errtitle, user, hvars, tList, errmsg}
|
||||
pi := Page{errtitle, user, getDefaultHeaderVar(), tList, errmsg}
|
||||
if preRenderHooks["pre_render_error"] != nil {
|
||||
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
err := templates.ExecuteTemplate(w, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
fmt.Fprintln(w, b.String())
|
||||
}
|
||||
|
||||
// nolint
|
||||
func CustomErrorJSQ(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User, isJs bool) {
|
||||
w.WriteHeader(errcode)
|
||||
if !isJs {
|
||||
pi := Page{errtitle, user, hvars, tList, errmsg}
|
||||
if preRenderHooks["pre_render_error"] != nil {
|
||||
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
}
|
||||
fmt.Fprintln(w, b.String())
|
||||
CustomError(errmsg, errcode, errtitle, w, r, user)
|
||||
} else {
|
||||
_, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
|
||||
CustomErrorJS(errmsg, errcode, errtitle, w, r, user)
|
||||
}
|
||||
}
|
||||
|
||||
// nolint
|
||||
func CustomErrorJS(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(errcode)
|
||||
_, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
|
||||
}
|
||||
|
@ -156,6 +156,7 @@ func NewPlugin(uname string, name string, author string, url string, settings st
|
||||
}
|
||||
}
|
||||
|
||||
// ? - Is this racey?
|
||||
func (plugin *Plugin) AddHook(name string, handler interface{}) {
|
||||
switch h := handler.(type) {
|
||||
case func(interface{}) interface{}:
|
||||
@ -193,6 +194,7 @@ func (plugin *Plugin) AddHook(name string, handler interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// ? - Is this racey?
|
||||
func (plugin *Plugin) RemoveHook(name string, handler interface{}) {
|
||||
switch handler.(type) {
|
||||
case func(interface{}) interface{}:
|
||||
@ -250,6 +252,7 @@ func initPlugins() {
|
||||
pluginsInited = true
|
||||
}
|
||||
|
||||
// ? - Are the following functions racey?
|
||||
func runHook(name string, data interface{}) interface{} {
|
||||
for _, hook := range hooks[name] {
|
||||
data = hook(data)
|
||||
|
23
gen_mysql.go
@ -35,7 +35,6 @@ var getUserReplyUIDStmt *sql.Stmt
|
||||
var hasLikedTopicStmt *sql.Stmt
|
||||
var hasLikedReplyStmt *sql.Stmt
|
||||
var getUserNameStmt *sql.Stmt
|
||||
var getUserActiveStmt *sql.Stmt
|
||||
var getEmailsByUserStmt *sql.Stmt
|
||||
var getTopicBasicStmt *sql.Stmt
|
||||
var getActivityEntryStmt *sql.Stmt
|
||||
@ -83,6 +82,8 @@ var editTopicStmt *sql.Stmt
|
||||
var editReplyStmt *sql.Stmt
|
||||
var stickTopicStmt *sql.Stmt
|
||||
var unstickTopicStmt *sql.Stmt
|
||||
var lockTopicStmt *sql.Stmt
|
||||
var unlockTopicStmt *sql.Stmt
|
||||
var updateLastIPStmt *sql.Stmt
|
||||
var updateSessionStmt *sql.Stmt
|
||||
var setPasswordStmt *sql.Stmt
|
||||
@ -292,12 +293,6 @@ func _gen_mysql() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing getUserActive statement.")
|
||||
getUserActiveStmt, err = db.Prepare("SELECT `active` FROM `users` WHERE `uid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing getEmailsByUser statement.")
|
||||
getEmailsByUserStmt, err = db.Prepare("SELECT `email`,`validated`,`token` FROM `emails` WHERE `uid` = ?")
|
||||
if err != nil {
|
||||
@ -557,7 +552,7 @@ func _gen_mysql() (err error) {
|
||||
}
|
||||
|
||||
log.Print("Preparing editTopic statement.")
|
||||
editTopicStmt, err = db.Prepare("UPDATE `topics` SET `title` = ?,`content` = ?,`parsed_content` = ?,`is_closed` = ? WHERE `tid` = ?")
|
||||
editTopicStmt, err = db.Prepare("UPDATE `topics` SET `title` = ?,`content` = ?,`parsed_content` = ? WHERE `tid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -580,6 +575,18 @@ func _gen_mysql() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing lockTopic statement.")
|
||||
lockTopicStmt, err = db.Prepare("UPDATE `topics` SET `is_closed` = 1 WHERE `tid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing unlockTopic statement.")
|
||||
unlockTopicStmt, err = db.Prepare("UPDATE `topics` SET `is_closed` = 0 WHERE `tid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing updateLastIP statement.")
|
||||
updateLastIPStmt, err = db.Prepare("UPDATE `users` SET `last_ip` = ? WHERE `uid` = ?")
|
||||
if err != nil {
|
||||
|
16
gen_pgsql.go
@ -18,6 +18,8 @@ var editTopicStmt *sql.Stmt
|
||||
var editReplyStmt *sql.Stmt
|
||||
var stickTopicStmt *sql.Stmt
|
||||
var unstickTopicStmt *sql.Stmt
|
||||
var lockTopicStmt *sql.Stmt
|
||||
var unlockTopicStmt *sql.Stmt
|
||||
var updateLastIPStmt *sql.Stmt
|
||||
var updateSessionStmt *sql.Stmt
|
||||
var setPasswordStmt *sql.Stmt
|
||||
@ -96,7 +98,7 @@ func _gen_pgsql() (err error) {
|
||||
}
|
||||
|
||||
log.Print("Preparing editTopic statement.")
|
||||
editTopicStmt, err = db.Prepare("UPDATE `topics` SET `title` = ?,`content` = ?,`parsed_content` = ?,`is_closed` = ? WHERE `tid` = ?")
|
||||
editTopicStmt, err = db.Prepare("UPDATE `topics` SET `title` = ?,`content` = ?,`parsed_content` = ? WHERE `tid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -119,6 +121,18 @@ func _gen_pgsql() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing lockTopic statement.")
|
||||
lockTopicStmt, err = db.Prepare("UPDATE `topics` SET `is_closed` = 1 WHERE `tid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing unlockTopic statement.")
|
||||
unlockTopicStmt, err = db.Prepare("UPDATE `topics` SET `is_closed` = 0 WHERE `tid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing updateLastIP statement.")
|
||||
updateLastIPStmt, err = db.Prepare("UPDATE `users` SET `last_ip` = ? WHERE `uid` = ?")
|
||||
if err != nil {
|
||||
|
@ -47,10 +47,6 @@ func gloinit() error {
|
||||
|
||||
initTemplates()
|
||||
dbProd.SetMaxOpenConns(64)
|
||||
err = initErrors()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = initPhrases()
|
||||
if err != nil {
|
||||
|
43
main.go
@ -72,7 +72,6 @@ func main() {
|
||||
log.Print("Running Gosora v" + version.String())
|
||||
fmt.Println("")
|
||||
startTime = time.Now()
|
||||
//timeLocation = startTime.Location()
|
||||
|
||||
log.Print("Processing configuration data")
|
||||
processConfig()
|
||||
@ -88,10 +87,6 @@ func main() {
|
||||
}
|
||||
|
||||
initTemplates()
|
||||
err = initErrors()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = initPhrases()
|
||||
if err != nil {
|
||||
@ -135,6 +130,8 @@ func main() {
|
||||
select {
|
||||
case <-secondTicker.C:
|
||||
//log.Print("Running the second ticker")
|
||||
// TODO: Add a plugin hook here
|
||||
|
||||
err := handleExpiredScheduledGroups()
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
@ -152,10 +149,16 @@ func main() {
|
||||
// TODO: Manage the TopicStore, UserStore, and ForumStore
|
||||
// TODO: Alert the admin, if CPU usage, RAM usage, or the number of posts in the past second are too high
|
||||
// TODO: Clean-up alerts with no unread matches which are over two weeks old. Move this to a 24 hour task?
|
||||
|
||||
// TODO: Add a plugin hook here
|
||||
case <-fifteenMinuteTicker.C:
|
||||
// TODO: Add a plugin hook here
|
||||
|
||||
// TODO: Automatically lock topics, if they're really old, and the associated setting is enabled.
|
||||
// TODO: Publish scheduled posts.
|
||||
// TODO: Delete the empty users_groups_scheduler entries
|
||||
|
||||
// TODO: Add a plugin hook here
|
||||
}
|
||||
}
|
||||
}()
|
||||
@ -181,6 +184,8 @@ func main() {
|
||||
router.HandleFunc("/topic/delete/submit/", routeDeleteTopic)
|
||||
router.HandleFunc("/topic/stick/submit/", routeStickTopic)
|
||||
router.HandleFunc("/topic/unstick/submit/", routeUnstickTopic)
|
||||
router.HandleFunc("/topic/lock/submit/", routeLockTopic)
|
||||
router.HandleFunc("/topic/unlock/submit/", routeUnlockTopic)
|
||||
router.HandleFunc("/topic/like/submit/", routeLikeTopic)
|
||||
|
||||
// Custom Pages
|
||||
@ -217,17 +222,17 @@ func main() {
|
||||
|
||||
// The Control Panel
|
||||
// TODO: Rename the commented route handlers to the new camelCase format :'(
|
||||
///router.HandleFunc("/panel/", route_panel)
|
||||
///router.HandleFunc("/panel/forums/", route_panel_forums)
|
||||
///router.HandleFunc("/panel/forums/create/", route_panel_forums_create_submit)
|
||||
///router.HandleFunc("/panel/forums/delete/", route_panel_forums_delete)
|
||||
///router.HandleFunc("/panel/forums/delete/submit/", route_panel_forums_delete_submit)
|
||||
///router.HandleFunc("/panel/forums/edit/", route_panel_forums_edit)
|
||||
///router.HandleFunc("/panel/forums/edit/submit/", route_panel_forums_edit_submit)
|
||||
///router.HandleFunc("/panel/forums/edit/perms/submit/", route_panel_forums_edit_perms_submit)
|
||||
///router.HandleFunc("/panel/settings/", route_panel_settings)
|
||||
///router.HandleFunc("/panel/settings/edit/", route_panel_setting)
|
||||
///router.HandleFunc("/panel/settings/edit/submit/", route_panel_setting_edit)
|
||||
////router.HandleFunc("/panel/", routePanel)
|
||||
////router.HandleFunc("/panel/forums/", routePanelForums)
|
||||
////router.HandleFunc("/panel/forums/create/", routePanelForumsCreateSubmit)
|
||||
////router.HandleFunc("/panel/forums/delete/", routePanelForumsDelete)
|
||||
////router.HandleFunc("/panel/forums/delete/submit/", routePanelForumsDeleteSubmit)
|
||||
////router.HandleFunc("/panel/forums/edit/", routePanelForumsEdit)
|
||||
////router.HandleFunc("/panel/forums/edit/submit/", routePanelForumsEditSubmit)
|
||||
////router.HandleFunc("/panel/forums/edit/perms/submit/", routePanelForumsEditPermsSubmit)
|
||||
////router.HandleFunc("/panel/settings/", routePanelSettings)
|
||||
////router.HandleFunc("/panel/settings/edit/", routePanelSetting)
|
||||
////router.HandleFunc("/panel/settings/edit/submit/", routePanelSettingEdit)
|
||||
///router.HandleFunc("/panel/themes/", route_panel_themes)
|
||||
///router.HandleFunc("/panel/themes/default/", route_panel_themes_default)
|
||||
///router.HandleFunc("/panel/plugins/", route_panel_plugins)
|
||||
@ -245,9 +250,9 @@ func main() {
|
||||
///router.HandleFunc("/panel/logs/mod/", route_panel_logs_mod)
|
||||
///router.HandleFunc("/panel/debug/", route_panel_debug)
|
||||
|
||||
///router.HandleFunc("/api/", route_api)
|
||||
//router.HandleFunc("/exit/", route_exit)
|
||||
///router.HandleFunc("/", default_route)
|
||||
////router.HandleFunc("/api/", routeAPI)
|
||||
//router.HandleFunc("/exit/", routeExit)
|
||||
////router.HandleFunc("/", config.DefaultRoute)
|
||||
router.HandleFunc("/ws/", routeWebsockets)
|
||||
|
||||
log.Print("Initialising the plugins")
|
||||
|
@ -242,14 +242,10 @@ func routeCreateReply(w http.ResponseWriter, r *http.Request, user User) {
|
||||
go notifyWatchers(lastID)
|
||||
}
|
||||
|
||||
// Reload the topic...
|
||||
err = topics.Reload(tid)
|
||||
if err != nil && err == ErrNoRows {
|
||||
LocalError("The destination no longer exists", w, r, user)
|
||||
return
|
||||
} else if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
// Flush the topic out of the cache
|
||||
tcache, ok := topics.(TopicCache)
|
||||
if ok {
|
||||
tcache.CacheRemove(tid)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||
@ -348,16 +344,11 @@ func routeLikeTopic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
// Live alerts, if the poster is online and WebSockets is enabled
|
||||
_ = wsHub.pushAlert(topic.CreatedBy, int(lastID), "like", "topic", user.ID, topic.CreatedBy, tid)
|
||||
|
||||
// Reload the topic...
|
||||
err = topics.Reload(tid)
|
||||
if err != nil && err == ErrNoRows {
|
||||
LocalError("The liked topic no longer exists", w, r, user)
|
||||
return
|
||||
} else if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
// Flush the topic out of the cache
|
||||
tcache, ok := topics.(TopicCache)
|
||||
if ok {
|
||||
tcache.CacheRemove(tid)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
@ -818,10 +809,9 @@ func routeAccountOwnEditAvatarSubmit(w http.ResponseWriter, r *http.Request, use
|
||||
return
|
||||
}
|
||||
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext
|
||||
err = users.Reload(user.ID)
|
||||
if err != nil {
|
||||
LocalError("This user no longer exists!", w, r, user)
|
||||
return
|
||||
ucache, ok := users.(UserCache)
|
||||
if ok {
|
||||
ucache.CacheRemove(user.ID)
|
||||
}
|
||||
|
||||
headerVars.NoticeList = append(headerVars.NoticeList, "Your avatar was successfully updated")
|
||||
@ -876,10 +866,9 @@ func routeAccountOwnEditUsernameSubmit(w http.ResponseWriter, r *http.Request, u
|
||||
|
||||
// TODO: Use the reloaded data instead for the name?
|
||||
user.Name = newUsername
|
||||
err = users.Reload(user.ID)
|
||||
if err != nil {
|
||||
LocalError("Your account doesn't exist!", w, r, user)
|
||||
return
|
||||
ucache, ok := users.(UserCache)
|
||||
if ok {
|
||||
ucache.CacheRemove(user.ID)
|
||||
}
|
||||
|
||||
headerVars.NoticeList = append(headerVars.NoticeList, "Your username was successfully updated")
|
||||
|
203
mod_routes.go
@ -13,7 +13,6 @@ import (
|
||||
// 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_socialgroups
|
||||
func routeEditTopic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
//log.Print("in routeEditTopic")
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
PreError("Bad Form", w, r)
|
||||
@ -21,8 +20,7 @@ func routeEditTopic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
}
|
||||
isJs := (r.PostFormValue("js") == "1")
|
||||
|
||||
var tid int
|
||||
tid, err = strconv.Atoi(r.URL.Path[len("/topic/edit/submit/"):])
|
||||
tid, err := strconv.Atoi(r.URL.Path[len("/topic/edit/submit/"):])
|
||||
if err != nil {
|
||||
PreErrorJSQ("The provided TopicID is not a valid number.", w, r, isJs)
|
||||
return
|
||||
@ -48,60 +46,24 @@ func routeEditTopic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
}
|
||||
|
||||
topicName := r.PostFormValue("topic_name")
|
||||
topicStatus := r.PostFormValue("topic_status")
|
||||
isClosed := (topicStatus == "closed")
|
||||
topicContent := html.EscapeString(r.PostFormValue("topic_content"))
|
||||
|
||||
// TODO: Move this bit to the TopicStore
|
||||
_, err = editTopicStmt.Exec(topicName, preparseMessage(topicContent), parseMessage(html.EscapeString(preparseMessage(topicContent))), isClosed, tid)
|
||||
_, err = editTopicStmt.Exec(topicName, preparseMessage(topicContent), parseMessage(html.EscapeString(preparseMessage(topicContent))), tid)
|
||||
if err != nil {
|
||||
InternalErrorJSQ(err, w, r, isJs)
|
||||
return
|
||||
}
|
||||
|
||||
ipaddress, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
LocalError("Bad IP", w, r, user)
|
||||
err = fstore.UpdateLastTopic(topicName, tid, user.Name, user.ID, time.Now().Format("2006-01-02 15:04:05"), oldTopic.ParentID)
|
||||
if err != nil && err != ErrNoRows {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
if oldTopic.IsClosed != isClosed {
|
||||
var action string
|
||||
if isClosed {
|
||||
action = "lock"
|
||||
} else {
|
||||
action = "unlock"
|
||||
}
|
||||
|
||||
err = addModLog(action, tid, "topic", ipaddress, user.ID)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
_, err = createActionReplyStmt.Exec(tid, action, ipaddress, user.ID)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
_, err = addRepliesToTopicStmt.Exec(1, user.ID, tid)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
err = fstore.UpdateLastTopic(topicName, tid, user.Name, user.ID, time.Now().Format("2006-01-02 15:04:05"), oldTopic.ParentID)
|
||||
if err != nil && err != ErrNoRows {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = topics.Reload(tid)
|
||||
if err == ErrNoRows {
|
||||
LocalErrorJSQ("This topic no longer exists!", w, r, user, isJs)
|
||||
return
|
||||
} else if err != nil {
|
||||
InternalErrorJSQ(err, w, r, isJs)
|
||||
return
|
||||
tcache, ok := topics.(TopicCache)
|
||||
if ok {
|
||||
tcache.CacheRemove(oldTopic.ID)
|
||||
}
|
||||
|
||||
if !isJs {
|
||||
@ -194,13 +156,13 @@ func routeStickTopic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Move this into the TopicStore?
|
||||
_, err = stickTopicStmt.Exec(tid)
|
||||
err = topic.Stick()
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
// ! - Can we use user.LastIP here? It might be racey, if another thread mutates it... We need to fix this.
|
||||
ipaddress, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
LocalError("Bad IP", w, r, user)
|
||||
@ -211,17 +173,11 @@ func routeStickTopic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
_, err = createActionReplyStmt.Exec(tid, "stick", ipaddress, user.ID)
|
||||
err = topic.CreateActionReply("stick", ipaddress, user)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
err = topics.Reload(tid)
|
||||
if err != nil {
|
||||
LocalError("This topic doesn't exist!", w, r, user)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
@ -251,7 +207,7 @@ func routeUnstickTopic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = unstickTopicStmt.Exec(tid)
|
||||
err = topic.Unstick()
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
@ -267,15 +223,111 @@ func routeUnstickTopic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
_, err = createActionReplyStmt.Exec(tid, "unstick", ipaddress, user.ID)
|
||||
err = topic.CreateActionReply("unstick", ipaddress, user)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func routeLockTopic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
tid, err := strconv.Atoi(r.URL.Path[len("/topic/lock/submit/"):])
|
||||
if err != nil {
|
||||
PreError("The provided TopicID is not a valid number.", w, r)
|
||||
return
|
||||
}
|
||||
|
||||
topic, err := topics.Get(tid)
|
||||
if err == ErrNoRows {
|
||||
PreError("The topic you tried to pin doesn't exist.", w, r)
|
||||
return
|
||||
} else if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Add hooks to make use of headerLite
|
||||
_, ok := SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if !user.Perms.ViewTopic || !user.Perms.CloseTopic {
|
||||
NoPermissions(w, r, user)
|
||||
return
|
||||
}
|
||||
|
||||
err = topic.Lock()
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
err = topics.Reload(tid)
|
||||
// ! - Can we use user.LastIP here? It might be racey, if another thread mutates it... We need to fix this.
|
||||
ipaddress, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
LocalError("This topic doesn't exist!", w, r, user)
|
||||
LocalError("Bad IP", w, r, user)
|
||||
return
|
||||
}
|
||||
err = addModLog("lock", tid, "topic", ipaddress, user.ID)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
err = topic.CreateActionReply("lock", ipaddress, user)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func routeUnlockTopic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
tid, err := strconv.Atoi(r.URL.Path[len("/topic/unlock/submit/"):])
|
||||
if err != nil {
|
||||
PreError("The provided TopicID is not a valid number.", w, r)
|
||||
return
|
||||
}
|
||||
|
||||
topic, err := topics.Get(tid)
|
||||
if err == ErrNoRows {
|
||||
PreError("The topic you tried to pin doesn't exist.", w, r)
|
||||
return
|
||||
} else if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Add hooks to make use of headerLite
|
||||
_, ok := SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if !user.Perms.ViewTopic || !user.Perms.CloseTopic {
|
||||
NoPermissions(w, r, user)
|
||||
return
|
||||
}
|
||||
|
||||
err = topic.Unlock()
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
// ! - Can we use user.LastIP here? It might be racey, if another thread mutates it... We need to fix this.
|
||||
ipaddress, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
LocalError("Bad IP", w, r, user)
|
||||
return
|
||||
}
|
||||
err = addModLog("unlock", tid, "topic", ipaddress, user.ID)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
err = topic.CreateActionReply("unlock", ipaddress, user)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||
@ -422,11 +474,9 @@ func routeReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user User) {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
err = topics.Reload(reply.ParentID)
|
||||
if err != nil {
|
||||
LocalError("This topic no longer exists!", w, r, user)
|
||||
return
|
||||
tcache, ok := topics.(TopicCache)
|
||||
if ok {
|
||||
tcache.CacheRemove(reply.ParentID)
|
||||
}
|
||||
}
|
||||
|
||||
@ -612,7 +662,7 @@ func routeIps(w http.ResponseWriter, r *http.Request, user User) {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = templates.ExecuteTemplate(w, "ip-search.html", pi)
|
||||
err = templates.ExecuteTemplate(w, "ip-search-results.html", pi)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
}
|
||||
@ -821,8 +871,7 @@ func routeActivate(w http.ResponseWriter, r *http.Request, user User) {
|
||||
return
|
||||
}
|
||||
|
||||
var active bool
|
||||
err = getUserActiveStmt.QueryRow(uid).Scan(&active)
|
||||
targetUser, err := users.Get(uid)
|
||||
if err == ErrNoRows {
|
||||
LocalError("The account you're trying to activate no longer exists.", w, r, user)
|
||||
return
|
||||
@ -831,17 +880,11 @@ func routeActivate(w http.ResponseWriter, r *http.Request, user User) {
|
||||
return
|
||||
}
|
||||
|
||||
if active {
|
||||
if targetUser.Active {
|
||||
LocalError("The account you're trying to activate has already been activated.", w, r, user)
|
||||
return
|
||||
}
|
||||
_, err = activateUserStmt.Exec(uid)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = changeGroupStmt.Exec(config.DefaultGroup, uid)
|
||||
err = targetUser.Activate()
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
@ -852,16 +895,10 @@ func routeActivate(w http.ResponseWriter, r *http.Request, user User) {
|
||||
LocalError("Bad IP", w, r, user)
|
||||
return
|
||||
}
|
||||
err = addModLog("activate", uid, "user", ipaddress, user.ID)
|
||||
err = addModLog("activate", targetUser.ID, "user", ipaddress, user.ID)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
err = users.Reload(uid)
|
||||
if err != nil {
|
||||
LocalError("This user no longer exists!", w, r, user)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther)
|
||||
http.Redirect(w, r, "/user/"+strconv.Itoa(targetUser.ID), http.StatusSeeOther)
|
||||
}
|
||||
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 196 KiB After Width: | Height: | Size: 196 KiB |
Before Width: | Height: | Size: 388 KiB After Width: | Height: | Size: 388 KiB |
Before Width: | Height: | Size: 579 KiB After Width: | Height: | Size: 579 KiB |
Before Width: | Height: | Size: 408 KiB After Width: | Height: | Size: 408 KiB |
22
pages.go
@ -1,12 +1,14 @@
|
||||
package main
|
||||
|
||||
//import "fmt"
|
||||
import "sync"
|
||||
import "bytes"
|
||||
import "strings"
|
||||
import "strconv"
|
||||
import "regexp"
|
||||
import "html/template"
|
||||
import (
|
||||
//"fmt"
|
||||
"bytes"
|
||||
"html/template"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type HeaderVars struct {
|
||||
NoticeList []string
|
||||
@ -32,12 +34,8 @@ type PageWidgets struct {
|
||||
RightSidebar template.HTML
|
||||
}
|
||||
|
||||
/*type UnsafeExtData struct
|
||||
{
|
||||
items map[string]interface{} // Key: pluginname
|
||||
}*/
|
||||
|
||||
// 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
|
||||
sync.RWMutex
|
||||
|
@ -1154,14 +1154,14 @@ func routePanelUsers(w http.ResponseWriter, r *http.Request, user User) {
|
||||
|
||||
// TODO: Add a UserStore method for iterating over global users and global user offsets
|
||||
for rows.Next() {
|
||||
puser := User{ID: 0}
|
||||
puser := &User{ID: 0}
|
||||
err := rows.Scan(&puser.ID, &puser.Name, &puser.Group, &puser.Active, &puser.IsSuperAdmin, &puser.Avatar)
|
||||
if err != nil {
|
||||
InternalError(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
initUserPerms(&puser)
|
||||
puser.initPerms()
|
||||
if puser.Avatar != "" {
|
||||
if puser.Avatar[0] == '.' {
|
||||
puser.Avatar = "/uploads/avatar_" + strconv.Itoa(puser.ID) + puser.Avatar
|
||||
@ -1175,7 +1175,7 @@ func routePanelUsers(w http.ResponseWriter, r *http.Request, user User) {
|
||||
} else {
|
||||
puser.Tag = ""
|
||||
}
|
||||
userList = append(userList, puser)
|
||||
userList = append(userList, *puser)
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
@ -1346,12 +1346,10 @@ func routePanelUsersEditSubmit(w http.ResponseWriter, r *http.Request, user User
|
||||
SetPassword(targetUser.ID, newpassword)
|
||||
}
|
||||
|
||||
err = users.Reload(targetUser.ID)
|
||||
if err != nil {
|
||||
LocalError("This user no longer exists!", w, r, user)
|
||||
return
|
||||
ucache, ok := users.(UserCache)
|
||||
if ok {
|
||||
ucache.CacheRemove(targetUser.ID)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/panel/users/edit/"+strconv.Itoa(targetUser.ID), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
|
2337
public/font-awesome-4.7.0/css/font-awesome.css
vendored
Normal file
4
public/font-awesome-4.7.0/css/font-awesome.min.css
vendored
Normal file
BIN
public/font-awesome-4.7.0/fonts/FontAwesome.otf
Normal file
BIN
public/font-awesome-4.7.0/fonts/fontawesome-webfont.eot
Normal file
2671
public/font-awesome-4.7.0/fonts/fontawesome-webfont.svg
Normal file
After Width: | Height: | Size: 434 KiB |
BIN
public/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf
Normal file
BIN
public/font-awesome-4.7.0/fonts/fontawesome-webfont.woff
Normal file
BIN
public/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2
Normal file
@ -253,8 +253,6 @@ func write_selects(adapter qgen.DB_Adapter) error {
|
||||
|
||||
adapter.SimpleSelect("getUserName", "users", "name", "uid = ?", "", "")
|
||||
|
||||
adapter.SimpleSelect("getUserActive", "users", "active", "uid = ?", "", "")
|
||||
|
||||
adapter.SimpleSelect("getEmailsByUser", "emails", "email, validated, token", "uid = ?", "", "")
|
||||
|
||||
adapter.SimpleSelect("getTopicBasic", "topics", "title, content", "tid = ?", "", "")
|
||||
@ -366,7 +364,7 @@ func write_updates(adapter qgen.DB_Adapter) error {
|
||||
|
||||
adapter.SimpleUpdate("addLikesToReply", "replies", "likeCount = likeCount + ?", "rid = ?")
|
||||
|
||||
adapter.SimpleUpdate("editTopic", "topics", "title = ?, content = ?, parsed_content = ?, is_closed = ?", "tid = ?")
|
||||
adapter.SimpleUpdate("editTopic", "topics", "title = ?, content = ?, parsed_content = ?", "tid = ?")
|
||||
|
||||
adapter.SimpleUpdate("editReply", "replies", "content = ?, parsed_content = ?", "rid = ?")
|
||||
|
||||
@ -374,6 +372,10 @@ func write_updates(adapter qgen.DB_Adapter) error {
|
||||
|
||||
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 = ?")
|
||||
|
@ -25,14 +25,9 @@ import (
|
||||
var tList []interface{}
|
||||
|
||||
//var nList []string
|
||||
var hvars *HeaderVars // We might need to rethink this now that it's a pointer
|
||||
var successJSONBytes = []byte(`{"success":"1"}`)
|
||||
var cacheControlMaxAge = "max-age=" + strconv.Itoa(day)
|
||||
|
||||
func init() {
|
||||
hvars = &HeaderVars{Site: site}
|
||||
}
|
||||
|
||||
// HTTPSRedirect is a connection handler which redirects all HTTP requests to HTTPS
|
||||
type HTTPSRedirect struct {
|
||||
}
|
||||
|
@ -23,6 +23,12 @@ var MemberCheck func(w http.ResponseWriter, r *http.Request, user *User) (header
|
||||
var SimpleUserCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, success bool) = simpleUserCheck
|
||||
var UserCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, success bool) = userCheck
|
||||
|
||||
// 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 getDefaultHeaderVar() *HeaderVars {
|
||||
return &HeaderVars{Site: site, ThemeName: fallbackTheme}
|
||||
}
|
||||
|
||||
// TODO: Support for left sidebars and sidebars on both sides
|
||||
// http.Request is for context.Context middleware. Mostly for plugin_socialgroups right now
|
||||
func BuildWidgets(zone string, data interface{}, headerVars *HeaderVars, r *http.Request) {
|
||||
@ -312,7 +318,7 @@ func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) {
|
||||
InternalError(err, w)
|
||||
return *user, false
|
||||
}
|
||||
user.LastIP = host
|
||||
user.LastIP = host // ! - Is this racey?
|
||||
}
|
||||
|
||||
h := w.Header()
|
||||
|
5
tasks.go
@ -22,6 +22,7 @@ func handleExpiredScheduledGroups() error {
|
||||
defer rows.Close()
|
||||
|
||||
var uid int
|
||||
ucache, ok := users.(UserCache)
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&uid)
|
||||
if err != nil {
|
||||
@ -35,7 +36,9 @@ func handleExpiredScheduledGroups() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = users.Reload(uid)
|
||||
if ok {
|
||||
ucache.CacheRemove(uid)
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
302
template_list.go
@ -103,134 +103,132 @@ var topic_13 = []byte(`">
|
||||
<h1 class='topic_name hide_on_edit'>`)
|
||||
var topic_14 = []byte(`</h1>
|
||||
`)
|
||||
var topic_15 = []byte(`<span class='username hide_on_micro topic_status_e topic_status_closed hide_on_edit' title='Status: Closed' style="font-weight:normal;float: right;position:relative;top:-5px;">🔒︎</span>`)
|
||||
var topic_15 = []byte(`<span class='username hide_on_micro topic_status_e topic_status_closed hide_on_edit' title='Status: Closed'>🔒︎</span>`)
|
||||
var topic_16 = []byte(`
|
||||
<input form='edit_topic_form' class='show_on_edit topic_name_input' name="topic_name" value='`)
|
||||
var topic_17 = []byte(`' type="text" />
|
||||
`)
|
||||
var topic_18 = []byte(`<select form='edit_topic_form' name="topic_status" class='show_on_edit topic_status_input' style='float: right;'>
|
||||
<option>open</option>
|
||||
<option>closed</option>
|
||||
</select>`)
|
||||
var topic_19 = []byte(`
|
||||
<button form='edit_topic_form' name="topic-button" class="formbutton show_on_edit submit_edit">Update</button>
|
||||
`)
|
||||
var topic_20 = []byte(`
|
||||
var topic_18 = []byte(`
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<article class="rowblock post_container top_post">
|
||||
<div class="rowitem passive editable_parent post_item `)
|
||||
var topic_21 = []byte(`" style="`)
|
||||
var topic_22 = []byte(`background-image:url(`)
|
||||
var topic_23 = []byte(`), url(/static/post-avatar-bg.jpg);background-position: 0px `)
|
||||
var topic_24 = []byte(`-1`)
|
||||
var topic_25 = []byte(`0px;background-repeat:no-repeat, repeat-y;`)
|
||||
var topic_26 = []byte(`">
|
||||
var topic_19 = []byte(`" style="`)
|
||||
var topic_20 = []byte(`background-image:url(`)
|
||||
var topic_21 = []byte(`), url(/static/post-avatar-bg.jpg);background-position: 0px `)
|
||||
var topic_22 = []byte(`-1`)
|
||||
var topic_23 = []byte(`0px;background-repeat:no-repeat, repeat-y;`)
|
||||
var topic_24 = []byte(`">
|
||||
<p class="hide_on_edit topic_content user_content" style="margin:0;padding:0;">`)
|
||||
var topic_27 = []byte(`</p>
|
||||
var topic_25 = []byte(`</p>
|
||||
<textarea name="topic_content" class="show_on_edit topic_content_input">`)
|
||||
var topic_28 = []byte(`</textarea>
|
||||
var topic_26 = []byte(`</textarea>
|
||||
|
||||
<span class="controls">
|
||||
|
||||
<a href="`)
|
||||
var topic_29 = []byte(`" class="username real_username">`)
|
||||
var topic_30 = []byte(`</a>
|
||||
var topic_27 = []byte(`" class="username real_username">`)
|
||||
var topic_28 = []byte(`</a>
|
||||
`)
|
||||
var topic_31 = []byte(`<a href="/topic/like/submit/`)
|
||||
var topic_32 = []byte(`" class="mod_button" title="Love it" style="color:#202020;">
|
||||
var topic_29 = []byte(`<a href="/topic/like/submit/`)
|
||||
var topic_30 = []byte(`" class="mod_button" title="Love it" style="color:#202020;">
|
||||
<button class="username like_label" style="`)
|
||||
var topic_33 = []byte(`background-color:/*#eaffea*/#D6FFD6;`)
|
||||
var topic_34 = []byte(`"></button></a>`)
|
||||
var topic_35 = []byte(`<a href='/topic/edit/`)
|
||||
var topic_36 = []byte(`' class="mod_button open_edit" style="font-weight:normal;" title="Edit Topic"><button class="username edit_label"></button></a>`)
|
||||
var topic_37 = []byte(`<a href='/topic/delete/submit/`)
|
||||
var topic_38 = []byte(`' class="mod_button" style="font-weight:normal;" title="Delete Topic"><button class="username trash_label"></button></a>`)
|
||||
var topic_39 = []byte(`<a class="mod_button" href='/topic/unstick/submit/`)
|
||||
var topic_40 = []byte(`' style="font-weight:normal;" title="Unpin Topic"><button class="username unpin_label"></button></a>`)
|
||||
var topic_41 = []byte(`<a href='/topic/stick/submit/`)
|
||||
var topic_42 = []byte(`' class="mod_button" style="font-weight:normal;" title="Pin Topic"><button class="username pin_label"></button></a>`)
|
||||
var topic_43 = []byte(`<a class="mod_button" href='/users/ips/`)
|
||||
var topic_44 = []byte(`' style="font-weight:normal;" title="View IP"><button class="username ip_label"></button></a>`)
|
||||
var topic_45 = []byte(`
|
||||
var topic_31 = []byte(`background-color:/*#eaffea*/#D6FFD6;`)
|
||||
var topic_32 = []byte(`"></button></a>`)
|
||||
var topic_33 = []byte(`<a href='/topic/edit/`)
|
||||
var topic_34 = []byte(`' class="mod_button open_edit" style="font-weight:normal;" title="Edit Topic"><button class="username edit_label"></button></a>`)
|
||||
var topic_35 = []byte(`<a href='/topic/delete/submit/`)
|
||||
var topic_36 = []byte(`' class="mod_button" style="font-weight:normal;" title="Delete Topic"><button class="username trash_label"></button></a>`)
|
||||
var topic_37 = []byte(`<a class="mod_button" href='/topic/unlock/submit/`)
|
||||
var topic_38 = []byte(`' style="font-weight:normal;" title="Unlock Topic"><button class="username unlock_label"></button></a>`)
|
||||
var topic_39 = []byte(`<a href='/topic/lock/submit/`)
|
||||
var topic_40 = []byte(`' class="mod_button" style="font-weight:normal;" title="Lock Topic"><button class="username lock_label"></button></a>`)
|
||||
var topic_41 = []byte(`<a class="mod_button" href='/topic/unstick/submit/`)
|
||||
var topic_42 = []byte(`' style="font-weight:normal;" title="Unpin Topic"><button class="username unpin_label"></button></a>`)
|
||||
var topic_43 = []byte(`<a href='/topic/stick/submit/`)
|
||||
var topic_44 = []byte(`' class="mod_button" style="font-weight:normal;" title="Pin Topic"><button class="username pin_label"></button></a>`)
|
||||
var topic_45 = []byte(`<a class="mod_button" href='/users/ips/`)
|
||||
var topic_46 = []byte(`' style="font-weight:normal;" title="View IP"><button class="username ip_label"></button></a>`)
|
||||
var topic_47 = []byte(`
|
||||
<a href="/report/submit/`)
|
||||
var topic_46 = []byte(`?session=`)
|
||||
var topic_47 = []byte(`&type=topic" class="mod_button report_item" style="font-weight:normal;" title="Flag Topic"><button class="username flag_label"></button></a>
|
||||
var topic_48 = []byte(`?session=`)
|
||||
var topic_49 = []byte(`&type=topic" class="mod_button report_item" style="font-weight:normal;" title="Flag Topic"><button class="username flag_label"></button></a>
|
||||
|
||||
`)
|
||||
var topic_48 = []byte(`<a class="username hide_on_micro like_count">`)
|
||||
var topic_49 = []byte(`</a><a class="username hide_on_micro like_count_label" title="Like Count"></a>`)
|
||||
var topic_50 = []byte(`<a class="username hide_on_micro user_tag">`)
|
||||
var topic_51 = []byte(`</a>`)
|
||||
var topic_52 = []byte(`<a class="username hide_on_micro level">`)
|
||||
var topic_53 = []byte(`</a><a class="username hide_on_micro level_label" style="float:right;" title="Level"></a>`)
|
||||
var topic_54 = []byte(`
|
||||
var topic_50 = []byte(`<a class="username hide_on_micro like_count">`)
|
||||
var topic_51 = []byte(`</a><a class="username hide_on_micro like_count_label" title="Like Count"></a>`)
|
||||
var topic_52 = []byte(`<a class="username hide_on_micro user_tag">`)
|
||||
var topic_53 = []byte(`</a>`)
|
||||
var topic_54 = []byte(`<a class="username hide_on_micro level">`)
|
||||
var topic_55 = []byte(`</a><a class="username hide_on_micro level_label" style="float:right;" title="Level"></a>`)
|
||||
var topic_56 = []byte(`
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</article>
|
||||
<div class="rowblock post_container" style="overflow: hidden;">`)
|
||||
var topic_55 = []byte(`
|
||||
var topic_57 = []byte(`
|
||||
<article class="rowitem passive deletable_block editable_parent post_item action_item">
|
||||
<span class="action_icon" style="font-size: 18px;padding-right: 5px;">`)
|
||||
var topic_56 = []byte(`</span>
|
||||
var topic_58 = []byte(`</span>
|
||||
<span>`)
|
||||
var topic_57 = []byte(`</span>
|
||||
var topic_59 = []byte(`</span>
|
||||
</article>
|
||||
`)
|
||||
var topic_58 = []byte(`
|
||||
var topic_60 = []byte(`
|
||||
<article class="rowitem passive deletable_block editable_parent post_item `)
|
||||
var topic_59 = []byte(`" style="`)
|
||||
var topic_60 = []byte(`background-image:url(`)
|
||||
var topic_61 = []byte(`), url(/static/post-avatar-bg.jpg);background-position: 0px `)
|
||||
var topic_62 = []byte(`-1`)
|
||||
var topic_63 = []byte(`0px;background-repeat:no-repeat, repeat-y;`)
|
||||
var topic_64 = []byte(`">
|
||||
var topic_61 = []byte(`" style="`)
|
||||
var topic_62 = []byte(`background-image:url(`)
|
||||
var topic_63 = []byte(`), url(/static/post-avatar-bg.jpg);background-position: 0px `)
|
||||
var topic_64 = []byte(`-1`)
|
||||
var topic_65 = []byte(`0px;background-repeat:no-repeat, repeat-y;`)
|
||||
var topic_66 = []byte(`">
|
||||
<p class="editable_block user_content" style="margin:0;padding:0;">`)
|
||||
var topic_65 = []byte(`</p>
|
||||
var topic_67 = []byte(`</p>
|
||||
|
||||
<span class="controls">
|
||||
|
||||
<a href="`)
|
||||
var topic_66 = []byte(`" class="username real_username">`)
|
||||
var topic_67 = []byte(`</a>
|
||||
var topic_68 = []byte(`" class="username real_username">`)
|
||||
var topic_69 = []byte(`</a>
|
||||
`)
|
||||
var topic_68 = []byte(`<a href="/reply/like/submit/`)
|
||||
var topic_69 = []byte(`" class="mod_button" title="Love it" style="color:#202020;"><button class="username like_label" style="`)
|
||||
var topic_70 = []byte(`background-color:/*#eaffea*/#D6FFD6;`)
|
||||
var topic_71 = []byte(`"></button></a>`)
|
||||
var topic_72 = []byte(`<a href="/reply/edit/submit/`)
|
||||
var topic_73 = []byte(`" class="mod_button" title="Edit Reply"><button class="username edit_item edit_label"></button></a>`)
|
||||
var topic_74 = []byte(`<a href="/reply/delete/submit/`)
|
||||
var topic_75 = []byte(`" class="mod_button" title="Delete Reply"><button class="username delete_item trash_label"></button></a>`)
|
||||
var topic_76 = []byte(`<a class="mod_button" href='/users/ips/`)
|
||||
var topic_77 = []byte(`' style="font-weight:normal;" title="View IP"><button class="username ip_label"></button></a>`)
|
||||
var topic_78 = []byte(`
|
||||
var topic_70 = []byte(`<a href="/reply/like/submit/`)
|
||||
var topic_71 = []byte(`" class="mod_button" title="Love it" style="color:#202020;"><button class="username like_label" style="`)
|
||||
var topic_72 = []byte(`background-color:/*#eaffea*/#D6FFD6;`)
|
||||
var topic_73 = []byte(`"></button></a>`)
|
||||
var topic_74 = []byte(`<a href="/reply/edit/submit/`)
|
||||
var topic_75 = []byte(`" class="mod_button" title="Edit Reply"><button class="username edit_item edit_label"></button></a>`)
|
||||
var topic_76 = []byte(`<a href="/reply/delete/submit/`)
|
||||
var topic_77 = []byte(`" class="mod_button" title="Delete Reply"><button class="username delete_item trash_label"></button></a>`)
|
||||
var topic_78 = []byte(`<a class="mod_button" href='/users/ips/`)
|
||||
var topic_79 = []byte(`' style="font-weight:normal;" title="View IP"><button class="username ip_label"></button></a>`)
|
||||
var topic_80 = []byte(`
|
||||
<a href="/report/submit/`)
|
||||
var topic_79 = []byte(`?session=`)
|
||||
var topic_80 = []byte(`&type=reply" class="mod_button report_item" title="Flag Reply"><button class="username report_item flag_label"></button></a>
|
||||
var topic_81 = []byte(`?session=`)
|
||||
var topic_82 = []byte(`&type=reply" class="mod_button report_item" title="Flag Reply"><button class="username report_item flag_label"></button></a>
|
||||
|
||||
`)
|
||||
var topic_81 = []byte(`<a class="username hide_on_micro like_count">`)
|
||||
var topic_82 = []byte(`</a><a class="username hide_on_micro like_count_label" title="Like Count"></a>`)
|
||||
var topic_83 = []byte(`<a class="username hide_on_micro user_tag">`)
|
||||
var topic_84 = []byte(`</a>`)
|
||||
var topic_85 = []byte(`<a class="username hide_on_micro level">`)
|
||||
var topic_86 = []byte(`</a><a class="username hide_on_micro level_label" style="float:right;" title="Level"></a>`)
|
||||
var topic_87 = []byte(`
|
||||
var topic_83 = []byte(`<a class="username hide_on_micro like_count">`)
|
||||
var topic_84 = []byte(`</a><a class="username hide_on_micro like_count_label" title="Like Count"></a>`)
|
||||
var topic_85 = []byte(`<a class="username hide_on_micro user_tag">`)
|
||||
var topic_86 = []byte(`</a>`)
|
||||
var topic_87 = []byte(`<a class="username hide_on_micro level">`)
|
||||
var topic_88 = []byte(`</a><a class="username hide_on_micro level_label" style="float:right;" title="Level"></a>`)
|
||||
var topic_89 = []byte(`
|
||||
|
||||
</span>
|
||||
</article>
|
||||
`)
|
||||
var topic_88 = []byte(`</div>
|
||||
var topic_90 = []byte(`</div>
|
||||
|
||||
`)
|
||||
var topic_89 = []byte(`
|
||||
var topic_91 = []byte(`
|
||||
<div class="rowblock topic_reply_form">
|
||||
<form action="/reply/create/" method="post">
|
||||
<input name="tid" value='`)
|
||||
var topic_90 = []byte(`' type="hidden" />
|
||||
var topic_92 = []byte(`' type="hidden" />
|
||||
<div class="formrow real_first_child">
|
||||
<div class="formitem"><textarea name="reply-content" placeholder="Insert reply here" required></textarea></div>
|
||||
</div>
|
||||
@ -240,7 +238,7 @@ var topic_90 = []byte(`' type="hidden" />
|
||||
</form>
|
||||
</div>
|
||||
`)
|
||||
var topic_91 = []byte(`
|
||||
var topic_93 = []byte(`
|
||||
|
||||
</main>
|
||||
|
||||
@ -299,15 +297,9 @@ var topic_alt_14 = []byte(`<span class='username hide_on_micro topic_status_e to
|
||||
var topic_alt_15 = []byte(`
|
||||
<input class='show_on_edit topic_name_input' name="topic_name" value='`)
|
||||
var topic_alt_16 = []byte(`' type="text" />
|
||||
`)
|
||||
var topic_alt_17 = []byte(`<select name="topic_status" class='show_on_edit topic_status_input' style='float: right;'>
|
||||
<option>open</option>
|
||||
<option>closed</option>
|
||||
</select>`)
|
||||
var topic_alt_18 = []byte(`
|
||||
<button name="topic-button" class="formbutton show_on_edit submit_edit">Update</button>
|
||||
`)
|
||||
var topic_alt_19 = []byte(`
|
||||
var topic_alt_17 = []byte(`
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -316,118 +308,122 @@ var topic_alt_19 = []byte(`
|
||||
<article class="rowitem passive deletable_block editable_parent post_item top_post">
|
||||
<div class="userinfo">
|
||||
<div class="avatar_item" style="background-image: url(`)
|
||||
var topic_alt_20 = []byte(`), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
var topic_alt_18 = []byte(`), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
<a href="`)
|
||||
var topic_alt_21 = []byte(`" class="the_name">`)
|
||||
var topic_alt_22 = []byte(`</a>
|
||||
var topic_alt_19 = []byte(`" class="the_name">`)
|
||||
var topic_alt_20 = []byte(`</a>
|
||||
`)
|
||||
var topic_alt_23 = []byte(`<div class="tag_block"><div class="tag_pre"></div><div class="post_tag">`)
|
||||
var topic_alt_21 = []byte(`<div class="tag_block"><div class="tag_pre"></div><div class="post_tag">`)
|
||||
var topic_alt_22 = []byte(`</div><div class="tag_post"></div></div>`)
|
||||
var topic_alt_23 = []byte(`<div class="tag_block"><div class="tag_pre"></div><div class="post_tag post_level">Level `)
|
||||
var topic_alt_24 = []byte(`</div><div class="tag_post"></div></div>`)
|
||||
var topic_alt_25 = []byte(`<div class="tag_block"><div class="tag_pre"></div><div class="post_tag post_level">Level `)
|
||||
var topic_alt_26 = []byte(`</div><div class="tag_post"></div></div>`)
|
||||
var topic_alt_27 = []byte(`
|
||||
var topic_alt_25 = []byte(`
|
||||
</div>
|
||||
<div class="content_container">
|
||||
<div class="hide_on_edit topic_content user_content">`)
|
||||
var topic_alt_28 = []byte(`</div>
|
||||
var topic_alt_26 = []byte(`</div>
|
||||
<textarea name="topic_content" class="show_on_edit topic_content_input">`)
|
||||
var topic_alt_29 = []byte(`</textarea>
|
||||
var topic_alt_27 = []byte(`</textarea>
|
||||
<div class="button_container">
|
||||
`)
|
||||
var topic_alt_30 = []byte(`<a href="/topic/like/submit/`)
|
||||
var topic_alt_31 = []byte(`" class="action_button">+1</a>`)
|
||||
var topic_alt_32 = []byte(`<a href="/topic/edit/`)
|
||||
var topic_alt_33 = []byte(`" class="action_button open_edit">Edit</a>`)
|
||||
var topic_alt_34 = []byte(`<a href="/topic/delete/submit/`)
|
||||
var topic_alt_35 = []byte(`" class="action_button delete_item">Delete</a>`)
|
||||
var topic_alt_36 = []byte(`<a href='/topic/unstick/submit/`)
|
||||
var topic_alt_37 = []byte(`' class="action_button">Unpin</a>`)
|
||||
var topic_alt_38 = []byte(`<a href='/topic/stick/submit/`)
|
||||
var topic_alt_39 = []byte(`' class="action_button">Pin</a>`)
|
||||
var topic_alt_40 = []byte(`
|
||||
var topic_alt_28 = []byte(`<a href="/topic/like/submit/`)
|
||||
var topic_alt_29 = []byte(`" class="action_button">+1</a>`)
|
||||
var topic_alt_30 = []byte(`<a href="/topic/edit/`)
|
||||
var topic_alt_31 = []byte(`" class="action_button open_edit">Edit</a>`)
|
||||
var topic_alt_32 = []byte(`<a href="/topic/delete/submit/`)
|
||||
var topic_alt_33 = []byte(`" class="action_button delete_item">Delete</a>`)
|
||||
var topic_alt_34 = []byte(`<a href='/topic/unlock/submit/`)
|
||||
var topic_alt_35 = []byte(`' class="action_button">Unlock</a>`)
|
||||
var topic_alt_36 = []byte(`<a href='/topic/lock/submit/`)
|
||||
var topic_alt_37 = []byte(`' class="action_button">Lock</a>`)
|
||||
var topic_alt_38 = []byte(`<a href='/topic/unstick/submit/`)
|
||||
var topic_alt_39 = []byte(`' class="action_button">Unpin</a>`)
|
||||
var topic_alt_40 = []byte(`<a href='/topic/stick/submit/`)
|
||||
var topic_alt_41 = []byte(`' class="action_button">Pin</a>`)
|
||||
var topic_alt_42 = []byte(`
|
||||
<a href="/report/submit/`)
|
||||
var topic_alt_41 = []byte(`?session=`)
|
||||
var topic_alt_42 = []byte(`&type=topic" class="action_button report_item">Report</a>
|
||||
var topic_alt_43 = []byte(`?session=`)
|
||||
var topic_alt_44 = []byte(`&type=topic" class="action_button report_item">Report</a>
|
||||
`)
|
||||
var topic_alt_43 = []byte(`<a class="action_button action_button_right like_count hide_on_micro">`)
|
||||
var topic_alt_44 = []byte(` up</a>`)
|
||||
var topic_alt_45 = []byte(`
|
||||
var topic_alt_45 = []byte(`<a class="action_button action_button_right like_count hide_on_micro">`)
|
||||
var topic_alt_46 = []byte(` up</a>`)
|
||||
var topic_alt_47 = []byte(`
|
||||
<a class="action_button action_button_right created_at hide_on_mobile">`)
|
||||
var topic_alt_46 = []byte(`</a>
|
||||
var topic_alt_48 = []byte(`</a>
|
||||
`)
|
||||
var topic_alt_47 = []byte(`<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">`)
|
||||
var topic_alt_48 = []byte(`</a>`)
|
||||
var topic_alt_49 = []byte(`
|
||||
var topic_alt_49 = []byte(`<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">`)
|
||||
var topic_alt_50 = []byte(`</a>`)
|
||||
var topic_alt_51 = []byte(`
|
||||
</div>
|
||||
</div><div style="clear:both;"></div>
|
||||
</article>
|
||||
`)
|
||||
var topic_alt_50 = []byte(`
|
||||
var topic_alt_52 = []byte(`
|
||||
<article class="rowitem passive deletable_block editable_parent post_item `)
|
||||
var topic_alt_51 = []byte(`action_item`)
|
||||
var topic_alt_52 = []byte(`">
|
||||
var topic_alt_53 = []byte(`action_item`)
|
||||
var topic_alt_54 = []byte(`">
|
||||
<div class="userinfo">
|
||||
<div class="avatar_item" style="background-image: url(`)
|
||||
var topic_alt_53 = []byte(`), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
var topic_alt_55 = []byte(`), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
<a href="`)
|
||||
var topic_alt_54 = []byte(`" class="the_name">`)
|
||||
var topic_alt_55 = []byte(`</a>
|
||||
var topic_alt_56 = []byte(`" class="the_name">`)
|
||||
var topic_alt_57 = []byte(`</a>
|
||||
`)
|
||||
var topic_alt_56 = []byte(`<div class="tag_block"><div class="tag_pre"></div><div class="post_tag">`)
|
||||
var topic_alt_57 = []byte(`</div><div class="tag_post"></div></div>`)
|
||||
var topic_alt_58 = []byte(`<div class="tag_block"><div class="tag_pre"></div><div class="post_tag post_level">Level `)
|
||||
var topic_alt_58 = []byte(`<div class="tag_block"><div class="tag_pre"></div><div class="post_tag">`)
|
||||
var topic_alt_59 = []byte(`</div><div class="tag_post"></div></div>`)
|
||||
var topic_alt_60 = []byte(`
|
||||
var topic_alt_60 = []byte(`<div class="tag_block"><div class="tag_pre"></div><div class="post_tag post_level">Level `)
|
||||
var topic_alt_61 = []byte(`</div><div class="tag_post"></div></div>`)
|
||||
var topic_alt_62 = []byte(`
|
||||
</div>
|
||||
<div class="content_container" `)
|
||||
var topic_alt_61 = []byte(`style="margin-left: 0px;"`)
|
||||
var topic_alt_62 = []byte(`>
|
||||
var topic_alt_63 = []byte(`style="margin-left: 0px;"`)
|
||||
var topic_alt_64 = []byte(`>
|
||||
`)
|
||||
var topic_alt_63 = []byte(`
|
||||
var topic_alt_65 = []byte(`
|
||||
<span class="action_icon" style="font-size: 18px;padding-right: 5px;">`)
|
||||
var topic_alt_64 = []byte(`</span>
|
||||
var topic_alt_66 = []byte(`</span>
|
||||
<span>`)
|
||||
var topic_alt_65 = []byte(`</span>
|
||||
var topic_alt_67 = []byte(`</span>
|
||||
`)
|
||||
var topic_alt_66 = []byte(`
|
||||
var topic_alt_68 = []byte(`
|
||||
<div class="editable_block user_content">`)
|
||||
var topic_alt_67 = []byte(`</div>
|
||||
var topic_alt_69 = []byte(`</div>
|
||||
<div class="button_container">
|
||||
`)
|
||||
var topic_alt_68 = []byte(`<a href="/reply/like/submit/`)
|
||||
var topic_alt_69 = []byte(`" class="action_button">+1</a>`)
|
||||
var topic_alt_70 = []byte(`<a href="/reply/edit/submit/`)
|
||||
var topic_alt_71 = []byte(`" class="action_button edit_item">Edit</a>`)
|
||||
var topic_alt_72 = []byte(`<a href="/reply/delete/submit/`)
|
||||
var topic_alt_73 = []byte(`" class="action_button delete_item">Delete</a>`)
|
||||
var topic_alt_74 = []byte(`
|
||||
var topic_alt_70 = []byte(`<a href="/reply/like/submit/`)
|
||||
var topic_alt_71 = []byte(`" class="action_button">+1</a>`)
|
||||
var topic_alt_72 = []byte(`<a href="/reply/edit/submit/`)
|
||||
var topic_alt_73 = []byte(`" class="action_button edit_item">Edit</a>`)
|
||||
var topic_alt_74 = []byte(`<a href="/reply/delete/submit/`)
|
||||
var topic_alt_75 = []byte(`" class="action_button delete_item">Delete</a>`)
|
||||
var topic_alt_76 = []byte(`
|
||||
<a href="/report/submit/`)
|
||||
var topic_alt_75 = []byte(`?session=`)
|
||||
var topic_alt_76 = []byte(`&type=reply" class="action_button report_item">Report</a>
|
||||
var topic_alt_77 = []byte(`?session=`)
|
||||
var topic_alt_78 = []byte(`&type=reply" class="action_button report_item">Report</a>
|
||||
`)
|
||||
var topic_alt_77 = []byte(`<a class="action_button action_button_right like_count hide_on_micro">`)
|
||||
var topic_alt_78 = []byte(` up</a>`)
|
||||
var topic_alt_79 = []byte(`
|
||||
var topic_alt_79 = []byte(`<a class="action_button action_button_right like_count hide_on_micro">`)
|
||||
var topic_alt_80 = []byte(` up</a>`)
|
||||
var topic_alt_81 = []byte(`
|
||||
<a class="action_button action_button_right created_at hide_on_mobile">`)
|
||||
var topic_alt_80 = []byte(`</a>
|
||||
var topic_alt_82 = []byte(`</a>
|
||||
`)
|
||||
var topic_alt_81 = []byte(`<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">`)
|
||||
var topic_alt_82 = []byte(`</a>`)
|
||||
var topic_alt_83 = []byte(`
|
||||
var topic_alt_83 = []byte(`<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">`)
|
||||
var topic_alt_84 = []byte(`</a>`)
|
||||
var topic_alt_85 = []byte(`
|
||||
</div>
|
||||
`)
|
||||
var topic_alt_84 = []byte(`
|
||||
var topic_alt_86 = []byte(`
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
</article>
|
||||
`)
|
||||
var topic_alt_85 = []byte(`</div>
|
||||
var topic_alt_87 = []byte(`</div>
|
||||
`)
|
||||
var topic_alt_86 = []byte(`
|
||||
var topic_alt_88 = []byte(`
|
||||
<div class="rowblock topic_reply_form">
|
||||
<form action="/reply/create/" method="post">
|
||||
<input name="tid" value='`)
|
||||
var topic_alt_87 = []byte(`' type="hidden" />
|
||||
var topic_alt_89 = []byte(`' type="hidden" />
|
||||
<div class="formrow">
|
||||
<div class="formitem"><textarea name="reply-content" placeholder="Insert reply here" required></textarea></div>
|
||||
</div>
|
||||
@ -437,7 +433,7 @@ var topic_alt_87 = []byte(`' type="hidden" />
|
||||
</form>
|
||||
</div>
|
||||
`)
|
||||
var topic_alt_88 = []byte(`
|
||||
var topic_alt_90 = []byte(`
|
||||
|
||||
</main>
|
||||
|
||||
|
@ -109,169 +109,176 @@ if tmpl_topic_vars.CurrentUser.Perms.EditTopic {
|
||||
w.Write(topic_16)
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Title))
|
||||
w.Write(topic_17)
|
||||
if tmpl_topic_vars.CurrentUser.Perms.CloseTopic {
|
||||
}
|
||||
w.Write(topic_18)
|
||||
}
|
||||
w.Write(topic_19)
|
||||
}
|
||||
w.Write(topic_20)
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.ClassName))
|
||||
w.Write(topic_21)
|
||||
w.Write(topic_19)
|
||||
if tmpl_topic_vars.Topic.Avatar != "" {
|
||||
w.Write(topic_22)
|
||||
w.Write(topic_20)
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Avatar))
|
||||
w.Write(topic_23)
|
||||
w.Write(topic_21)
|
||||
if tmpl_topic_vars.Topic.ContentLines <= 5 {
|
||||
w.Write(topic_22)
|
||||
}
|
||||
w.Write(topic_23)
|
||||
}
|
||||
w.Write(topic_24)
|
||||
}
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Content))
|
||||
w.Write(topic_25)
|
||||
}
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Content))
|
||||
w.Write(topic_26)
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Content))
|
||||
w.Write(topic_27)
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Content))
|
||||
w.Write(topic_28)
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.UserLink))
|
||||
w.Write(topic_29)
|
||||
w.Write(topic_27)
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.CreatedByName))
|
||||
w.Write(topic_30)
|
||||
w.Write(topic_28)
|
||||
if tmpl_topic_vars.CurrentUser.Perms.LikeItem {
|
||||
w.Write(topic_31)
|
||||
w.Write(topic_29)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_32)
|
||||
w.Write(topic_30)
|
||||
if tmpl_topic_vars.Topic.Liked {
|
||||
w.Write(topic_33)
|
||||
w.Write(topic_31)
|
||||
}
|
||||
w.Write(topic_34)
|
||||
w.Write(topic_32)
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.EditTopic {
|
||||
w.Write(topic_33)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_34)
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.DeleteTopic {
|
||||
w.Write(topic_35)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_36)
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.DeleteTopic {
|
||||
if tmpl_topic_vars.CurrentUser.Perms.CloseTopic {
|
||||
if tmpl_topic_vars.Topic.IsClosed {
|
||||
w.Write(topic_37)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_38)
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.PinTopic {
|
||||
if tmpl_topic_vars.Topic.Sticky {
|
||||
} else {
|
||||
w.Write(topic_39)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_40)
|
||||
} else {
|
||||
}
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.PinTopic {
|
||||
if tmpl_topic_vars.Topic.Sticky {
|
||||
w.Write(topic_41)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_42)
|
||||
} else {
|
||||
w.Write(topic_43)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_44)
|
||||
}
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_43)
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.IPAddress))
|
||||
w.Write(topic_44)
|
||||
}
|
||||
w.Write(topic_45)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.IPAddress))
|
||||
w.Write(topic_46)
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
}
|
||||
w.Write(topic_47)
|
||||
if tmpl_topic_vars.Topic.LikeCount > 0 {
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_48)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.LikeCount)))
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_49)
|
||||
if tmpl_topic_vars.Topic.LikeCount > 0 {
|
||||
w.Write(topic_50)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.LikeCount)))
|
||||
w.Write(topic_51)
|
||||
}
|
||||
if tmpl_topic_vars.Topic.Tag != "" {
|
||||
w.Write(topic_50)
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Tag))
|
||||
w.Write(topic_51)
|
||||
} else {
|
||||
w.Write(topic_52)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.Level)))
|
||||
w.Write([]byte(tmpl_topic_vars.Topic.Tag))
|
||||
w.Write(topic_53)
|
||||
}
|
||||
} else {
|
||||
w.Write(topic_54)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.Level)))
|
||||
w.Write(topic_55)
|
||||
}
|
||||
w.Write(topic_56)
|
||||
if len(tmpl_topic_vars.ItemList) != 0 {
|
||||
for _, item := range tmpl_topic_vars.ItemList {
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_55)
|
||||
w.Write([]byte(item.ActionIcon))
|
||||
w.Write(topic_56)
|
||||
w.Write([]byte(item.ActionType))
|
||||
w.Write(topic_57)
|
||||
} else {
|
||||
w.Write([]byte(item.ActionIcon))
|
||||
w.Write(topic_58)
|
||||
w.Write([]byte(item.ClassName))
|
||||
w.Write([]byte(item.ActionType))
|
||||
w.Write(topic_59)
|
||||
if item.Avatar != "" {
|
||||
} else {
|
||||
w.Write(topic_60)
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write([]byte(item.ClassName))
|
||||
w.Write(topic_61)
|
||||
if item.ContentLines <= 5 {
|
||||
if item.Avatar != "" {
|
||||
w.Write(topic_62)
|
||||
}
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write(topic_63)
|
||||
}
|
||||
if item.ContentLines <= 5 {
|
||||
w.Write(topic_64)
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
}
|
||||
w.Write(topic_65)
|
||||
w.Write([]byte(item.UserLink))
|
||||
}
|
||||
w.Write(topic_66)
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
w.Write(topic_67)
|
||||
if tmpl_topic_vars.CurrentUser.Perms.LikeItem {
|
||||
w.Write([]byte(item.UserLink))
|
||||
w.Write(topic_68)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write(topic_69)
|
||||
if item.Liked {
|
||||
if tmpl_topic_vars.CurrentUser.Perms.LikeItem {
|
||||
w.Write(topic_70)
|
||||
}
|
||||
w.Write(topic_71)
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.EditReply {
|
||||
w.Write(topic_72)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_71)
|
||||
if item.Liked {
|
||||
w.Write(topic_72)
|
||||
}
|
||||
w.Write(topic_73)
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.DeleteReply {
|
||||
if tmpl_topic_vars.CurrentUser.Perms.EditReply {
|
||||
w.Write(topic_74)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_75)
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.ViewIPs {
|
||||
if tmpl_topic_vars.CurrentUser.Perms.DeleteReply {
|
||||
w.Write(topic_76)
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_77)
|
||||
}
|
||||
if tmpl_topic_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_78)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write(topic_79)
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
}
|
||||
w.Write(topic_80)
|
||||
if item.LikeCount > 0 {
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_81)
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||
w.Write(topic_82)
|
||||
if item.LikeCount > 0 {
|
||||
w.Write(topic_83)
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(topic_84)
|
||||
}
|
||||
if item.Tag != "" {
|
||||
w.Write(topic_83)
|
||||
w.Write([]byte(item.Tag))
|
||||
w.Write(topic_84)
|
||||
} else {
|
||||
w.Write(topic_85)
|
||||
w.Write([]byte(strconv.Itoa(item.Level)))
|
||||
w.Write([]byte(item.Tag))
|
||||
w.Write(topic_86)
|
||||
}
|
||||
} else {
|
||||
w.Write(topic_87)
|
||||
}
|
||||
}
|
||||
}
|
||||
w.Write([]byte(strconv.Itoa(item.Level)))
|
||||
w.Write(topic_88)
|
||||
if tmpl_topic_vars.CurrentUser.Perms.CreateReply {
|
||||
w.Write(topic_89)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_90)
|
||||
}
|
||||
w.Write(topic_89)
|
||||
}
|
||||
}
|
||||
}
|
||||
w.Write(topic_90)
|
||||
if tmpl_topic_vars.CurrentUser.Perms.CreateReply {
|
||||
w.Write(topic_91)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||
w.Write(topic_92)
|
||||
}
|
||||
w.Write(topic_93)
|
||||
w.Write(footer_0)
|
||||
if len(tmpl_topic_vars.Header.Themes) != 0 {
|
||||
for _, item := range tmpl_topic_vars.Header.Themes {
|
||||
|
@ -108,163 +108,170 @@ if tmpl_topic_alt_vars.CurrentUser.Perms.EditTopic {
|
||||
w.Write(topic_alt_15)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Title))
|
||||
w.Write(topic_alt_16)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.CloseTopic {
|
||||
}
|
||||
w.Write(topic_alt_17)
|
||||
}
|
||||
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(topic_alt_18)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.UserLink))
|
||||
w.Write(topic_alt_21)
|
||||
w.Write(topic_alt_19)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.CreatedByName))
|
||||
w.Write(topic_alt_22)
|
||||
w.Write(topic_alt_20)
|
||||
if tmpl_topic_alt_vars.Topic.Tag != "" {
|
||||
w.Write(topic_alt_23)
|
||||
w.Write(topic_alt_21)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Tag))
|
||||
w.Write(topic_alt_24)
|
||||
w.Write(topic_alt_22)
|
||||
} else {
|
||||
w.Write(topic_alt_25)
|
||||
w.Write(topic_alt_23)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.Level)))
|
||||
w.Write(topic_alt_26)
|
||||
w.Write(topic_alt_24)
|
||||
}
|
||||
w.Write(topic_alt_25)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Content))
|
||||
w.Write(topic_alt_26)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Content))
|
||||
w.Write(topic_alt_27)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Content))
|
||||
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_28)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_29)
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.EditTopic {
|
||||
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 {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.DeleteTopic {
|
||||
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 {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.CloseTopic {
|
||||
if tmpl_topic_alt_vars.Topic.IsClosed {
|
||||
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.PinTopic {
|
||||
if tmpl_topic_alt_vars.Topic.Sticky {
|
||||
} else {
|
||||
w.Write(topic_alt_36)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_37)
|
||||
} else {
|
||||
}
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.PinTopic {
|
||||
if tmpl_topic_alt_vars.Topic.Sticky {
|
||||
w.Write(topic_alt_38)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_39)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w.Write(topic_alt_40)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_41)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_42)
|
||||
}
|
||||
if tmpl_topic_alt_vars.Topic.LikeCount > 0 {
|
||||
}
|
||||
w.Write(topic_alt_42)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_43)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.LikeCount)))
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_44)
|
||||
}
|
||||
if tmpl_topic_alt_vars.Topic.LikeCount > 0 {
|
||||
w.Write(topic_alt_45)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.CreatedAt))
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.LikeCount)))
|
||||
w.Write(topic_alt_46)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_alt_47)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.IPAddress))
|
||||
w.Write(topic_alt_48)
|
||||
}
|
||||
w.Write(topic_alt_47)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.CreatedAt))
|
||||
w.Write(topic_alt_48)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_alt_49)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.IPAddress))
|
||||
w.Write(topic_alt_50)
|
||||
}
|
||||
w.Write(topic_alt_51)
|
||||
if len(tmpl_topic_alt_vars.ItemList) != 0 {
|
||||
for _, item := range tmpl_topic_alt_vars.ItemList {
|
||||
w.Write(topic_alt_50)
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_51)
|
||||
}
|
||||
w.Write(topic_alt_52)
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write(topic_alt_53)
|
||||
w.Write([]byte(item.UserLink))
|
||||
w.Write(topic_alt_54)
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write(topic_alt_55)
|
||||
if item.Tag != "" {
|
||||
w.Write(topic_alt_56)
|
||||
w.Write([]byte(item.Tag))
|
||||
w.Write(topic_alt_57)
|
||||
} else {
|
||||
w.Write(topic_alt_58)
|
||||
w.Write([]byte(strconv.Itoa(item.Level)))
|
||||
w.Write(topic_alt_59)
|
||||
}
|
||||
w.Write(topic_alt_60)
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_53)
|
||||
}
|
||||
w.Write(topic_alt_54)
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write(topic_alt_55)
|
||||
w.Write([]byte(item.UserLink))
|
||||
w.Write(topic_alt_56)
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write(topic_alt_57)
|
||||
if item.Tag != "" {
|
||||
w.Write(topic_alt_58)
|
||||
w.Write([]byte(item.Tag))
|
||||
w.Write(topic_alt_59)
|
||||
} else {
|
||||
w.Write(topic_alt_60)
|
||||
w.Write([]byte(strconv.Itoa(item.Level)))
|
||||
w.Write(topic_alt_61)
|
||||
}
|
||||
w.Write(topic_alt_62)
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_63)
|
||||
w.Write([]byte(item.ActionIcon))
|
||||
}
|
||||
w.Write(topic_alt_64)
|
||||
w.Write([]byte(item.ActionType))
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_65)
|
||||
} else {
|
||||
w.Write([]byte(item.ActionIcon))
|
||||
w.Write(topic_alt_66)
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
w.Write([]byte(item.ActionType))
|
||||
w.Write(topic_alt_67)
|
||||
} else {
|
||||
w.Write(topic_alt_68)
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
w.Write(topic_alt_69)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Loggedin {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.LikeItem {
|
||||
w.Write(topic_alt_68)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_69)
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.EditReply {
|
||||
w.Write(topic_alt_70)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_71)
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.DeleteReply {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.EditReply {
|
||||
w.Write(topic_alt_72)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_73)
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.DeleteReply {
|
||||
w.Write(topic_alt_74)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_75)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_76)
|
||||
}
|
||||
if item.LikeCount > 0 {
|
||||
w.Write(topic_alt_76)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_77)
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_78)
|
||||
}
|
||||
if item.LikeCount > 0 {
|
||||
w.Write(topic_alt_79)
|
||||
w.Write([]byte(item.CreatedAt))
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(topic_alt_80)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
}
|
||||
w.Write(topic_alt_81)
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write([]byte(item.CreatedAt))
|
||||
w.Write(topic_alt_82)
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_alt_83)
|
||||
}
|
||||
w.Write([]byte(item.IPAddress))
|
||||
w.Write(topic_alt_84)
|
||||
}
|
||||
}
|
||||
w.Write(topic_alt_85)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.CreateReply {
|
||||
w.Write(topic_alt_86)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_87)
|
||||
}
|
||||
w.Write(topic_alt_86)
|
||||
}
|
||||
}
|
||||
w.Write(topic_alt_87)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.CreateReply {
|
||||
w.Write(topic_alt_88)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_89)
|
||||
}
|
||||
w.Write(topic_alt_90)
|
||||
w.Write(footer_0)
|
||||
if len(tmpl_topic_alt_vars.Header.Themes) != 0 {
|
||||
for _, item := range tmpl_topic_alt_vars.Header.Themes {
|
||||
|
@ -13,13 +13,9 @@
|
||||
<div class="rowblock rowhead topic_block">
|
||||
<div class="rowitem topic_item{{if .Topic.Sticky}} topic_sticky_head{{else if .Topic.IsClosed}} topic_closed_head{{end}}">
|
||||
<h1 class='topic_name hide_on_edit'>{{.Topic.Title}}</h1>
|
||||
{{if .Topic.IsClosed}}<span class='username hide_on_micro topic_status_e topic_status_closed hide_on_edit' title='Status: Closed' style="font-weight:normal;float: right;position:relative;top:-5px;">🔒︎</span>{{end}}
|
||||
{{if .Topic.IsClosed}}<span class='username hide_on_micro topic_status_e topic_status_closed hide_on_edit' title='Status: Closed'>🔒︎</span>{{end}}
|
||||
{{if .CurrentUser.Perms.EditTopic}}
|
||||
<input form='edit_topic_form' class='show_on_edit topic_name_input' name="topic_name" value='{{.Topic.Title}}' type="text" />
|
||||
{{if .CurrentUser.Perms.CloseTopic}}<select form='edit_topic_form' name="topic_status" class='show_on_edit topic_status_input' style='float: right;'>
|
||||
<option>open</option>
|
||||
<option>closed</option>
|
||||
</select>{{end}}
|
||||
<button form='edit_topic_form' name="topic-button" class="formbutton show_on_edit submit_edit">Update</button>
|
||||
{{end}}
|
||||
</div>
|
||||
@ -40,6 +36,8 @@
|
||||
|
||||
{{if .CurrentUser.Perms.DeleteTopic}}<a href='/topic/delete/submit/{{.Topic.ID}}' class="mod_button" style="font-weight:normal;" title="Delete Topic"><button class="username trash_label"></button></a>{{end}}
|
||||
|
||||
{{if .CurrentUser.Perms.CloseTopic}}{{if .Topic.IsClosed}}<a class="mod_button" href='/topic/unlock/submit/{{.Topic.ID}}' style="font-weight:normal;" title="Unlock Topic"><button class="username unlock_label"></button></a>{{else}}<a href='/topic/lock/submit/{{.Topic.ID}}' class="mod_button" style="font-weight:normal;" title="Lock Topic"><button class="username lock_label"></button></a>{{end}}{{end}}
|
||||
|
||||
{{if .CurrentUser.Perms.PinTopic}}{{if .Topic.Sticky}}<a class="mod_button" href='/topic/unstick/submit/{{.Topic.ID}}' style="font-weight:normal;" title="Unpin Topic"><button class="username unpin_label"></button></a>{{else}}<a href='/topic/stick/submit/{{.Topic.ID}}' class="mod_button" style="font-weight:normal;" title="Pin Topic"><button class="username pin_label"></button></a>{{end}}{{end}}
|
||||
{{if .CurrentUser.Perms.ViewIPs}}<a class="mod_button" href='/users/ips/{{.Topic.IPAddress}}' style="font-weight:normal;" title="View IP"><button class="username ip_label"></button></a>{{end}}
|
||||
<a href="/report/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}&type=topic" class="mod_button report_item" style="font-weight:normal;" title="Flag Topic"><button class="username flag_label"></button></a>
|
||||
|
@ -9,13 +9,10 @@
|
||||
<form action='/topic/edit/submit/{{.Topic.ID}}' method="post">
|
||||
<div class="rowitem topic_item{{if .Topic.Sticky}} topic_sticky_head{{else if .Topic.IsClosed}} topic_closed_head{{end}}">
|
||||
<h1 class='topic_name hide_on_edit'>{{.Topic.Title}}</h1>
|
||||
{{/** TODO: Inline this CSS **/}}
|
||||
{{if .Topic.IsClosed}}<span class='username hide_on_micro topic_status_e topic_status_closed hide_on_edit' title='Status: Closed' style="font-weight:normal;float: right;position:relative;top:-5px;">🔒︎</span>{{end}}
|
||||
{{if .CurrentUser.Perms.EditTopic}}
|
||||
<input class='show_on_edit topic_name_input' name="topic_name" value='{{.Topic.Title}}' type="text" />
|
||||
{{if .CurrentUser.Perms.CloseTopic}}<select name="topic_status" class='show_on_edit topic_status_input' style='float: right;'>
|
||||
<option>open</option>
|
||||
<option>closed</option>
|
||||
</select>{{end}}
|
||||
<button name="topic-button" class="formbutton show_on_edit submit_edit">Update</button>
|
||||
{{end}}
|
||||
</div>
|
||||
@ -37,6 +34,8 @@
|
||||
{{if .CurrentUser.Perms.LikeItem}}<a href="/topic/like/submit/{{.Topic.ID}}" class="action_button">+1</a>{{end}}
|
||||
{{if .CurrentUser.Perms.EditTopic}}<a href="/topic/edit/{{.Topic.ID}}" class="action_button open_edit">Edit</a>{{end}}
|
||||
{{if .CurrentUser.Perms.DeleteTopic}}<a href="/topic/delete/submit/{{.Topic.ID}}" class="action_button delete_item">Delete</a>{{end}}
|
||||
{{if .CurrentUser.Perms.CloseTopic}}
|
||||
{{if .Topic.IsClosed}}<a href='/topic/unlock/submit/{{.Topic.ID}}' class="action_button">Unlock</a>{{else}}<a href='/topic/lock/submit/{{.Topic.ID}}' class="action_button">Lock</a>{{end}}{{end}}
|
||||
{{if .CurrentUser.Perms.PinTopic}}
|
||||
{{if .Topic.Sticky}}<a href='/topic/unstick/submit/{{.Topic.ID}}' class="action_button">Unpin</a>{{else}}<a href='/topic/stick/submit/{{.Topic.ID}}' class="action_button">Pin</a>{{end}}{{end}}
|
||||
<a href="/report/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}&type=topic" class="action_button report_item">Report</a>
|
||||
|
@ -23,6 +23,9 @@ var themes = make(map[string]Theme)
|
||||
var defaultThemeBox atomic.Value
|
||||
var changeDefaultThemeMutex sync.Mutex
|
||||
|
||||
// TODO: Use this when the default theme doesn't exist
|
||||
var fallbackTheme = "shadow"
|
||||
|
||||
//var overridenTemplates map[string]interface{} = make(map[string]interface{})
|
||||
var overridenTemplates = make(map[string]bool)
|
||||
|
||||
|
@ -244,6 +244,12 @@ a {
|
||||
.pin_label:before {
|
||||
content: "Pin";
|
||||
}
|
||||
.lock_label:before {
|
||||
content: "Lock";
|
||||
}
|
||||
.unlock_label:before {
|
||||
content: "Unlock";
|
||||
}
|
||||
.unpin_label:before {
|
||||
content: "Unpin";
|
||||
}
|
||||
@ -321,7 +327,7 @@ textarea.large {
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
.formitem button {
|
||||
.formitem button, .formbutton {
|
||||
background-color: #444444;
|
||||
border: 1px solid #555555;
|
||||
color: #999999;
|
||||
@ -527,6 +533,28 @@ input, select, textarea {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.topic_item {
|
||||
display: flex;
|
||||
}
|
||||
.topic_name_input {
|
||||
width: 100%;
|
||||
margin-right: 10px;
|
||||
background-color: #444444;
|
||||
border: 1px solid #555555;
|
||||
color: #999999;
|
||||
padding-bottom: 6px;
|
||||
font-size: 13px;
|
||||
padding: 5px;
|
||||
}
|
||||
.topic_item .submit_edit {
|
||||
margin-left: auto;
|
||||
}
|
||||
.topic_item .topic_status_closed {
|
||||
margin-left: auto;
|
||||
position: relative;
|
||||
top: -5px;
|
||||
}
|
||||
|
||||
/* Profiles */
|
||||
#profile_left_lane {
|
||||
width: 220px;
|
||||
|
@ -389,6 +389,9 @@ button {
|
||||
.topic_status_sticky {
|
||||
display: none;
|
||||
}
|
||||
.topic_status_closed {
|
||||
margin-left: auto;
|
||||
}
|
||||
.topic_sticky {
|
||||
background-color: rgb(255,255,234);
|
||||
}
|
||||
@ -407,7 +410,26 @@ button {
|
||||
color: #505050; /* 80,80,80 */
|
||||
border-radius: 2px;
|
||||
}
|
||||
.topic_status:empty { display: none; }
|
||||
.topic_status:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.topic_item {
|
||||
display: flex;
|
||||
}
|
||||
.topic_item .topic_name_input {
|
||||
padding: 5px;
|
||||
width: 100%;
|
||||
margin-right: 9px;
|
||||
}
|
||||
.topic_item .submit_edit {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.topic_content_input {
|
||||
width: 100%;
|
||||
min-height: 143px;
|
||||
}
|
||||
|
||||
.rowhead, .colstack_head {
|
||||
border-bottom: none;
|
||||
@ -739,6 +761,23 @@ button.username {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.pageset {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
margin-top: -5px;
|
||||
}
|
||||
.pageitem {
|
||||
border: 1px solid hsl(0,0%,80%);
|
||||
background-color: white;
|
||||
padding: 5px;
|
||||
margin-right: 5px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
.pageitem a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Firefox specific CSS */
|
||||
@supports (-moz-appearance: none) {
|
||||
.footer, .rowmenu, #profile_right_lane .topic_reply_form, .content_container {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* The Media Queries */
|
||||
|
||||
@media(min-width: 881px) {
|
||||
@media(min-width: 951px) {
|
||||
.shrink_main {
|
||||
float: left;
|
||||
width: calc(75% - 12px);
|
||||
@ -12,7 +12,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 880px) {
|
||||
@media (max-width: 950px) {
|
||||
li {
|
||||
height: 29px;
|
||||
font-size: 15px;
|
||||
|
@ -6,6 +6,7 @@
|
||||
"FullImage": "tempra-cursive.png",
|
||||
"ForkOf": "tempra-simple",
|
||||
"MobileFriendly": true,
|
||||
"HideFromThemes": true,
|
||||
"URL": "github.com/Azareal/Gosora",
|
||||
"Sidebars":"right"
|
||||
}
|
||||
|
@ -390,9 +390,33 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
.username, .panel_tag {
|
||||
text-transform: none;
|
||||
margin-left: 0px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
color: #505050; /* 80,80,80 */
|
||||
background-color: #FFFFFF;
|
||||
border-style: solid;
|
||||
border-color: #ccc;
|
||||
border-width: 1px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.topic_item {
|
||||
display: flex;
|
||||
}
|
||||
.topic_status_sticky {
|
||||
display: none;
|
||||
}
|
||||
.topic_status_closed {
|
||||
margin-left: auto;
|
||||
margin-top: -5px;
|
||||
font-size: 0.90em;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
.topic_sticky {
|
||||
background-color: rgb(255,255,234);
|
||||
}
|
||||
@ -421,20 +445,6 @@ button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.username, .panel_tag {
|
||||
text-transform: none;
|
||||
margin-left: 0px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
color: #505050; /* 80,80,80 */
|
||||
background-color: #FFFFFF;
|
||||
border-style: solid;
|
||||
border-color: #ccc;
|
||||
border-width: 1px;
|
||||
font-size: 15px;
|
||||
}
|
||||
button.username {
|
||||
position: relative;
|
||||
top: -0.25px;
|
||||
@ -501,15 +511,34 @@ button.username {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.edit_label:before { content: "🖊️"; }
|
||||
.trash_label:before { content: "🗑️"; }
|
||||
.pin_label:before { content: "📌"; }
|
||||
.unpin_label:before { content: "📌"; }
|
||||
.unpin_label { background-color: #D6FFD6; }
|
||||
.ip_label:before { content: "🔍"; }
|
||||
.flag_label:before { content: "🚩"; }
|
||||
.level_label:before { content: "👑"; }
|
||||
.level_label { color: #505050; opacity:0.85; }
|
||||
.edit_label:before {
|
||||
content: "🖊️";
|
||||
}
|
||||
.trash_label:before {
|
||||
content: "🗑️";
|
||||
}
|
||||
.pin_label:before, .unpin_label:before {
|
||||
content: "📌";
|
||||
}
|
||||
.unpin_label, .unlock_label {
|
||||
background-color: #D6FFD6;
|
||||
}
|
||||
.lock_label:before, .unlock_label:before {
|
||||
content: "🔒";
|
||||
}
|
||||
.ip_label:before {
|
||||
content: "🔍";
|
||||
}
|
||||
.flag_label:before {
|
||||
content: "🚩";
|
||||
}
|
||||
.level_label:before {
|
||||
content: "👑";
|
||||
}
|
||||
.level_label {
|
||||
color: #505050;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.controls {
|
||||
margin-top: 23px;
|
||||
@ -652,9 +681,27 @@ button.username {
|
||||
#profile_comments {
|
||||
overflow: hidden;
|
||||
border-top: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.simple .user_tag {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.pageset {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
margin-top: -5px;
|
||||
}
|
||||
.pageitem {
|
||||
background-color: white;
|
||||
padding: 5px;
|
||||
margin-right: 5px;
|
||||
padding-bottom: 4px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
.pageitem a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
{{template "media.partial.css" }}
|
||||
|
62
topic.go
@ -90,6 +90,68 @@ type TopicsRow struct {
|
||||
ForumLink string
|
||||
}
|
||||
|
||||
func (topic *Topic) Lock() (err error) {
|
||||
_, err = lockTopicStmt.Exec(topic.ID)
|
||||
tcache, ok := topics.(TopicCache)
|
||||
if ok {
|
||||
tcache.CacheRemove(topic.ID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (topic *Topic) Unlock() (err error) {
|
||||
_, err = unlockTopicStmt.Exec(topic.ID)
|
||||
tcache, ok := topics.(TopicCache)
|
||||
if ok {
|
||||
tcache.CacheRemove(topic.ID)
|
||||
}
|
||||
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.
|
||||
// ? - We do a CacheDelete() here instead of mutating the pointer to avoid creating a race condition
|
||||
func (topic *Topic) Stick() (err error) {
|
||||
_, err = stickTopicStmt.Exec(topic.ID)
|
||||
tcache, ok := topics.(TopicCache)
|
||||
if ok {
|
||||
tcache.CacheRemove(topic.ID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (topic *Topic) Unstick() (err error) {
|
||||
_, err = unstickTopicStmt.Exec(topic.ID)
|
||||
tcache, ok := topics.(TopicCache)
|
||||
if ok {
|
||||
tcache.CacheRemove(topic.ID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Implement this
|
||||
func (topic *Topic) AddLike(uid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: Implement this
|
||||
func (topic *Topic) RemoveLike(uid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (topic *Topic) CreateActionReply(action string, ipaddress string, user User) (err error) {
|
||||
_, err = createActionReplyStmt.Exec(topic.ID, action, ipaddress, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = addRepliesToTopicStmt.Exec(1, user.ID, topic.ID)
|
||||
tcache, ok := topics.(TopicCache)
|
||||
if ok {
|
||||
tcache.CacheRemove(topic.ID)
|
||||
}
|
||||
// ? - Update the last topic cache for the parent forum?
|
||||
return err
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
@ -22,7 +22,6 @@ import (
|
||||
var topics TopicStore
|
||||
|
||||
type TopicStore interface {
|
||||
Reload(id int) error // ? - Should we move this to TopicCache? Might require us to do a lot more casting in Gosora though...
|
||||
Get(id int) (*Topic, error)
|
||||
BypassGet(id int) (*Topic, error)
|
||||
Delete(id int) error
|
||||
@ -43,6 +42,7 @@ type TopicCache interface {
|
||||
CacheRemove(id int) error
|
||||
CacheRemoveUnsafe(id int) error
|
||||
Flush()
|
||||
Reload(id int) error
|
||||
GetLength() int
|
||||
SetCapacity(capacity int)
|
||||
GetCapacity() int
|
||||
@ -310,11 +310,6 @@ func (sts *SQLTopicStore) BypassGet(id int) (*Topic, error) {
|
||||
return topic, err
|
||||
}
|
||||
|
||||
// Reload uses a similar query to Exists(), as we don't have any entries to reload, and the secondary benefit of calling Reload() is seeing if the item you're trying to reload exists
|
||||
func (sts *SQLTopicStore) Reload(id int) error {
|
||||
return sts.exists.QueryRow(id).Scan(&id)
|
||||
}
|
||||
|
||||
func (sts *SQLTopicStore) Exists(id int) bool {
|
||||
return sts.exists.QueryRow(id).Scan(&id) == nil
|
||||
}
|
||||
|
240
user.go
@ -64,10 +64,11 @@ func (user *User) Ban(duration time.Duration, issuedBy int) error {
|
||||
|
||||
func (user *User) Unban() error {
|
||||
err := user.RevertGroupUpdate()
|
||||
if err != nil {
|
||||
return err
|
||||
ucache, ok := users.(UserCache)
|
||||
if ok {
|
||||
ucache.CacheRemove(user.ID)
|
||||
}
|
||||
return users.Reload(user.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Use a transaction to avoid race conditions
|
||||
@ -84,10 +85,11 @@ func (user *User) ScheduleGroupUpdate(gid int, issuedBy int, duration time.Durat
|
||||
return err
|
||||
}
|
||||
_, err = setTempGroupStmt.Exec(gid, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
ucache, ok := users.(UserCache)
|
||||
if ok {
|
||||
ucache.CacheRemove(user.ID)
|
||||
}
|
||||
return users.Reload(user.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Use a transaction to avoid race conditions
|
||||
@ -97,10 +99,129 @@ func (user *User) RevertGroupUpdate() error {
|
||||
return err
|
||||
}
|
||||
_, err = setTempGroupStmt.Exec(0, user.ID)
|
||||
ucache, ok := users.(UserCache)
|
||||
if ok {
|
||||
ucache.CacheRemove(user.ID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Use a transaction here
|
||||
// TODO: Add a Deactivate method?
|
||||
func (user *User) Activate() (err error) {
|
||||
_, err = activateUserStmt.Exec(user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return users.Reload(user.ID)
|
||||
_, err = changeGroupStmt.Exec(config.DefaultGroup, user.ID)
|
||||
ucache, ok := users.(UserCache)
|
||||
if ok {
|
||||
ucache.CacheRemove(user.ID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (user *User) increasePostStats(wcount int, topic bool) error {
|
||||
var mod int
|
||||
baseScore := 1
|
||||
if topic {
|
||||
_, err := incrementUserTopicsStmt.Exec(1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
baseScore = 2
|
||||
}
|
||||
|
||||
settings := settingBox.Load().(SettingBox)
|
||||
if wcount >= settings["megapost_min_words"].(int) {
|
||||
_, err := incrementUserMegapostsStmt.Exec(1, 1, 1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mod = 4
|
||||
} else if wcount >= settings["bigpost_min_words"].(int) {
|
||||
_, err := incrementUserBigpostsStmt.Exec(1, 1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mod = 1
|
||||
} else {
|
||||
_, err := incrementUserPostsStmt.Exec(1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err := incrementUserScoreStmt.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 = updateUserLevelStmt.Exec(getLevel(user.Score+baseScore+mod), user.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (user *User) decreasePostStats(wcount int, topic bool) error {
|
||||
var mod int
|
||||
baseScore := -1
|
||||
if topic {
|
||||
_, err := incrementUserTopicsStmt.Exec(-1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
baseScore = -2
|
||||
}
|
||||
|
||||
settings := settingBox.Load().(SettingBox)
|
||||
if wcount >= settings["megapost_min_words"].(int) {
|
||||
_, err := incrementUserMegapostsStmt.Exec(-1, -1, -1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mod = 4
|
||||
} else if wcount >= settings["bigpost_min_words"].(int) {
|
||||
_, err := incrementUserBigpostsStmt.Exec(-1, -1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mod = 1
|
||||
} else {
|
||||
_, err := incrementUserPostsStmt.Exec(-1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err := incrementUserScoreStmt.Exec(baseScore-mod, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: Use a transaction to prevent level desyncs?
|
||||
_, err = updateUserLevelStmt.Exec(getLevel(user.Score-baseScore-mod), user.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (user *User) initPerms() {
|
||||
if user.TempGroup != 0 {
|
||||
user.Group = user.TempGroup
|
||||
}
|
||||
|
||||
group := gstore.DirtyGet(user.Group)
|
||||
if user.IsSuperAdmin {
|
||||
user.Perms = AllPerms
|
||||
user.PluginPerms = AllPluginPerms
|
||||
} else {
|
||||
user.Perms = group.Perms
|
||||
user.PluginPerms = group.PluginPerms
|
||||
}
|
||||
|
||||
user.IsAdmin = user.IsSuperAdmin || group.IsAdmin
|
||||
user.IsSuperMod = user.IsAdmin || group.IsMod
|
||||
user.IsMod = user.IsSuperMod
|
||||
user.IsBanned = group.IsBanned
|
||||
if user.IsBanned && user.IsSuperMod {
|
||||
user.IsBanned = false
|
||||
}
|
||||
}
|
||||
|
||||
func BcryptCheckPassword(realPassword string, password string, salt string) (err error) {
|
||||
@ -167,111 +288,6 @@ func wordsToScore(wcount int, topic bool) (score int) {
|
||||
return score
|
||||
}
|
||||
|
||||
// TODO: Move this to where the other User methods are
|
||||
func (user *User) increasePostStats(wcount int, topic bool) error {
|
||||
var mod int
|
||||
baseScore := 1
|
||||
if topic {
|
||||
_, err := incrementUserTopicsStmt.Exec(1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
baseScore = 2
|
||||
}
|
||||
|
||||
settings := settingBox.Load().(SettingBox)
|
||||
if wcount >= settings["megapost_min_words"].(int) {
|
||||
_, err := incrementUserMegapostsStmt.Exec(1, 1, 1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mod = 4
|
||||
} else if wcount >= settings["bigpost_min_words"].(int) {
|
||||
_, err := incrementUserBigpostsStmt.Exec(1, 1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mod = 1
|
||||
} else {
|
||||
_, err := incrementUserPostsStmt.Exec(1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err := incrementUserScoreStmt.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 = updateUserLevelStmt.Exec(getLevel(user.Score+baseScore+mod), user.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Move this to where the other User methods are
|
||||
func (user *User) decreasePostStats(wcount int, topic bool) error {
|
||||
var mod int
|
||||
baseScore := -1
|
||||
if topic {
|
||||
_, err := incrementUserTopicsStmt.Exec(-1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
baseScore = -2
|
||||
}
|
||||
|
||||
settings := settingBox.Load().(SettingBox)
|
||||
if wcount >= settings["megapost_min_words"].(int) {
|
||||
_, err := incrementUserMegapostsStmt.Exec(-1, -1, -1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mod = 4
|
||||
} else if wcount >= settings["bigpost_min_words"].(int) {
|
||||
_, err := incrementUserBigpostsStmt.Exec(-1, -1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mod = 1
|
||||
} else {
|
||||
_, err := incrementUserPostsStmt.Exec(-1, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err := incrementUserScoreStmt.Exec(baseScore-mod, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: Use a transaction to prevent level desyncs?
|
||||
_, err = updateUserLevelStmt.Exec(getLevel(user.Score-baseScore-mod), user.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
func initUserPerms(user *User) {
|
||||
if user.TempGroup != 0 {
|
||||
user.Group = user.TempGroup
|
||||
}
|
||||
|
||||
group := gstore.DirtyGet(user.Group)
|
||||
if user.IsSuperAdmin {
|
||||
user.Perms = AllPerms
|
||||
user.PluginPerms = AllPluginPerms
|
||||
} else {
|
||||
user.Perms = group.Perms
|
||||
user.PluginPerms = group.PluginPerms
|
||||
}
|
||||
|
||||
user.IsAdmin = user.IsSuperAdmin || group.IsAdmin
|
||||
user.IsSuperMod = user.IsAdmin || group.IsMod
|
||||
user.IsMod = user.IsSuperMod
|
||||
user.IsBanned = group.IsBanned
|
||||
if user.IsBanned && user.IsSuperMod {
|
||||
user.IsBanned = false
|
||||
}
|
||||
}
|
||||
|
||||
func buildProfileURL(slug string, uid int) string {
|
||||
if slug == "" {
|
||||
return "/user/" + strconv.Itoa(uid)
|
||||
|
@ -19,7 +19,6 @@ var users UserStore
|
||||
var errAccountExists = errors.New("this username is already in use")
|
||||
|
||||
type UserStore interface {
|
||||
Reload(id int) error // ? - Should we move this to TopicCache? Might require us to do a lot more casting in Gosora though...
|
||||
Get(id int) (*User, error)
|
||||
Exists(id int) bool
|
||||
//BulkGet(ids []int) ([]*User, error)
|
||||
@ -38,6 +37,7 @@ type UserCache interface {
|
||||
CacheRemove(id int) error
|
||||
CacheRemoveUnsafe(id int) error
|
||||
Flush()
|
||||
Reload(id int) error
|
||||
GetLength() int
|
||||
SetCapacity(capacity int)
|
||||
GetCapacity() int
|
||||
@ -133,7 +133,7 @@ func (mus *MemoryUserStore) Get(id int) (*User, error) {
|
||||
}
|
||||
user.Link = buildProfileURL(nameToSlug(user.Name), id)
|
||||
user.Tag = gstore.DirtyGet(user.Group).Tag
|
||||
initUserPerms(user)
|
||||
user.initPerms()
|
||||
if err == nil {
|
||||
mus.CacheSet(user)
|
||||
}
|
||||
@ -211,7 +211,7 @@ func (mus *MemoryUserStore) BulkGetMap(ids []int) (list map[int]*User, err error
|
||||
}
|
||||
user.Link = buildProfileURL(nameToSlug(user.Name), user.ID)
|
||||
user.Tag = gstore.DirtyGet(user.Group).Tag
|
||||
initUserPerms(user)
|
||||
user.initPerms()
|
||||
|
||||
// Add it to the cache...
|
||||
_ = mus.CacheSet(user)
|
||||
@ -261,7 +261,7 @@ func (mus *MemoryUserStore) BypassGet(id int) (*User, error) {
|
||||
}
|
||||
user.Link = buildProfileURL(nameToSlug(user.Name), id)
|
||||
user.Tag = gstore.DirtyGet(user.Group).Tag
|
||||
initUserPerms(user)
|
||||
user.initPerms()
|
||||
return user, err
|
||||
}
|
||||
|
||||
@ -282,7 +282,7 @@ func (mus *MemoryUserStore) Reload(id int) error {
|
||||
}
|
||||
user.Link = buildProfileURL(nameToSlug(user.Name), id)
|
||||
user.Tag = gstore.DirtyGet(user.Group).Tag
|
||||
initUserPerms(user)
|
||||
user.initPerms()
|
||||
_ = mus.CacheSet(user)
|
||||
return nil
|
||||
}
|
||||
@ -443,7 +443,7 @@ func NewSQLUserStore() *SQLUserStore {
|
||||
}
|
||||
|
||||
func (mus *SQLUserStore) Get(id int) (*User, error) {
|
||||
user := User{ID: id, Loggedin: true}
|
||||
user := &User{ID: id, Loggedin: true}
|
||||
err := mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.LastIP, &user.TempGroup)
|
||||
|
||||
if user.Avatar != "" {
|
||||
@ -455,8 +455,8 @@ func (mus *SQLUserStore) Get(id int) (*User, error) {
|
||||
}
|
||||
user.Link = buildProfileURL(nameToSlug(user.Name), id)
|
||||
user.Tag = gstore.DirtyGet(user.Group).Tag
|
||||
initUserPerms(&user)
|
||||
return &user, err
|
||||
user.initPerms()
|
||||
return user, err
|
||||
}
|
||||
|
||||
// TODO: Optimise the query to avoid preparing it on the spot? Maybe, use knowledge of the most common IN() parameter counts?
|
||||
@ -497,7 +497,7 @@ func (mus *SQLUserStore) BulkGetMap(ids []int) (list map[int]*User, err error) {
|
||||
}
|
||||
user.Link = buildProfileURL(nameToSlug(user.Name), user.ID)
|
||||
user.Tag = gstore.DirtyGet(user.Group).Tag
|
||||
initUserPerms(user)
|
||||
user.initPerms()
|
||||
|
||||
// Add it to the list to be returned
|
||||
list[user.ID] = user
|
||||
@ -507,7 +507,7 @@ func (mus *SQLUserStore) BulkGetMap(ids []int) (list map[int]*User, err error) {
|
||||
}
|
||||
|
||||
func (mus *SQLUserStore) BypassGet(id int) (*User, error) {
|
||||
user := User{ID: id, Loggedin: true}
|
||||
user := &User{ID: id, Loggedin: true}
|
||||
err := mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.LastIP, &user.TempGroup)
|
||||
|
||||
if user.Avatar != "" {
|
||||
@ -519,12 +519,8 @@ func (mus *SQLUserStore) BypassGet(id int) (*User, error) {
|
||||
}
|
||||
user.Link = buildProfileURL(nameToSlug(user.Name), id)
|
||||
user.Tag = gstore.DirtyGet(user.Group).Tag
|
||||
initUserPerms(&user)
|
||||
return &user, err
|
||||
}
|
||||
|
||||
func (mus *SQLUserStore) Reload(id int) error {
|
||||
return mus.exists.QueryRow(id).Scan(&id)
|
||||
user.initPerms()
|
||||
return user, err
|
||||
}
|
||||
|
||||
func (mus *SQLUserStore) Exists(id int) bool {
|
||||
|