Refactored the code to follow best standards better.
Added Basic IP Search. Added more items to .gitignore Add a VSCode settings file. Refactored the theme system to allow me to add a per-user theme switcher in the following commit. Fixed h1s, rowmenus, profiles and the Control Panel Dashboard on Tempra Simple. We now catch more extreme edge case errors. Renamed route_panel_themes_default to route_panel_themes_set_default. Centralised some of the per-route ExtData fields. Added an ExtData field to headerLite. Moved SettingLabels into the Phrase System.
This commit is contained in:
parent
99da1fcbaa
commit
ba36814d8d
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,6 +1,9 @@
|
|||||||
tmp/*
|
tmp/*
|
||||||
tmp2/*
|
tmp2/*
|
||||||
cert_test/*
|
cert_test/*
|
||||||
|
tmp.txt
|
||||||
|
run_notemplategen.bat
|
||||||
|
brun.bat
|
||||||
|
|
||||||
uploads/avatar_*
|
uploads/avatar_*
|
||||||
uploads/socialgroup_*
|
uploads/socialgroup_*
|
||||||
@ -10,3 +13,4 @@ bin/*
|
|||||||
*.prof
|
*.prof
|
||||||
*.log
|
*.log
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.vscode/launch.json
|
||||||
|
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// Place your settings in this file to overwrite default and user settings.
|
||||||
|
{
|
||||||
|
"editor.insertSpaces": false
|
||||||
|
}
|
49
alerts.go
49
alerts.go
@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* Gosora Alerts System
|
||||||
|
* Copyright Azareal 2017 - 2018
|
||||||
|
*
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "log"
|
import "log"
|
||||||
@ -20,10 +26,10 @@ import "errors"
|
|||||||
"{x}{created a new topic}{topic}"
|
"{x}{created a new topic}{topic}"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func build_alert(asid int, event string, elementType string, actor_id int, targetUser_id int, elementID int, user User /* The current user */) (string, error) {
|
func buildAlert(asid int, event string, elementType string, actorID int, targetUserID int, elementID int, user User /* The current user */) (string, error) {
|
||||||
var targetUser *User
|
var targetUser *User
|
||||||
|
|
||||||
actor, err := users.CascadeGet(actor_id)
|
actor, err := users.CascadeGet(actorID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New("Unable to find the actor")
|
return "", errors.New("Unable to find the actor")
|
||||||
}
|
}
|
||||||
@ -40,9 +46,9 @@ func build_alert(asid int, event string, elementType string, actor_id int, targe
|
|||||||
return `{"msg":"You received a friend invite from {0}","sub":["` + actor.Name + `"],"path":"` + actor.Link + `","avatar":"` + strings.Replace(actor.Avatar, "/", "\\/", -1) + `","asid":"` + strconv.Itoa(asid) + `"}`, nil
|
return `{"msg":"You received a friend invite from {0}","sub":["` + actor.Name + `"],"path":"` + actor.Link + `","avatar":"` + strings.Replace(actor.Avatar, "/", "\\/", -1) + `","asid":"` + strconv.Itoa(asid) + `"}`, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var act, post_act, url, area string
|
var act, postAct, url, area string
|
||||||
var start_frag, end_frag string
|
var startFrag, endFrag string
|
||||||
switch(elementType) {
|
switch elementType {
|
||||||
case "forum":
|
case "forum":
|
||||||
if event == "reply" {
|
if event == "reply" {
|
||||||
act = "created a new topic"
|
act = "created a new topic"
|
||||||
@ -65,8 +71,8 @@ func build_alert(asid int, event string, elementType string, actor_id int, targe
|
|||||||
url = topic.Link
|
url = topic.Link
|
||||||
area = topic.Title
|
area = topic.Title
|
||||||
|
|
||||||
if targetUser_id == user.ID {
|
if targetUserID == user.ID {
|
||||||
post_act = " your topic"
|
postAct = " your topic"
|
||||||
}
|
}
|
||||||
case "user":
|
case "user":
|
||||||
targetUser, err = users.CascadeGet(elementID)
|
targetUser, err = users.CascadeGet(elementID)
|
||||||
@ -74,27 +80,27 @@ func build_alert(asid int, event string, elementType string, actor_id int, targe
|
|||||||
return "", errors.New("Unable to find the target user")
|
return "", errors.New("Unable to find the target user")
|
||||||
}
|
}
|
||||||
area = targetUser.Name
|
area = targetUser.Name
|
||||||
end_frag = "'s profile"
|
endFrag = "'s profile"
|
||||||
url = targetUser.Link
|
url = targetUser.Link
|
||||||
case "post":
|
case "post":
|
||||||
topic, err := get_topic_by_reply(elementID)
|
topic, err := getTopicByReply(elementID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New("Unable to find the linked reply or parent topic")
|
return "", errors.New("Unable to find the linked reply or parent topic")
|
||||||
}
|
}
|
||||||
url = topic.Link
|
url = topic.Link
|
||||||
area = topic.Title
|
area = topic.Title
|
||||||
if targetUser_id == user.ID {
|
if targetUserID == user.ID {
|
||||||
post_act = " your post in"
|
postAct = " your post in"
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return "", errors.New("Invalid elementType")
|
return "", errors.New("Invalid elementType")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(event) {
|
switch event {
|
||||||
case "like":
|
case "like":
|
||||||
if elementType == "user" {
|
if elementType == "user" {
|
||||||
act = "likes"
|
act = "likes"
|
||||||
end_frag = ""
|
endFrag = ""
|
||||||
if targetUser.ID == user.ID {
|
if targetUser.ID == user.ID {
|
||||||
area = "you"
|
area = "you"
|
||||||
}
|
}
|
||||||
@ -106,15 +112,16 @@ func build_alert(asid int, event string, elementType string, actor_id int, targe
|
|||||||
act = "mentioned you on"
|
act = "mentioned you on"
|
||||||
} else {
|
} else {
|
||||||
act = "mentioned you in"
|
act = "mentioned you in"
|
||||||
post_act = ""
|
postAct = ""
|
||||||
}
|
}
|
||||||
case "reply": act = "replied to"
|
case "reply":
|
||||||
|
act = "replied to"
|
||||||
}
|
}
|
||||||
|
|
||||||
return `{"msg":"{0} ` + start_frag + act + post_act + ` {1}` + end_frag + `","sub":["` + actor.Name + `","` + area + `"],"path":"` + url + `","avatar":"` + actor.Avatar + `","asid":"`+strconv.Itoa(asid)+`"}`, nil
|
return `{"msg":"{0} ` + startFrag + act + postAct + ` {1}` + endFrag + `","sub":["` + actor.Name + `","` + area + `"],"path":"` + url + `","avatar":"` + actor.Avatar + `","asid":"` + strconv.Itoa(asid) + `"}`, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func notify_watchers(asid int64) {
|
func notifyWatchers(asid int64) {
|
||||||
rows, err := get_watchers_stmt.Query(asid)
|
rows, err := get_watchers_stmt.Query(asid)
|
||||||
if err != nil && err != ErrNoRows {
|
if err != nil && err != ErrNoRows {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
@ -136,15 +143,15 @@ func notify_watchers(asid int64) {
|
|||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rows.Close()
|
_ = rows.Close()
|
||||||
|
|
||||||
var actor_id, targetUser_id, elementID int
|
var actorID, targetUserID, elementID int
|
||||||
var event, elementType string
|
var event, elementType string
|
||||||
err = get_activity_entry_stmt.QueryRow(asid).Scan(&actor_id, &targetUser_id, &event, &elementType, &elementID)
|
err = get_activity_entry_stmt.QueryRow(asid).Scan(&actorID, &targetUserID, &event, &elementType, &elementID)
|
||||||
if err != nil && err != ErrNoRows {
|
if err != nil && err != ErrNoRows {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = ws_hub.push_alerts(uids, int(asid), event, elementType, actor_id, targetUser_id, elementID)
|
_ = wsHub.pushAlerts(uids, int(asid), event, elementType, actorID, targetUserID, elementID)
|
||||||
}
|
}
|
||||||
|
61
auth.go
61
auth.go
@ -1,4 +1,9 @@
|
|||||||
/* Work in progress */
|
/*
|
||||||
|
*
|
||||||
|
* Gosora Authentication Interface
|
||||||
|
* Copyright Azareal 2017 - 2018
|
||||||
|
*
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "log"
|
import "log"
|
||||||
@ -11,11 +16,15 @@ import "./query_gen/lib"
|
|||||||
import "golang.org/x/crypto/bcrypt"
|
import "golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
var auth Auth
|
var auth Auth
|
||||||
var ErrMismatchedHashAndPassword = bcrypt.ErrMismatchedHashAndPassword
|
|
||||||
var ErrPasswordTooLong = errors.New("The password you selected is too long") // Silly, but we don't want bcrypt to bork on us
|
|
||||||
|
|
||||||
type Auth interface
|
// ErrMismatchedHashAndPassword is thrown whenever a hash doesn't match it's unhashed password
|
||||||
{
|
var ErrMismatchedHashAndPassword = bcrypt.ErrMismatchedHashAndPassword
|
||||||
|
|
||||||
|
// ErrPasswordTooLong is silly, but we don't want bcrypt to bork on us
|
||||||
|
var ErrPasswordTooLong = errors.New("The password you selected is too long")
|
||||||
|
|
||||||
|
// Auth is the main authentication interface.
|
||||||
|
type Auth interface {
|
||||||
Authenticate(username string, password string) (uid int, err error)
|
Authenticate(username string, password string) (uid int, err error)
|
||||||
Logout(w http.ResponseWriter, uid int)
|
Logout(w http.ResponseWriter, uid int)
|
||||||
ForceLogout(uid int) error
|
ForceLogout(uid int) error
|
||||||
@ -25,70 +34,74 @@ type Auth interface
|
|||||||
CreateSession(uid int) (session string, err error)
|
CreateSession(uid int) (session string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type DefaultAuth struct
|
// DefaultAuth is the default authenticator used by Gosora, may be swapped with an alternate authenticator in some situations. E.g. To support LDAP.
|
||||||
{
|
type DefaultAuth struct {
|
||||||
login *sql.Stmt
|
login *sql.Stmt
|
||||||
logout *sql.Stmt
|
logout *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDefaultAuth is a factory for spitting out DefaultAuths
|
||||||
func NewDefaultAuth() *DefaultAuth {
|
func NewDefaultAuth() *DefaultAuth {
|
||||||
login_stmt, err := qgen.Builder.SimpleSelect("users","uid, password, salt","name = ?","","")
|
loginStmt, err := qgen.Builder.SimpleSelect("users", "uid, password, salt", "name = ?", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
logout_stmt, err := qgen.Builder.SimpleUpdate("users","session = ''","uid = ?")
|
logoutStmt, err := qgen.Builder.SimpleUpdate("users", "session = ''", "uid = ?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
return &DefaultAuth{
|
return &DefaultAuth{
|
||||||
login: login_stmt,
|
login: loginStmt,
|
||||||
logout: logout_stmt,
|
logout: logoutStmt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Authenticate checks if a specific username and password is valid and returns the UID for the corresponding user, if so. Otherwise, a user safe error.
|
||||||
func (auth *DefaultAuth) Authenticate(username string, password string) (uid int, err error) {
|
func (auth *DefaultAuth) Authenticate(username string, password string) (uid int, err error) {
|
||||||
var real_password, salt string
|
var realPassword, salt string
|
||||||
err = auth.login.QueryRow(username).Scan(&uid, &real_password, &salt)
|
err = auth.login.QueryRow(username).Scan(&uid, &realPassword, &salt)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
return 0, errors.New("We couldn't find an account with that username.")
|
return 0, errors.New("We couldn't find an account with that username.") // nolint
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
LogError(err)
|
LogError(err)
|
||||||
return 0, errors.New("There was a glitch in the system. Please contact the system administrator.")
|
return 0, errors.New("There was a glitch in the system. Please contact your local administrator.") // nolint
|
||||||
}
|
}
|
||||||
|
|
||||||
if salt == "" {
|
if salt == "" {
|
||||||
// Send an email to admin for this?
|
// Send an email to admin for this?
|
||||||
LogError(errors.New("Missing salt for user #" + strconv.Itoa(uid) + ". Potential security breach."))
|
LogError(errors.New("Missing salt for user #" + strconv.Itoa(uid) + ". Potential security breach."))
|
||||||
return 0, errors.New("There was a glitch in the system. Please contact the system administrator.")
|
return 0, errors.New("There was a glitch in the system. Please contact your local administrator")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = CheckPassword(real_password,password,salt)
|
err = CheckPassword(realPassword, password, salt)
|
||||||
if err == ErrMismatchedHashAndPassword {
|
if err == ErrMismatchedHashAndPassword {
|
||||||
return 0, errors.New("That's not the correct password.")
|
return 0, errors.New("That's not the correct password.")
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
LogError(err)
|
LogError(err)
|
||||||
return 0, errors.New("There was a glitch in the system. Please contact the system administrator.")
|
return 0, errors.New("There was a glitch in the system. Please contact your local administrator.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return uid, nil
|
return uid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForceLogout logs the user out of every computer, not just the one they logged out of
|
||||||
func (auth *DefaultAuth) ForceLogout(uid int) error {
|
func (auth *DefaultAuth) ForceLogout(uid int) error {
|
||||||
_, err := auth.logout.Exec(uid)
|
_, err := auth.logout.Exec(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError(err)
|
LogError(err)
|
||||||
return errors.New("There was a glitch in the system. Please contact the system administrator.")
|
return errors.New("There was a glitch in the system. Please contact your local administrator.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush the user out of the cache and reload
|
// Flush the user out of the cache and reload
|
||||||
err = users.Load(uid)
|
err = users.Load(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("Your account no longer exists!")
|
return errors.New("Your account no longer exists.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Logout logs you out of the computer you requested the logout for, but not the other computers you're logged in with
|
||||||
func (auth *DefaultAuth) Logout(w http.ResponseWriter, _ int) {
|
func (auth *DefaultAuth) Logout(w http.ResponseWriter, _ int) {
|
||||||
cookie := http.Cookie{Name: "uid", Value: "", Path: "/", MaxAge: year}
|
cookie := http.Cookie{Name: "uid", Value: "", Path: "/", MaxAge: year}
|
||||||
http.SetCookie(w, &cookie)
|
http.SetCookie(w, &cookie)
|
||||||
@ -123,20 +136,20 @@ func (auth *DefaultAuth) GetCookies(r *http.Request) (uid int, session string, e
|
|||||||
func (auth *DefaultAuth) SessionCheck(w http.ResponseWriter, r *http.Request) (user *User, halt bool) {
|
func (auth *DefaultAuth) SessionCheck(w http.ResponseWriter, r *http.Request) (user *User, halt bool) {
|
||||||
uid, session, err := auth.GetCookies(r)
|
uid, session, err := auth.GetCookies(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &guest_user, false
|
return &guestUser, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this session valid..?
|
// Is this session valid..?
|
||||||
user, err = users.CascadeGet(uid)
|
user, err = users.CascadeGet(uid)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
return &guest_user, false
|
return &guestUser, false
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return &guest_user, true
|
return &guestUser, true
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.Session == "" || session != user.Session {
|
if user.Session == "" || session != user.Session {
|
||||||
return &guest_user, false
|
return &guestUser, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, false
|
return user, false
|
||||||
|
11
cache.go
11
cache.go
@ -1,13 +1,20 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
|
// Go away, linter. We need to differentiate constants from variables somehow ;)
|
||||||
|
// nolint
|
||||||
const CACHE_STATIC int = 0
|
const CACHE_STATIC int = 0
|
||||||
const CACHE_DYNAMIC int = 1
|
const CACHE_DYNAMIC int = 1
|
||||||
const CACHE_SQL int = 2
|
const CACHE_SQL int = 2
|
||||||
|
|
||||||
var ErrCacheDesync = errors.New("The cache is out of synchronisation with the database.") // TO-DO: A cross-server synchronisation mechanism
|
// ErrCacheDesync is thrown whenever a piece of data, for instance, a user is out of sync with the database. Currently unused.
|
||||||
var ErrStoreCapacityOverflow = errors.New("This datastore has already reached it's max capacity")
|
var ErrCacheDesync = errors.New("The cache is out of sync with the database.") // TO-DO: A cross-server synchronisation mechanism
|
||||||
|
|
||||||
|
// ErrStoreCapacityOverflow is thrown whenever a datastore reaches it's maximum hard capacity. I'm not sure *if* this one is used, at the moment. Probably.
|
||||||
|
var ErrStoreCapacityOverflow = errors.New("This datastore has reached it's maximum capacity.")
|
||||||
|
|
||||||
|
// nolint
|
||||||
type DataStore interface {
|
type DataStore interface {
|
||||||
Load(id int) error
|
Load(id int) error
|
||||||
Get(id int) (interface{}, error)
|
Get(id int) (interface{}, error)
|
||||||
|
25
database.go
25
database.go
@ -5,14 +5,15 @@ import "encoding/json"
|
|||||||
import "database/sql"
|
import "database/sql"
|
||||||
|
|
||||||
var db *sql.DB
|
var db *sql.DB
|
||||||
var db_version string
|
var dbVersion string
|
||||||
var db_adapter string
|
var dbAdapter string
|
||||||
|
|
||||||
|
// ErrNoRows is an alias of sql.ErrNoRows, just in case we end up with non-database/sql datastores
|
||||||
var ErrNoRows = sql.ErrNoRows
|
var ErrNoRows = sql.ErrNoRows
|
||||||
|
|
||||||
func init_database() (err error) {
|
func initDatabase() (err error) {
|
||||||
// Engine specific code
|
// Engine specific code
|
||||||
err = _init_database()
|
err = _initDatabase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -28,8 +29,8 @@ func init_database() (err error) {
|
|||||||
|
|
||||||
i := 1
|
i := 1
|
||||||
for ; rows.Next(); i++ {
|
for ; rows.Next(); i++ {
|
||||||
group := Group{ID: 0,}
|
group := Group{ID: 0}
|
||||||
err := rows.Scan(&group.ID, &group.Name, &group.PermissionsText, &group.PluginPermsText, &group.Is_Mod, &group.Is_Admin, &group.Is_Banned, &group.Tag)
|
err := rows.Scan(&group.ID, &group.Name, &group.PermissionsText, &group.PluginPermsText, &group.IsMod, &group.IsAdmin, &group.IsBanned, &group.Tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -37,7 +38,7 @@ func init_database() (err error) {
|
|||||||
// Ugh, you really shouldn't physically delete these items, it makes a big mess of things
|
// Ugh, you really shouldn't physically delete these items, it makes a big mess of things
|
||||||
if group.ID != i {
|
if group.ID != i {
|
||||||
log.Print("Stop physically deleting groups. You are messing up the IDs. Use the Group Manager or delete_group() instead x.x")
|
log.Print("Stop physically deleting groups. You are messing up the IDs. Use the Group Manager or delete_group() instead x.x")
|
||||||
fill_group_id_gap(i, group.ID)
|
fillGroupIDGap(i, group.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(group.PermissionsText, &group.Perms)
|
err = json.Unmarshal(group.PermissionsText, &group.Perms)
|
||||||
@ -78,12 +79,11 @@ func init_database() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Loading the forum permissions.")
|
log.Print("Loading the forum permissions.")
|
||||||
err = build_forum_permissions()
|
err = buildForumPermissions()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
log.Print("Loading the settings.")
|
log.Print("Loading the settings.")
|
||||||
err = LoadSettings()
|
err = LoadSettings()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -97,10 +97,5 @@ func init_database() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Loading the themes.")
|
log.Print("Loading the themes.")
|
||||||
err = LoadThemes()
|
return LoadThemes()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
222
errors.go
222
errors.go
@ -8,14 +8,15 @@ import "net/http"
|
|||||||
import "runtime/debug"
|
import "runtime/debug"
|
||||||
|
|
||||||
// TO-DO: 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?
|
// TO-DO: 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?
|
||||||
var error_buffer_mutex sync.RWMutex
|
var errorBufferMutex sync.RWMutex
|
||||||
var error_buffer []error
|
var errorBuffer []error
|
||||||
|
|
||||||
//var notfound_count_per_second int
|
//var notfound_count_per_second int
|
||||||
//var noperms_count_per_second int
|
//var noperms_count_per_second int
|
||||||
var error_internal []byte
|
var errorInternal []byte
|
||||||
var error_notfound []byte
|
var errorNotfound []byte
|
||||||
|
|
||||||
func init_errors() error {
|
func initErrors() error {
|
||||||
var b bytes.Buffer
|
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}
|
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."}
|
pi := Page{"Internal Server Error", user, hvars, tList, "A problem has occurred in the system."}
|
||||||
@ -23,7 +24,7 @@ func init_errors() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
error_internal = b.Bytes()
|
errorInternal = b.Bytes()
|
||||||
|
|
||||||
b.Reset()
|
b.Reset()
|
||||||
pi = Page{"Not Found", user, hvars, tList, "The requested page doesn't exist."}
|
pi = Page{"Not Found", user, hvars, tList, "The requested page doesn't exist."}
|
||||||
@ -31,260 +32,307 @@ func init_errors() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
error_notfound = b.Bytes()
|
errorNotfound = b.Bytes()
|
||||||
return nil
|
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) {
|
func LogError(err error) {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
debug.PrintStack()
|
debug.PrintStack()
|
||||||
error_buffer_mutex.Lock()
|
errorBufferMutex.Lock()
|
||||||
defer error_buffer_mutex.Unlock()
|
defer errorBufferMutex.Unlock()
|
||||||
error_buffer = append(error_buffer,err)
|
errorBuffer = append(errorBuffer, err)
|
||||||
log.Fatal("")
|
log.Fatal("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
func InternalError(err error, w http.ResponseWriter) {
|
func InternalError(err error, w http.ResponseWriter) {
|
||||||
w.Write(error_internal)
|
_, _ = w.Write(errorInternal)
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
debug.PrintStack()
|
debug.PrintStack()
|
||||||
error_buffer_mutex.Lock()
|
errorBufferMutex.Lock()
|
||||||
defer error_buffer_mutex.Unlock()
|
defer errorBufferMutex.Unlock()
|
||||||
error_buffer = append(error_buffer,err)
|
errorBuffer = append(errorBuffer, err)
|
||||||
log.Fatal("")
|
log.Fatal("")
|
||||||
}
|
}
|
||||||
|
|
||||||
func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, is_js string) {
|
// InternalErrorJSQ is the JSON "maybe" version of InternalError which can handle both JSON and normal requests
|
||||||
|
func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, isJs bool) {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
if is_js == "0" {
|
if !isJs {
|
||||||
w.Write(error_internal)
|
_, _ = w.Write(errorInternal)
|
||||||
} else {
|
} else {
|
||||||
w.Write([]byte(`{"errmsg":"A problem has occured in the system."}`))
|
_, _ = w.Write([]byte(`{"errmsg":"A problem has occured in the system."}`))
|
||||||
}
|
}
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
debug.PrintStack()
|
debug.PrintStack()
|
||||||
error_buffer_mutex.Lock()
|
errorBufferMutex.Lock()
|
||||||
defer error_buffer_mutex.Unlock()
|
defer errorBufferMutex.Unlock()
|
||||||
error_buffer = append(error_buffer,err)
|
errorBuffer = append(errorBuffer, err)
|
||||||
log.Fatal("")
|
log.Fatal("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InternalErrorJS is the JSON version of InternalError on routes we know will only be requested via JSON. E.g. An API.
|
||||||
func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) {
|
func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
w.Write([]byte(`{"errmsg":"A problem has occured in the system."}`))
|
_, _ = w.Write([]byte(`{"errmsg":"A problem has occured in the system."}`))
|
||||||
error_buffer_mutex.Lock()
|
errorBufferMutex.Lock()
|
||||||
defer error_buffer_mutex.Unlock()
|
defer errorBufferMutex.Unlock()
|
||||||
error_buffer = append(error_buffer,err)
|
errorBuffer = append(errorBuffer, err)
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PreError(errmsg string, w http.ResponseWriter, r *http.Request) {
|
func PreError(errmsg string, w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
user := User{ID:0,Group:6,Perms:GuestPerms,}
|
user := User{ID: 0, Group: 6, Perms: GuestPerms}
|
||||||
pi := Page{"Error", user, hvars, tList, errmsg}
|
pi := Page{"Error", user, hvars, tList, errmsg}
|
||||||
if pre_render_hooks["pre_render_error"] != nil {
|
if preRenderHooks["pre_render_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html",pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
fmt.Fprintln(w, b.String())
|
fmt.Fprintln(w, b.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User) {
|
func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User) {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
pi := Page{"Local Error", user, hvars, tList, errmsg}
|
pi := Page{"Local Error", user, hvars, tList, errmsg}
|
||||||
if pre_render_hooks["pre_render_error"] != nil {
|
if preRenderHooks["pre_render_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html",pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
fmt.Fprintln(w, b.String())
|
fmt.Fprintln(w, b.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoginRequired(w http.ResponseWriter, r *http.Request, user User) {
|
func LoginRequired(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(401)
|
||||||
pi := Page{"Local Error", user, hvars, tList, "You need to login to do that."}
|
pi := Page{"Local Error", user, hvars, tList, "You need to login to do that."}
|
||||||
if pre_render_hooks["pre_render_error"] != nil {
|
if preRenderHooks["pre_render_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html",pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
fmt.Fprintln(w, b.String())
|
fmt.Fprintln(w, b.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func PreErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) {
|
func PreErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
|
_, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
|
||||||
}
|
}
|
||||||
|
|
||||||
func PreErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, is_js string) {
|
func PreErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, isJs bool) {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
if is_js == "0" {
|
if !isJs {
|
||||||
user := User{ID:0,Group:6,Perms:GuestPerms,}
|
user := User{ID: 0, Group: 6, Perms: GuestPerms}
|
||||||
pi := Page{"Local Error", user, hvars, tList, errmsg}
|
pi := Page{"Local Error", user, hvars, tList, errmsg}
|
||||||
if pre_render_hooks["pre_render_error"] != nil {
|
if preRenderHooks["pre_render_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
fmt.Fprintln(w, b.String())
|
fmt.Fprintln(w, b.String())
|
||||||
} else {
|
} else {
|
||||||
w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
|
_, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func LocalErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, user User, is_js string) {
|
func LocalErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, user User, isJs bool) {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
if is_js == "0" {
|
if !isJs {
|
||||||
pi := Page{"Local Error", user, hvars, tList, errmsg}
|
pi := Page{"Local Error", user, hvars, tList, errmsg}
|
||||||
if pre_render_hooks["pre_render_error"] != nil {
|
if preRenderHooks["pre_render_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
fmt.Fprintln(w, b.String())
|
fmt.Fprintln(w, b.String())
|
||||||
} else {
|
} else {
|
||||||
w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
|
_, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func LocalErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) {
|
func LocalErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
w.Write([]byte(`{'errmsg': '` + errmsg + `'}`))
|
_, _ = w.Write([]byte(`{'errmsg': '` + errmsg + `'}`))
|
||||||
}
|
}
|
||||||
|
|
||||||
func NoPermissions(w http.ResponseWriter, r *http.Request, user User) {
|
func NoPermissions(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
w.WriteHeader(403)
|
w.WriteHeader(403)
|
||||||
pi := Page{"Local Error", user, hvars, tList, "You don't have permission to do that."}
|
pi := Page{"Local Error", user, hvars, tList, "You don't have permission to do that."}
|
||||||
if pre_render_hooks["pre_render_error"] != nil {
|
if preRenderHooks["pre_render_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
errpage := b.String()
|
errpage := b.String()
|
||||||
fmt.Fprintln(w, errpage)
|
fmt.Fprintln(w, errpage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NoPermissionsJSQ(w http.ResponseWriter, r *http.Request, user User, is_js string) {
|
func NoPermissionsJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) {
|
||||||
w.WriteHeader(403)
|
w.WriteHeader(403)
|
||||||
if is_js == "0" {
|
if !isJs {
|
||||||
pi := Page{"Local Error", user, hvars, tList, "You don't have permission to do that."}
|
pi := Page{"Local Error", user, hvars, tList, "You don't have permission to do that."}
|
||||||
if pre_render_hooks["pre_render_error"] != nil {
|
if preRenderHooks["pre_render_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
fmt.Fprintln(w, b.String())
|
fmt.Fprintln(w, b.String())
|
||||||
} else {
|
} else {
|
||||||
w.Write([]byte(`{"errmsg":"You don't have permission to do that."}`))
|
_, _ = w.Write([]byte(`{"errmsg":"You don't have permission to do that."}`))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Banned(w http.ResponseWriter, r *http.Request, user User) {
|
func Banned(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
w.WriteHeader(403)
|
w.WriteHeader(403)
|
||||||
pi := Page{"Banned", user, hvars, tList, "You have been banned from this site."}
|
pi := Page{"Banned", user, hvars, tList, "You have been banned from this site."}
|
||||||
if pre_render_hooks["pre_render_error"] != nil {
|
if preRenderHooks["pre_render_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
fmt.Fprintln(w, b.String())
|
fmt.Fprintln(w, b.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func BannedJSQ(w http.ResponseWriter, r *http.Request, user User, is_js string) {
|
// nolint
|
||||||
|
func BannedJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) {
|
||||||
w.WriteHeader(403)
|
w.WriteHeader(403)
|
||||||
if is_js == "0" {
|
if !isJs {
|
||||||
pi := Page{"Banned", user, hvars, tList, "You have been banned from this site."}
|
pi := Page{"Banned", user, hvars, tList, "You have been banned from this site."}
|
||||||
if pre_render_hooks["pre_render_error"] != nil {
|
if preRenderHooks["pre_render_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
fmt.Fprintln(w, b.String())
|
fmt.Fprintln(w, b.String())
|
||||||
} else {
|
} else {
|
||||||
w.Write([]byte(`{"errmsg":"You have been banned from this site."}`))
|
_, _ = w.Write([]byte(`{"errmsg":"You have been banned from this site."}`))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, is_js string) {
|
// nolint
|
||||||
|
func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bool) {
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(401)
|
||||||
if is_js == "0" {
|
if !isJs {
|
||||||
pi := Page{"Local Error", user, hvars, tList, "You need to login to do that."}
|
pi := Page{"Local Error", user, hvars, tList, "You need to login to do that."}
|
||||||
if pre_render_hooks["pre_render_error"] != nil {
|
if preRenderHooks["pre_render_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
fmt.Fprintln(w, b.String())
|
fmt.Fprintln(w, b.String())
|
||||||
} else {
|
} else {
|
||||||
w.Write([]byte(`{"errmsg":"You need to login to do that."}`))
|
_, _ = w.Write([]byte(`{"errmsg":"You need to login to do that."}`))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SecurityError(w http.ResponseWriter, r *http.Request, user User) {
|
func SecurityError(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
w.WriteHeader(403)
|
w.WriteHeader(403)
|
||||||
pi := Page{"Security Error", user, hvars, tList, "There was a security issue with your request."}
|
pi := Page{"Security Error", user, hvars, tList, "There was a security issue with your request."}
|
||||||
if pre_render_hooks["pre_render_security_error"] != nil {
|
if preRenderHooks["pre_render_security_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_security_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_security_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
fmt.Fprintln(w, b.String())
|
fmt.Fprintln(w, b.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func NotFound(w http.ResponseWriter, r *http.Request) {
|
func NotFound(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(404)
|
w.WriteHeader(404)
|
||||||
w.Write(error_notfound)
|
_, _ = w.Write(errorNotfound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) {
|
func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) {
|
||||||
w.WriteHeader(errcode)
|
w.WriteHeader(errcode)
|
||||||
pi := Page{errtitle, user, hvars, tList, errmsg}
|
pi := Page{errtitle, user, hvars, tList, errmsg}
|
||||||
if pre_render_hooks["pre_render_error"] != nil {
|
if preRenderHooks["pre_render_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
fmt.Fprintln(w, b.String())
|
fmt.Fprintln(w, b.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func CustomErrorJSQ(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User, is_js string) {
|
// nolint
|
||||||
|
func CustomErrorJSQ(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User, isJs bool) {
|
||||||
w.WriteHeader(errcode)
|
w.WriteHeader(errcode)
|
||||||
if is_js == "0" {
|
if !isJs {
|
||||||
pi := Page{errtitle, user, hvars, tList, errmsg}
|
pi := Page{errtitle, user, hvars, tList, errmsg}
|
||||||
if pre_render_hooks["pre_render_error"] != nil {
|
if preRenderHooks["pre_render_error"] != nil {
|
||||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_error", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
err := templates.ExecuteTemplate(&b, "error.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
fmt.Fprintln(w, b.String())
|
fmt.Fprintln(w, b.String())
|
||||||
} else {
|
} else {
|
||||||
w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
|
_, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
experimental/plugin_geoip.go
Normal file
19
experimental/plugin_geoip.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/oschwald/geoip2-golang"
|
||||||
|
|
||||||
|
var geoip_db *geoip.DB
|
||||||
|
var geoip_db_location string = "geoip_db.mmdb"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
plugins["geoip"] = NewPlugin("geoip","Geoip","Azareal","http://github.com/Azareal","","","",init_geoip,nil,deactivate_geoip,nil,nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init_geoip() (err error) {
|
||||||
|
geoip_db, err = geoip2.Open(geoip_db_location)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func deactivate_geoip() {
|
||||||
|
geoip_db.Close()
|
||||||
|
}
|
63
extend.go
63
extend.go
@ -1,19 +1,25 @@
|
|||||||
/* Copyright Azareal 2016 - 2018 */
|
/*
|
||||||
|
*
|
||||||
|
* Gosora Plugin System
|
||||||
|
* Copyright Azareal 2016 - 2018
|
||||||
|
*
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "log"
|
import "log"
|
||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
||||||
var plugins map[string]*Plugin = make(map[string]*Plugin)
|
var plugins = make(map[string]*Plugin)
|
||||||
|
|
||||||
// Hooks with a single argument. Is this redundant? Might be useful for inlining, as variadics aren't inlined? Are closures even inlined to begin with?
|
// Hooks with a single argument. Is this redundant? Might be useful for inlining, as variadics aren't inlined? Are closures even inlined to begin with?
|
||||||
var hooks map[string][]func(interface{})interface{} = map[string][]func(interface{})interface{}{
|
var hooks = map[string][]func(interface{}) interface{}{
|
||||||
"forums_frow_assign": nil,
|
"forums_frow_assign": nil,
|
||||||
"topic_create_frow_assign": nil,
|
"topic_create_frow_assign": nil,
|
||||||
"rrow_assign": nil, // TO-DO: Rename this hook to topic_rrow_assign
|
"rrow_assign": nil, // TO-DO: Rename this hook to topic_rrow_assign
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hooks with a variable number of arguments
|
// Hooks with a variable number of arguments
|
||||||
var vhooks map[string]func(...interface{})interface{} = map[string]func(...interface{})interface{}{
|
var vhooks = map[string]func(...interface{}) interface{}{
|
||||||
"simple_forum_check_pre_perms": nil,
|
"simple_forum_check_pre_perms": nil,
|
||||||
"forum_check_pre_perms": nil,
|
"forum_check_pre_perms": nil,
|
||||||
"intercept_build_widgets": nil,
|
"intercept_build_widgets": nil,
|
||||||
@ -25,13 +31,13 @@ var vhooks map[string]func(...interface{})interface{} = map[string]func(...inter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hooks which take in and spit out a string. This is usually used for parser components
|
// Hooks which take in and spit out a string. This is usually used for parser components
|
||||||
var sshooks map[string][]func(string)string = map[string][]func(string)string{
|
var sshooks = map[string][]func(string) string{
|
||||||
"preparse_preassign": nil,
|
"preparse_preassign": nil,
|
||||||
"parse_assign": nil,
|
"parse_assign": nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
// The hooks which run before the template is rendered for a route
|
// The hooks which run before the template is rendered for a route
|
||||||
var pre_render_hooks map[string][]func(http.ResponseWriter, *http.Request, *User, interface{})bool = map[string][]func(http.ResponseWriter, *http.Request, *User, interface{})bool{
|
var preRenderHooks = map[string][]func(http.ResponseWriter, *http.Request, *User, interface{}) bool{
|
||||||
"pre_render": nil,
|
"pre_render": nil,
|
||||||
|
|
||||||
"pre_render_forum_list": nil,
|
"pre_render_forum_list": nil,
|
||||||
@ -50,6 +56,7 @@ var pre_render_hooks map[string][]func(http.ResponseWriter, *http.Request, *User
|
|||||||
"pre_render_login": nil,
|
"pre_render_login": nil,
|
||||||
"pre_render_register": nil,
|
"pre_render_register": nil,
|
||||||
"pre_render_ban": nil,
|
"pre_render_ban": nil,
|
||||||
|
"pre_render_ips": nil,
|
||||||
|
|
||||||
"pre_render_panel_dashboard": nil,
|
"pre_render_panel_dashboard": nil,
|
||||||
"pre_render_panel_forums": nil,
|
"pre_render_panel_forums": nil,
|
||||||
@ -72,8 +79,7 @@ var pre_render_hooks map[string][]func(http.ResponseWriter, *http.Request, *User
|
|||||||
"pre_render_security_error": nil,
|
"pre_render_security_error": nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Plugin struct
|
type Plugin struct {
|
||||||
{
|
|
||||||
UName string
|
UName string
|
||||||
Name string
|
Name string
|
||||||
Author string
|
Author string
|
||||||
@ -119,11 +125,7 @@ func LoadPlugins() error {
|
|||||||
plugin.Installed = installed
|
plugin.Installed = installed
|
||||||
plugins[uname] = plugin
|
plugins[uname] = plugin
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
return rows.Err()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPlugin(uname string, name string, author string, url string, settings string, tag string, ptype string, init func() error, activate func() error, deactivate func(), install func() error, uninstall func() error) *Plugin {
|
func NewPlugin(uname string, name string, author string, url string, settings string, tag string, ptype string, init func() error, activate func() error, deactivate func(), install func() error, uninstall func() error) *Plugin {
|
||||||
@ -172,14 +174,14 @@ func (plugin *Plugin) AddHook(name string, handler interface{}) {
|
|||||||
}
|
}
|
||||||
plugin.Hooks[name] = len(sshooks[name])
|
plugin.Hooks[name] = len(sshooks[name])
|
||||||
case func(http.ResponseWriter, *http.Request, *User, interface{}) bool:
|
case func(http.ResponseWriter, *http.Request, *User, interface{}) bool:
|
||||||
if len(pre_render_hooks[name]) == 0 {
|
if len(preRenderHooks[name]) == 0 {
|
||||||
var hookSlice []func(http.ResponseWriter, *http.Request, *User, interface{}) bool
|
var hookSlice []func(http.ResponseWriter, *http.Request, *User, interface{}) bool
|
||||||
hookSlice = append(hookSlice, h)
|
hookSlice = append(hookSlice, h)
|
||||||
pre_render_hooks[name] = hookSlice
|
preRenderHooks[name] = hookSlice
|
||||||
} else {
|
} else {
|
||||||
pre_render_hooks[name] = append(pre_render_hooks[name], h)
|
preRenderHooks[name] = append(preRenderHooks[name], h)
|
||||||
}
|
}
|
||||||
plugin.Hooks[name] = len(pre_render_hooks[name])
|
plugin.Hooks[name] = len(preRenderHooks[name])
|
||||||
case func(...interface{}) interface{}:
|
case func(...interface{}) interface{}:
|
||||||
vhooks[name] = h
|
vhooks[name] = h
|
||||||
plugin.Hooks[name] = 0
|
plugin.Hooks[name] = 0
|
||||||
@ -210,13 +212,13 @@ func (plugin *Plugin) RemoveHook(name string, handler interface{}) {
|
|||||||
sshooks[name] = hook
|
sshooks[name] = hook
|
||||||
case func(http.ResponseWriter, *http.Request, *User, interface{}) bool:
|
case func(http.ResponseWriter, *http.Request, *User, interface{}) bool:
|
||||||
key := plugin.Hooks[name]
|
key := plugin.Hooks[name]
|
||||||
hook := pre_render_hooks[name]
|
hook := preRenderHooks[name]
|
||||||
if len(hook) == 1 {
|
if len(hook) == 1 {
|
||||||
hook = []func(http.ResponseWriter, *http.Request, *User, interface{}) bool{}
|
hook = []func(http.ResponseWriter, *http.Request, *User, interface{}) bool{}
|
||||||
} else {
|
} else {
|
||||||
hook = append(hook[:key], hook[key+1:]...)
|
hook = append(hook[:key], hook[key+1:]...)
|
||||||
}
|
}
|
||||||
pre_render_hooks[name] = hook
|
preRenderHooks[name] = hook
|
||||||
case func(...interface{}) interface{}:
|
case func(...interface{}) interface{}:
|
||||||
delete(vhooks, name)
|
delete(vhooks, name)
|
||||||
default:
|
default:
|
||||||
@ -225,8 +227,9 @@ func (plugin *Plugin) RemoveHook(name string, handler interface{}) {
|
|||||||
delete(plugin.Hooks, name)
|
delete(plugin.Hooks, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
var plugins_inited bool = false
|
var pluginsInited = false
|
||||||
func init_plugins() {
|
|
||||||
|
func initPlugins() {
|
||||||
for name, body := range plugins {
|
for name, body := range plugins {
|
||||||
log.Print("Added plugin " + name)
|
log.Print("Added plugin " + name)
|
||||||
if body.Active {
|
if body.Active {
|
||||||
@ -241,48 +244,48 @@ func init_plugins() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
plugins_inited = true
|
pluginsInited = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func run_hook(name string, data interface{}) interface{} {
|
func runHook(name string, data interface{}) interface{} {
|
||||||
for _, hook := range hooks[name] {
|
for _, hook := range hooks[name] {
|
||||||
data = hook(data)
|
data = hook(data)
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func run_hook_noreturn(name string, data interface{}) {
|
func runHookNoreturn(name string, data interface{}) {
|
||||||
for _, hook := range hooks[name] {
|
for _, hook := range hooks[name] {
|
||||||
_ = hook(data)
|
_ = hook(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func run_vhook(name string, data ...interface{}) interface{} {
|
func runVhook(name string, data ...interface{}) interface{} {
|
||||||
return vhooks[name](data...)
|
return vhooks[name](data...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func run_vhook_noreturn(name string, data ...interface{}) {
|
func runVhookNoreturn(name string, data ...interface{}) {
|
||||||
_ = vhooks[name](data...)
|
_ = vhooks[name](data...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trying to get a teeny bit of type-safety where-ever possible, especially for such a critical set of hooks
|
// Trying to get a teeny bit of type-safety where-ever possible, especially for such a critical set of hooks
|
||||||
func run_sshook(name string, data string) string {
|
func runSshook(name string, data string) string {
|
||||||
for _, hook := range sshooks[name] {
|
for _, hook := range sshooks[name] {
|
||||||
data = hook(data)
|
data = hook(data)
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func run_pre_render_hook(name string, w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) {
|
func runPreRenderHook(name string, w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) {
|
||||||
// This hook runs on ALL pre_render hooks
|
// This hook runs on ALL pre_render hooks
|
||||||
for _, hook := range pre_render_hooks["pre_render"] {
|
for _, hook := range preRenderHooks["pre_render"] {
|
||||||
if hook(w, r, user, data) {
|
if hook(w, r, user, data) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The actual pre_render hook
|
// The actual pre_render hook
|
||||||
for _, hook := range pre_render_hooks[name] {
|
for _, hook := range preRenderHooks[name] {
|
||||||
if hook(w, r, user, data) {
|
if hook(w, r, user, data) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
46
files.go
46
files.go
@ -1,20 +1,19 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
"log"
|
||||||
"mime"
|
"mime"
|
||||||
|
"strings"
|
||||||
//"errors"
|
//"errors"
|
||||||
"os"
|
|
||||||
"io/ioutil"
|
|
||||||
"path/filepath"
|
|
||||||
"net/http"
|
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SFile struct
|
type SFile struct {
|
||||||
{
|
|
||||||
Data []byte
|
Data []byte
|
||||||
GzipData []byte
|
GzipData []byte
|
||||||
Pos int64
|
Pos int64
|
||||||
@ -25,14 +24,12 @@ type SFile struct
|
|||||||
FormattedModTime string
|
FormattedModTime string
|
||||||
}
|
}
|
||||||
|
|
||||||
type CssData struct
|
type CssData struct {
|
||||||
{
|
|
||||||
ComingSoon string
|
ComingSoon string
|
||||||
}
|
}
|
||||||
|
|
||||||
func init_static_files() {
|
func initStaticFiles() error {
|
||||||
log.Print("Loading the static files.")
|
return filepath.Walk("./public", func(path string, f os.FileInfo, err error) error {
|
||||||
err := filepath.Walk("./public", func(path string, f os.FileInfo, err error) error {
|
|
||||||
if f.IsDir() {
|
if f.IsDir() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -44,22 +41,19 @@ func init_static_files() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
path = strings.TrimPrefix(path, "public/")
|
path = strings.TrimPrefix(path, "public/")
|
||||||
var ext string = filepath.Ext("/public/" + path)
|
var ext = filepath.Ext("/public/" + path)
|
||||||
gzip_data := compress_bytes_gzip(data)
|
gzipData := compressBytesGzip(data)
|
||||||
|
|
||||||
static_files["/static/" + path] = SFile{data,gzip_data,0,int64(len(data)),int64(len(gzip_data)),mime.TypeByExtension(ext),f,f.ModTime().UTC().Format(http.TimeFormat)}
|
staticFiles["/static/"+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}
|
||||||
|
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Added the '" + path + "' static file.")
|
log.Print("Added the '" + path + "' static file.")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func add_static_file(path string, prefix string) error {
|
func addStaticFile(path string, prefix string) error {
|
||||||
data, err := ioutil.ReadFile(path)
|
data, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -73,11 +67,11 @@ func add_static_file(path string, prefix string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ext string = filepath.Ext(path)
|
var ext = filepath.Ext(path)
|
||||||
path = strings.TrimPrefix(path, prefix)
|
path = strings.TrimPrefix(path, prefix)
|
||||||
gzip_data := compress_bytes_gzip(data)
|
gzipData := compressBytesGzip(data)
|
||||||
|
|
||||||
static_files["/static" + path] = SFile{data,gzip_data,0,int64(len(data)),int64(len(gzip_data)),mime.TypeByExtension(ext),f,f.ModTime().UTC().Format(http.TimeFormat)}
|
staticFiles["/static"+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}
|
||||||
|
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Added the '" + path + "' static file")
|
log.Print("Added the '" + path + "' static file")
|
||||||
@ -85,10 +79,10 @@ func add_static_file(path string, prefix string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func compress_bytes_gzip(in []byte) []byte {
|
func compressBytesGzip(in []byte) []byte {
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
gz := gzip.NewWriter(&buff)
|
gz := gzip.NewWriter(&buff)
|
||||||
gz.Write(in)
|
_, _ = gz.Write(in) // TO-DO: What if this errors? What circumstances could it error under? Should we add a second return value?
|
||||||
gz.Close()
|
_ = gz.Close()
|
||||||
return buff.Bytes()
|
return buff.Bytes()
|
||||||
}
|
}
|
||||||
|
13
forum.go
13
forum.go
@ -4,8 +4,7 @@ package main
|
|||||||
import "strconv"
|
import "strconv"
|
||||||
import _ "github.com/go-sql-driver/mysql"
|
import _ "github.com/go-sql-driver/mysql"
|
||||||
|
|
||||||
type ForumAdmin struct
|
type ForumAdmin struct {
|
||||||
{
|
|
||||||
ID int
|
ID int
|
||||||
Name string
|
Name string
|
||||||
Desc string
|
Desc string
|
||||||
@ -15,8 +14,7 @@ type ForumAdmin struct
|
|||||||
PresetLang string
|
PresetLang string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Forum struct
|
type Forum struct {
|
||||||
{
|
|
||||||
ID int
|
ID int
|
||||||
Link string
|
Link string
|
||||||
Name string
|
Name string
|
||||||
@ -34,21 +32,20 @@ type Forum struct
|
|||||||
LastTopicTime string
|
LastTopicTime string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ForumSimple struct
|
type ForumSimple struct {
|
||||||
{
|
|
||||||
ID int
|
ID int
|
||||||
Name string
|
Name string
|
||||||
Active bool
|
Active bool
|
||||||
Preset string
|
Preset string
|
||||||
}
|
}
|
||||||
|
|
||||||
func build_forum_url(slug string, fid int) string {
|
func buildForumUrl(slug string, fid int) string {
|
||||||
if slug == "" {
|
if slug == "" {
|
||||||
return "/forum/" + strconv.Itoa(fid)
|
return "/forum/" + strconv.Itoa(fid)
|
||||||
}
|
}
|
||||||
return "/forum/" + slug + "." + strconv.Itoa(fid)
|
return "/forum/" + slug + "." + strconv.Itoa(fid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func get_forum_url_prefix() string {
|
func getForumURLPrefix() string {
|
||||||
return "/forum/"
|
return "/forum/"
|
||||||
}
|
}
|
||||||
|
109
forum_store.go
109
forum_store.go
@ -3,17 +3,17 @@ package main
|
|||||||
|
|
||||||
import "log"
|
import "log"
|
||||||
import "sync"
|
import "sync"
|
||||||
|
|
||||||
//import "sync/atomic"
|
//import "sync/atomic"
|
||||||
import "database/sql"
|
import "database/sql"
|
||||||
import "./query_gen/lib"
|
import "./query_gen/lib"
|
||||||
|
|
||||||
var forum_update_mutex sync.Mutex
|
var forumUpdateMutex sync.Mutex
|
||||||
var forum_create_mutex sync.Mutex
|
var forumCreateMutex sync.Mutex
|
||||||
var forum_perms map[int]map[int]ForumPerms // [gid][fid]Perms
|
var forumPerms map[int]map[int]ForumPerms // [gid][fid]Perms
|
||||||
var fstore ForumStore
|
var fstore ForumStore
|
||||||
|
|
||||||
type ForumStore interface
|
type ForumStore interface {
|
||||||
{
|
|
||||||
LoadForums() error
|
LoadForums() error
|
||||||
DirtyGet(id int) *Forum
|
DirtyGet(id int) *Forum
|
||||||
Get(id int) (*Forum, error)
|
Get(id int) (*Forum, error)
|
||||||
@ -28,52 +28,51 @@ type ForumStore interface
|
|||||||
CascadeDelete(id int) error
|
CascadeDelete(id int) error
|
||||||
IncrementTopicCount(id int) error
|
IncrementTopicCount(id int) error
|
||||||
DecrementTopicCount(id int) error
|
DecrementTopicCount(id int) error
|
||||||
UpdateLastTopic(topic_name string, tid int, username string, uid int, time string, fid int) error
|
UpdateLastTopic(topicName string, tid int, username string, uid int, time string, fid int) error
|
||||||
Exists(id int) bool
|
Exists(id int) bool
|
||||||
GetAll() ([]*Forum, error)
|
GetAll() ([]*Forum, error)
|
||||||
GetAllIDs() ([]int, error)
|
GetAllIDs() ([]int, error)
|
||||||
//GetChildren(parentID int, parentType string) ([]*Forum,error)
|
//GetChildren(parentID int, parentType string) ([]*Forum,error)
|
||||||
//GetFirstChild(parentID int, parentType string) (*Forum,error)
|
//GetFirstChild(parentID int, parentType string) (*Forum,error)
|
||||||
CreateForum(forum_name string, forum_desc string, active bool, preset string) (int, error)
|
CreateForum(forumName string, forumDesc string, active bool, preset string) (int, error)
|
||||||
|
|
||||||
GetGlobalCount() int
|
GetGlobalCount() int
|
||||||
}
|
}
|
||||||
|
|
||||||
type StaticForumStore struct
|
type StaticForumStore struct {
|
||||||
{
|
|
||||||
forums []*Forum // The IDs for a forum tend to be low and sequential for the most part, so we can get more performance out of using a slice instead of a map AND it has better concurrency
|
forums []*Forum // The IDs for a forum tend to be low and sequential for the most part, so we can get more performance out of using a slice instead of a map AND it has better concurrency
|
||||||
//fids []int
|
//fids []int
|
||||||
forumCapCount int
|
forumCapCount int
|
||||||
|
|
||||||
get *sql.Stmt
|
get *sql.Stmt
|
||||||
get_all *sql.Stmt
|
getAll *sql.Stmt
|
||||||
forum_count *sql.Stmt
|
forumCount *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStaticForumStore() *StaticForumStore {
|
func NewStaticForumStore() *StaticForumStore {
|
||||||
get_stmt, err := qgen.Builder.SimpleSelect("forums","name, desc, active, preset, parentID, parentType, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","fid = ?","","")
|
getStmt, err := qgen.Builder.SimpleSelect("forums", "name, desc, active, preset, parentID, parentType, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime", "fid = ?", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
get_all_stmt, err := qgen.Builder.SimpleSelect("forums","fid, name, desc, active, preset, parentID, parentType, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","","fid ASC","")
|
getAllStmt, err := qgen.Builder.SimpleSelect("forums", "fid, name, desc, active, preset, parentID, parentType, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime", "", "fid ASC", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
forum_count_stmt, err := qgen.Builder.SimpleCount("forums","name != ''","")
|
forumCountStmt, err := qgen.Builder.SimpleCount("forums", "name != ''", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
return &StaticForumStore{
|
return &StaticForumStore{
|
||||||
get: get_stmt,
|
get: getStmt,
|
||||||
get_all: get_all_stmt,
|
getAll: getAllStmt,
|
||||||
forum_count: forum_count_stmt,
|
forumCount: forumCountStmt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sfs *StaticForumStore) LoadForums() error {
|
func (sfs *StaticForumStore) LoadForums() error {
|
||||||
log.Print("Adding the uncategorised forum")
|
log.Print("Adding the uncategorised forum")
|
||||||
var forums []*Forum = []*Forum{
|
var forums = []*Forum{
|
||||||
&Forum{0,build_forum_url(name_to_slug("Uncategorised"),0),"Uncategorised","",config.UncategorisedForumVisible,"all",0,"",0,"","",0,"",0,""},
|
&Forum{0, buildForumUrl(nameToSlug("Uncategorised"), 0), "Uncategorised", "", config.UncategorisedForumVisible, "all", 0, "", 0, "", "", 0, "", 0, ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := get_forums_stmt.Query()
|
rows, err := get_forums_stmt.Query()
|
||||||
@ -82,7 +81,7 @@ func (sfs *StaticForumStore) LoadForums() error {
|
|||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
var i int = 1
|
var i = 1
|
||||||
for ; rows.Next(); i++ {
|
for ; rows.Next(); i++ {
|
||||||
forum := Forum{ID: 0, Active: true, Preset: "all"}
|
forum := Forum{ID: 0, Active: true, Preset: "all"}
|
||||||
err = rows.Scan(&forum.ID, &forum.Name, &forum.Desc, &forum.Active, &forum.Preset, &forum.ParentID, &forum.ParentType, &forum.TopicCount, &forum.LastTopic, &forum.LastTopicID, &forum.LastReplyer, &forum.LastReplyerID, &forum.LastTopicTime)
|
err = rows.Scan(&forum.ID, &forum.Name, &forum.Desc, &forum.Active, &forum.Preset, &forum.ParentID, &forum.ParentType, &forum.TopicCount, &forum.LastTopic, &forum.LastTopicID, &forum.LastReplyer, &forum.LastReplyerID, &forum.LastTopicTime)
|
||||||
@ -93,7 +92,7 @@ func (sfs *StaticForumStore) LoadForums() error {
|
|||||||
// Ugh, you really shouldn't physically delete these items, it makes a big mess of things
|
// Ugh, you really shouldn't physically delete these items, it makes a big mess of things
|
||||||
if forum.ID != i {
|
if forum.ID != i {
|
||||||
log.Print("Stop physically deleting forums. You are messing up the IDs. Use the Forum Manager or delete_forum() instead x.x")
|
log.Print("Stop physically deleting forums. You are messing up the IDs. Use the Forum Manager or delete_forum() instead x.x")
|
||||||
sfs.fill_forum_id_gap(i, forum.ID)
|
sfs.fillForumIDGap(i, forum.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if forum.Name == "" {
|
if forum.Name == "" {
|
||||||
@ -104,8 +103,8 @@ func (sfs *StaticForumStore) LoadForums() error {
|
|||||||
log.Print("Adding the " + forum.Name + " forum")
|
log.Print("Adding the " + forum.Name + " forum")
|
||||||
}
|
}
|
||||||
|
|
||||||
forum.Link = build_forum_url(name_to_slug(forum.Name),forum.ID)
|
forum.Link = buildForumUrl(nameToSlug(forum.Name), forum.ID)
|
||||||
forum.LastTopicLink = build_topic_url(name_to_slug(forum.LastTopic),forum.LastTopicID)
|
forum.LastTopicLink = buildTopicURL(nameToSlug(forum.LastTopic), forum.LastTopicID)
|
||||||
forums = append(forums, &forum)
|
forums = append(forums, &forum)
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
err = rows.Err()
|
||||||
@ -147,16 +146,13 @@ func (sfs *StaticForumStore) CascadeGetCopy(id int) (forum Forum, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sfs *StaticForumStore) BypassGet(id int) (*Forum, error) {
|
func (sfs *StaticForumStore) BypassGet(id int) (*Forum, error) {
|
||||||
var forum Forum = Forum{ID:id}
|
var forum = Forum{ID: id}
|
||||||
err := sfs.get.QueryRow(id).Scan(&forum.Name, &forum.Desc, &forum.Active, &forum.Preset, &forum.TopicCount, &forum.LastTopic, &forum.LastTopicID, &forum.LastReplyer, &forum.LastReplyerID, &forum.LastTopicTime)
|
err := sfs.get.QueryRow(id).Scan(&forum.Name, &forum.Desc, &forum.Active, &forum.Preset, &forum.TopicCount, &forum.LastTopic, &forum.LastTopicID, &forum.LastReplyer, &forum.LastReplyerID, &forum.LastTopicTime)
|
||||||
if err != nil {
|
return &forum, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &forum, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sfs *StaticForumStore) Load(id int) error {
|
func (sfs *StaticForumStore) Load(id int) error {
|
||||||
var forum Forum = Forum{ID:id}
|
var forum = Forum{ID: id}
|
||||||
err := sfs.get.QueryRow(id).Scan(&forum.Name, &forum.Desc, &forum.Active, &forum.Preset, &forum.TopicCount, &forum.LastTopic, &forum.LastTopicID, &forum.LastReplyer, &forum.LastReplyerID, &forum.LastTopicTime)
|
err := sfs.get.QueryRow(id).Scan(&forum.Name, &forum.Desc, &forum.Active, &forum.Preset, &forum.TopicCount, &forum.LastTopic, &forum.LastTopicID, &forum.LastReplyer, &forum.LastReplyerID, &forum.LastTopicTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -167,13 +163,13 @@ func (sfs *StaticForumStore) Load(id int) error {
|
|||||||
|
|
||||||
// TO-DO: Set should be able to add new indices not just replace existing ones for consistency with UserStore and TopicStore
|
// TO-DO: Set should be able to add new indices not just replace existing ones for consistency with UserStore and TopicStore
|
||||||
func (sfs *StaticForumStore) Set(forum *Forum) error {
|
func (sfs *StaticForumStore) Set(forum *Forum) error {
|
||||||
forum_update_mutex.Lock()
|
forumUpdateMutex.Lock()
|
||||||
if !sfs.Exists(forum.ID) {
|
if !sfs.Exists(forum.ID) {
|
||||||
forum_update_mutex.Unlock()
|
forumUpdateMutex.Unlock()
|
||||||
return ErrNoRows
|
return ErrNoRows
|
||||||
}
|
}
|
||||||
sfs.forums[forum.ID] = forum
|
sfs.forums[forum.ID] = forum
|
||||||
forum_update_mutex.Unlock()
|
forumUpdateMutex.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,8 +188,8 @@ func (sfs *StaticForumStore) GetFirstChild(parentID int, parentType string) (*Fo
|
|||||||
// We can cheat slightly, as the StaticForumStore has all the IDs under the cap ;)
|
// We can cheat slightly, as the StaticForumStore has all the IDs under the cap ;)
|
||||||
// Should we cache this? Well, it's only really used for superadmins right now.
|
// Should we cache this? Well, it's only really used for superadmins right now.
|
||||||
func (sfs *StaticForumStore) GetAllIDs() ([]int, error) {
|
func (sfs *StaticForumStore) GetAllIDs() ([]int, error) {
|
||||||
var max int = sfs.forumCapCount
|
var max = sfs.forumCapCount
|
||||||
var ids []int = make([]int,max)
|
var ids = make([]int, max)
|
||||||
for i := 0; i < max; i++ {
|
for i := 0; i < max; i++ {
|
||||||
ids[i] = i
|
ids[i] = i
|
||||||
}
|
}
|
||||||
@ -205,13 +201,13 @@ func (sfs *StaticForumStore) Exists(id int) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sfs *StaticForumStore) Delete(id int) error {
|
func (sfs *StaticForumStore) Delete(id int) error {
|
||||||
forum_update_mutex.Lock()
|
forumUpdateMutex.Lock()
|
||||||
if !sfs.Exists(id) {
|
if !sfs.Exists(id) {
|
||||||
forum_update_mutex.Unlock()
|
forumUpdateMutex.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
sfs.forums[id].Name = ""
|
sfs.forums[id].Name = ""
|
||||||
forum_update_mutex.Unlock()
|
forumUpdateMutex.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,13 +217,13 @@ func (sfs *StaticForumStore) CascadeDelete(id int) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
forum_update_mutex.Lock()
|
forumUpdateMutex.Lock()
|
||||||
_, err = delete_forum_stmt.Exec(id)
|
_, err = delete_forum_stmt.Exec(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
forum.Name = ""
|
forum.Name = ""
|
||||||
forum_update_mutex.Unlock()
|
forumUpdateMutex.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +236,7 @@ func (sfs *StaticForumStore) IncrementTopicCount(id int) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
forum.TopicCount += 1
|
forum.TopicCount++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +249,7 @@ func (sfs *StaticForumStore) DecrementTopicCount(id int) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
forum.TopicCount -= 1
|
forum.TopicCount--
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,15 +274,15 @@ func (sfs *StaticForumStore) UpdateLastTopic(topic_name string, tid int, usernam
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sfs *StaticForumStore) CreateForum(forum_name string, forum_desc string, active bool, preset string) (int, error) {
|
func (sfs *StaticForumStore) CreateForum(forumName string, forumDesc string, active bool, preset string) (int, error) {
|
||||||
var fid int
|
var fid int
|
||||||
err := forum_entry_exists_stmt.QueryRow().Scan(&fid)
|
err := forum_entry_exists_stmt.QueryRow().Scan(&fid)
|
||||||
if err != nil && err != ErrNoRows {
|
if err != nil && err != ErrNoRows {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if err != ErrNoRows {
|
if err != ErrNoRows {
|
||||||
forum_update_mutex.Lock()
|
forumUpdateMutex.Lock()
|
||||||
_, err = update_forum_stmt.Exec(forum_name, forum_desc, active, preset, fid)
|
_, err = update_forum_stmt.Exec(forumName, forumDesc, active, preset, fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fid, err
|
return fid, err
|
||||||
}
|
}
|
||||||
@ -294,16 +290,16 @@ func (sfs *StaticForumStore) CreateForum(forum_name string, forum_desc string, a
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, ErrCacheDesync
|
return 0, ErrCacheDesync
|
||||||
}
|
}
|
||||||
forum.Name = forum_name
|
forum.Name = forumName
|
||||||
forum.Desc = forum_desc
|
forum.Desc = forumDesc
|
||||||
forum.Active = active
|
forum.Active = active
|
||||||
forum.Preset = preset
|
forum.Preset = preset
|
||||||
forum_update_mutex.Unlock()
|
forumUpdateMutex.Unlock()
|
||||||
return fid, nil
|
return fid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
forum_create_mutex.Lock()
|
forumCreateMutex.Lock()
|
||||||
res, err := create_forum_stmt.Exec(forum_name, forum_desc, active, preset)
|
res, err := create_forum_stmt.Exec(forumName, forumDesc, active, preset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -314,27 +310,26 @@ func (sfs *StaticForumStore) CreateForum(forum_name string, forum_desc string, a
|
|||||||
}
|
}
|
||||||
fid = int(fid64)
|
fid = int(fid64)
|
||||||
|
|
||||||
sfs.forums = append(sfs.forums, &Forum{fid,build_forum_url(name_to_slug(forum_name),fid),forum_name,forum_desc,active,preset,0,"",0,"","",0,"",0,""})
|
sfs.forums = append(sfs.forums, &Forum{fid, buildForumUrl(nameToSlug(forumName), fid), forumName, forumDesc, active, preset, 0, "", 0, "", "", 0, "", 0, ""})
|
||||||
sfs.forumCapCount++
|
sfs.forumCapCount++
|
||||||
|
|
||||||
// TO-DO: Add a GroupStore. How would it interact with the ForumStore?
|
// TO-DO: Add a GroupStore. How would it interact with the ForumStore?
|
||||||
permmap_to_query(preset_to_permmap(preset),fid)
|
permmapToQuery(presetToPermmap(preset), fid)
|
||||||
forum_create_mutex.Unlock()
|
forumCreateMutex.Unlock()
|
||||||
return fid, nil
|
return fid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sfs *StaticForumStore) fill_forum_id_gap(biggerID int, smallerID int) {
|
func (sfs *StaticForumStore) fillForumIDGap(biggerID int, smallerID int) {
|
||||||
dummy := Forum{ID: 0, Name: "", Active: false, Preset: "all"}
|
dummy := Forum{ID: 0, Name: "", Active: false, Preset: "all"}
|
||||||
for i := smallerID; i > biggerID; i++ {
|
for i := smallerID; i > biggerID; i++ {
|
||||||
sfs.forums = append(sfs.forums, &dummy)
|
sfs.forums = append(sfs.forums, &dummy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the total number of forums
|
|
||||||
// TO-DO: Get the total count of forums in the forum store minus the blanked forums rather than doing a heavy query for this?
|
// TO-DO: Get the total count of forums in the forum store minus the blanked forums rather than doing a heavy query for this?
|
||||||
func (sfs *StaticForumStore) GetGlobalCount() int {
|
// GetGlobalCount returns the total number of forums
|
||||||
var fcount int
|
func (sfs *StaticForumStore) GetGlobalCount() (fcount int) {
|
||||||
err := sfs.forum_count.QueryRow().Scan(&fcount)
|
err := sfs.forumCount.QueryRow().Scan(&fcount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError(err)
|
LogError(err)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ package main
|
|||||||
import "log"
|
import "log"
|
||||||
import "database/sql"
|
import "database/sql"
|
||||||
|
|
||||||
|
// nolint
|
||||||
var get_user_stmt *sql.Stmt
|
var get_user_stmt *sql.Stmt
|
||||||
var get_reply_stmt *sql.Stmt
|
var get_reply_stmt *sql.Stmt
|
||||||
var get_user_reply_stmt *sql.Stmt
|
var get_user_reply_stmt *sql.Stmt
|
||||||
@ -123,6 +124,7 @@ var add_forum_perms_to_forum_staff_stmt *sql.Stmt
|
|||||||
var add_forum_perms_to_forum_members_stmt *sql.Stmt
|
var add_forum_perms_to_forum_members_stmt *sql.Stmt
|
||||||
var notify_watchers_stmt *sql.Stmt
|
var notify_watchers_stmt *sql.Stmt
|
||||||
|
|
||||||
|
// nolint
|
||||||
func _gen_mysql() (err error) {
|
func _gen_mysql() (err error) {
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Building the generated statements")
|
log.Print("Building the generated statements")
|
||||||
|
@ -6,6 +6,7 @@ package main
|
|||||||
import "log"
|
import "log"
|
||||||
import "database/sql"
|
import "database/sql"
|
||||||
|
|
||||||
|
// nolint
|
||||||
var add_replies_to_topic_stmt *sql.Stmt
|
var add_replies_to_topic_stmt *sql.Stmt
|
||||||
var remove_replies_from_topic_stmt *sql.Stmt
|
var remove_replies_from_topic_stmt *sql.Stmt
|
||||||
var add_topics_to_forum_stmt *sql.Stmt
|
var add_topics_to_forum_stmt *sql.Stmt
|
||||||
@ -46,6 +47,7 @@ var verify_email_stmt *sql.Stmt
|
|||||||
var set_temp_group_stmt *sql.Stmt
|
var set_temp_group_stmt *sql.Stmt
|
||||||
var update_word_filter_stmt *sql.Stmt
|
var update_word_filter_stmt *sql.Stmt
|
||||||
|
|
||||||
|
// nolint
|
||||||
func _gen_pgsql() (err error) {
|
func _gen_pgsql() (err error) {
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Building the generated statements")
|
log.Print("Building the generated statements")
|
||||||
|
@ -169,7 +169,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
route_panel_themes(w,req,user)
|
route_panel_themes(w,req,user)
|
||||||
return
|
return
|
||||||
case "/panel/themes/default/":
|
case "/panel/themes/default/":
|
||||||
route_panel_themes_default(w,req,user,extra_data)
|
route_panel_themes_set_default(w,req,user,extra_data)
|
||||||
return
|
return
|
||||||
case "/panel/plugins/":
|
case "/panel/plugins/":
|
||||||
route_panel_plugins(w,req,user)
|
route_panel_plugins(w,req,user)
|
||||||
|
363
general_test.go
363
general_test.go
@ -2,56 +2,52 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
//"os"
|
//"os"
|
||||||
"log"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
//"math/rand"
|
//"math/rand"
|
||||||
"testing"
|
"database/sql"
|
||||||
"time"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"html/template"
|
"testing"
|
||||||
"io/ioutil"
|
"time"
|
||||||
"database/sql"
|
|
||||||
//"runtime/pprof"
|
//"runtime/pprof"
|
||||||
|
|
||||||
//_ "github.com/go-sql-driver/mysql"
|
//_ "github.com/go-sql-driver/mysql"
|
||||||
//"github.com/erikstmartin/go-testdb"
|
//"github.com/erikstmartin/go-testdb"
|
||||||
//"github.com/husobee/vestigo"
|
//"github.com/husobee/vestigo"
|
||||||
)
|
)
|
||||||
|
|
||||||
var db_test *sql.DB
|
var dbTest *sql.DB
|
||||||
var db_prod *sql.DB
|
var dbProd *sql.DB
|
||||||
var gloinited bool
|
var gloinited bool
|
||||||
|
|
||||||
func gloinit() error {
|
func gloinit() error {
|
||||||
dev.DebugMode = false
|
dev.DebugMode = false
|
||||||
//nogrouplog = true
|
//nogrouplog = true
|
||||||
|
|
||||||
// init_database is a little noisy for a benchmark
|
|
||||||
//discard := ioutil.Discard
|
|
||||||
//log.SetOutput(discard)
|
|
||||||
|
|
||||||
startTime = time.Now()
|
startTime = time.Now()
|
||||||
//timeLocation = startTime.Location()
|
processConfig()
|
||||||
process_config()
|
|
||||||
|
|
||||||
init_themes()
|
err := initThemes()
|
||||||
err := init_database()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
db_prod = db
|
err = initDatabase()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dbProd = db
|
||||||
//db_test, err = sql.Open("testdb","")
|
//db_test, err = sql.Open("testdb","")
|
||||||
//if err != nil {
|
//if err != nil {
|
||||||
// return err
|
// return err
|
||||||
//}
|
//}
|
||||||
|
|
||||||
init_templates()
|
initTemplates()
|
||||||
db_prod.SetMaxOpenConns(64)
|
dbProd.SetMaxOpenConns(64)
|
||||||
err = init_errors()
|
err = initErrors()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -64,11 +60,14 @@ func gloinit() error {
|
|||||||
topics = NewSqlTopicStore()
|
topics = NewSqlTopicStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
init_static_files()
|
log.Print("Loading the static files.")
|
||||||
//log.SetOutput(os.Stdout)
|
err = initStaticFiles()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
auth = NewDefaultAuth()
|
auth = NewDefaultAuth()
|
||||||
|
|
||||||
err = init_word_filters()
|
err = initWordFilters()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -79,182 +78,20 @@ func gloinit() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
gloinit()
|
err := gloinit()
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkTopicTemplateSerial(b *testing.B) {
|
|
||||||
b.ReportAllocs()
|
|
||||||
|
|
||||||
user := User{0,"bob","Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,make(map[string]bool),"",false,"","","","","",0,0,"127.0.0.1"}
|
|
||||||
admin := User{1,"admin-alice","Admin Alice","admin@localhost",0,true,true,true,true,true,false,AllPerms,make(map[string]bool),"",false,"","","","","",-1,58,"127.0.0.1"}
|
|
||||||
|
|
||||||
topic := TopicUser{Title: "Lol",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",ClassName: "",Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}
|
|
||||||
|
|
||||||
var replyList []Reply
|
|
||||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry","Jerry",config.DefaultGroup,"",0,0,"","",0,"","","","",0,"127.0.0.1",false,1,"",""})
|
|
||||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry2","Jerry2",config.DefaultGroup,"",0,0,"","",0,"","","","",0,"127.0.0.1",false,1,"",""})
|
|
||||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry3","Jerry3",config.DefaultGroup,"",0,0,"","",0,"","","","",0,"127.0.0.1",false,1,"",""})
|
|
||||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry4","Jerry4",config.DefaultGroup,"",0,0,"","",0,"","","","",0,"127.0.0.1",false,1,"",""})
|
|
||||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry5","Jerry5",config.DefaultGroup,"",0,0,"","",0,"","","","",0,"127.0.0.1",false,1,"",""})
|
|
||||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry6","Jerry6",config.DefaultGroup,"",0,0,"","",0,"","","","",0,"127.0.0.1",false,1,"",""})
|
|
||||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry7","Jerry7",config.DefaultGroup,"",0,0,"","",0,"","","","",0,"127.0.0.1",false,1,"",""})
|
|
||||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry8","Jerry8",config.DefaultGroup,"",0,0,"","",0,"","","","",0,"127.0.0.1",false,1,"",""})
|
|
||||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry9","Jerry9",config.DefaultGroup,"",0,0,"","",0,"","","","",0,"127.0.0.1",false,1,"",""})
|
|
||||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry10","Jerry10",config.DefaultGroup,"",0,0,"","",0,"","","","",0,"127.0.0.1",false,1,"",""})
|
|
||||||
|
|
||||||
headerVars := HeaderVars{
|
|
||||||
NoticeList:[]string{"test"},
|
|
||||||
Stylesheets:[]string{"panel"},
|
|
||||||
Scripts:[]string{"whatever"},
|
|
||||||
Widgets:PageWidgets{
|
|
||||||
LeftSidebar: template.HTML("lalala"),
|
|
||||||
},
|
|
||||||
Site:site,
|
|
||||||
}
|
|
||||||
|
|
||||||
tpage := TopicPage{"Topic Blah",user,headerVars,replyList,topic,1,1,extData}
|
|
||||||
tpage2 := TopicPage{"Topic Blah",admin,headerVars,replyList,topic,1,1,extData}
|
|
||||||
w := ioutil.Discard
|
|
||||||
|
|
||||||
b.Run("compiled_useradmin", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
template_topic(tpage2,w)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
b.Run("interpreted_useradmin", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
templates.ExecuteTemplate(w,"topic.html", tpage2)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
b.Run("compiled_userguest", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
template_topic(tpage,w)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
b.Run("interpreted_userguest", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
templates.ExecuteTemplate(w,"topic.html", tpage)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
w2 := httptest.NewRecorder()
|
|
||||||
b.Run("compiled_useradmin_recorder", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
w2.Body.Reset()
|
|
||||||
template_topic(tpage2,w2)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
b.Run("interpreted_useradmin_recorder", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
w2.Body.Reset()
|
|
||||||
templates.ExecuteTemplate(w2,"topic.html", tpage2)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
b.Run("compiled_userguest_recorder", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
w2.Body.Reset()
|
|
||||||
template_topic(tpage,w2)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
b.Run("interpreted_userguest_recorder", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
w2.Body.Reset()
|
|
||||||
templates.ExecuteTemplate(w2,"topic.html", tpage)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/*f, err := os.Create("topic_bench.prof")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
pprof.StartCPUProfile(f)
|
|
||||||
defer pprof.StopCPUProfile()*/
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkTopicsTemplateSerial(b *testing.B) {
|
|
||||||
b.ReportAllocs()
|
|
||||||
|
|
||||||
user := User{0,build_profile_url("bob",0),"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,make(map[string]bool),"",false,"","","","","",0,0,"127.0.0.1"}
|
|
||||||
admin := User{1,build_profile_url("admin-alice",1),"Admin Alice","admin@localhost",0,true,true,true,true,true,false,AllPerms,make(map[string]bool),"",false,"","","","","Admin",58,580,"127.0.0.1"}
|
|
||||||
|
|
||||||
var topicList []*TopicsRow
|
|
||||||
topicList = append(topicList, &TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,Creator:&admin,LastUser:&user,ClassName:"", IpAddress: "127.0.0.1"})
|
|
||||||
topicList = append(topicList, &TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,Creator:&admin,LastUser:&user,ClassName:"", IpAddress: "127.0.0.1"})
|
|
||||||
topicList = append(topicList, &TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,Creator:&admin,LastUser:&user,ClassName:"", IpAddress: "127.0.0.1"})
|
|
||||||
topicList = append(topicList, &TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,Creator:&admin,LastUser:&user,ClassName:"", IpAddress: "127.0.0.1"})
|
|
||||||
topicList = append(topicList, &TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,Creator:&admin,LastUser:&user,ClassName:"", IpAddress: "127.0.0.1"})
|
|
||||||
topicList = append(topicList, &TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,Creator:&admin,LastUser:&user,ClassName:"", IpAddress: "127.0.0.1"})
|
|
||||||
topicList = append(topicList, &TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,Creator:&admin,LastUser:&user,ClassName:"", IpAddress: "127.0.0.1"})
|
|
||||||
topicList = append(topicList, &TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,Creator:&admin,LastUser:&user,ClassName:"", IpAddress: "127.0.0.1"})
|
|
||||||
topicList = append(topicList, &TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,Creator:&admin,LastUser:&user,ClassName:"", IpAddress: "127.0.0.1"})
|
|
||||||
topicList = append(topicList, &TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,Creator:&admin,LastUser:&user,ClassName:"", IpAddress: "127.0.0.1"})
|
|
||||||
|
|
||||||
headerVars := HeaderVars{
|
|
||||||
NoticeList:[]string{"test"},
|
|
||||||
Stylesheets:[]string{"panel"},
|
|
||||||
Scripts:[]string{"whatever"},
|
|
||||||
Widgets:PageWidgets{
|
|
||||||
LeftSidebar: template.HTML("lalala"),
|
|
||||||
},
|
|
||||||
Site:site,
|
|
||||||
}
|
|
||||||
|
|
||||||
w := ioutil.Discard
|
|
||||||
tpage := TopicsPage{"Topic Blah",user,headerVars,topicList,extData}
|
|
||||||
tpage2 := TopicsPage{"Topic Blah",admin,headerVars,topicList,extData}
|
|
||||||
|
|
||||||
b.Run("compiled_useradmin", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
template_topics(tpage2,w)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
b.Run("interpreted_useradmin",func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
templates.ExecuteTemplate(w,"topics.html", tpage2)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
b.Run("compiled_userguest",func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
template_topics(tpage,w)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
b.Run("interpreted_userguest",func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
templates.ExecuteTemplate(w,"topics.html", tpage)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkStaticRouteParallel(b *testing.B) {
|
|
||||||
b.ReportAllocs()
|
|
||||||
if !gloinited {
|
|
||||||
gloinit()
|
|
||||||
}
|
|
||||||
if !plugins_inited {
|
|
||||||
init_plugins()
|
|
||||||
}
|
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
|
||||||
static_w := httptest.NewRecorder()
|
|
||||||
static_req := httptest.NewRequest("get","/static/global.js",bytes.NewReader(nil))
|
|
||||||
static_handler := http.HandlerFunc(route_static)
|
|
||||||
for pb.Next() {
|
|
||||||
//static_w.Code = 200
|
|
||||||
static_w.Body.Reset()
|
|
||||||
static_handler.ServeHTTP(static_w,static_req)
|
|
||||||
//if static_w.Code != 200 {
|
|
||||||
// pb.Print(static_w.Body)
|
|
||||||
// panic("HTTP Error!")
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: Swap out LocalError for a panic for this?
|
// TO-DO: Swap out LocalError for a panic for this?
|
||||||
func BenchmarkTopicAdminRouteParallel(b *testing.B) {
|
func BenchmarkTopicAdminRouteParallel(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
if !gloinited {
|
if !gloinited {
|
||||||
gloinit()
|
err := gloinit()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
@ -262,27 +99,27 @@ func BenchmarkTopicAdminRouteParallel(b *testing.B) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
if !admin.Is_Admin {
|
if !admin.IsAdmin {
|
||||||
b.Fatal("UID1 is not an admin")
|
b.Fatal("UID1 is not an admin")
|
||||||
}
|
}
|
||||||
admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year}
|
adminUIDCookie := http.Cookie{Name: "uid", Value: "1", Path: "/", MaxAge: year}
|
||||||
admin_session_cookie := http.Cookie{Name:"session",Value: admin.Session,Path:"/",MaxAge: year}
|
adminSessionCookie := http.Cookie{Name: "session", Value: admin.Session, Path: "/", MaxAge: year}
|
||||||
|
|
||||||
topic_w := httptest.NewRecorder()
|
topicW := httptest.NewRecorder()
|
||||||
topic_req := httptest.NewRequest("get","/topic/1",bytes.NewReader(nil))
|
topicReq := httptest.NewRequest("get", "/topic/1", bytes.NewReader(nil))
|
||||||
topic_req_admin := topic_req
|
topicReqAdmin := topicReq
|
||||||
topic_req_admin.AddCookie(&admin_uid_cookie)
|
topicReqAdmin.AddCookie(&adminUIDCookie)
|
||||||
topic_req_admin.AddCookie(&admin_session_cookie)
|
topicReqAdmin.AddCookie(&adminSessionCookie)
|
||||||
|
|
||||||
// Deal with the session stuff, etc.
|
// Deal with the session stuff, etc.
|
||||||
user, ok := PreRoute(topic_w,topic_req_admin)
|
user, ok := PreRoute(topicW, topicReqAdmin)
|
||||||
if !ok {
|
if !ok {
|
||||||
b.Fatal("Mysterious error!")
|
b.Fatal("Mysterious error!")
|
||||||
}
|
}
|
||||||
|
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
topic_w.Body.Reset()
|
topicW.Body.Reset()
|
||||||
route_topic_id(topic_w,topic_req_admin,user)
|
route_topic_id(topicW, topicReqAdmin, user)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -290,15 +127,18 @@ func BenchmarkTopicAdminRouteParallel(b *testing.B) {
|
|||||||
func BenchmarkTopicGuestRouteParallel(b *testing.B) {
|
func BenchmarkTopicGuestRouteParallel(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
if !gloinited {
|
if !gloinited {
|
||||||
gloinit()
|
err := gloinit()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
topic_w := httptest.NewRecorder()
|
topicW := httptest.NewRecorder()
|
||||||
topic_req := httptest.NewRequest("get","/topic/1",bytes.NewReader(nil))
|
topicReq := httptest.NewRequest("get", "/topic/1", bytes.NewReader(nil))
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
topic_w.Body.Reset()
|
topicW.Body.Reset()
|
||||||
route_topic_id(topic_w,topic_req,guest_user)
|
route_topic_id(topicW, topicReq, guestUser)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -628,13 +468,16 @@ func BenchmarkForumsGuestRouteParallel(b *testing.B) {
|
|||||||
func BenchmarkQueryTopicParallel(b *testing.B) {
|
func BenchmarkQueryTopicParallel(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
if !gloinited {
|
if !gloinited {
|
||||||
gloinit()
|
err := gloinit()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
var tu TopicUser
|
var tu TopicUser
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.Is_Closed, &tu.Sticky, &tu.ParentID, &tu.IpAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
log.Fatal("No rows found!")
|
log.Fatal("No rows found!")
|
||||||
return
|
return
|
||||||
@ -649,13 +492,16 @@ func BenchmarkQueryTopicParallel(b *testing.B) {
|
|||||||
func BenchmarkQueryPreparedTopicParallel(b *testing.B) {
|
func BenchmarkQueryPreparedTopicParallel(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
if !gloinited {
|
if !gloinited {
|
||||||
gloinit()
|
err := gloinit()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
var tu TopicUser
|
var tu TopicUser
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
err := get_topic_user_stmt.QueryRow(1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.Is_Closed, &tu.Sticky, &tu.ParentID, &tu.IpAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
err := get_topic_user_stmt.QueryRow(1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
b.Fatal("No rows found!")
|
b.Fatal("No rows found!")
|
||||||
return
|
return
|
||||||
@ -672,7 +518,7 @@ func BenchmarkQueriesSerial(b *testing.B) {
|
|||||||
var tu TopicUser
|
var tu TopicUser
|
||||||
b.Run("topic", func(b *testing.B) {
|
b.Run("topic", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.Is_Closed, &tu.Sticky, &tu.ParentID, &tu.IpAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
b.Fatal("No rows found!")
|
b.Fatal("No rows found!")
|
||||||
return
|
return
|
||||||
@ -691,7 +537,8 @@ func BenchmarkQueriesSerial(b *testing.B) {
|
|||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
for rows.Next() {}
|
for rows.Next() {
|
||||||
|
}
|
||||||
err = rows.Err()
|
err = rows.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
@ -701,7 +548,7 @@ func BenchmarkQueriesSerial(b *testing.B) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
var replyItem Reply
|
var replyItem Reply
|
||||||
var is_super_admin bool
|
var isSuperAdmin bool
|
||||||
var group int
|
var group int
|
||||||
b.Run("topic_replies_scan", func(b *testing.B) {
|
b.Run("topic_replies_scan", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
@ -711,7 +558,7 @@ func BenchmarkQueriesSerial(b *testing.B) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &is_super_admin, &group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IpAddress)
|
err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &isSuperAdmin, &group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IPAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
return
|
return
|
||||||
@ -1059,32 +906,32 @@ func BenchmarkParserSerial(b *testing.B) {
|
|||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.Run("empty_post", func(b *testing.B) {
|
b.Run("empty_post", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = parse_message("")
|
_ = parseMessage("")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("short_post", func(b *testing.B) {
|
b.Run("short_post", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = parse_message("Hey everyone, how's it going?")
|
_ = parseMessage("Hey everyone, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("one_smily", func(b *testing.B) {
|
b.Run("one_smily", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = parse_message("Hey everyone, how's it going? :)")
|
_ = parseMessage("Hey everyone, how's it going? :)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("five_smilies", func(b *testing.B) {
|
b.Run("five_smilies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = parse_message("Hey everyone, how's it going? :):):):):)")
|
_ = parseMessage("Hey everyone, how's it going? :):):):):)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("ten_smilies", func(b *testing.B) {
|
b.Run("ten_smilies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = parse_message("Hey everyone, how's it going? :):):):):):):):):):)")
|
_ = parseMessage("Hey everyone, how's it going? :):):):):):):):):):)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("twenty_smilies", func(b *testing.B) {
|
b.Run("twenty_smilies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = parse_message("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
|
_ = parseMessage("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1093,47 +940,47 @@ func BenchmarkBBCodePluginWithRegexpSerial(b *testing.B) {
|
|||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.Run("empty_post", func(b *testing.B) {
|
b.Run("empty_post", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_regex_parse("")
|
_ = bbcodeRegexParse("")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("short_post", func(b *testing.B) {
|
b.Run("short_post", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_regex_parse("Hey everyone, how's it going?")
|
_ = bbcodeRegexParse("Hey everyone, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("one_smily", func(b *testing.B) {
|
b.Run("one_smily", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_regex_parse("Hey everyone, how's it going? :)")
|
_ = bbcodeRegexParse("Hey everyone, how's it going? :)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("five_smilies", func(b *testing.B) {
|
b.Run("five_smilies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_regex_parse("Hey everyone, how's it going? :):):):):)")
|
_ = bbcodeRegexParse("Hey everyone, how's it going? :):):):):)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("ten_smilies", func(b *testing.B) {
|
b.Run("ten_smilies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_regex_parse("Hey everyone, how's it going? :):):):):):):):):):)")
|
_ = bbcodeRegexParse("Hey everyone, how's it going? :):):):):):):):):):)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("twenty_smilies", func(b *testing.B) {
|
b.Run("twenty_smilies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_regex_parse("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
|
_ = bbcodeRegexParse("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("one_bold", func(b *testing.B) {
|
b.Run("one_bold", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_regex_parse("[b]H[/b]ey everyone, how's it going?")
|
_ = bbcodeRegexParse("[b]H[/b]ey everyone, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("five_bold", func(b *testing.B) {
|
b.Run("five_bold", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_regex_parse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
|
_ = bbcodeRegexParse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("ten_bold", func(b *testing.B) {
|
b.Run("ten_bold", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_regex_parse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
|
_ = bbcodeRegexParse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1142,47 +989,47 @@ func BenchmarkBBCodePluginWithoutCodeTagSerial(b *testing.B) {
|
|||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.Run("empty_post", func(b *testing.B) {
|
b.Run("empty_post", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_parse_without_code("")
|
_ = bbcodeParseWithoutCode("")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("short_post", func(b *testing.B) {
|
b.Run("short_post", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_parse_without_code("Hey everyone, how's it going?")
|
_ = bbcodeParseWithoutCode("Hey everyone, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("one_smily", func(b *testing.B) {
|
b.Run("one_smily", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_parse_without_code("Hey everyone, how's it going? :)")
|
_ = bbcodeParseWithoutCode("Hey everyone, how's it going? :)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("five_smilies", func(b *testing.B) {
|
b.Run("five_smilies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_parse_without_code("Hey everyone, how's it going? :):):):):)")
|
_ = bbcodeParseWithoutCode("Hey everyone, how's it going? :):):):):)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("ten_smilies", func(b *testing.B) {
|
b.Run("ten_smilies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_parse_without_code("Hey everyone, how's it going? :):):):):):):):):):)")
|
_ = bbcodeParseWithoutCode("Hey everyone, how's it going? :):):):):):):):):):)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("twenty_smilies", func(b *testing.B) {
|
b.Run("twenty_smilies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_parse_without_code("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
|
_ = bbcodeParseWithoutCode("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("one_bold", func(b *testing.B) {
|
b.Run("one_bold", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_parse_without_code("[b]H[/b]ey everyone, how's it going?")
|
_ = bbcodeParseWithoutCode("[b]H[/b]ey everyone, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("five_bold", func(b *testing.B) {
|
b.Run("five_bold", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_parse_without_code("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
|
_ = bbcodeParseWithoutCode("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("ten_bold", func(b *testing.B) {
|
b.Run("ten_bold", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_parse_without_code("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
|
_ = bbcodeParseWithoutCode("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1191,47 +1038,47 @@ func BenchmarkBBCodePluginWithFullParserSerial(b *testing.B) {
|
|||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.Run("empty_post", func(b *testing.B) {
|
b.Run("empty_post", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_full_parse("")
|
_ = bbcodeFullParse("")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("short_post", func(b *testing.B) {
|
b.Run("short_post", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_full_parse("Hey everyone, how's it going?")
|
_ = bbcodeFullParse("Hey everyone, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("one_smily", func(b *testing.B) {
|
b.Run("one_smily", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_full_parse("Hey everyone, how's it going? :)")
|
_ = bbcodeFullParse("Hey everyone, how's it going? :)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("five_smilies", func(b *testing.B) {
|
b.Run("five_smilies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_full_parse("Hey everyone, how's it going? :):):):):)")
|
_ = bbcodeFullParse("Hey everyone, how's it going? :):):):):)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("ten_smilies", func(b *testing.B) {
|
b.Run("ten_smilies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_full_parse("Hey everyone, how's it going? :):):):):):):):):):)")
|
_ = bbcodeFullParse("Hey everyone, how's it going? :):):):):):):):):):)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("twenty_smilies", func(b *testing.B) {
|
b.Run("twenty_smilies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_full_parse("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
|
_ = bbcodeFullParse("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("one_bold", func(b *testing.B) {
|
b.Run("one_bold", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_full_parse("[b]H[/b]ey everyone, how's it going?")
|
_ = bbcodeFullParse("[b]H[/b]ey everyone, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("five_bold", func(b *testing.B) {
|
b.Run("five_bold", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_full_parse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
|
_ = bbcodeFullParse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
b.Run("ten_bold", func(b *testing.B) {
|
b.Run("ten_bold", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = bbcode_full_parse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
|
_ = bbcodeFullParse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1450,28 +1297,28 @@ func TestForumsGuestRoute(t *testing.T) {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
func TestSplittyThing(t *testing.T) {
|
func TestSplittyThing(t *testing.T) {
|
||||||
var extra_data string
|
var extraData string
|
||||||
var path string = "/pages/hohoho"
|
var path = "/pages/hohoho"
|
||||||
t.Log("Raw Path:", path)
|
t.Log("Raw Path:", path)
|
||||||
if path[len(path)-1] != '/' {
|
if path[len(path)-1] != '/' {
|
||||||
extra_data = path[strings.LastIndexByte(path,'/') + 1:]
|
extraData = path[strings.LastIndexByte(path, '/')+1:]
|
||||||
path = path[:strings.LastIndexByte(path, '/')+1]
|
path = path[:strings.LastIndexByte(path, '/')+1]
|
||||||
}
|
}
|
||||||
t.Log("Path:", path)
|
t.Log("Path:", path)
|
||||||
t.Log("Extra Data:", extra_data)
|
t.Log("Extra Data:", extraData)
|
||||||
t.Log("Path Bytes:", []byte(path))
|
t.Log("Path Bytes:", []byte(path))
|
||||||
t.Log("Extra Data Bytes:", []byte(extra_data))
|
t.Log("Extra Data Bytes:", []byte(extraData))
|
||||||
|
|
||||||
t.Log("Splitty thing test")
|
t.Log("Splitty thing test")
|
||||||
path = "/topics/"
|
path = "/topics/"
|
||||||
extra_data = ""
|
extraData = ""
|
||||||
t.Log("Raw Path:", path)
|
t.Log("Raw Path:", path)
|
||||||
if path[len(path)-1] != '/' {
|
if path[len(path)-1] != '/' {
|
||||||
extra_data = path[strings.LastIndexByte(path,'/') + 1:]
|
extraData = path[strings.LastIndexByte(path, '/')+1:]
|
||||||
path = path[:strings.LastIndexByte(path, '/')+1]
|
path = path[:strings.LastIndexByte(path, '/')+1]
|
||||||
}
|
}
|
||||||
t.Log("Path:", path)
|
t.Log("Path:", path)
|
||||||
t.Log("Extra Data:", extra_data)
|
t.Log("Extra Data:", extraData)
|
||||||
t.Log("Path Bytes:", []byte(path))
|
t.Log("Path Bytes:", []byte(path))
|
||||||
t.Log("Extra Data Bytes:", []byte(extra_data))
|
t.Log("Extra Data Bytes:", []byte(extraData))
|
||||||
}
|
}
|
||||||
|
69
group.go
69
group.go
@ -3,10 +3,9 @@ package main
|
|||||||
import "sync"
|
import "sync"
|
||||||
import "encoding/json"
|
import "encoding/json"
|
||||||
|
|
||||||
var group_update_mutex sync.Mutex
|
var groupUpdateMutex sync.Mutex
|
||||||
|
|
||||||
type GroupAdmin struct
|
type GroupAdmin struct {
|
||||||
{
|
|
||||||
ID int
|
ID int
|
||||||
Name string
|
Name string
|
||||||
Rank string
|
Rank string
|
||||||
@ -15,13 +14,12 @@ type GroupAdmin struct
|
|||||||
CanDelete bool
|
CanDelete bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Group struct
|
type Group struct {
|
||||||
{
|
|
||||||
ID int
|
ID int
|
||||||
Name string
|
Name string
|
||||||
Is_Mod bool
|
IsMod bool
|
||||||
Is_Admin bool
|
IsAdmin bool
|
||||||
Is_Banned bool
|
IsBanned bool
|
||||||
Tag string
|
Tag string
|
||||||
Perms Perms
|
Perms Perms
|
||||||
PermissionsText []byte
|
PermissionsText []byte
|
||||||
@ -31,37 +29,38 @@ type Group struct
|
|||||||
CanSee []int // The IDs of the forums this group can see
|
CanSee []int // The IDs of the forums this group can see
|
||||||
}
|
}
|
||||||
|
|
||||||
var group_create_mutex sync.Mutex
|
var groupCreateMutex sync.Mutex
|
||||||
func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_banned bool) (int, error) {
|
|
||||||
|
func createGroup(groupName string, tag string, isAdmin bool, isMod bool, isBanned bool) (int, error) {
|
||||||
var gid int
|
var gid int
|
||||||
err := group_entry_exists_stmt.QueryRow().Scan(&gid)
|
err := group_entry_exists_stmt.QueryRow().Scan(&gid)
|
||||||
if err != nil && err != ErrNoRows {
|
if err != nil && err != ErrNoRows {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if err != ErrNoRows {
|
if err != ErrNoRows {
|
||||||
group_update_mutex.Lock()
|
groupUpdateMutex.Lock()
|
||||||
_, err = update_group_rank_stmt.Exec(is_admin, is_mod, is_banned, gid)
|
_, err = update_group_rank_stmt.Exec(isAdmin, isMod, isBanned, gid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gid, err
|
return gid, err
|
||||||
}
|
}
|
||||||
_, err = update_group_stmt.Exec(group_name, tag, gid)
|
_, err = update_group_stmt.Exec(groupName, tag, gid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gid, err
|
return gid, err
|
||||||
}
|
}
|
||||||
|
|
||||||
groups[gid].Name = group_name
|
groups[gid].Name = groupName
|
||||||
groups[gid].Tag = tag
|
groups[gid].Tag = tag
|
||||||
groups[gid].Is_Banned = is_banned
|
groups[gid].IsBanned = isBanned
|
||||||
groups[gid].Is_Mod = is_mod
|
groups[gid].IsMod = isMod
|
||||||
groups[gid].Is_Admin = is_admin
|
groups[gid].IsAdmin = isAdmin
|
||||||
|
|
||||||
group_update_mutex.Unlock()
|
groupUpdateMutex.Unlock()
|
||||||
return gid, nil
|
return gid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
group_create_mutex.Lock()
|
groupCreateMutex.Lock()
|
||||||
var permstr string = "{}"
|
var permstr = "{}"
|
||||||
res, err := create_group_stmt.Exec(group_name, tag, is_admin, is_mod, is_banned, permstr)
|
res, err := create_group_stmt.Exec(groupName, tag, isAdmin, isMod, isBanned, permstr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -72,17 +71,17 @@ func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_
|
|||||||
}
|
}
|
||||||
gid = int(gid64)
|
gid = int(gid64)
|
||||||
|
|
||||||
var perms Perms = BlankPerms
|
var perms = BlankPerms
|
||||||
var blankForums []ForumPerms
|
var blankForums []ForumPerms
|
||||||
var blankIntList []int
|
var blankIntList []int
|
||||||
var plugin_perms map[string]bool = make(map[string]bool)
|
var pluginPerms = make(map[string]bool)
|
||||||
var plugin_perms_bytes []byte = []byte("{}")
|
var pluginPermsBytes = []byte("{}")
|
||||||
if vhooks["create_group_preappend"] != nil {
|
if vhooks["create_group_preappend"] != nil {
|
||||||
run_vhook("create_group_preappend", &plugin_perms, &plugin_perms_bytes)
|
runVhook("create_group_preappend", &pluginPerms, &pluginPermsBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
groups = append(groups, Group{gid,group_name,is_mod,is_admin,is_banned,tag,perms,[]byte(permstr),plugin_perms,plugin_perms_bytes,blankForums,blankIntList})
|
groups = append(groups, Group{gid, groupName, isMod, isAdmin, isBanned, tag, perms, []byte(permstr), pluginPerms, pluginPermsBytes, blankForums, blankIntList})
|
||||||
group_create_mutex.Unlock()
|
groupCreateMutex.Unlock()
|
||||||
|
|
||||||
// Generate the forum permissions based on the presets...
|
// Generate the forum permissions based on the presets...
|
||||||
fdata, err := fstore.GetAll()
|
fdata, err := fstore.GetAll()
|
||||||
@ -90,20 +89,20 @@ func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
permupdate_mutex.Lock()
|
permUpdateMutex.Lock()
|
||||||
for _, forum := range fdata {
|
for _, forum := range fdata {
|
||||||
var thePreset string
|
var thePreset string
|
||||||
if is_admin {
|
if isAdmin {
|
||||||
thePreset = "admins"
|
thePreset = "admins"
|
||||||
} else if is_mod {
|
} else if isMod {
|
||||||
thePreset = "staff"
|
thePreset = "staff"
|
||||||
} else if is_banned {
|
} else if isBanned {
|
||||||
thePreset = "banned"
|
thePreset = "banned"
|
||||||
} else {
|
} else {
|
||||||
thePreset = "members"
|
thePreset = "members"
|
||||||
}
|
}
|
||||||
|
|
||||||
permmap := preset_to_permmap(forum.Preset)
|
permmap := presetToPermmap(forum.Preset)
|
||||||
permitem := permmap[thePreset]
|
permitem := permmap[thePreset]
|
||||||
permitem.Overrides = true
|
permitem.Overrides = true
|
||||||
permstr, err := json.Marshal(permitem)
|
permstr, err := json.Marshal(permitem)
|
||||||
@ -116,15 +115,15 @@ func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_
|
|||||||
return gid, err
|
return gid, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = rebuild_forum_permissions(forum.ID)
|
err = rebuildForumPermissions(forum.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gid, err
|
return gid, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
permupdate_mutex.Unlock()
|
permUpdateMutex.Unlock()
|
||||||
return gid, nil
|
return gid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func group_exists(gid int) bool {
|
func groupExists(gid int) bool {
|
||||||
return (gid <= groupCapCount) && (gid > 0) && groups[gid].Name != ""
|
return (gid <= groupCapCount) && (gid > 0) && groups[gid].Name != ""
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,47 @@
|
|||||||
/* Copyright Azareal 2017 - 2018 */
|
/*
|
||||||
|
*
|
||||||
|
* Gosora Installer
|
||||||
|
* Copyright Azareal 2017 - 2018
|
||||||
|
*
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"bufio"
|
|
||||||
"strconv"
|
|
||||||
"database/sql"
|
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"../query_gen/lib"
|
"../query_gen/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
const saltLength int = 32
|
const saltLength int = 32
|
||||||
|
|
||||||
var db *sql.DB
|
var db *sql.DB
|
||||||
var scanner *bufio.Scanner
|
var scanner *bufio.Scanner
|
||||||
|
|
||||||
var db_adapter string = "mysql"
|
var dbAdapter = "mysql"
|
||||||
var db_host string
|
var dbHost string
|
||||||
var db_username string
|
var dbUsername string
|
||||||
var db_password string
|
var dbPassword string
|
||||||
var db_name string
|
var dbName string
|
||||||
var db_port string
|
var dbPort string
|
||||||
var site_name, site_url, server_port string
|
var siteName, siteURL, serverPort string
|
||||||
|
|
||||||
var default_adapter string = "mysql"
|
var defaultAdapter = "mysql"
|
||||||
var default_host string = "localhost"
|
var defaultHost = "localhost"
|
||||||
var default_username string = "root"
|
var defaultUsername = "root"
|
||||||
var default_dbname string = "gosora"
|
var defaultDbname = "gosora"
|
||||||
var default_site_name string = "Site Name"
|
var defaultSiteName = "Site Name"
|
||||||
var default_site_url string = "localhost"
|
var defaultsiteURL = "localhost"
|
||||||
var default_server_port string = "80" // 8080's a good one, if you're testing and don't want it to clash with port 80
|
var defaultServerPort = "80" // 8080's a good one, if you're testing and don't want it to clash with port 80
|
||||||
|
|
||||||
var init_database func()error = _init_mysql
|
// func() error, removing type to satisfy lint
|
||||||
var table_defs func()error = _table_defs_mysql
|
var initDatabase = _initMysql
|
||||||
var initial_data func()error = _initial_data_mysql
|
var tableDefs = _tableDefsMysql
|
||||||
|
var initialData = _initialDataMysql
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Capture panics rather than immediately closing the window on Windows
|
// Capture panics rather than immediately closing the window on Windows
|
||||||
@ -43,7 +50,7 @@ func main() {
|
|||||||
if r != nil {
|
if r != nil {
|
||||||
fmt.Println(r)
|
fmt.Println(r)
|
||||||
debug.PrintStack()
|
debug.PrintStack()
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -51,7 +58,7 @@ func main() {
|
|||||||
scanner = bufio.NewScanner(os.Stdin)
|
scanner = bufio.NewScanner(os.Stdin)
|
||||||
fmt.Println("Welcome to Gosora's Installer")
|
fmt.Println("Welcome to Gosora's Installer")
|
||||||
fmt.Println("We're going to take you through a few steps to help you get started :)")
|
fmt.Println("We're going to take you through a few steps to help you get started :)")
|
||||||
if !get_database_details() {
|
if !getDatabaseDetails() {
|
||||||
err := scanner.Err()
|
err := scanner.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@ -59,11 +66,11 @@ func main() {
|
|||||||
fmt.Println("Something went wrong!")
|
fmt.Println("Something went wrong!")
|
||||||
}
|
}
|
||||||
fmt.Println("Aborting installation...")
|
fmt.Println("Aborting installation...")
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !get_site_details() {
|
if !getSiteDetails() {
|
||||||
err := scanner.Err()
|
err := scanner.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@ -71,66 +78,66 @@ func main() {
|
|||||||
fmt.Println("Something went wrong!")
|
fmt.Println("Something went wrong!")
|
||||||
}
|
}
|
||||||
fmt.Println("Aborting installation...")
|
fmt.Println("Aborting installation...")
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := init_database()
|
err := initDatabase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
fmt.Println("Aborting installation...")
|
fmt.Println("Aborting installation...")
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = table_defs()
|
err = tableDefs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
fmt.Println("Aborting installation...")
|
fmt.Println("Aborting installation...")
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hashed_password, salt, err := BcryptGeneratePassword("password")
|
hashedPassword, salt, err := BcryptGeneratePassword("password")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
fmt.Println("Aborting installation...")
|
fmt.Println("Aborting installation...")
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the admin user query
|
// Build the admin user query
|
||||||
admin_user_stmt, err := qgen.Builder.SimpleInsert("users","name, password, salt, email, group, is_super_admin, active, createdAt, lastActiveAt, message, last_ip","'Admin',?,?,'admin@localhost',1,1,1,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'','127.0.0.1'")
|
adminUserStmt, err := qgen.Builder.SimpleInsert("users", "name, password, salt, email, group, is_super_admin, active, createdAt, lastActiveAt, message, last_ip", "'Admin',?,?,'admin@localhost',1,1,1,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'','127.0.0.1'")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
fmt.Println("Aborting installation...")
|
fmt.Println("Aborting installation...")
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the admin user query
|
// Run the admin user query
|
||||||
_, err = admin_user_stmt.Exec(hashed_password,salt)
|
_, err = adminUserStmt.Exec(hashedPassword, salt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
fmt.Println("Aborting installation...")
|
fmt.Println("Aborting installation...")
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = initial_data()
|
err = initialData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
fmt.Println("Aborting installation...")
|
fmt.Println("Aborting installation...")
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if db_adapter == "mysql" {
|
if dbAdapter == "mysql" {
|
||||||
err = _mysql_seed_database()
|
err = _mysqlSeedDatabase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
fmt.Println("Aborting installation...")
|
fmt.Println("Aborting installation...")
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,10 +146,10 @@ func main() {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Site Info
|
// Site Info
|
||||||
site.Name = "` + site_name + `" // Should be a setting in the database
|
site.Name = "` + siteName + `" // Should be a setting in the database
|
||||||
site.Email = "" // Should be a setting in the database
|
site.Email = "" // Should be a setting in the database
|
||||||
site.Url = "` + site_url + `"
|
site.Url = "` + siteURL + `"
|
||||||
site.Port = "` + server_port + `"
|
site.Port = "` + serverPort + `"
|
||||||
site.EnableSsl = false
|
site.EnableSsl = false
|
||||||
site.EnableEmails = false
|
site.EnableEmails = false
|
||||||
site.HasProxy = false // Cloudflare counts as this, if it's sitting in the middle
|
site.HasProxy = false // Cloudflare counts as this, if it's sitting in the middle
|
||||||
@ -150,11 +157,11 @@ config.SslPrivkey = ""
|
|||||||
config.SslFullchain = ""
|
config.SslFullchain = ""
|
||||||
|
|
||||||
// Database details
|
// Database details
|
||||||
db_config.Host = "` + db_host + `"
|
db_config.Host = "` + dbHost + `"
|
||||||
db_config.Username = "` + db_username + `"
|
db_config.Username = "` + dbUsername + `"
|
||||||
db_config.Password = "` + db_password + `"
|
db_config.Password = "` + dbPassword + `"
|
||||||
db_config.Dbname = "` + db_name + `"
|
db_config.Dbname = "` + dbName + `"
|
||||||
db_config.Port = "` + db_port + `" // You probably won't need to change this
|
db_config.Port = "` + dbPort + `" // You probably won't need to change this
|
||||||
|
|
||||||
// Limiters
|
// Limiters
|
||||||
config.MaxRequestSize = 5 * megabyte
|
config.MaxRequestSize = 5 * megabyte
|
||||||
@ -195,7 +202,7 @@ dev.DebugMode = true
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
fmt.Println("Aborting installation...")
|
fmt.Println("Aborting installation...")
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +211,7 @@ dev.DebugMode = true
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
fmt.Println("Aborting installation...")
|
fmt.Println("Aborting installation...")
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,121 +221,122 @@ dev.DebugMode = true
|
|||||||
|
|
||||||
fmt.Println("Yay, you have successfully installed Gosora!")
|
fmt.Println("Yay, you have successfully installed Gosora!")
|
||||||
fmt.Println("Your name is Admin and you can login with the password 'password'. Don't forget to change it! Seriously. It's really insecure.")
|
fmt.Println("Your name is Admin and you can login with the password 'password'. Don't forget to change it! Seriously. It's really insecure.")
|
||||||
press_any_key()
|
pressAnyKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
func get_database_details() bool {
|
func getDatabaseDetails() bool {
|
||||||
fmt.Println("Which database driver do you wish to use? mysql, mysql, or mysql? Default: mysql")
|
fmt.Println("Which database driver do you wish to use? mysql, mysql, or mysql? Default: mysql")
|
||||||
if !scanner.Scan() {
|
if !scanner.Scan() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
db_adapter = scanner.Text()
|
dbAdapter = scanner.Text()
|
||||||
if db_adapter == "" {
|
if dbAdapter == "" {
|
||||||
db_adapter = default_adapter
|
dbAdapter = defaultAdapter
|
||||||
}
|
}
|
||||||
db_adapter = set_db_adapter(db_adapter)
|
dbAdapter = setDBAdapter(dbAdapter)
|
||||||
fmt.Println("Set database adapter to " + db_adapter)
|
fmt.Println("Set database adapter to " + dbAdapter)
|
||||||
|
|
||||||
fmt.Println("Database Host? Default: " + default_host)
|
fmt.Println("Database Host? Default: " + defaultHost)
|
||||||
if !scanner.Scan() {
|
if !scanner.Scan() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
db_host = scanner.Text()
|
dbHost = scanner.Text()
|
||||||
if db_host == "" {
|
if dbHost == "" {
|
||||||
db_host = default_host
|
dbHost = defaultHost
|
||||||
}
|
}
|
||||||
fmt.Println("Set database host to " + db_host)
|
fmt.Println("Set database host to " + dbHost)
|
||||||
|
|
||||||
fmt.Println("Database Username? Default: " + default_username)
|
fmt.Println("Database Username? Default: " + defaultUsername)
|
||||||
if !scanner.Scan() {
|
if !scanner.Scan() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
db_username = scanner.Text()
|
dbUsername = scanner.Text()
|
||||||
if db_username == "" {
|
if dbUsername == "" {
|
||||||
db_username = default_username
|
dbUsername = defaultUsername
|
||||||
}
|
}
|
||||||
fmt.Println("Set database username to " + db_username)
|
fmt.Println("Set database username to " + dbUsername)
|
||||||
|
|
||||||
fmt.Println("Database Password? Default: ''")
|
fmt.Println("Database Password? Default: ''")
|
||||||
if !scanner.Scan() {
|
if !scanner.Scan() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
db_password = scanner.Text()
|
dbPassword = scanner.Text()
|
||||||
if len(db_password) == 0 {
|
if len(dbPassword) == 0 {
|
||||||
fmt.Println("You didn't set a password for this user. This won't block the installation process, but it might create security issues in the future.\n")
|
fmt.Println("You didn't set a password for this user. This won't block the installation process, but it might create security issues in the future.")
|
||||||
|
fmt.Println("")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Set password to " + obfuscate_password(db_password))
|
fmt.Println("Set password to " + obfuscatePassword(dbPassword))
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Database Name? Pick a name you like or one provided to you. Default: " + default_dbname)
|
fmt.Println("Database Name? Pick a name you like or one provided to you. Default: " + defaultDbname)
|
||||||
if !scanner.Scan() {
|
if !scanner.Scan() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
db_name = scanner.Text()
|
dbName = scanner.Text()
|
||||||
if db_name == "" {
|
if dbName == "" {
|
||||||
db_name = default_dbname
|
dbName = defaultDbname
|
||||||
}
|
}
|
||||||
fmt.Println("Set database name to " + db_name)
|
fmt.Println("Set database name to " + dbName)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func get_site_details() bool {
|
func getSiteDetails() bool {
|
||||||
fmt.Println("Okay. We also need to know some actual information about your site!")
|
fmt.Println("Okay. We also need to know some actual information about your site!")
|
||||||
fmt.Println("What's your site's name? Default: " + default_site_name)
|
fmt.Println("What's your site's name? Default: " + defaultSiteName)
|
||||||
if !scanner.Scan() {
|
if !scanner.Scan() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
site_name = scanner.Text()
|
siteName = scanner.Text()
|
||||||
if site_name == "" {
|
if siteName == "" {
|
||||||
site_name = default_site_name
|
siteName = defaultSiteName
|
||||||
}
|
}
|
||||||
fmt.Println("Set the site name to " + site_name)
|
fmt.Println("Set the site name to " + siteName)
|
||||||
|
|
||||||
fmt.Println("What's your site's url? Default: " + default_site_url)
|
fmt.Println("What's your site's url? Default: " + defaultsiteURL)
|
||||||
if !scanner.Scan() {
|
if !scanner.Scan() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
site_url = scanner.Text()
|
siteURL = scanner.Text()
|
||||||
if site_url == "" {
|
if siteURL == "" {
|
||||||
site_url = default_site_url
|
siteURL = defaultsiteURL
|
||||||
}
|
}
|
||||||
fmt.Println("Set the site url to " + site_url)
|
fmt.Println("Set the site url to " + siteURL)
|
||||||
|
|
||||||
fmt.Println("What port do you want the server to listen on? If you don't know what this means, you should probably leave it on the default. Default: " + default_server_port)
|
fmt.Println("What port do you want the server to listen on? If you don't know what this means, you should probably leave it on the default. Default: " + defaultServerPort)
|
||||||
if !scanner.Scan() {
|
if !scanner.Scan() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
server_port = scanner.Text()
|
serverPort = scanner.Text()
|
||||||
if server_port == "" {
|
if serverPort == "" {
|
||||||
server_port = default_server_port
|
serverPort = defaultServerPort
|
||||||
}
|
}
|
||||||
_, err := strconv.Atoi(server_port)
|
_, err := strconv.Atoi(serverPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("That's not a valid number!")
|
fmt.Println("That's not a valid number!")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
fmt.Println("Set the server port to " + server_port)
|
fmt.Println("Set the server port to " + serverPort)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func set_db_adapter(name string) string {
|
func setDBAdapter(name string) string {
|
||||||
switch(name) {
|
switch name {
|
||||||
//case "wip-pgsql":
|
//case "wip-pgsql":
|
||||||
// set_pgsql_adapter()
|
// set_pgsql_adapter()
|
||||||
// return "wip-pgsql"
|
// return "wip-pgsql"
|
||||||
}
|
}
|
||||||
_set_mysql_adapter()
|
_setMysqlAdapter()
|
||||||
return "mysql"
|
return "mysql"
|
||||||
}
|
}
|
||||||
|
|
||||||
func obfuscate_password(password string) (out string) {
|
func obfuscatePassword(password string) (out string) {
|
||||||
for i := 0; i < len(password); i++ {
|
for i := 0; i < len(password); i++ {
|
||||||
out += "*"
|
out += "*"
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func press_any_key() {
|
func pressAnyKey() {
|
||||||
//fmt.Println("Press any key to exit...")
|
//fmt.Println("Press any key to exit...")
|
||||||
fmt.Println("Please press enter to exit...")
|
fmt.Println("Please press enter to exit...")
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
|
@ -1,34 +1,39 @@
|
|||||||
/* Copyright Azareal 2017 - 2018 */
|
/*
|
||||||
|
*
|
||||||
|
* Gosora MySQL Interface
|
||||||
|
* Copyright Azareal 2017 - 2018
|
||||||
|
*
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
"database/sql"
|
||||||
"strconv"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"database/sql"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"../query_gen/lib"
|
"../query_gen/lib"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
)
|
)
|
||||||
|
|
||||||
//var db_collation string = "utf8mb4_general_ci"
|
//var dbCollation string = "utf8mb4_general_ci"
|
||||||
|
|
||||||
func _set_mysql_adapter() {
|
func _setMysqlAdapter() {
|
||||||
db_port = "3306"
|
dbPort = "3306"
|
||||||
init_database = _init_mysql
|
initDatabase = _initMysql
|
||||||
table_defs = _table_defs_mysql
|
tableDefs = _tableDefsMysql
|
||||||
initial_data = _initial_data_mysql
|
initialData = _initialDataMysql
|
||||||
}
|
}
|
||||||
|
|
||||||
func _init_mysql() (err error) {
|
func _initMysql() (err error) {
|
||||||
_db_password := db_password
|
_dbPassword := dbPassword
|
||||||
if _db_password != "" {
|
if _dbPassword != "" {
|
||||||
_db_password = ":" + _db_password
|
_dbPassword = ":" + _dbPassword
|
||||||
}
|
}
|
||||||
db, err = sql.Open("mysql",db_username + _db_password + "@tcp(" + db_host + ":" + db_port + ")/")
|
db, err = sql.Open("mysql", dbUsername+_dbPassword+"@tcp("+dbHost+":"+dbPort+")/")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -41,22 +46,22 @@ func _init_mysql() (err error) {
|
|||||||
fmt.Println("Successfully connected to the database")
|
fmt.Println("Successfully connected to the database")
|
||||||
|
|
||||||
var waste string
|
var waste string
|
||||||
err = db.QueryRow("SHOW DATABASES LIKE '" + db_name + "'").Scan(&waste)
|
err = db.QueryRow("SHOW DATABASES LIKE '" + dbName + "'").Scan(&waste)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
fmt.Println("Unable to find the database. Attempting to create it")
|
fmt.Println("Unable to find the database. Attempting to create it")
|
||||||
_,err = db.Exec("CREATE DATABASE IF NOT EXISTS " + db_name + "")
|
_, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + dbName + "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("The database was successfully created")
|
fmt.Println("The database was successfully created")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Switching to database " + db_name)
|
fmt.Println("Switching to database " + dbName)
|
||||||
_, err = db.Exec("USE " + db_name)
|
_, err = db.Exec("USE " + dbName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -71,7 +76,7 @@ func _init_mysql() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func _table_defs_mysql() error {
|
func _tableDefsMysql() error {
|
||||||
//fmt.Println("Creating the tables")
|
//fmt.Println("Creating the tables")
|
||||||
files, _ := ioutil.ReadDir("./schema/mysql/")
|
files, _ := ioutil.ReadDir("./schema/mysql/")
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
@ -105,10 +110,10 @@ func _table_defs_mysql() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func _initial_data_mysql() error {
|
func _initialDataMysql() error {
|
||||||
return nil // Coming Soon
|
return nil // Coming Soon
|
||||||
|
|
||||||
fmt.Println("Seeding the tables")
|
/*fmt.Println("Seeding the tables")
|
||||||
data, err := ioutil.ReadFile("./schema/mysql/inserts.sql")
|
data, err := ioutil.ReadFile("./schema/mysql/inserts.sql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -122,10 +127,10 @@ func _initial_data_mysql() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//fmt.Println("Finished inserting the database data")
|
//fmt.Println("Finished inserting the database data")
|
||||||
return nil
|
return nil*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func _mysql_seed_database() error {
|
func _mysqlSeedDatabase() error {
|
||||||
fmt.Println("Opening the database seed file")
|
fmt.Println("Opening the database seed file")
|
||||||
sqlContents, err := ioutil.ReadFile("./mysql.sql")
|
sqlContents, err := ioutil.ReadFile("./mysql.sql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
/* Under heavy development */
|
/*
|
||||||
/* Copyright Azareal 2017 - 2018 */
|
*
|
||||||
|
* Gosora PostgreSQL Interface
|
||||||
|
* Under heavy development
|
||||||
|
* Copyright Azareal 2017 - 2018
|
||||||
|
*
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
@ -8,19 +13,19 @@ import "database/sql"
|
|||||||
import _ "github.com/go-sql-driver/mysql"
|
import _ "github.com/go-sql-driver/mysql"
|
||||||
|
|
||||||
// We don't need SSL to run an installer... Do we?
|
// We don't need SSL to run an installer... Do we?
|
||||||
var db_sslmode = "disable"
|
var dbSslmode = "disable"
|
||||||
|
|
||||||
func _set_pgsql_adapter() {
|
func _setPgsqlAdapter() {
|
||||||
db_port = "5432"
|
dbPort = "5432"
|
||||||
init_database = _init_pgsql
|
initDatabase = _initPgsql
|
||||||
}
|
}
|
||||||
|
|
||||||
func _init_pgsql() (err error) {
|
func _initPgsql() (err error) {
|
||||||
_db_password := db_password
|
_dbPassword := dbPassword
|
||||||
if _db_password != "" {
|
if _dbPassword != "" {
|
||||||
_db_password = " password=" + _pg_escape_bit(_db_password)
|
_dbPassword = " password=" + _pgEscapeBit(_dbPassword)
|
||||||
}
|
}
|
||||||
db, err = sql.Open("postgres", "host='" + _pg_escape_bit(db_host) + "' port='" + _pg_escape_bit(db_port) + "' user='" + _pg_escape_bit(db_username) + "' dbname='" + _pg_escape_bit(db_name) + "'" + _db_password + " sslmode='" + db_sslmode + "'")
|
db, err = sql.Open("postgres", "host='"+_pgEscapeBit(dbHost)+"' port='"+_pgEscapeBit(dbPort)+"' user='"+_pgEscapeBit(dbUsername)+"' dbname='"+_pgEscapeBit(dbName)+"'"+_dbPassword+" sslmode='"+dbSslmode+"'")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -31,7 +36,7 @@ func _init_pgsql() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func _pg_escape_bit(bit string) string {
|
func _pgEscapeBit(bit string) string {
|
||||||
// TO-DO: Write a custom parser, so that backslashes work properly in the sql.Open string. Do something similar for the database driver, if possible?
|
// TO-DO: Write a custom parser, so that backslashes work properly in the sql.Open string. Do something similar for the database driver, if possible?
|
||||||
return strings.Replace(bit, "'", "\\'", -1)
|
return strings.Replace(bit, "'", "\\'", -1)
|
||||||
}
|
}
|
@ -14,24 +14,25 @@ func GenerateSafeString(length int) (string, error) {
|
|||||||
return base64.URLEncoding.EncodeToString(rb), nil
|
return base64.URLEncoding.EncodeToString(rb), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func BcryptGeneratePassword(password string) (hashed_password string, salt string, err error) {
|
// Generate a bcrypt hash from a password and a salt
|
||||||
|
func BcryptGeneratePassword(password string) (hashedPassword string, salt string, err error) {
|
||||||
salt, err = GenerateSafeString(saltLength)
|
salt, err = GenerateSafeString(saltLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
password = password + salt
|
password = password + salt
|
||||||
hashed_password, err = BcryptGeneratePasswordNoSalt(password)
|
hashedPassword, err = bcryptGeneratePasswordNoSalt(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
return hashed_password, salt, nil
|
return hashedPassword, salt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func BcryptGeneratePasswordNoSalt(password string) (hash string, err error) {
|
func bcryptGeneratePasswordNoSalt(password string) (hash string, err error) {
|
||||||
hashed_password, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(hashed_password), nil
|
return string(hashedPassword), nil
|
||||||
}
|
}
|
||||||
|
67
main.go
67
main.go
@ -3,17 +3,17 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"log"
|
||||||
"sync/atomic"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
//"runtime/pprof"
|
//"runtime/pprof"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version Version = Version{Major:0,Minor:1,Patch:0,Tag:"dev"}
|
var version = Version{Major: 0, Minor: 1, Patch: 0, Tag: "dev"}
|
||||||
|
|
||||||
const hour int = 60 * 60
|
const hour int = 60 * 60
|
||||||
const day int = hour * 24
|
const day int = hour * 24
|
||||||
@ -26,17 +26,18 @@ const gigabyte int = megabyte * 1024
|
|||||||
const terabyte int = gigabyte * 1024
|
const terabyte int = gigabyte * 1024
|
||||||
const saltLength int = 32
|
const saltLength int = 32
|
||||||
const sessionLength int = 80
|
const sessionLength int = 80
|
||||||
var enable_websockets bool = false // Don't change this, the value is overwritten by an initialiser
|
|
||||||
|
var enableWebsockets = false // Don't change this, the value is overwritten by an initialiser
|
||||||
|
|
||||||
var router *GenRouter
|
var router *GenRouter
|
||||||
var startTime time.Time
|
var startTime time.Time
|
||||||
var external_sites map[string]string = map[string]string{
|
var externalSites = map[string]string{
|
||||||
"YT": "https://www.youtube.com/",
|
"YT": "https://www.youtube.com/",
|
||||||
}
|
}
|
||||||
var groups []Group
|
var groups []Group
|
||||||
var groupCapCount int
|
var groupCapCount int
|
||||||
var static_files map[string]SFile = make(map[string]SFile)
|
var staticFiles = make(map[string]SFile)
|
||||||
var logWriter io.Writer = io.MultiWriter(os.Stderr)
|
var logWriter = io.MultiWriter(os.Stderr)
|
||||||
|
|
||||||
type WordFilter struct {
|
type WordFilter struct {
|
||||||
ID int
|
ID int
|
||||||
@ -44,20 +45,21 @@ type WordFilter struct {
|
|||||||
Replacement string
|
Replacement string
|
||||||
}
|
}
|
||||||
type WordFilterBox map[int]WordFilter
|
type WordFilterBox map[int]WordFilter
|
||||||
|
|
||||||
var wordFilterBox atomic.Value // An atomic value holding a WordFilterBox
|
var wordFilterBox atomic.Value // An atomic value holding a WordFilterBox
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
wordFilterBox.Store(WordFilterBox(make(map[int]WordFilter)))
|
wordFilterBox.Store(WordFilterBox(make(map[int]WordFilter)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func init_word_filters() error {
|
func initWordFilters() error {
|
||||||
rows, err := get_word_filters_stmt.Query()
|
rows, err := get_word_filters_stmt.Query()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
var wordFilters WordFilterBox = wordFilterBox.Load().(WordFilterBox)
|
var wordFilters = wordFilterBox.Load().(WordFilterBox)
|
||||||
var wfid int
|
var wfid int
|
||||||
var find string
|
var find string
|
||||||
var replacement string
|
var replacement string
|
||||||
@ -73,13 +75,13 @@ func init_word_filters() error {
|
|||||||
return rows.Err()
|
return rows.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func add_word_filter(id int, find string, replacement string) {
|
func addWordFilter(id int, find string, replacement string) {
|
||||||
wordFilters := wordFilterBox.Load().(WordFilterBox)
|
wordFilters := wordFilterBox.Load().(WordFilterBox)
|
||||||
wordFilters[id] = WordFilter{ID: id, Find: find, Replacement: replacement}
|
wordFilters[id] = WordFilter{ID: id, Find: find, Replacement: replacement}
|
||||||
wordFilterBox.Store(wordFilters)
|
wordFilterBox.Store(wordFilters)
|
||||||
}
|
}
|
||||||
|
|
||||||
func process_config() {
|
func processConfig() {
|
||||||
config.Noavatar = strings.Replace(config.Noavatar, "{site_url}", site.Url, -1)
|
config.Noavatar = strings.Replace(config.Noavatar, "{site_url}", site.Url, -1)
|
||||||
if site.Port != "80" && site.Port != "443" {
|
if site.Port != "80" && site.Port != "443" {
|
||||||
site.Url = strings.TrimSuffix(site.Url, "/")
|
site.Url = strings.TrimSuffix(site.Url, "/")
|
||||||
@ -113,16 +115,20 @@ func main(){
|
|||||||
//timeLocation = startTime.Location()
|
//timeLocation = startTime.Location()
|
||||||
|
|
||||||
log.Print("Processing configuration data")
|
log.Print("Processing configuration data")
|
||||||
process_config()
|
processConfig()
|
||||||
|
|
||||||
init_themes()
|
err = initThemes()
|
||||||
err = init_database()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
init_templates()
|
err = initDatabase()
|
||||||
err = init_errors()
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
initTemplates()
|
||||||
|
err = initErrors()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -135,10 +141,14 @@ func main(){
|
|||||||
topics = NewSqlTopicStore()
|
topics = NewSqlTopicStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
init_static_files()
|
log.Print("Loading the static files.")
|
||||||
|
err = initStaticFiles()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
log.Print("Initialising the widgets")
|
log.Print("Initialising the widgets")
|
||||||
err = init_widgets()
|
err = initWidgets()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -146,21 +156,21 @@ func main(){
|
|||||||
log.Print("Initialising the authentication system")
|
log.Print("Initialising the authentication system")
|
||||||
auth = NewDefaultAuth()
|
auth = NewDefaultAuth()
|
||||||
|
|
||||||
err = init_word_filters()
|
err = initWordFilters()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run this goroutine once a second
|
// Run this goroutine once a second
|
||||||
second_ticker := time.NewTicker(1 * time.Second)
|
secondTicker := time.NewTicker(1 * time.Second)
|
||||||
fifteen_minute_ticker := time.NewTicker(15 * time.Minute)
|
fifteenMinuteTicker := time.NewTicker(15 * time.Minute)
|
||||||
//hour_ticker := time.NewTicker(1 * time.Hour)
|
//hour_ticker := time.NewTicker(1 * time.Hour)
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <- second_ticker.C:
|
case <-secondTicker.C:
|
||||||
//log.Print("Running the second ticker")
|
//log.Print("Running the second ticker")
|
||||||
err := handle_expired_scheduled_groups()
|
err := handleExpiredScheduledGroups()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError(err)
|
LogError(err)
|
||||||
}
|
}
|
||||||
@ -170,7 +180,7 @@ func main(){
|
|||||||
// TO-DO: Manage the TopicStore, UserStore, and ForumStore
|
// TO-DO: Manage the TopicStore, UserStore, and ForumStore
|
||||||
// TO-DO: Alert the admin, if CPU usage, RAM usage, or the number of posts in the past second are too high
|
// TO-DO: Alert the admin, if CPU usage, RAM usage, or the number of posts in the past second are too high
|
||||||
// TO-DO: Clean-up alerts with no unread matches which are over two weeks old. Move this to a 24 hour task?
|
// TO-DO: Clean-up alerts with no unread matches which are over two weeks old. Move this to a 24 hour task?
|
||||||
case <- fifteen_minute_ticker.C:
|
case <-fifteenMinuteTicker.C:
|
||||||
// TO-DO: Automatically lock topics, if they're really old, and the associated setting is enabled.
|
// TO-DO: Automatically lock topics, if they're really old, and the associated setting is enabled.
|
||||||
// TO-DO: Publish scheduled posts.
|
// TO-DO: Publish scheduled posts.
|
||||||
// TO-DO: Delete the empty users_groups_scheduler entries
|
// TO-DO: Delete the empty users_groups_scheduler entries
|
||||||
@ -231,6 +241,7 @@ func main(){
|
|||||||
router.HandleFunc("/users/ban/submit/", route_ban_submit)
|
router.HandleFunc("/users/ban/submit/", route_ban_submit)
|
||||||
router.HandleFunc("/users/unban/", route_unban)
|
router.HandleFunc("/users/unban/", route_unban)
|
||||||
router.HandleFunc("/users/activate/", route_activate)
|
router.HandleFunc("/users/activate/", route_activate)
|
||||||
|
router.HandleFunc("/users/ips/", route_ips)
|
||||||
|
|
||||||
// The Control Panel
|
// The Control Panel
|
||||||
///router.HandleFunc("/panel/", route_panel)
|
///router.HandleFunc("/panel/", route_panel)
|
||||||
@ -267,7 +278,7 @@ func main(){
|
|||||||
router.HandleFunc("/ws/", route_websockets)
|
router.HandleFunc("/ws/", route_websockets)
|
||||||
|
|
||||||
log.Print("Initialising the plugins")
|
log.Print("Initialising the plugins")
|
||||||
init_plugins()
|
initPlugins()
|
||||||
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
|
37
misc_test.go
37
misc_test.go
@ -6,10 +6,13 @@ import "testing"
|
|||||||
// TO-DO: Generate a test database to work with rather than a live one
|
// TO-DO: Generate a test database to work with rather than a live one
|
||||||
func TestUserStore(t *testing.T) {
|
func TestUserStore(t *testing.T) {
|
||||||
if !gloinited {
|
if !gloinited {
|
||||||
gloinit()
|
err := gloinit()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !plugins_inited {
|
}
|
||||||
init_plugins()
|
if !pluginsInited {
|
||||||
|
initPlugins()
|
||||||
}
|
}
|
||||||
|
|
||||||
var user *User
|
var user *User
|
||||||
@ -42,12 +45,12 @@ func TestUserStore(t *testing.T) {
|
|||||||
|
|
||||||
// TO-DO: Lock onto the specific error type. Is this even possible without sacrificing the detailed information in the error message?
|
// TO-DO: Lock onto the specific error type. Is this even possible without sacrificing the detailed information in the error message?
|
||||||
var userList map[int]*User
|
var userList map[int]*User
|
||||||
userList, err = users.BulkCascadeGetMap([]int{-1})
|
_, err = users.BulkCascadeGetMap([]int{-1})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("UID #-1 shouldn't exist")
|
t.Error("UID #-1 shouldn't exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
userList, err = users.BulkCascadeGetMap([]int{0})
|
_, err = users.BulkCascadeGetMap([]int{0})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("UID #0 shouldn't exist")
|
t.Error("UID #0 shouldn't exist")
|
||||||
}
|
}
|
||||||
@ -80,8 +83,8 @@ func TestForumStore(t *testing.T) {
|
|||||||
if !gloinited {
|
if !gloinited {
|
||||||
gloinit()
|
gloinit()
|
||||||
}
|
}
|
||||||
if !plugins_inited {
|
if !pluginsInited {
|
||||||
init_plugins()
|
initPlugins()
|
||||||
}
|
}
|
||||||
|
|
||||||
var forum *Forum
|
var forum *Forum
|
||||||
@ -155,7 +158,7 @@ func TestSlugs(t *testing.T) {
|
|||||||
|
|
||||||
for _, item := range msgList {
|
for _, item := range msgList {
|
||||||
t.Log("Testing string '" + item.Msg + "'")
|
t.Log("Testing string '" + item.Msg + "'")
|
||||||
res = name_to_slug(item.Msg)
|
res = nameToSlug(item.Msg)
|
||||||
if res != item.Expects {
|
if res != item.Expects {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected:", item.Expects)
|
t.Error("Expected:", item.Expects)
|
||||||
@ -165,25 +168,25 @@ func TestSlugs(t *testing.T) {
|
|||||||
|
|
||||||
func TestAuth(t *testing.T) {
|
func TestAuth(t *testing.T) {
|
||||||
// bcrypt likes doing stupid things, so this test will probably fail
|
// bcrypt likes doing stupid things, so this test will probably fail
|
||||||
var real_password string
|
var realPassword string
|
||||||
var hashed_password string
|
var hashedPassword string
|
||||||
var password string
|
var password string
|
||||||
var salt string
|
var salt string
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
/* No extra salt tests, we might not need this extra salt, as bcrypt has it's own? */
|
/* No extra salt tests, we might not need this extra salt, as bcrypt has it's own? */
|
||||||
real_password = "Madame Cassandra's Mystic Orb"
|
realPassword = "Madame Cassandra's Mystic Orb"
|
||||||
t.Log("Set real_password to '" + real_password + "'")
|
t.Log("Set real_password to '" + realPassword + "'")
|
||||||
t.Log("Hashing the real password")
|
t.Log("Hashing the real password")
|
||||||
hashed_password, err = BcryptGeneratePasswordNoSalt(real_password)
|
hashedPassword, err = BcryptGeneratePasswordNoSalt(realPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
password = real_password
|
password = realPassword
|
||||||
t.Log("Testing password '" + password + "'")
|
t.Log("Testing password '" + password + "'")
|
||||||
t.Log("Testing salt '" + salt + "'")
|
t.Log("Testing salt '" + salt + "'")
|
||||||
err = CheckPassword(hashed_password,password,salt)
|
err = CheckPassword(hashedPassword, password, salt)
|
||||||
if err == ErrMismatchedHashAndPassword {
|
if err == ErrMismatchedHashAndPassword {
|
||||||
t.Error("The two don't match")
|
t.Error("The two don't match")
|
||||||
} else if err == ErrPasswordTooLong {
|
} else if err == ErrPasswordTooLong {
|
||||||
@ -195,7 +198,7 @@ func TestAuth(t *testing.T) {
|
|||||||
password = "hahaha"
|
password = "hahaha"
|
||||||
t.Log("Testing password '" + password + "'")
|
t.Log("Testing password '" + password + "'")
|
||||||
t.Log("Testing salt '" + salt + "'")
|
t.Log("Testing salt '" + salt + "'")
|
||||||
err = CheckPassword(hashed_password,password,salt)
|
err = CheckPassword(hashedPassword, password, salt)
|
||||||
if err == ErrPasswordTooLong {
|
if err == ErrPasswordTooLong {
|
||||||
t.Error("CheckPassword thinks the password is too long")
|
t.Error("CheckPassword thinks the password is too long")
|
||||||
} else if err == nil {
|
} else if err == nil {
|
||||||
@ -205,7 +208,7 @@ func TestAuth(t *testing.T) {
|
|||||||
password = "Madame Cassandra's Mystic"
|
password = "Madame Cassandra's Mystic"
|
||||||
t.Log("Testing password '" + password + "'")
|
t.Log("Testing password '" + password + "'")
|
||||||
t.Log("Testing salt '" + salt + "'")
|
t.Log("Testing salt '" + salt + "'")
|
||||||
err = CheckPassword(hashed_password,password,salt)
|
err = CheckPassword(hashedPassword, password, salt)
|
||||||
if err == ErrPasswordTooLong {
|
if err == ErrPasswordTooLong {
|
||||||
t.Error("CheckPassword thinks the password is too long")
|
t.Error("CheckPassword thinks the password is too long")
|
||||||
} else if err == nil {
|
} else if err == nil {
|
||||||
|
291
mod_routes.go
291
mod_routes.go
@ -3,11 +3,11 @@ package main
|
|||||||
import (
|
import (
|
||||||
//"log"
|
//"log"
|
||||||
//"fmt"
|
//"fmt"
|
||||||
"strconv"
|
"html"
|
||||||
"time"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"html"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func route_edit_topic(w http.ResponseWriter, r *http.Request, user User) {
|
func route_edit_topic(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
@ -17,44 +17,42 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
PreError("Bad Form", w, r)
|
PreError("Bad Form", w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
is_js := r.PostFormValue("js")
|
isJs := (r.PostFormValue("js") == "1")
|
||||||
if is_js == "" {
|
|
||||||
is_js = "0"
|
|
||||||
}
|
|
||||||
|
|
||||||
var tid int
|
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 {
|
if err != nil {
|
||||||
PreErrorJSQ("The provided TopicID is not a valid number.",w,r,is_js)
|
PreErrorJSQ("The provided TopicID is not a valid number.", w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
old_topic, err := topics.CascadeGet(tid)
|
oldTopic, err := topics.CascadeGet(tid)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
PreErrorJSQ("The topic you tried to edit doesn't exist.",w,r,is_js)
|
PreErrorJSQ("The topic you tried to edit doesn't exist.", w, r, isJs)
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := SimpleForumSessionCheck(w,r,&user,old_topic.ParentID)
|
// TO-DO: Add hooks to make use of headerLite
|
||||||
|
_, ok := SimpleForumSessionCheck(w, r, &user, oldTopic.ParentID)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !user.Perms.ViewTopic || !user.Perms.EditTopic {
|
if !user.Perms.ViewTopic || !user.Perms.EditTopic {
|
||||||
NoPermissionsJSQ(w,r,user,is_js)
|
NoPermissionsJSQ(w, r, user, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
topic_name := r.PostFormValue("topic_name")
|
topicName := r.PostFormValue("topic_name")
|
||||||
topic_status := r.PostFormValue("topic_status")
|
topicStatus := r.PostFormValue("topic_status")
|
||||||
is_closed := (topic_status == "closed")
|
isClosed := (topicStatus == "closed")
|
||||||
|
|
||||||
topic_content := html.EscapeString(r.PostFormValue("topic_content"))
|
topicContent := html.EscapeString(r.PostFormValue("topic_content"))
|
||||||
_, err = edit_topic_stmt.Exec(topic_name, preparse_message(topic_content), parse_message(html.EscapeString(preparse_message(topic_content))), is_closed, tid)
|
_, err = edit_topic_stmt.Exec(topicName, preparseMessage(topicContent), parseMessage(html.EscapeString(preparseMessage(topicContent))), isClosed, tid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,9 +62,9 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if old_topic.Is_Closed != is_closed {
|
if oldTopic.IsClosed != isClosed {
|
||||||
var action string
|
var action string
|
||||||
if is_closed {
|
if isClosed {
|
||||||
action = "lock"
|
action = "lock"
|
||||||
} else {
|
} else {
|
||||||
action = "unlock"
|
action = "unlock"
|
||||||
@ -87,7 +85,7 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = fstore.UpdateLastTopic(topic_name,tid,user.Name,user.ID,time.Now().Format("2006-01-02 15:04:05"),old_topic.ParentID)
|
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 {
|
if err != nil && err != ErrNoRows {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
@ -96,17 +94,17 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
|
|
||||||
err = topics.Load(tid)
|
err = topics.Load(tid)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
LocalErrorJSQ("This topic no longer exists!",w,r,user,is_js)
|
LocalErrorJSQ("This topic no longer exists!", w, r, user, isJs)
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_js == "0" {
|
if !isJs {
|
||||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||||
} else {
|
} else {
|
||||||
w.Write(success_json_bytes)
|
_, _ = w.Write(successJSONBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +124,8 @@ func route_delete_topic(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := SimpleForumSessionCheck(w,r,&user,topic.ParentID)
|
// TO-DO: Add hooks to make use of headerLite
|
||||||
|
_, ok := SimpleForumSessionCheck(w, r, &user, topic.ParentID)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -162,7 +161,7 @@ func route_delete_topic(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
//log.Print("Topic #" + strconv.Itoa(tid) + " was deleted by User #" + strconv.Itoa(user.ID))
|
//log.Print("Topic #" + strconv.Itoa(tid) + " was deleted by User #" + strconv.Itoa(user.ID))
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
|
|
||||||
wcount := word_count(topic.Content)
|
wcount := wordCount(topic.Content)
|
||||||
err = decrease_post_user_stats(wcount, topic.CreatedBy, true, user)
|
err = decrease_post_user_stats(wcount, topic.CreatedBy, true, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
@ -193,7 +192,8 @@ func route_stick_topic(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := SimpleForumSessionCheck(w,r,&user,topic.ParentID)
|
// TO-DO: Add hooks to make use of headerLite
|
||||||
|
_, ok := SimpleForumSessionCheck(w, r, &user, topic.ParentID)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -248,7 +248,8 @@ func route_unstick_topic(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := SimpleForumSessionCheck(w,r,&user,topic.ParentID)
|
// TO-DO: Add hooks to make use of headerLite
|
||||||
|
_, ok := SimpleForumSessionCheck(w, r, &user, topic.ParentID)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -293,21 +294,18 @@ func route_reply_edit_submit(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
PreError("Bad Form", w, r)
|
PreError("Bad Form", w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
is_js := r.PostFormValue("js")
|
isJs := (r.PostFormValue("js") == "1")
|
||||||
if is_js == "" {
|
|
||||||
is_js = "0"
|
|
||||||
}
|
|
||||||
|
|
||||||
rid, err := strconv.Atoi(r.URL.Path[len("/reply/edit/submit/"):])
|
rid, err := strconv.Atoi(r.URL.Path[len("/reply/edit/submit/"):])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
PreErrorJSQ("The provided Reply ID is not a valid number.",w,r,is_js)
|
PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content := html.EscapeString(preparse_message(r.PostFormValue("edit_item")))
|
content := html.EscapeString(preparseMessage(r.PostFormValue("edit_item")))
|
||||||
_, err = edit_reply_stmt.Exec(content, parse_message(content), rid)
|
_, err = edit_reply_stmt.Exec(content, parseMessage(content), rid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,33 +313,34 @@ func route_reply_edit_submit(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
var tid int
|
var tid int
|
||||||
err = get_reply_tid_stmt.QueryRow(rid).Scan(&tid)
|
err = get_reply_tid_stmt.QueryRow(rid).Scan(&tid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var fid int
|
var fid int
|
||||||
err = get_topic_fid_stmt.QueryRow(tid).Scan(&fid)
|
err = get_topic_fid_stmt.QueryRow(tid).Scan(&fid)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
PreErrorJSQ("The parent topic doesn't exist.",w,r,is_js)
|
PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs)
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := SimpleForumSessionCheck(w,r,&user,fid)
|
// TO-DO: Add hooks to make use of headerLite
|
||||||
|
_, ok := SimpleForumSessionCheck(w, r, &user, fid)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !user.Perms.ViewTopic || !user.Perms.EditReply {
|
if !user.Perms.ViewTopic || !user.Perms.EditReply {
|
||||||
NoPermissionsJSQ(w,r,user,is_js)
|
NoPermissionsJSQ(w, r, user, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_js == "0" {
|
if !isJs {
|
||||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
||||||
} else {
|
} else {
|
||||||
w.Write(success_json_bytes)
|
w.Write(successJSONBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,66 +350,64 @@ func route_reply_delete_submit(w http.ResponseWriter, r *http.Request, user User
|
|||||||
PreError("Bad Form", w, r)
|
PreError("Bad Form", w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
is_js := r.PostFormValue("is_js")
|
isJs := (r.PostFormValue("isJs") == "1")
|
||||||
if is_js == "" {
|
|
||||||
is_js = "0"
|
|
||||||
}
|
|
||||||
|
|
||||||
rid, err := strconv.Atoi(r.URL.Path[len("/reply/delete/submit/"):])
|
rid, err := strconv.Atoi(r.URL.Path[len("/reply/delete/submit/"):])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
PreErrorJSQ("The provided Reply ID is not a valid number.",w,r,is_js)
|
PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
reply, err := get_reply(rid)
|
reply, err := getReply(rid)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
PreErrorJSQ("The reply you tried to delete doesn't exist.",w,r,is_js)
|
PreErrorJSQ("The reply you tried to delete doesn't exist.", w, r, isJs)
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var fid int
|
var fid int
|
||||||
err = get_topic_fid_stmt.QueryRow(reply.ParentID).Scan(&fid)
|
err = get_topic_fid_stmt.QueryRow(reply.ParentID).Scan(&fid)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
PreErrorJSQ("The parent topic doesn't exist.",w,r,is_js)
|
PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs)
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := SimpleForumSessionCheck(w,r,&user,fid)
|
// TO-DO: Add hooks to make use of headerLite
|
||||||
|
_, ok := SimpleForumSessionCheck(w, r, &user, fid)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !user.Perms.ViewTopic || !user.Perms.DeleteReply {
|
if !user.Perms.ViewTopic || !user.Perms.DeleteReply {
|
||||||
NoPermissionsJSQ(w,r,user,is_js)
|
NoPermissionsJSQ(w, r, user, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = delete_reply_stmt.Exec(rid)
|
_, err = delete_reply_stmt.Exec(rid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//log.Print("Reply #" + strconv.Itoa(rid) + " was deleted by User #" + strconv.Itoa(user.ID))
|
//log.Print("Reply #" + strconv.Itoa(rid) + " was deleted by User #" + strconv.Itoa(user.ID))
|
||||||
if is_js == "0" {
|
if !isJs {
|
||||||
//http.Redirect(w,r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther)
|
//http.Redirect(w,r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther)
|
||||||
} else {
|
} else {
|
||||||
w.Write(success_json_bytes)
|
w.Write(successJSONBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
wcount := word_count(reply.Content)
|
wcount := wordCount(reply.Content)
|
||||||
err = decrease_post_user_stats(wcount, reply.CreatedBy, false, user)
|
err = decrease_post_user_stats(wcount, reply.CreatedBy, false, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = remove_replies_from_topic_stmt.Exec(1, reply.ParentID)
|
_, err = remove_replies_from_topic_stmt.Exec(1, reply.ParentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
}
|
}
|
||||||
|
|
||||||
ipaddress, _, err := net.SplitHostPort(r.RemoteAddr)
|
ipaddress, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||||
@ -437,14 +434,11 @@ func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request, use
|
|||||||
LocalError("Bad Form", w, r, user)
|
LocalError("Bad Form", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
is_js := r.PostFormValue("js")
|
isJs := (r.PostFormValue("js") == "1")
|
||||||
if is_js == "" {
|
|
||||||
is_js = "0"
|
|
||||||
}
|
|
||||||
|
|
||||||
rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/edit/submit/"):])
|
rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/edit/submit/"):])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalErrorJSQ("The provided Reply ID is not a valid number.",w,r,user,is_js)
|
LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,26 +446,26 @@ func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request, use
|
|||||||
var uid int
|
var uid int
|
||||||
err = get_user_reply_uid_stmt.QueryRow(rid).Scan(&uid)
|
err = get_user_reply_uid_stmt.QueryRow(rid).Scan(&uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.ID != uid && !user.Perms.EditReply {
|
if user.ID != uid && !user.Perms.EditReply {
|
||||||
NoPermissionsJSQ(w,r,user,is_js)
|
NoPermissionsJSQ(w, r, user, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content := html.EscapeString(preparse_message(r.PostFormValue("edit_item")))
|
content := html.EscapeString(preparseMessage(r.PostFormValue("edit_item")))
|
||||||
_, err = edit_profile_reply_stmt.Exec(content, parse_message(content), rid)
|
_, err = edit_profile_reply_stmt.Exec(content, parseMessage(content), rid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_js == "0" {
|
if !isJs {
|
||||||
http.Redirect(w, r, "/user/"+strconv.Itoa(uid)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
http.Redirect(w, r, "/user/"+strconv.Itoa(uid)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
||||||
} else {
|
} else {
|
||||||
w.Write(success_json_bytes)
|
w.Write(successJSONBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,43 +475,144 @@ func route_profile_reply_delete_submit(w http.ResponseWriter, r *http.Request, u
|
|||||||
LocalError("Bad Form", w, r, user)
|
LocalError("Bad Form", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
is_js := r.PostFormValue("is_js")
|
isJs := (r.PostFormValue("isJs") == "1")
|
||||||
if is_js == "" {
|
|
||||||
is_js = "0"
|
|
||||||
}
|
|
||||||
|
|
||||||
rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/delete/submit/"):])
|
rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/delete/submit/"):])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalErrorJSQ("The provided Reply ID is not a valid number.",w,r,user,is_js)
|
LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var uid int
|
var uid int
|
||||||
err = get_user_reply_uid_stmt.QueryRow(rid).Scan(&uid)
|
err = get_user_reply_uid_stmt.QueryRow(rid).Scan(&uid)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
LocalErrorJSQ("The reply you tried to delete doesn't exist.",w,r,user,is_js)
|
LocalErrorJSQ("The reply you tried to delete doesn't exist.", w, r, user, isJs)
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.ID != uid && !user.Perms.DeleteReply {
|
if user.ID != uid && !user.Perms.DeleteReply {
|
||||||
NoPermissionsJSQ(w,r,user,is_js)
|
NoPermissionsJSQ(w, r, user, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = delete_profile_reply_stmt.Exec(rid)
|
_, err = delete_profile_reply_stmt.Exec(rid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalErrorJSQ(err,w,r,is_js)
|
InternalErrorJSQ(err, w, r, isJs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//log.Print("The profile post '" + strconv.Itoa(rid) + "' was deleted by User #" + strconv.Itoa(user.ID))
|
//log.Print("The profile post '" + strconv.Itoa(rid) + "' was deleted by User #" + strconv.Itoa(user.ID))
|
||||||
|
|
||||||
if is_js == "0" {
|
if !isJs {
|
||||||
//http.Redirect(w,r, "/user/" + strconv.Itoa(uid), http.StatusSeeOther)
|
//http.Redirect(w,r, "/user/" + strconv.Itoa(uid), http.StatusSeeOther)
|
||||||
} else {
|
} else {
|
||||||
w.Write(success_json_bytes)
|
w.Write(successJSONBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func route_ips(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
|
headerVars, ok := SessionCheck(w, r, &user)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !user.Perms.ViewIPs {
|
||||||
|
NoPermissions(w, r, user)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := html.EscapeString(r.URL.Path[len("/users/ips/"):])
|
||||||
|
var uid int
|
||||||
|
var reqUserList map[int]bool = make(map[int]bool)
|
||||||
|
|
||||||
|
rows, err := find_users_by_ip_users_stmt.Query(ip)
|
||||||
|
if err != nil {
|
||||||
|
InternalError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
err := rows.Scan(&uid)
|
||||||
|
if err != nil {
|
||||||
|
InternalError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reqUserList[uid] = true
|
||||||
|
}
|
||||||
|
err = rows.Err()
|
||||||
|
if err != nil {
|
||||||
|
InternalError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rows2, err := find_users_by_ip_topics_stmt.Query(ip)
|
||||||
|
if err != nil {
|
||||||
|
InternalError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rows2.Close()
|
||||||
|
|
||||||
|
for rows2.Next() {
|
||||||
|
err := rows2.Scan(&uid)
|
||||||
|
if err != nil {
|
||||||
|
InternalError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reqUserList[uid] = true
|
||||||
|
}
|
||||||
|
err = rows2.Err()
|
||||||
|
if err != nil {
|
||||||
|
InternalError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rows3, err := find_users_by_ip_replies_stmt.Query(ip)
|
||||||
|
if err != nil {
|
||||||
|
InternalError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rows3.Close()
|
||||||
|
|
||||||
|
for rows3.Next() {
|
||||||
|
err := rows3.Scan(&uid)
|
||||||
|
if err != nil {
|
||||||
|
InternalError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reqUserList[uid] = true
|
||||||
|
}
|
||||||
|
err = rows3.Err()
|
||||||
|
if err != nil {
|
||||||
|
InternalError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the user ID map to a slice, then bulk load the users
|
||||||
|
var idSlice []int = make([]int, len(reqUserList))
|
||||||
|
var i int
|
||||||
|
for userID := range reqUserList {
|
||||||
|
idSlice[i] = userID
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
// TO-DO: What if a user is deleted via the Control Panel?
|
||||||
|
userList, err := users.BulkCascadeGetMap(idSlice)
|
||||||
|
if err != nil {
|
||||||
|
InternalError(err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pi := IPSearchPage{"IP Search", user, headerVars, userList, ip}
|
||||||
|
if preRenderHooks["pre_render_ips"] != nil {
|
||||||
|
if runPreRenderHook("pre_render_ips", w, r, &user, &pi) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = templates.ExecuteTemplate(w, "ip-search.html", pi)
|
||||||
|
if err != nil {
|
||||||
|
InternalError(err, w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,8 +647,8 @@ func route_profile_reply_delete_submit(w http.ResponseWriter, r *http.Request, u
|
|||||||
yousure := AreYouSure{"/users/ban/submit/" + strconv.Itoa(uid),confirm_msg}
|
yousure := AreYouSure{"/users/ban/submit/" + strconv.Itoa(uid),confirm_msg}
|
||||||
|
|
||||||
pi := Page{"Ban User",user,headerVars,tList,yousure}
|
pi := Page{"Ban User",user,headerVars,tList,yousure}
|
||||||
if pre_render_hooks["pre_render_ban"] != nil {
|
if preRenderHooks["pre_render_ban"] != nil {
|
||||||
if run_pre_render_hook("pre_render_ban", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_ban", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -589,7 +684,7 @@ func route_ban_submit(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if targetUser.Is_Super_Admin || targetUser.Is_Admin || targetUser.Is_Mod {
|
if targetUser.IsSuperAdmin || targetUser.IsAdmin || targetUser.IsMod {
|
||||||
LocalError("You may not ban another staff member.", w, r, user)
|
LocalError("You may not ban another staff member.", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -598,37 +693,37 @@ func route_ban_submit(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if targetUser.Is_Banned {
|
if targetUser.IsBanned {
|
||||||
LocalError("The user you're trying to unban is already banned.", w, r, user)
|
LocalError("The user you're trying to unban is already banned.", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
duration_days, err := strconv.Atoi(r.FormValue("ban-duration-days"))
|
durationDays, err := strconv.Atoi(r.FormValue("ban-duration-days"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalError("You can only use whole numbers for the number of days", w, r, user)
|
LocalError("You can only use whole numbers for the number of days", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
duration_weeks, err := strconv.Atoi(r.FormValue("ban-duration-weeks"))
|
durationWeeks, err := strconv.Atoi(r.FormValue("ban-duration-weeks"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalError("You can only use whole numbers for the number of weeks", w, r, user)
|
LocalError("You can only use whole numbers for the number of weeks", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
duration_months, err := strconv.Atoi(r.FormValue("ban-duration-months"))
|
durationMonths, err := strconv.Atoi(r.FormValue("ban-duration-months"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalError("You can only use whole numbers for the number of months", w, r, user)
|
LocalError("You can only use whole numbers for the number of months", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var duration time.Duration
|
var duration time.Duration
|
||||||
if duration_days > 1 && duration_weeks > 1 && duration_months > 1 {
|
if durationDays > 1 && durationWeeks > 1 && durationMonths > 1 {
|
||||||
duration, _ = time.ParseDuration("0")
|
duration, _ = time.ParseDuration("0")
|
||||||
} else {
|
} else {
|
||||||
var seconds int
|
var seconds int
|
||||||
seconds += duration_days * day
|
seconds += durationDays * day
|
||||||
seconds += duration_weeks * week
|
seconds += durationWeeks * week
|
||||||
seconds += duration_months * month
|
seconds += durationMonths * month
|
||||||
duration, _ = time.ParseDuration(strconv.Itoa(seconds) + "s")
|
duration, _ = time.ParseDuration(strconv.Itoa(seconds) + "s")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,7 +775,7 @@ func route_unban(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !targetUser.Is_Banned {
|
if !targetUser.IsBanned {
|
||||||
LocalError("The user you're trying to unban isn't banned.", w, r, user)
|
LocalError("The user you're trying to unban isn't banned.", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
33
mysql.go
33
mysql.go
@ -4,31 +4,35 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "log"
|
import "log"
|
||||||
|
|
||||||
//import "time"
|
//import "time"
|
||||||
import "database/sql"
|
import "database/sql"
|
||||||
import _ "github.com/go-sql-driver/mysql"
|
import _ "github.com/go-sql-driver/mysql"
|
||||||
import "./query_gen/lib"
|
import "./query_gen/lib"
|
||||||
|
|
||||||
var db_collation string = "utf8mb4_general_ci"
|
var dbCollation = "utf8mb4_general_ci"
|
||||||
var get_activity_feed_by_watcher_stmt *sql.Stmt
|
var get_activity_feed_by_watcher_stmt *sql.Stmt
|
||||||
var get_activity_count_by_watcher_stmt *sql.Stmt
|
var get_activity_count_by_watcher_stmt *sql.Stmt
|
||||||
var todays_post_count_stmt *sql.Stmt
|
var todays_post_count_stmt *sql.Stmt
|
||||||
var todays_topic_count_stmt *sql.Stmt
|
var todays_topic_count_stmt *sql.Stmt
|
||||||
var todays_report_count_stmt *sql.Stmt
|
var todays_report_count_stmt *sql.Stmt
|
||||||
var todays_newuser_count_stmt *sql.Stmt
|
var todays_newuser_count_stmt *sql.Stmt
|
||||||
|
var find_users_by_ip_users_stmt *sql.Stmt
|
||||||
|
var find_users_by_ip_topics_stmt *sql.Stmt
|
||||||
|
var find_users_by_ip_replies_stmt *sql.Stmt
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
db_adapter = "mysql"
|
dbAdapter = "mysql"
|
||||||
}
|
}
|
||||||
|
|
||||||
func _init_database() (err error) {
|
func _initDatabase() (err error) {
|
||||||
var _dbpassword string
|
var _dbpassword string
|
||||||
if(db_config.Password != ""){
|
if db_config.Password != "" {
|
||||||
_dbpassword = ":" + db_config.Password
|
_dbpassword = ":" + db_config.Password
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the database connection
|
// Open the database connection
|
||||||
db, err = sql.Open("mysql", db_config.Username + _dbpassword + "@tcp(" + db_config.Host + ":" + db_config.Port + ")/" + db_config.Dbname + "?collation=" + db_collation)
|
db, err = sql.Open("mysql", db_config.Username+_dbpassword+"@tcp("+db_config.Host+":"+db_config.Port+")/"+db_config.Dbname+"?collation="+dbCollation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -40,7 +44,7 @@ func _init_database() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the database version
|
// Fetch the database version
|
||||||
db.QueryRow("SELECT VERSION()").Scan(&db_version)
|
db.QueryRow("SELECT VERSION()").Scan(&dbVersion)
|
||||||
|
|
||||||
// Set the number of max open connections
|
// Set the number of max open connections
|
||||||
db.SetMaxOpenConns(64)
|
db.SetMaxOpenConns(64)
|
||||||
@ -62,6 +66,7 @@ func _init_database() (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TO-DO: Is there a less noisy way of doing this for tests?
|
||||||
log.Print("Preparing get_activity_feed_by_watcher statement.")
|
log.Print("Preparing get_activity_feed_by_watcher statement.")
|
||||||
get_activity_feed_by_watcher_stmt, err = db.Prepare("SELECT activity_stream_matches.asid, activity_stream.actor, activity_stream.targetUser, activity_stream.event, activity_stream.elementType, activity_stream.elementID FROM `activity_stream_matches` INNER JOIN `activity_stream` ON activity_stream_matches.asid = activity_stream.asid AND activity_stream_matches.watcher != activity_stream.actor WHERE `watcher` = ? ORDER BY activity_stream.asid ASC LIMIT 8")
|
get_activity_feed_by_watcher_stmt, err = db.Prepare("SELECT activity_stream_matches.asid, activity_stream.actor, activity_stream.targetUser, activity_stream.event, activity_stream.elementType, activity_stream.elementID FROM `activity_stream_matches` INNER JOIN `activity_stream` ON activity_stream_matches.asid = activity_stream.asid AND activity_stream_matches.watcher != activity_stream.actor WHERE `watcher` = ? ORDER BY activity_stream.asid ASC LIMIT 8")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -98,5 +103,19 @@ func _init_database() (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
log.Print("Preparing find_users_by_ip_users statement.")
|
||||||
|
find_users_by_ip_users_stmt, err = db.Prepare("select uid from users where last_ip = ?")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Print("Preparing find_users_by_ip_topics statement.")
|
||||||
|
find_users_by_ip_topics_stmt, err = db.Prepare("select uid from users where uid in(select createdBy from topics where ipaddress = ?)")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Print("Preparing find_users_by_ip_replies statement.")
|
||||||
|
find_users_by_ip_replies_stmt, err = db.Prepare("select uid from users where uid in(select createdBy from replies where ipaddress = ?)")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,10 @@ package main
|
|||||||
import "errors"
|
import "errors"
|
||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
||||||
var ws_hub WS_Hub
|
var wsHub WS_Hub
|
||||||
var ws_nouser error = errors.New("This user isn't connected via WebSockets")
|
var wsNouser error = errors.New("This user isn't connected via WebSockets")
|
||||||
|
|
||||||
type WS_Hub struct
|
type WS_Hub struct {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ *WS_Hub) guest_count() int {
|
func (_ *WS_Hub) guest_count() int {
|
||||||
@ -25,15 +24,15 @@ func (hub *WS_Hub) broadcast_message(_ string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WS_Hub) push_message(_ int, _ string) error {
|
func (hub *WS_Hub) push_message(_ int, _ string) error {
|
||||||
return ws_nouser
|
return wsNouser
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WS_Hub) push_alert(_ int, _ int, _ string, _ string, _ int, _ int, _ int) error {
|
func (hub *WS_Hub) push_alert(_ int, _ int, _ string, _ string, _ int, _ int, _ int) error {
|
||||||
return ws_nouser
|
return wsNouser
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WS_Hub) push_alerts(_ []int, _ int, _ string, _ string, _ int, _ int, _ int) error {
|
func (hub *WS_Hub) push_alerts(_ []int, _ int, _ string, _ string, _ int, _ int, _ int) error {
|
||||||
return ws_nouser
|
return wsNouser
|
||||||
}
|
}
|
||||||
|
|
||||||
func route_websockets(_ http.ResponseWriter, _ *http.Request, _ User) {
|
func route_websockets(_ http.ResponseWriter, _ *http.Request, _ User) {
|
||||||
|
337
pages.go
337
pages.go
@ -8,26 +8,25 @@ import "strconv"
|
|||||||
import "regexp"
|
import "regexp"
|
||||||
import "html/template"
|
import "html/template"
|
||||||
|
|
||||||
type HeaderVars struct
|
type HeaderVars struct {
|
||||||
{
|
|
||||||
NoticeList []string
|
NoticeList []string
|
||||||
Scripts []string
|
Scripts []string
|
||||||
Stylesheets []string
|
Stylesheets []string
|
||||||
Widgets PageWidgets
|
Widgets PageWidgets
|
||||||
Site *Site
|
Site *Site
|
||||||
Settings map[string]interface{}
|
Settings map[string]interface{}
|
||||||
|
ThemeName string
|
||||||
ExtData ExtData
|
ExtData ExtData
|
||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: Add this to routes which don't use templates. E.g. Json APIs.
|
// TO-DO: Add this to routes which don't use templates. E.g. Json APIs.
|
||||||
type HeaderLite struct
|
type HeaderLite struct {
|
||||||
{
|
|
||||||
Site *Site
|
Site *Site
|
||||||
Settings SettingBox
|
Settings SettingBox
|
||||||
|
ExtData ExtData
|
||||||
}
|
}
|
||||||
|
|
||||||
type PageWidgets struct
|
type PageWidgets struct {
|
||||||
{
|
|
||||||
LeftSidebar template.HTML
|
LeftSidebar template.HTML
|
||||||
RightSidebar template.HTML
|
RightSidebar template.HTML
|
||||||
}
|
}
|
||||||
@ -37,85 +36,79 @@ type PageWidgets struct
|
|||||||
items map[string]interface{} // Key: pluginname
|
items map[string]interface{} // Key: pluginname
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
type ExtData struct
|
// TO-DO: Add a ExtDataHolder interface with methods for manipulating the contents?
|
||||||
{
|
type ExtData struct {
|
||||||
items map[string]interface{} // Key: pluginname
|
items map[string]interface{} // Key: pluginname
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
type Page struct
|
type Page struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
ItemList []interface{}
|
ItemList []interface{}
|
||||||
Something interface{}
|
Something interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type TopicPage struct
|
type TopicPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
ItemList []Reply
|
ItemList []Reply
|
||||||
Topic TopicUser
|
Topic TopicUser
|
||||||
Page int
|
Page int
|
||||||
LastPage int
|
LastPage int
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TopicsPage struct
|
type TopicsPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
ItemList []*TopicsRow
|
ItemList []*TopicsRow
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ForumPage struct
|
type ForumPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
ItemList []*TopicsRow
|
ItemList []*TopicsRow
|
||||||
Forum Forum
|
Forum Forum
|
||||||
Page int
|
Page int
|
||||||
LastPage int
|
LastPage int
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ForumsPage struct
|
type ForumsPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
ItemList []Forum
|
ItemList []Forum
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProfilePage struct
|
type ProfilePage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
ItemList []Reply
|
ItemList []Reply
|
||||||
ProfileOwner User
|
ProfileOwner User
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateTopicPage struct
|
type CreateTopicPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
ItemList []Forum
|
ItemList []Forum
|
||||||
FID int
|
FID int
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelStats struct
|
type IPSearchPage struct {
|
||||||
{
|
Title string
|
||||||
|
CurrentUser User
|
||||||
|
Header *HeaderVars
|
||||||
|
ItemList map[int]*User
|
||||||
|
IP string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PanelStats struct {
|
||||||
Users int
|
Users int
|
||||||
Groups int
|
Groups int
|
||||||
Forums int
|
Forums int
|
||||||
@ -125,18 +118,16 @@ type PanelStats struct
|
|||||||
Reports int
|
Reports int
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelPage struct
|
type PanelPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
ItemList []interface{}
|
ItemList []interface{}
|
||||||
Something interface{}
|
Something interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type GridElement struct
|
type GridElement struct {
|
||||||
{
|
|
||||||
ID string
|
ID string
|
||||||
Body string
|
Body string
|
||||||
Order int // For future use
|
Order int // For future use
|
||||||
@ -146,78 +137,66 @@ type GridElement struct
|
|||||||
Note string
|
Note string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelDashboardPage struct
|
type PanelDashboardPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
GridItems []GridElement
|
GridItems []GridElement
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelThemesPage struct
|
type PanelThemesPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
PrimaryThemes []Theme
|
PrimaryThemes []Theme
|
||||||
VariantThemes []Theme
|
VariantThemes []Theme
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelUserPage struct
|
type PanelUserPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
ItemList []User
|
ItemList []User
|
||||||
PageList []int
|
PageList []int
|
||||||
Page int
|
Page int
|
||||||
LastPage int
|
LastPage int
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelGroupPage struct
|
type PanelGroupPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
ItemList []GroupAdmin
|
ItemList []GroupAdmin
|
||||||
PageList []int
|
PageList []int
|
||||||
Page int
|
Page int
|
||||||
LastPage int
|
LastPage int
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelEditGroupPage struct
|
type PanelEditGroupPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
ID int
|
ID int
|
||||||
Name string
|
Name string
|
||||||
Tag string
|
Tag string
|
||||||
Rank string
|
Rank string
|
||||||
DisableRank bool
|
DisableRank bool
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type GroupForumPermPreset struct
|
type GroupForumPermPreset struct {
|
||||||
{
|
|
||||||
Group Group
|
Group Group
|
||||||
Preset string
|
Preset string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelEditForumPage struct
|
type PanelEditForumPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
ID int
|
ID int
|
||||||
Name string
|
Name string
|
||||||
@ -225,33 +204,28 @@ type PanelEditForumPage struct
|
|||||||
Active bool
|
Active bool
|
||||||
Preset string
|
Preset string
|
||||||
Groups []GroupForumPermPreset
|
Groups []GroupForumPermPreset
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type NameLangPair struct
|
type NameLangPair struct {
|
||||||
{
|
|
||||||
Name string
|
Name string
|
||||||
LangStr string
|
LangStr string
|
||||||
}
|
}
|
||||||
|
|
||||||
type NameLangToggle struct
|
type NameLangToggle struct {
|
||||||
{
|
|
||||||
Name string
|
Name string
|
||||||
LangStr string
|
LangStr string
|
||||||
Toggle bool
|
Toggle bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelEditGroupPermsPage struct
|
type PanelEditGroupPermsPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
ID int
|
ID int
|
||||||
Name string
|
Name string
|
||||||
LocalPerms []NameLangToggle
|
LocalPerms []NameLangToggle
|
||||||
GlobalPerms []NameLangToggle
|
GlobalPerms []NameLangToggle
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Log struct {
|
type Log struct {
|
||||||
@ -260,63 +234,57 @@ type Log struct {
|
|||||||
DoneAt string
|
DoneAt string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelLogsPage struct
|
type PanelLogsPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
Logs []Log
|
Logs []Log
|
||||||
PageList []int
|
PageList []int
|
||||||
Page int
|
Page int
|
||||||
LastPage int
|
LastPage int
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelDebugPage struct
|
type PanelDebugPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
Uptime string
|
Uptime string
|
||||||
OpenConns int
|
OpenConns int
|
||||||
DBAdapter string
|
DBAdapter string
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PageSimple struct
|
type PageSimple struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
Something interface{}
|
Something interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type AreYouSure struct
|
type AreYouSure struct {
|
||||||
{
|
|
||||||
URL string
|
URL string
|
||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
var space_gap []byte = []byte(" ")
|
var spaceGap = []byte(" ")
|
||||||
var http_prot_b []byte = []byte("http://")
|
var httpProtBytes = []byte("http://")
|
||||||
var invalid_url []byte = []byte("<span style='color: red;'>[Invalid URL]</span>")
|
var invalidURL = []byte("<span style='color: red;'>[Invalid URL]</span>")
|
||||||
var invalid_topic []byte = []byte("<span style='color: red;'>[Invalid Topic]</span>")
|
var invalidTopic = []byte("<span style='color: red;'>[Invalid Topic]</span>")
|
||||||
var invalid_profile []byte = []byte("<span style='color: red;'>[Invalid Profile]</span>")
|
var invalidProfile = []byte("<span style='color: red;'>[Invalid Profile]</span>")
|
||||||
var invalid_forum []byte = []byte("<span style='color: red;'>[Invalid Forum]</span>")
|
var invalidForum = []byte("<span style='color: red;'>[Invalid Forum]</span>")
|
||||||
var url_open []byte = []byte("<a href='")
|
var urlOpen = []byte("<a href='")
|
||||||
var url_open2 []byte = []byte("'>")
|
var urlOpen2 = []byte("'>")
|
||||||
var bytes_singlequote []byte = []byte("'")
|
var bytesSinglequote = []byte("'")
|
||||||
var bytes_greaterthan []byte = []byte(">")
|
var bytesGreaterthan = []byte(">")
|
||||||
var url_mention []byte = []byte(" class='mention'")
|
var urlMention = []byte(" class='mention'")
|
||||||
var url_close []byte = []byte("</a>")
|
var urlClose = []byte("</a>")
|
||||||
var urlpattern string = `(?s)([ {1}])((http|https|ftp|mailto)*)(:{??)\/\/([\.a-zA-Z\/]+)([ {1}])`
|
var urlpattern = `(?s)([ {1}])((http|https|ftp|mailto)*)(:{??)\/\/([\.a-zA-Z\/]+)([ {1}])`
|
||||||
var url_reg *regexp.Regexp
|
var urlReg *regexp.Regexp
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
url_reg = regexp.MustCompile(urlpattern)
|
urlReg = regexp.MustCompile(urlpattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
func shortcode_to_unicode(msg string) string {
|
func shortcodeToUnicode(msg string) string {
|
||||||
//re := regexp.MustCompile(":(.):")
|
//re := regexp.MustCompile(":(.):")
|
||||||
msg = strings.Replace(msg, ":grinning:", "😀", -1)
|
msg = strings.Replace(msg, ":grinning:", "😀", -1)
|
||||||
msg = strings.Replace(msg, ":grin:", "😁", -1)
|
msg = strings.Replace(msg, ":grin:", "😁", -1)
|
||||||
@ -447,14 +415,14 @@ func shortcode_to_unicode(msg string) string {
|
|||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
func preparse_message(msg string) string {
|
func preparseMessage(msg string) string {
|
||||||
if sshooks["preparse_preassign"] != nil {
|
if sshooks["preparse_preassign"] != nil {
|
||||||
msg = run_sshook("preparse_preassign", msg)
|
msg = runSshook("preparse_preassign", msg)
|
||||||
}
|
}
|
||||||
return shortcode_to_unicode(msg)
|
return shortcodeToUnicode(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parse_message(msg string/*, user User*/) string {
|
func parseMessage(msg string /*, user User*/) string {
|
||||||
msg = strings.Replace(msg, ":)", "😀", -1)
|
msg = strings.Replace(msg, ":)", "😀", -1)
|
||||||
msg = strings.Replace(msg, ":(", "😞", -1)
|
msg = strings.Replace(msg, ":(", "😞", -1)
|
||||||
msg = strings.Replace(msg, ":D", "😃", -1)
|
msg = strings.Replace(msg, ":D", "😃", -1)
|
||||||
@ -474,7 +442,7 @@ func parse_message(msg string/*, user User*/) string {
|
|||||||
//log.Print("Parser Loop!")
|
//log.Print("Parser Loop!")
|
||||||
var msgbytes = []byte(msg)
|
var msgbytes = []byte(msg)
|
||||||
var outbytes []byte
|
var outbytes []byte
|
||||||
msgbytes = append(msgbytes,space_gap...)
|
msgbytes = append(msgbytes, spaceGap...)
|
||||||
//log.Print(`"`+string(msgbytes)+`"`)
|
//log.Print(`"`+string(msgbytes)+`"`)
|
||||||
lastItem := 0
|
lastItem := 0
|
||||||
i := 0
|
i := 0
|
||||||
@ -502,23 +470,23 @@ func parse_message(msg string/*, user User*/) string {
|
|||||||
outbytes = append(outbytes, msgbytes[lastItem:i]...)
|
outbytes = append(outbytes, msgbytes[lastItem:i]...)
|
||||||
i += 5
|
i += 5
|
||||||
start := i
|
start := i
|
||||||
tid, int_len := coerce_int_bytes(msgbytes[start:])
|
tid, intLen := coerceIntBytes(msgbytes[start:])
|
||||||
i += int_len
|
i += intLen
|
||||||
|
|
||||||
topic, err := topics.CascadeGet(tid)
|
topic, err := topics.CascadeGet(tid)
|
||||||
if err != nil || !fstore.Exists(topic.ParentID) {
|
if err != nil || !fstore.Exists(topic.ParentID) {
|
||||||
outbytes = append(outbytes,invalid_topic...)
|
outbytes = append(outbytes, invalidTopic...)
|
||||||
lastItem = i
|
lastItem = i
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
outbytes = append(outbytes, url_open...)
|
outbytes = append(outbytes, urlOpen...)
|
||||||
var url_bit []byte = []byte(build_topic_url("",tid))
|
var urlBit = []byte(buildTopicURL("", tid))
|
||||||
outbytes = append(outbytes, url_bit...)
|
outbytes = append(outbytes, urlBit...)
|
||||||
outbytes = append(outbytes, url_open2...)
|
outbytes = append(outbytes, urlOpen2...)
|
||||||
var tid_bit []byte = []byte("#tid-" + strconv.Itoa(tid))
|
var tidBit = []byte("#tid-" + strconv.Itoa(tid))
|
||||||
outbytes = append(outbytes, tid_bit...)
|
outbytes = append(outbytes, tidBit...)
|
||||||
outbytes = append(outbytes, url_close...)
|
outbytes = append(outbytes, urlClose...)
|
||||||
lastItem = i
|
lastItem = i
|
||||||
|
|
||||||
//log.Print("string(msgbytes)",string(msgbytes))
|
//log.Print("string(msgbytes)",string(msgbytes))
|
||||||
@ -531,44 +499,44 @@ func parse_message(msg string/*, user User*/) string {
|
|||||||
outbytes = append(outbytes, msgbytes[lastItem:i]...)
|
outbytes = append(outbytes, msgbytes[lastItem:i]...)
|
||||||
i += 5
|
i += 5
|
||||||
start := i
|
start := i
|
||||||
rid, int_len := coerce_int_bytes(msgbytes[start:])
|
rid, intLen := coerceIntBytes(msgbytes[start:])
|
||||||
i += int_len
|
i += intLen
|
||||||
|
|
||||||
topic, err := get_topic_by_reply(rid)
|
topic, err := getTopicByReply(rid)
|
||||||
if err != nil || !fstore.Exists(topic.ParentID) {
|
if err != nil || !fstore.Exists(topic.ParentID) {
|
||||||
outbytes = append(outbytes,invalid_topic...)
|
outbytes = append(outbytes, invalidTopic...)
|
||||||
lastItem = i
|
lastItem = i
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
outbytes = append(outbytes, url_open...)
|
outbytes = append(outbytes, urlOpen...)
|
||||||
var url_bit []byte = []byte(build_topic_url("",topic.ID))
|
var urlBit = []byte(buildTopicURL("", topic.ID))
|
||||||
outbytes = append(outbytes, url_bit...)
|
outbytes = append(outbytes, urlBit...)
|
||||||
outbytes = append(outbytes, url_open2...)
|
outbytes = append(outbytes, urlOpen2...)
|
||||||
var rid_bit []byte = []byte("#rid-" + strconv.Itoa(rid))
|
var ridBit = []byte("#rid-" + strconv.Itoa(rid))
|
||||||
outbytes = append(outbytes, rid_bit...)
|
outbytes = append(outbytes, ridBit...)
|
||||||
outbytes = append(outbytes, url_close...)
|
outbytes = append(outbytes, urlClose...)
|
||||||
lastItem = i
|
lastItem = i
|
||||||
} else if bytes.Equal(msgbytes[i+1:i+5], []byte("fid-")) {
|
} else if bytes.Equal(msgbytes[i+1:i+5], []byte("fid-")) {
|
||||||
outbytes = append(outbytes, msgbytes[lastItem:i]...)
|
outbytes = append(outbytes, msgbytes[lastItem:i]...)
|
||||||
i += 5
|
i += 5
|
||||||
start := i
|
start := i
|
||||||
fid, int_len := coerce_int_bytes(msgbytes[start:])
|
fid, intLen := coerceIntBytes(msgbytes[start:])
|
||||||
i += int_len
|
i += intLen
|
||||||
|
|
||||||
if !fstore.Exists(fid) {
|
if !fstore.Exists(fid) {
|
||||||
outbytes = append(outbytes,invalid_forum...)
|
outbytes = append(outbytes, invalidForum...)
|
||||||
lastItem = i
|
lastItem = i
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
outbytes = append(outbytes, url_open...)
|
outbytes = append(outbytes, urlOpen...)
|
||||||
var url_bit []byte = []byte(build_forum_url("",fid))
|
var urlBit = []byte(buildForumUrl("", fid))
|
||||||
outbytes = append(outbytes, url_bit...)
|
outbytes = append(outbytes, urlBit...)
|
||||||
outbytes = append(outbytes, url_open2...)
|
outbytes = append(outbytes, urlOpen2...)
|
||||||
var fid_bit []byte = []byte("#fid-" + strconv.Itoa(fid))
|
var fidBit = []byte("#fid-" + strconv.Itoa(fid))
|
||||||
outbytes = append(outbytes, fid_bit...)
|
outbytes = append(outbytes, fidBit...)
|
||||||
outbytes = append(outbytes, url_close...)
|
outbytes = append(outbytes, urlClose...)
|
||||||
lastItem = i
|
lastItem = i
|
||||||
} else {
|
} else {
|
||||||
// TO-DO: Forum Shortcode Link
|
// TO-DO: Forum Shortcode Link
|
||||||
@ -578,25 +546,25 @@ func parse_message(msg string/*, user User*/) string {
|
|||||||
outbytes = append(outbytes, msgbytes[lastItem:i]...)
|
outbytes = append(outbytes, msgbytes[lastItem:i]...)
|
||||||
i++
|
i++
|
||||||
start := i
|
start := i
|
||||||
uid, int_len := coerce_int_bytes(msgbytes[start:])
|
uid, intLen := coerceIntBytes(msgbytes[start:])
|
||||||
i += int_len
|
i += intLen
|
||||||
|
|
||||||
menUser, err := users.CascadeGet(uid)
|
menUser, err := users.CascadeGet(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
outbytes = append(outbytes,invalid_profile...)
|
outbytes = append(outbytes, invalidProfile...)
|
||||||
lastItem = i
|
lastItem = i
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
outbytes = append(outbytes, url_open...)
|
outbytes = append(outbytes, urlOpen...)
|
||||||
var url_bit []byte = []byte(menUser.Link)
|
var urlBit = []byte(menUser.Link)
|
||||||
outbytes = append(outbytes, url_bit...)
|
outbytes = append(outbytes, urlBit...)
|
||||||
outbytes = append(outbytes, bytes_singlequote...)
|
outbytes = append(outbytes, bytesSinglequote...)
|
||||||
outbytes = append(outbytes, url_mention...)
|
outbytes = append(outbytes, urlMention...)
|
||||||
outbytes = append(outbytes, bytes_greaterthan...)
|
outbytes = append(outbytes, bytesGreaterthan...)
|
||||||
var uid_bit []byte = []byte("@" + menUser.Name)
|
var uidBit = []byte("@" + menUser.Name)
|
||||||
outbytes = append(outbytes, uid_bit...)
|
outbytes = append(outbytes, uidBit...)
|
||||||
outbytes = append(outbytes, url_close...)
|
outbytes = append(outbytes, urlClose...)
|
||||||
lastItem = i
|
lastItem = i
|
||||||
|
|
||||||
//log.Print(string(msgbytes))
|
//log.Print(string(msgbytes))
|
||||||
@ -624,18 +592,18 @@ func parse_message(msg string/*, user User*/) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
outbytes = append(outbytes, msgbytes[lastItem:i]...)
|
outbytes = append(outbytes, msgbytes[lastItem:i]...)
|
||||||
url_len := partial_url_bytes_len(msgbytes[i:])
|
urlLen := partialURLBytesLen(msgbytes[i:])
|
||||||
if msgbytes[i + url_len] != ' ' && msgbytes[i + url_len] != 10 {
|
if msgbytes[i+urlLen] != ' ' && msgbytes[i+urlLen] != 10 {
|
||||||
outbytes = append(outbytes,invalid_url...)
|
outbytes = append(outbytes, invalidURL...)
|
||||||
i += url_len
|
i += urlLen
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
outbytes = append(outbytes, url_open...)
|
outbytes = append(outbytes, urlOpen...)
|
||||||
outbytes = append(outbytes, msgbytes[i:i + url_len]...)
|
outbytes = append(outbytes, msgbytes[i:i+urlLen]...)
|
||||||
outbytes = append(outbytes, url_open2...)
|
outbytes = append(outbytes, urlOpen2...)
|
||||||
outbytes = append(outbytes, msgbytes[i:i + url_len]...)
|
outbytes = append(outbytes, msgbytes[i:i+urlLen]...)
|
||||||
outbytes = append(outbytes, url_close...)
|
outbytes = append(outbytes, urlClose...)
|
||||||
i += url_len
|
i += urlLen
|
||||||
lastItem = i
|
lastItem = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -662,33 +630,33 @@ func parse_message(msg string/*, user User*/) string {
|
|||||||
|
|
||||||
msg = strings.Replace(msg, "\n", "<br>", -1)
|
msg = strings.Replace(msg, "\n", "<br>", -1)
|
||||||
if sshooks["parse_assign"] != nil {
|
if sshooks["parse_assign"] != nil {
|
||||||
msg = run_sshook("parse_assign", msg)
|
msg = runSshook("parse_assign", msg)
|
||||||
}
|
}
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
func regex_parse_message(msg string) string {
|
func regexParseMessage(msg string) string {
|
||||||
msg = strings.Replace(msg, ":)", "😀", -1)
|
msg = strings.Replace(msg, ":)", "😀", -1)
|
||||||
msg = strings.Replace(msg, ":D", "😃", -1)
|
msg = strings.Replace(msg, ":D", "😃", -1)
|
||||||
msg = strings.Replace(msg, ":P", "😛", -1)
|
msg = strings.Replace(msg, ":P", "😛", -1)
|
||||||
msg = url_reg.ReplaceAllString(msg,"<a href=\"$2$3//$4\" rel=\"nofollow\">$2$3//$4</a>")
|
msg = urlReg.ReplaceAllString(msg, "<a href=\"$2$3//$4\" rel=\"nofollow\">$2$3//$4</a>")
|
||||||
msg = strings.Replace(msg, "\n", "<br>", -1)
|
msg = strings.Replace(msg, "\n", "<br>", -1)
|
||||||
if sshooks["parse_assign"] != nil {
|
if sshooks["parse_assign"] != nil {
|
||||||
msg = run_sshook("parse_assign", msg)
|
msg = runSshook("parse_assign", msg)
|
||||||
}
|
}
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6, 7, 8, 6, 7
|
// 6, 7, 8, 6, 7
|
||||||
// ftp://, http://, https:// git://, mailto: (not a URL, just here for length comparison purposes)
|
// ftp://, http://, https:// git://, mailto: (not a URL, just here for length comparison purposes)
|
||||||
func validate_url_bytes(data []byte) bool {
|
func validateURLBytes(data []byte) bool {
|
||||||
datalen := len(data)
|
datalen := len(data)
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
if datalen >= 6 {
|
if datalen >= 6 {
|
||||||
if bytes.Equal(data[0:6], []byte("ftp://")) || bytes.Equal(data[0:6], []byte("git://")) {
|
if bytes.Equal(data[0:6], []byte("ftp://")) || bytes.Equal(data[0:6], []byte("git://")) {
|
||||||
i = 6
|
i = 6
|
||||||
} else if datalen >= 7 && bytes.Equal(data[0:7],http_prot_b) {
|
} else if datalen >= 7 && bytes.Equal(data[0:7], httpProtBytes) {
|
||||||
i = 7
|
i = 7
|
||||||
} else if datalen >= 8 && bytes.Equal(data[0:8], []byte("https://")) {
|
} else if datalen >= 8 && bytes.Equal(data[0:8], []byte("https://")) {
|
||||||
i = 8
|
i = 8
|
||||||
@ -703,14 +671,14 @@ func validate_url_bytes(data []byte) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func validated_url_bytes(data []byte) (url []byte) {
|
func validatedURLBytes(data []byte) (url []byte) {
|
||||||
datalen := len(data)
|
datalen := len(data)
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
if datalen >= 6 {
|
if datalen >= 6 {
|
||||||
if bytes.Equal(data[0:6], []byte("ftp://")) || bytes.Equal(data[0:6], []byte("git://")) {
|
if bytes.Equal(data[0:6], []byte("ftp://")) || bytes.Equal(data[0:6], []byte("git://")) {
|
||||||
i = 6
|
i = 6
|
||||||
} else if datalen >= 7 && bytes.Equal(data[0:7],http_prot_b) {
|
} else if datalen >= 7 && bytes.Equal(data[0:7], httpProtBytes) {
|
||||||
i = 7
|
i = 7
|
||||||
} else if datalen >= 8 && bytes.Equal(data[0:8], []byte("https://")) {
|
} else if datalen >= 8 && bytes.Equal(data[0:8], []byte("https://")) {
|
||||||
i = 8
|
i = 8
|
||||||
@ -719,7 +687,7 @@ func validated_url_bytes(data []byte) (url []byte) {
|
|||||||
|
|
||||||
for ; datalen > i; i++ {
|
for ; datalen > i; i++ {
|
||||||
if data[i] != '\\' && data[i] != '_' && !(data[i] > 44 && data[i] < 58) && !(data[i] > 64 && data[i] < 91) && !(data[i] > 96 && data[i] < 123) {
|
if data[i] != '\\' && data[i] != '_' && !(data[i] > 44 && data[i] < 58) && !(data[i] > 64 && data[i] < 91) && !(data[i] > 96 && data[i] < 123) {
|
||||||
return invalid_url
|
return invalidURL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -727,7 +695,7 @@ func validated_url_bytes(data []byte) (url []byte) {
|
|||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
func partial_url_bytes(data []byte) (url []byte) {
|
func partialURLBytes(data []byte) (url []byte) {
|
||||||
datalen := len(data)
|
datalen := len(data)
|
||||||
i := 0
|
i := 0
|
||||||
end := datalen - 1
|
end := datalen - 1
|
||||||
@ -735,7 +703,7 @@ func partial_url_bytes(data []byte) (url []byte) {
|
|||||||
if datalen >= 6 {
|
if datalen >= 6 {
|
||||||
if bytes.Equal(data[0:6], []byte("ftp://")) || bytes.Equal(data[0:6], []byte("git://")) {
|
if bytes.Equal(data[0:6], []byte("ftp://")) || bytes.Equal(data[0:6], []byte("git://")) {
|
||||||
i = 6
|
i = 6
|
||||||
} else if datalen >= 7 && bytes.Equal(data[0:7],http_prot_b) {
|
} else if datalen >= 7 && bytes.Equal(data[0:7], httpProtBytes) {
|
||||||
i = 7
|
i = 7
|
||||||
} else if datalen >= 8 && bytes.Equal(data[0:8], []byte("https://")) {
|
} else if datalen >= 8 && bytes.Equal(data[0:8], []byte("https://")) {
|
||||||
i = 8
|
i = 8
|
||||||
@ -752,7 +720,7 @@ func partial_url_bytes(data []byte) (url []byte) {
|
|||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
func partial_url_bytes_len(data []byte) int {
|
func partialURLBytesLen(data []byte) int {
|
||||||
datalen := len(data)
|
datalen := len(data)
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
@ -760,7 +728,7 @@ func partial_url_bytes_len(data []byte) int {
|
|||||||
//log.Print(string(data[0:5]))
|
//log.Print(string(data[0:5]))
|
||||||
if bytes.Equal(data[0:6], []byte("ftp://")) || bytes.Equal(data[0:6], []byte("git://")) {
|
if bytes.Equal(data[0:6], []byte("ftp://")) || bytes.Equal(data[0:6], []byte("git://")) {
|
||||||
i = 6
|
i = 6
|
||||||
} else if datalen >= 7 && bytes.Equal(data[0:7],http_prot_b) {
|
} else if datalen >= 7 && bytes.Equal(data[0:7], httpProtBytes) {
|
||||||
i = 7
|
i = 7
|
||||||
} else if datalen >= 8 && bytes.Equal(data[0:8], []byte("https://")) {
|
} else if datalen >= 8 && bytes.Equal(data[0:8], []byte("https://")) {
|
||||||
i = 8
|
i = 8
|
||||||
@ -778,7 +746,7 @@ func partial_url_bytes_len(data []byte) int {
|
|||||||
return datalen
|
return datalen
|
||||||
}
|
}
|
||||||
|
|
||||||
func parse_media_bytes(data []byte) (protocol []byte, url []byte) {
|
func parseMediaBytes(data []byte) (protocol []byte, url []byte) {
|
||||||
datalen := len(data)
|
datalen := len(data)
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
@ -786,7 +754,7 @@ func parse_media_bytes(data []byte) (protocol []byte, url []byte) {
|
|||||||
if bytes.Equal(data[0:6], []byte("ftp://")) || bytes.Equal(data[0:6], []byte("git://")) {
|
if bytes.Equal(data[0:6], []byte("ftp://")) || bytes.Equal(data[0:6], []byte("git://")) {
|
||||||
i = 6
|
i = 6
|
||||||
protocol = data[0:2]
|
protocol = data[0:2]
|
||||||
} else if datalen >= 7 && bytes.Equal(data[0:7],http_prot_b) {
|
} else if datalen >= 7 && bytes.Equal(data[0:7], httpProtBytes) {
|
||||||
i = 7
|
i = 7
|
||||||
protocol = []byte("http")
|
protocol = []byte("http")
|
||||||
} else if datalen >= 8 && bytes.Equal(data[0:8], []byte("https://")) {
|
} else if datalen >= 8 && bytes.Equal(data[0:8], []byte("https://")) {
|
||||||
@ -797,7 +765,7 @@ func parse_media_bytes(data []byte) (protocol []byte, url []byte) {
|
|||||||
|
|
||||||
for ; datalen > i; i++ {
|
for ; datalen > i; i++ {
|
||||||
if data[i] != '\\' && data[i] != '_' && !(data[i] > 44 && data[i] < 58) && !(data[i] > 64 && data[i] < 91) && !(data[i] > 96 && data[i] < 123) {
|
if data[i] != '\\' && data[i] != '_' && !(data[i] > 44 && data[i] < 58) && !(data[i] > 64 && data[i] < 91) && !(data[i] > 96 && data[i] < 123) {
|
||||||
return []byte(""), invalid_url
|
return []byte(""), invalidURL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -807,7 +775,7 @@ func parse_media_bytes(data []byte) (protocol []byte, url []byte) {
|
|||||||
return protocol, data[i:]
|
return protocol, data[i:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func coerce_int_bytes(data []byte) (res int, length int) {
|
func coerceIntBytes(data []byte) (res int, length int) {
|
||||||
if !(data[0] > 47 && data[0] < 58) {
|
if !(data[0] > 47 && data[0] < 58) {
|
||||||
return 0, 1
|
return 0, 1
|
||||||
}
|
}
|
||||||
@ -831,14 +799,13 @@ func coerce_int_bytes(data []byte) (res int, length int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: Write tests for this
|
// TO-DO: Write tests for this
|
||||||
func paginate(count int, per_page int, maxPages int) []int {
|
func paginate(count int, perPage int, maxPages int) []int {
|
||||||
if count < per_page {
|
if count < perPage {
|
||||||
return []int{1}
|
return []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
var page int
|
var page int
|
||||||
var out []int
|
var out []int
|
||||||
for current := 0; current < count; current += per_page {
|
for current := 0; current < count; current += perPage {
|
||||||
page++
|
page++
|
||||||
out = append(out, page)
|
out = append(out, page)
|
||||||
if len(out) >= maxPages {
|
if len(out) >= maxPages {
|
||||||
@ -849,9 +816,9 @@ func paginate(count int, per_page int, maxPages int) []int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: Write tests for this
|
// TO-DO: Write tests for this
|
||||||
func page_offset(count int, page int, perPage int) (int, int, int) {
|
func pageOffset(count int, page int, perPage int) (int, int, int) {
|
||||||
var offset int
|
var offset int
|
||||||
lastPage := int(count / perPage) + 1
|
lastPage := (count / perPage) + 1
|
||||||
if page > 1 {
|
if page > 1 {
|
||||||
offset = (perPage * page) - perPage
|
offset = (perPage * page) - perPage
|
||||||
} else if page == -1 {
|
} else if page == -1 {
|
||||||
|
459
panel_routes.go
459
panel_routes.go
File diff suppressed because it is too large
Load Diff
161
permissions.go
161
permissions.go
@ -5,7 +5,7 @@ import "sync"
|
|||||||
import "strconv"
|
import "strconv"
|
||||||
import "encoding/json"
|
import "encoding/json"
|
||||||
|
|
||||||
var permupdate_mutex sync.Mutex
|
var permUpdateMutex sync.Mutex
|
||||||
var BlankPerms Perms
|
var BlankPerms Perms
|
||||||
var BlankForumPerms ForumPerms
|
var BlankForumPerms ForumPerms
|
||||||
var GuestPerms Perms
|
var GuestPerms Perms
|
||||||
@ -14,9 +14,9 @@ var ReadReplyForumPerms ForumPerms
|
|||||||
var ReadWriteForumPerms ForumPerms
|
var ReadWriteForumPerms ForumPerms
|
||||||
var AllPerms Perms
|
var AllPerms Perms
|
||||||
var AllForumPerms ForumPerms
|
var AllForumPerms ForumPerms
|
||||||
var AllPluginPerms map[string]bool = make(map[string]bool)
|
var AllPluginPerms = make(map[string]bool)
|
||||||
|
|
||||||
var LocalPermList []string = []string{
|
var LocalPermList = []string{
|
||||||
"ViewTopic",
|
"ViewTopic",
|
||||||
"LikeItem",
|
"LikeItem",
|
||||||
"CreateTopic",
|
"CreateTopic",
|
||||||
@ -29,7 +29,7 @@ var LocalPermList []string = []string{
|
|||||||
"CloseTopic",
|
"CloseTopic",
|
||||||
}
|
}
|
||||||
|
|
||||||
var GlobalPermList []string = []string{
|
var GlobalPermList = []string{
|
||||||
"BanUsers",
|
"BanUsers",
|
||||||
"ActivateUsers",
|
"ActivateUsers",
|
||||||
"EditUser",
|
"EditUser",
|
||||||
@ -52,8 +52,7 @@ var GlobalPermList []string = []string{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Permission Structure: ActionComponent[Subcomponent]Flag
|
// Permission Structure: ActionComponent[Subcomponent]Flag
|
||||||
type Perms struct
|
type Perms struct {
|
||||||
{
|
|
||||||
// Global Permissions
|
// Global Permissions
|
||||||
BanUsers bool
|
BanUsers bool
|
||||||
ActivateUsers bool
|
ActivateUsers bool
|
||||||
@ -94,8 +93,7 @@ type Perms struct
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Inherit from group permissions for ones we don't have */
|
/* Inherit from group permissions for ones we don't have */
|
||||||
type ForumPerms struct
|
type ForumPerms struct {
|
||||||
{
|
|
||||||
ViewTopic bool
|
ViewTopic bool
|
||||||
LikeItem bool
|
LikeItem bool
|
||||||
CreateTopic bool
|
CreateTopic bool
|
||||||
@ -202,7 +200,7 @@ func init() {
|
|||||||
ExtData: make(map[string]bool),
|
ExtData: make(map[string]bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
guest_user.Perms = GuestPerms
|
guestUser.Perms = GuestPerms
|
||||||
|
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Printf("Guest Perms: %+v\n", GuestPerms)
|
log.Printf("Guest Perms: %+v\n", GuestPerms)
|
||||||
@ -210,9 +208,9 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func preset_to_permmap(preset string) (out map[string]ForumPerms) {
|
func presetToPermmap(preset string) (out map[string]ForumPerms) {
|
||||||
out = make(map[string]ForumPerms)
|
out = make(map[string]ForumPerms)
|
||||||
switch(preset) {
|
switch preset {
|
||||||
case "all":
|
case "all":
|
||||||
out["guests"] = ReadForumPerms
|
out["guests"] = ReadForumPerms
|
||||||
out["members"] = ReadWriteForumPerms
|
out["members"] = ReadWriteForumPerms
|
||||||
@ -252,9 +250,9 @@ func preset_to_permmap(preset string) (out map[string]ForumPerms) {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func permmap_to_query(permmap map[string]ForumPerms, fid int) error {
|
func permmapToQuery(permmap map[string]ForumPerms, fid int) error {
|
||||||
permupdate_mutex.Lock()
|
permUpdateMutex.Lock()
|
||||||
defer permupdate_mutex.Unlock()
|
defer permUpdateMutex.Unlock()
|
||||||
|
|
||||||
_, err := delete_forum_perms_by_forum_stmt.Exec(fid)
|
_, err := delete_forum_perms_by_forum_stmt.Exec(fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -297,10 +295,10 @@ func permmap_to_query(permmap map[string]ForumPerms, fid int) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return rebuild_forum_permissions(fid)
|
return rebuildForumPermissions(fid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func rebuild_forum_permissions(fid int) error {
|
func rebuildForumPermissions(fid int) error {
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Loading the forum permissions")
|
log.Print("Loading the forum permissions")
|
||||||
}
|
}
|
||||||
@ -332,34 +330,34 @@ func rebuild_forum_permissions(fid int) error {
|
|||||||
}
|
}
|
||||||
pperms.ExtData = make(map[string]bool)
|
pperms.ExtData = make(map[string]bool)
|
||||||
pperms.Overrides = true
|
pperms.Overrides = true
|
||||||
_, ok := forum_perms[gid]
|
_, ok := forumPerms[gid]
|
||||||
if !ok {
|
if !ok {
|
||||||
forum_perms[gid] = make(map[int]ForumPerms)
|
forumPerms[gid] = make(map[int]ForumPerms)
|
||||||
}
|
}
|
||||||
forum_perms[gid][fid] = pperms
|
forumPerms[gid][fid] = pperms
|
||||||
}
|
}
|
||||||
for gid, _ := range groups {
|
for gid := range groups {
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Updating the forum permissions for Group #" + strconv.Itoa(gid))
|
log.Print("Updating the forum permissions for Group #" + strconv.Itoa(gid))
|
||||||
}
|
}
|
||||||
var blank_list []ForumPerms
|
var blankList []ForumPerms
|
||||||
var blank_int_list []int
|
var blankIntList []int
|
||||||
groups[gid].Forums = blank_list
|
groups[gid].Forums = blankList
|
||||||
groups[gid].CanSee = blank_int_list
|
groups[gid].CanSee = blankIntList
|
||||||
|
|
||||||
for ffid, _ := range forums {
|
for ffid := range forums {
|
||||||
forum_perm, ok := forum_perms[gid][ffid]
|
forumPerm, ok := forumPerms[gid][ffid]
|
||||||
if ok {
|
if ok {
|
||||||
//log.Print("Overriding permissions for forum #" + strconv.Itoa(fid))
|
//log.Print("Overriding permissions for forum #" + strconv.Itoa(fid))
|
||||||
groups[gid].Forums = append(groups[gid].Forums,forum_perm)
|
groups[gid].Forums = append(groups[gid].Forums, forumPerm)
|
||||||
} else {
|
} else {
|
||||||
//log.Print("Inheriting from default for forum #" + strconv.Itoa(fid))
|
//log.Print("Inheriting from default for forum #" + strconv.Itoa(fid))
|
||||||
forum_perm = BlankForumPerms
|
forumPerm = BlankForumPerms
|
||||||
groups[gid].Forums = append(groups[gid].Forums,forum_perm)
|
groups[gid].Forums = append(groups[gid].Forums, forumPerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
if forum_perm.Overrides {
|
if forumPerm.Overrides {
|
||||||
if forum_perm.ViewTopic {
|
if forumPerm.ViewTopic {
|
||||||
groups[gid].CanSee = append(groups[gid].CanSee, ffid)
|
groups[gid].CanSee = append(groups[gid].CanSee, ffid)
|
||||||
}
|
}
|
||||||
} else if groups[gid].Perms.ViewTopic {
|
} else if groups[gid].Perms.ViewTopic {
|
||||||
@ -375,7 +373,7 @@ func rebuild_forum_permissions(fid int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func build_forum_permissions() error {
|
func buildForumPermissions() error {
|
||||||
forums, err := fstore.GetAll()
|
forums, err := fstore.GetAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -391,7 +389,7 @@ func build_forum_permissions() error {
|
|||||||
log.Print("Adding the forum permissions")
|
log.Print("Adding the forum permissions")
|
||||||
}
|
}
|
||||||
// Temporarily store the forum perms in a map before transferring it to a much faster and thread-safe slice
|
// Temporarily store the forum perms in a map before transferring it to a much faster and thread-safe slice
|
||||||
forum_perms = make(map[int]map[int]ForumPerms)
|
forumPerms = make(map[int]map[int]ForumPerms)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var gid, fid int
|
var gid, fid int
|
||||||
var perms []byte
|
var perms []byte
|
||||||
@ -406,32 +404,32 @@ func build_forum_permissions() error {
|
|||||||
}
|
}
|
||||||
pperms.ExtData = make(map[string]bool)
|
pperms.ExtData = make(map[string]bool)
|
||||||
pperms.Overrides = true
|
pperms.Overrides = true
|
||||||
_, ok := forum_perms[gid]
|
_, ok := forumPerms[gid]
|
||||||
if !ok {
|
if !ok {
|
||||||
forum_perms[gid] = make(map[int]ForumPerms)
|
forumPerms[gid] = make(map[int]ForumPerms)
|
||||||
}
|
}
|
||||||
forum_perms[gid][fid] = pperms
|
forumPerms[gid][fid] = pperms
|
||||||
}
|
}
|
||||||
for gid, _ := range groups {
|
for gid := range groups {
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Adding the forum permissions for Group #" + strconv.Itoa(gid) + " - " + groups[gid].Name)
|
log.Print("Adding the forum permissions for Group #" + strconv.Itoa(gid) + " - " + groups[gid].Name)
|
||||||
}
|
}
|
||||||
//groups[gid].Forums = append(groups[gid].Forums,BlankForumPerms) // GID 0. No longer needed now that Uncategorised occupies that slot
|
//groups[gid].Forums = append(groups[gid].Forums,BlankForumPerms) // GID 0. No longer needed now that Uncategorised occupies that slot
|
||||||
for fid, _ := range forums {
|
for fid := range forums {
|
||||||
forum_perm, ok := forum_perms[gid][fid]
|
forumPerm, ok := forumPerms[gid][fid]
|
||||||
if ok {
|
if ok {
|
||||||
// Override group perms
|
// Override group perms
|
||||||
//log.Print("Overriding permissions for forum #" + strconv.Itoa(fid))
|
//log.Print("Overriding permissions for forum #" + strconv.Itoa(fid))
|
||||||
groups[gid].Forums = append(groups[gid].Forums,forum_perm)
|
groups[gid].Forums = append(groups[gid].Forums, forumPerm)
|
||||||
} else {
|
} else {
|
||||||
// Inherit from Group
|
// Inherit from Group
|
||||||
//log.Print("Inheriting from default for forum #" + strconv.Itoa(fid))
|
//log.Print("Inheriting from default for forum #" + strconv.Itoa(fid))
|
||||||
forum_perm = BlankForumPerms
|
forumPerm = BlankForumPerms
|
||||||
groups[gid].Forums = append(groups[gid].Forums,forum_perm)
|
groups[gid].Forums = append(groups[gid].Forums, forumPerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
if forum_perm.Overrides {
|
if forumPerm.Overrides {
|
||||||
if forum_perm.ViewTopic {
|
if forumPerm.ViewTopic {
|
||||||
groups[gid].CanSee = append(groups[gid].CanSee, fid)
|
groups[gid].CanSee = append(groups[gid].CanSee, fid)
|
||||||
}
|
}
|
||||||
} else if groups[gid].Perms.ViewTopic {
|
} else if groups[gid].Perms.ViewTopic {
|
||||||
@ -448,26 +446,26 @@ func build_forum_permissions() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func forum_perms_to_group_forum_preset(fperms ForumPerms) string {
|
func forumPermsToGroupForumPreset(fperms ForumPerms) string {
|
||||||
if !fperms.Overrides {
|
if !fperms.Overrides {
|
||||||
return "default"
|
return "default"
|
||||||
}
|
}
|
||||||
if !fperms.ViewTopic {
|
if !fperms.ViewTopic {
|
||||||
return "no_access"
|
return "no_access"
|
||||||
}
|
}
|
||||||
var can_post bool = (fperms.LikeItem && fperms.CreateTopic && fperms.CreateReply)
|
var canPost = (fperms.LikeItem && fperms.CreateTopic && fperms.CreateReply)
|
||||||
var can_moderate bool = (can_post && fperms.EditTopic && fperms.DeleteTopic && fperms.EditReply && fperms.DeleteReply && fperms.PinTopic && fperms.CloseTopic)
|
var canModerate = (canPost && fperms.EditTopic && fperms.DeleteTopic && fperms.EditReply && fperms.DeleteReply && fperms.PinTopic && fperms.CloseTopic)
|
||||||
if can_moderate {
|
if canModerate {
|
||||||
return "can_moderate"
|
return "can_moderate"
|
||||||
}
|
}
|
||||||
if (fperms.EditTopic || fperms.DeleteTopic || fperms.EditReply || fperms.DeleteReply || fperms.PinTopic || fperms.CloseTopic) {
|
if fperms.EditTopic || fperms.DeleteTopic || fperms.EditReply || fperms.DeleteReply || fperms.PinTopic || fperms.CloseTopic {
|
||||||
if !can_post {
|
if !canPost {
|
||||||
return "custom"
|
return "custom"
|
||||||
}
|
}
|
||||||
return "quasi_mod"
|
return "quasi_mod"
|
||||||
}
|
}
|
||||||
|
|
||||||
if can_post {
|
if canPost {
|
||||||
return "can_post"
|
return "can_post"
|
||||||
}
|
}
|
||||||
if fperms.ViewTopic && !fperms.LikeItem && !fperms.CreateTopic && !fperms.CreateReply {
|
if fperms.ViewTopic && !fperms.LikeItem && !fperms.CreateTopic && !fperms.CreateReply {
|
||||||
@ -476,8 +474,8 @@ func forum_perms_to_group_forum_preset(fperms ForumPerms) string {
|
|||||||
return "custom"
|
return "custom"
|
||||||
}
|
}
|
||||||
|
|
||||||
func group_forum_preset_to_forum_perms(preset string) (fperms ForumPerms, changed bool) {
|
func groupForumPresetToForumPerms(preset string) (fperms ForumPerms, changed bool) {
|
||||||
switch(preset) {
|
switch preset {
|
||||||
case "read_only":
|
case "read_only":
|
||||||
return ReadForumPerms, true
|
return ReadForumPerms, true
|
||||||
case "can_post":
|
case "can_post":
|
||||||
@ -493,37 +491,46 @@ func group_forum_preset_to_forum_perms(preset string) (fperms ForumPerms, change
|
|||||||
return fperms, false
|
return fperms, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func strip_invalid_group_forum_preset(preset string) string {
|
func stripInvalidGroupForumPreset(preset string) string {
|
||||||
switch(preset) {
|
switch preset {
|
||||||
case "read_only", "can_post", "can_moderate", "no_access", "default", "custom":
|
case "read_only", "can_post", "can_moderate", "no_access", "default", "custom":
|
||||||
return preset
|
return preset
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func strip_invalid_preset(preset string) string {
|
func stripInvalidPreset(preset string) string {
|
||||||
switch(preset) {
|
switch preset {
|
||||||
case "all", "announce", "members", "staff", "admins", "archive", "custom":
|
case "all", "announce", "members", "staff", "admins", "archive", "custom":
|
||||||
break
|
|
||||||
default: return ""
|
|
||||||
}
|
|
||||||
return preset
|
return preset
|
||||||
}
|
default:
|
||||||
|
|
||||||
func preset_to_lang(preset string) string {
|
|
||||||
switch(preset) {
|
|
||||||
case "all": return "Public"
|
|
||||||
case "announce": return "Announcements"
|
|
||||||
case "members": return "Member Only"
|
|
||||||
case "staff": return "Staff Only"
|
|
||||||
case "admins": return "Admin Only"
|
|
||||||
case "archive": return "Archive"
|
|
||||||
case "custom": return "Custom"
|
|
||||||
}
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func rebuild_group_permissions(gid int) error {
|
// TO-DO: Move this into the phrase system?
|
||||||
|
func presetToLang(preset string) string {
|
||||||
|
switch preset {
|
||||||
|
case "all":
|
||||||
|
return "Public"
|
||||||
|
case "announce":
|
||||||
|
return "Announcements"
|
||||||
|
case "members":
|
||||||
|
return "Member Only"
|
||||||
|
case "staff":
|
||||||
|
return "Staff Only"
|
||||||
|
case "admins":
|
||||||
|
return "Admin Only"
|
||||||
|
case "archive":
|
||||||
|
return "Archive"
|
||||||
|
case "custom":
|
||||||
|
return "Custom"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rebuildGroupPermissions(gid int) error {
|
||||||
var permstr []byte
|
var permstr []byte
|
||||||
log.Print("Reloading a group")
|
log.Print("Reloading a group")
|
||||||
err := db.QueryRow("select permissions from users_groups where gid = ?", gid).Scan(&permstr)
|
err := db.QueryRow("select permissions from users_groups where gid = ?", gid).Scan(&permstr)
|
||||||
@ -543,7 +550,7 @@ func rebuild_group_permissions(gid int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func override_perms(perms *Perms, status bool) {
|
func overridePerms(perms *Perms, status bool) {
|
||||||
if status {
|
if status {
|
||||||
*perms = AllPerms
|
*perms = AllPerms
|
||||||
} else {
|
} else {
|
||||||
@ -552,7 +559,7 @@ func override_perms(perms *Perms, status bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: We need a better way of overriding forum perms rather than setting them one by one
|
// TO-DO: We need a better way of overriding forum perms rather than setting them one by one
|
||||||
func override_forum_perms(perms *Perms, status bool) {
|
func overrideForumPerms(perms *Perms, status bool) {
|
||||||
perms.ViewTopic = status
|
perms.ViewTopic = status
|
||||||
perms.LikeItem = status
|
perms.LikeItem = status
|
||||||
perms.CreateTopic = status
|
perms.CreateTopic = status
|
||||||
@ -565,10 +572,10 @@ func override_forum_perms(perms *Perms, status bool) {
|
|||||||
perms.CloseTopic = status
|
perms.CloseTopic = status
|
||||||
}
|
}
|
||||||
|
|
||||||
func register_plugin_perm(name string) {
|
func registerPluginPerm(name string) {
|
||||||
AllPluginPerms[name] = true
|
AllPluginPerms[name] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func deregister_plugin_perm(name string) {
|
func deregisterPluginPerm(name string) {
|
||||||
delete(AllPluginPerms, name)
|
delete(AllPluginPerms, name)
|
||||||
}
|
}
|
||||||
|
78
phrases.go
78
phrases.go
@ -1,16 +1,22 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* Gosora Phrase System
|
||||||
|
* Copyright Azareal 2017 - 2018
|
||||||
|
*
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "sync"
|
import (
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
// I wish we had constant maps x.x
|
// TO-DO: Let the admin edit phrases from inside the Control Panel? How should we persist these? Should we create a copy of the langpack or edit the primaries? Use the changeLangpack mutex for this?
|
||||||
var phrase_mutex sync.RWMutex
|
var changeLangpackMutex sync.Mutex
|
||||||
var perm_phrase_mutex sync.RWMutex
|
var currentLanguage = "english"
|
||||||
var change_langpack_mutex sync.Mutex
|
var currentLangPack atomic.Value
|
||||||
var currentLanguage string = "english"
|
|
||||||
var currentLangPack *LanguagePack
|
|
||||||
|
|
||||||
type LevelPhrases struct
|
type LevelPhrases struct {
|
||||||
{
|
|
||||||
Level string
|
Level string
|
||||||
LevelMax string
|
LevelMax string
|
||||||
|
|
||||||
@ -18,17 +24,17 @@ type LevelPhrases struct
|
|||||||
Levels []string // index = level
|
Levels []string // index = level
|
||||||
}
|
}
|
||||||
|
|
||||||
type LanguagePack struct
|
type LanguagePack struct {
|
||||||
{
|
|
||||||
Name string
|
Name string
|
||||||
Phrases map[string]string // Should we use a sync map or a struct for these? It would be nice, if we could keep all the phrases consistent.
|
Phrases map[string]string // Should we use a sync map or a struct for these? It would be nice, if we could keep all the phrases consistent.
|
||||||
LevelPhrases LevelPhrases
|
LevelPhrases LevelPhrases
|
||||||
GlobalPermPhrases map[string]string
|
GlobalPermPhrases map[string]string
|
||||||
LocalPermPhrases map[string]string
|
LocalPermPhrases map[string]string
|
||||||
|
SettingLabels map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: Move the english language pack into it's own file and just keep the common logic here
|
// TO-DO: Move the english language pack into it's own file and just keep the common logic here
|
||||||
var langpacks map[string]*LanguagePack = map[string]*LanguagePack{
|
var langpacks = map[string]*LanguagePack{
|
||||||
"english": &LanguagePack{
|
"english": &LanguagePack{
|
||||||
Name: "english",
|
Name: "english",
|
||||||
|
|
||||||
@ -72,30 +78,25 @@ var langpacks map[string]*LanguagePack = map[string]*LanguagePack{
|
|||||||
"PinTopic": "Can pin topics",
|
"PinTopic": "Can pin topics",
|
||||||
"CloseTopic": "Can lock topics",
|
"CloseTopic": "Can lock topics",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
SettingLabels: map[string]string{
|
||||||
|
"activation_type": "Activate All,Email Activation,Admin Approval",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
currentLangPack = langpacks[currentLanguage]
|
currentLangPack.Store(langpacks[currentLanguage])
|
||||||
}
|
}
|
||||||
|
|
||||||
// We might not need to use a mutex for this, we shouldn't need to change the phrases after start-up, and when we do we could overwrite the entire map
|
// We might not need to use a mutex for this, we shouldn't need to change the phrases after start-up, and when we do we could overwrite the entire map
|
||||||
func GetPhrase(name string) (string, bool) {
|
func GetPhrase(name string) (string, bool) {
|
||||||
phrase_mutex.RLock()
|
res, ok := currentLangPack.Load().(*LanguagePack).Phrases[name]
|
||||||
defer perm_phrase_mutex.RUnlock()
|
|
||||||
res, ok := currentLangPack.Phrases[name]
|
|
||||||
return res, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetPhraseUnsafe(name string) (string,bool) {
|
|
||||||
res, ok := currentLangPack.Phrases[name]
|
|
||||||
return res, ok
|
return res, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGlobalPermPhrase(name string) string {
|
func GetGlobalPermPhrase(name string) string {
|
||||||
perm_phrase_mutex.RLock()
|
res, ok := currentLangPack.Load().(*LanguagePack).GlobalPermPhrases[name]
|
||||||
defer perm_phrase_mutex.RUnlock()
|
|
||||||
res, ok := currentLangPack.GlobalPermPhrases[name]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return "{name}"
|
return "{name}"
|
||||||
}
|
}
|
||||||
@ -103,31 +104,46 @@ func GetGlobalPermPhrase(name string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetLocalPermPhrase(name string) string {
|
func GetLocalPermPhrase(name string) string {
|
||||||
perm_phrase_mutex.RLock()
|
res, ok := currentLangPack.Load().(*LanguagePack).LocalPermPhrases[name]
|
||||||
defer perm_phrase_mutex.RUnlock()
|
|
||||||
res, ok := currentLangPack.LocalPermPhrases[name]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return "{name}"
|
return "{name}"
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetSettingLabel(name string) string {
|
||||||
|
res, ok := currentLangPack.Load().(*LanguagePack).SettingLabels[name]
|
||||||
|
if !ok {
|
||||||
|
return "{name}"
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this a copy of the map or a pointer to it? We don't want to accidentally create a race condition
|
||||||
|
func GetAllSettingLabels() map[string]string {
|
||||||
|
return currentLangPack.Load().(*LanguagePack).SettingLabels
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use runtime reflection for updating phrases?
|
||||||
func AddPhrase() {
|
func AddPhrase() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
func UpdatePhrase() {
|
||||||
|
|
||||||
|
}
|
||||||
func DeletePhrase() {
|
func DeletePhrase() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TO-DO: Use atomics to store the pointer of the current active langpack?
|
||||||
func ChangeLanguagePack(name string) (exists bool) {
|
func ChangeLanguagePack(name string) (exists bool) {
|
||||||
change_langpack_mutex.Lock()
|
changeLangpackMutex.Lock()
|
||||||
pack, ok := langpacks[name]
|
pack, ok := langpacks[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
change_langpack_mutex.Unlock()
|
changeLangpackMutex.Unlock()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
currentLangPack = pack
|
currentLangPack.Store(pack)
|
||||||
change_langpack_mutex.Unlock()
|
changeLangpackMutex.Unlock()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
310
plugin_bbcode.go
310
plugin_bbcode.go
@ -1,124 +1,127 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
//import "log"
|
import (
|
||||||
//import "fmt"
|
//"log"
|
||||||
import "bytes"
|
//"fmt"
|
||||||
//import "strings"
|
"bytes"
|
||||||
import "strconv"
|
|
||||||
import "regexp"
|
//"strings"
|
||||||
import "time"
|
"math/rand"
|
||||||
import "math/rand"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
var random *rand.Rand
|
var random *rand.Rand
|
||||||
var bbcode_invalid_number []byte
|
var bbcodeInvalidNumber []byte
|
||||||
var bbcode_no_negative []byte
|
var bbcodeNoNegative []byte
|
||||||
var bbcode_missing_tag []byte
|
var bbcodeMissingTag []byte
|
||||||
|
|
||||||
var bbcode_bold *regexp.Regexp
|
var bbcodeBold *regexp.Regexp
|
||||||
var bbcode_italic *regexp.Regexp
|
var bbcodeItalic *regexp.Regexp
|
||||||
var bbcode_underline *regexp.Regexp
|
var bbcodeUnderline *regexp.Regexp
|
||||||
var bbcode_strikethrough *regexp.Regexp
|
var bbcodeStrikethrough *regexp.Regexp
|
||||||
var bbcode_url *regexp.Regexp
|
var bbcodeURL *regexp.Regexp
|
||||||
var bbcode_url_label *regexp.Regexp
|
var bbcodeURLLabel *regexp.Regexp
|
||||||
var bbcode_quotes *regexp.Regexp
|
var bbcodeQuotes *regexp.Regexp
|
||||||
var bbcode_code *regexp.Regexp
|
var bbcodeCode *regexp.Regexp
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
plugins["bbcode"] = NewPlugin("bbcode","BBCode","Azareal","http://github.com/Azareal","","","",init_bbcode,nil,deactivate_bbcode,nil,nil)
|
plugins["bbcode"] = NewPlugin("bbcode", "BBCode", "Azareal", "http://github.com/Azareal", "", "", "", initBbcode, nil, deactivateBbcode, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init_bbcode() error {
|
func initBbcode() error {
|
||||||
//plugins["bbcode"].AddHook("parse_assign", bbcode_parse_without_code)
|
//plugins["bbcode"].AddHook("parse_assign", bbcode_parse_without_code)
|
||||||
plugins["bbcode"].AddHook("parse_assign", bbcode_full_parse)
|
plugins["bbcode"].AddHook("parse_assign", bbcodeFullParse)
|
||||||
|
|
||||||
bbcode_invalid_number = []byte("<span style='color: red;'>[Invalid Number]</span>")
|
bbcodeInvalidNumber = []byte("<span style='color: red;'>[Invalid Number]</span>")
|
||||||
bbcode_no_negative = []byte("<span style='color: red;'>[No Negative Numbers]</span>")
|
bbcodeNoNegative = []byte("<span style='color: red;'>[No Negative Numbers]</span>")
|
||||||
bbcode_missing_tag = []byte("<span style='color: red;'>[Missing Tag]</span>")
|
bbcodeMissingTag = []byte("<span style='color: red;'>[Missing Tag]</span>")
|
||||||
|
|
||||||
bbcode_bold = regexp.MustCompile(`(?s)\[b\](.*)\[/b\]`)
|
bbcodeBold = regexp.MustCompile(`(?s)\[b\](.*)\[/b\]`)
|
||||||
bbcode_italic = regexp.MustCompile(`(?s)\[i\](.*)\[/i\]`)
|
bbcodeItalic = regexp.MustCompile(`(?s)\[i\](.*)\[/i\]`)
|
||||||
bbcode_underline = regexp.MustCompile(`(?s)\[u\](.*)\[/u\]`)
|
bbcodeUnderline = regexp.MustCompile(`(?s)\[u\](.*)\[/u\]`)
|
||||||
bbcode_strikethrough = regexp.MustCompile(`(?s)\[s\](.*)\[/s\]`)
|
bbcodeStrikethrough = regexp.MustCompile(`(?s)\[s\](.*)\[/s\]`)
|
||||||
urlpattern := `(http|https|ftp|mailto*)(:??)\/\/([\.a-zA-Z\/]+)`
|
urlpattern := `(http|https|ftp|mailto*)(:??)\/\/([\.a-zA-Z\/]+)`
|
||||||
bbcode_url = regexp.MustCompile(`\[url\]` + urlpattern + `\[/url\]`)
|
bbcodeURL = regexp.MustCompile(`\[url\]` + urlpattern + `\[/url\]`)
|
||||||
bbcode_url_label = regexp.MustCompile(`(?s)\[url=` + urlpattern + `\](.*)\[/url\]`)
|
bbcodeURLLabel = regexp.MustCompile(`(?s)\[url=` + urlpattern + `\](.*)\[/url\]`)
|
||||||
bbcode_quotes = regexp.MustCompile(`\[quote\](.*)\[/quote\]`)
|
bbcodeQuotes = regexp.MustCompile(`\[quote\](.*)\[/quote\]`)
|
||||||
bbcode_code = regexp.MustCompile(`\[code\](.*)\[/code\]`)
|
bbcodeCode = regexp.MustCompile(`\[code\](.*)\[/code\]`)
|
||||||
|
|
||||||
random = rand.New(rand.NewSource(time.Now().UnixNano()))
|
random = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deactivate_bbcode() {
|
func deactivateBbcode() {
|
||||||
//plugins["bbcode"].RemoveHook("parse_assign", bbcode_parse_without_code)
|
//plugins["bbcode"].RemoveHook("parse_assign", bbcode_parse_without_code)
|
||||||
plugins["bbcode"].RemoveHook("parse_assign", bbcode_full_parse)
|
plugins["bbcode"].RemoveHook("parse_assign", bbcodeFullParse)
|
||||||
}
|
}
|
||||||
|
|
||||||
func bbcode_regex_parse(msg string) string {
|
func bbcodeRegexParse(msg string) string {
|
||||||
msg = bbcode_bold.ReplaceAllString(msg,"<b>$1</b>")
|
msg = bbcodeBold.ReplaceAllString(msg, "<b>$1</b>")
|
||||||
msg = bbcode_italic.ReplaceAllString(msg,"<i>$1</i>")
|
msg = bbcodeItalic.ReplaceAllString(msg, "<i>$1</i>")
|
||||||
msg = bbcode_underline.ReplaceAllString(msg,"<u>$1</u>")
|
msg = bbcodeUnderline.ReplaceAllString(msg, "<u>$1</u>")
|
||||||
msg = bbcode_strikethrough.ReplaceAllString(msg,"<s>$1</s>")
|
msg = bbcodeStrikethrough.ReplaceAllString(msg, "<s>$1</s>")
|
||||||
msg = bbcode_url.ReplaceAllString(msg,"<a href=''$1$2//$3' rel='nofollow'>$1$2//$3</i>")
|
msg = bbcodeURL.ReplaceAllString(msg, "<a href=''$1$2//$3' rel='nofollow'>$1$2//$3</i>")
|
||||||
msg = bbcode_url_label.ReplaceAllString(msg,"<a href=''$1$2//$3' rel='nofollow'>$4</i>")
|
msg = bbcodeURLLabel.ReplaceAllString(msg, "<a href=''$1$2//$3' rel='nofollow'>$4</i>")
|
||||||
msg = bbcode_quotes.ReplaceAllString(msg,"<span class='postQuote'>$1</span>")
|
msg = bbcodeQuotes.ReplaceAllString(msg, "<span class='postQuote'>$1</span>")
|
||||||
//msg = bbcode_code.ReplaceAllString(msg,"<span class='codequotes'>$1</span>")
|
//msg = bbcodeCode.ReplaceAllString(msg,"<span class='codequotes'>$1</span>")
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only does the simple BBCode like [u], [b], [i] and [s]
|
// Only does the simple BBCode like [u], [b], [i] and [s]
|
||||||
func bbcode_simple_parse(msg string) string {
|
func bbcodeSimpleParse(msg string) string {
|
||||||
var has_u, has_b, has_i, has_s bool
|
var hasU, hasB, hasI, hasS bool
|
||||||
msgbytes := []byte(msg)
|
msgbytes := []byte(msg)
|
||||||
for i := 0; (i + 2) < len(msgbytes); i++ {
|
for i := 0; (i + 2) < len(msgbytes); i++ {
|
||||||
if msgbytes[i] == '[' && msgbytes[i+2] == ']' {
|
if msgbytes[i] == '[' && msgbytes[i+2] == ']' {
|
||||||
if msgbytes[i + 1] == 'b' && !has_b {
|
if msgbytes[i+1] == 'b' && !hasB {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
msgbytes[i+2] = '>'
|
||||||
has_b = true
|
hasB = true
|
||||||
} else if msgbytes[i + 1] == 'i' && !has_i {
|
} else if msgbytes[i+1] == 'i' && !hasI {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
msgbytes[i+2] = '>'
|
||||||
has_i = true
|
hasI = true
|
||||||
} else if msgbytes[i + 1] == 'u' && !has_u {
|
} else if msgbytes[i+1] == 'u' && !hasU {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
msgbytes[i+2] = '>'
|
||||||
has_u = true
|
hasU = true
|
||||||
} else if msgbytes[i + 1] == 's' && !has_s {
|
} else if msgbytes[i+1] == 's' && !hasS {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
msgbytes[i+2] = '>'
|
||||||
has_s = true
|
hasS = true
|
||||||
}
|
}
|
||||||
i += 2
|
i += 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's an unclosed tag in there x.x
|
// There's an unclosed tag in there x.x
|
||||||
if has_i || has_u || has_b || has_s {
|
if hasI || hasU || hasB || hasS {
|
||||||
close_under := []byte("</u>")
|
closeUnder := []byte("</u>")
|
||||||
close_italic := []byte("</i>")
|
closeItalic := []byte("</i>")
|
||||||
close_bold := []byte("</b>")
|
closeBold := []byte("</b>")
|
||||||
close_strike := []byte("</s>")
|
closeStrike := []byte("</s>")
|
||||||
if has_i {
|
if hasI {
|
||||||
msgbytes = append(msgbytes, close_italic...)
|
msgbytes = append(msgbytes, closeItalic...)
|
||||||
}
|
}
|
||||||
if has_u {
|
if hasU {
|
||||||
msgbytes = append(msgbytes, close_under...)
|
msgbytes = append(msgbytes, closeUnder...)
|
||||||
}
|
}
|
||||||
if has_b {
|
if hasB {
|
||||||
msgbytes = append(msgbytes, close_bold...)
|
msgbytes = append(msgbytes, closeBold...)
|
||||||
}
|
}
|
||||||
if has_s {
|
if hasS {
|
||||||
msgbytes = append(msgbytes, close_strike...)
|
msgbytes = append(msgbytes, closeStrike...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return string(msgbytes)
|
return string(msgbytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here for benchmarking purposes. Might add a plugin setting for disabling [code] as it has it's paws everywhere
|
// Here for benchmarking purposes. Might add a plugin setting for disabling [code] as it has it's paws everywhere
|
||||||
func bbcode_parse_without_code(msg string) string {
|
func bbcodeParseWithoutCode(msg string) string {
|
||||||
var has_u, has_b, has_i, has_s bool
|
var hasU, hasB, hasI, hasS bool
|
||||||
var complex_bbc bool
|
var complexBbc bool
|
||||||
msgbytes := []byte(msg)
|
msgbytes := []byte(msg)
|
||||||
|
|
||||||
for i := 0; (i + 3) < len(msgbytes); i++ {
|
for i := 0; (i + 3) < len(msgbytes); i++ {
|
||||||
@ -129,44 +132,44 @@ func bbcode_parse_without_code(msg string) string {
|
|||||||
if msgbytes[i+2] == 'b' {
|
if msgbytes[i+2] == 'b' {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
msgbytes[i+3] = '>'
|
||||||
has_b = false
|
hasB = false
|
||||||
} else if msgbytes[i+2] == 'i' {
|
} else if msgbytes[i+2] == 'i' {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
msgbytes[i+3] = '>'
|
||||||
has_i = false
|
hasI = false
|
||||||
} else if msgbytes[i+2] == 'u' {
|
} else if msgbytes[i+2] == 'u' {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
msgbytes[i+3] = '>'
|
||||||
has_u = false
|
hasU = false
|
||||||
} else if msgbytes[i+2] == 's' {
|
} else if msgbytes[i+2] == 's' {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
msgbytes[i+3] = '>'
|
||||||
has_s = false
|
hasS = false
|
||||||
}
|
}
|
||||||
i += 3
|
i += 3
|
||||||
} else {
|
} else {
|
||||||
complex_bbc = true
|
complexBbc = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
complex_bbc = true
|
complexBbc = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if msgbytes[i + 1] == 'b' && !has_b {
|
if msgbytes[i+1] == 'b' && !hasB {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
msgbytes[i+2] = '>'
|
||||||
has_b = true
|
hasB = true
|
||||||
} else if msgbytes[i + 1] == 'i' && !has_i {
|
} else if msgbytes[i+1] == 'i' && !hasI {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
msgbytes[i+2] = '>'
|
||||||
has_i = true
|
hasI = true
|
||||||
} else if msgbytes[i + 1] == 'u' && !has_u {
|
} else if msgbytes[i+1] == 'u' && !hasU {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
msgbytes[i+2] = '>'
|
||||||
has_u = true
|
hasU = true
|
||||||
} else if msgbytes[i + 1] == 's' && !has_s {
|
} else if msgbytes[i+1] == 's' && !hasS {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
msgbytes[i+2] = '>'
|
||||||
has_s = true
|
hasS = true
|
||||||
}
|
}
|
||||||
i += 2
|
i += 2
|
||||||
}
|
}
|
||||||
@ -174,43 +177,44 @@ func bbcode_parse_without_code(msg string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// There's an unclosed tag in there x.x
|
// There's an unclosed tag in there x.x
|
||||||
if has_i || has_u || has_b || has_s {
|
if hasI || hasU || hasB || hasS {
|
||||||
close_under := []byte("</u>")
|
closeUnder := []byte("</u>")
|
||||||
close_italic := []byte("</i>")
|
closeItalic := []byte("</i>")
|
||||||
close_bold := []byte("</b>")
|
closeBold := []byte("</b>")
|
||||||
close_strike := []byte("</s>")
|
closeStrike := []byte("</s>")
|
||||||
if has_i {
|
if hasI {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_italic...)
|
msgbytes = append(bytes.TrimSpace(msgbytes), closeItalic...)
|
||||||
}
|
}
|
||||||
if has_u {
|
if hasU {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_under...)
|
msgbytes = append(bytes.TrimSpace(msgbytes), closeUnder...)
|
||||||
}
|
}
|
||||||
if has_b {
|
if hasB {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_bold...)
|
msgbytes = append(bytes.TrimSpace(msgbytes), closeBold...)
|
||||||
}
|
}
|
||||||
if has_s {
|
if hasS {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_strike...)
|
msgbytes = append(bytes.TrimSpace(msgbytes), closeStrike...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the new complex parser over once the rough edges have been smoothed over
|
// Copy the new complex parser over once the rough edges have been smoothed over
|
||||||
if complex_bbc {
|
if complexBbc {
|
||||||
msg = bbcode_url.ReplaceAllString(msg,"<a href='$1$2//$3' rel='nofollow'>$1$2//$3</i>")
|
msg = string(msgbytes)
|
||||||
msg = bbcode_url_label.ReplaceAllString(msg,"<a href='$1$2//$3' rel='nofollow'>$4</i>")
|
msg = bbcodeURL.ReplaceAllString(msg, "<a href='$1$2//$3' rel='nofollow'>$1$2//$3</i>")
|
||||||
msg = bbcode_quotes.ReplaceAllString(msg,"<span class='postQuote'>$1</span>")
|
msg = bbcodeURLLabel.ReplaceAllString(msg, "<a href='$1$2//$3' rel='nofollow'>$4</i>")
|
||||||
msg = bbcode_code.ReplaceAllString(msg,"<span class='codequotes'>$1</span>")
|
msg = bbcodeQuotes.ReplaceAllString(msg, "<span class='postQuote'>$1</span>")
|
||||||
}
|
return bbcodeCode.ReplaceAllString(msg, "<span class='codequotes'>$1</span>")
|
||||||
|
} else {
|
||||||
return string(msgbytes)
|
return string(msgbytes)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Does every type of BBCode
|
// Does every type of BBCode
|
||||||
func bbcode_full_parse(msg string) string {
|
func bbcodeFullParse(msg string) string {
|
||||||
var has_u, has_b, has_i, has_s, has_c bool
|
var hasU, hasB, hasI, hasS, hasC bool
|
||||||
var complex_bbc bool
|
var complexBbc bool
|
||||||
|
|
||||||
msgbytes := []byte(msg)
|
msgbytes := []byte(msg)
|
||||||
msgbytes = append(msgbytes,space_gap...)
|
msgbytes = append(msgbytes, spaceGap...)
|
||||||
//log.Print("BBCode Simple Pre:","`"+string(msgbytes)+"`")
|
//log.Print("BBCode Simple Pre:","`"+string(msgbytes)+"`")
|
||||||
//log.Print("----")
|
//log.Print("----")
|
||||||
|
|
||||||
@ -219,29 +223,29 @@ func bbcode_full_parse(msg string) string {
|
|||||||
if msgbytes[i+2] != ']' {
|
if msgbytes[i+2] != ']' {
|
||||||
if msgbytes[i+1] == '/' {
|
if msgbytes[i+1] == '/' {
|
||||||
if msgbytes[i+3] == ']' {
|
if msgbytes[i+3] == ']' {
|
||||||
if !has_c {
|
if !hasC {
|
||||||
if msgbytes[i+2] == 'b' {
|
if msgbytes[i+2] == 'b' {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
msgbytes[i+3] = '>'
|
||||||
has_b = false
|
hasB = false
|
||||||
} else if msgbytes[i+2] == 'i' {
|
} else if msgbytes[i+2] == 'i' {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
msgbytes[i+3] = '>'
|
||||||
has_i = false
|
hasI = false
|
||||||
} else if msgbytes[i+2] == 'u' {
|
} else if msgbytes[i+2] == 'u' {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
msgbytes[i+3] = '>'
|
||||||
has_u = false
|
hasU = false
|
||||||
} else if msgbytes[i+2] == 's' {
|
} else if msgbytes[i+2] == 's' {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+3] = '>'
|
msgbytes[i+3] = '>'
|
||||||
has_s = false
|
hasS = false
|
||||||
}
|
}
|
||||||
i += 3
|
i += 3
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if msgbytes[i+2] == 'c' && msgbytes[i+3] == 'o' && msgbytes[i+4] == 'd' && msgbytes[i+5] == 'e' && msgbytes[i+6] == ']' {
|
if msgbytes[i+2] == 'c' && msgbytes[i+3] == 'o' && msgbytes[i+4] == 'd' && msgbytes[i+5] == 'e' && msgbytes[i+6] == ']' {
|
||||||
has_c = false
|
hasC = false
|
||||||
i += 7
|
i += 7
|
||||||
}
|
}
|
||||||
//if msglen >= (i+6) {
|
//if msglen >= (i+6) {
|
||||||
@ -250,36 +254,36 @@ func bbcode_full_parse(msg string) string {
|
|||||||
// log.Print(i+6)
|
// log.Print(i+6)
|
||||||
// log.Print(string(msgbytes[i:i+6]))
|
// log.Print(string(msgbytes[i:i+6]))
|
||||||
//}
|
//}
|
||||||
complex_bbc = true
|
complexBbc = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if msgbytes[i+1] == 'c' && msgbytes[i+2] == 'o' && msgbytes[i+3] == 'd' && msgbytes[i+4] == 'e' && msgbytes[i+5] == ']' {
|
if msgbytes[i+1] == 'c' && msgbytes[i+2] == 'o' && msgbytes[i+3] == 'd' && msgbytes[i+4] == 'e' && msgbytes[i+5] == ']' {
|
||||||
has_c = true
|
hasC = true
|
||||||
i += 6
|
i += 6
|
||||||
}
|
}
|
||||||
//if msglen >= (i+5) {
|
//if msglen >= (i+5) {
|
||||||
// log.Print("boo2")
|
// log.Print("boo2")
|
||||||
// log.Print(string(msgbytes[i:i+5]))
|
// log.Print(string(msgbytes[i:i+5]))
|
||||||
//}
|
//}
|
||||||
complex_bbc = true
|
complexBbc = true
|
||||||
}
|
}
|
||||||
} else if !has_c {
|
} else if !hasC {
|
||||||
if msgbytes[i + 1] == 'b' && !has_b {
|
if msgbytes[i+1] == 'b' && !hasB {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
msgbytes[i+2] = '>'
|
||||||
has_b = true
|
hasB = true
|
||||||
} else if msgbytes[i + 1] == 'i' && !has_i {
|
} else if msgbytes[i+1] == 'i' && !hasI {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
msgbytes[i+2] = '>'
|
||||||
has_i = true
|
hasI = true
|
||||||
} else if msgbytes[i + 1] == 'u' && !has_u {
|
} else if msgbytes[i+1] == 'u' && !hasU {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
msgbytes[i+2] = '>'
|
||||||
has_u = true
|
hasU = true
|
||||||
} else if msgbytes[i + 1] == 's' && !has_s {
|
} else if msgbytes[i+1] == 's' && !hasS {
|
||||||
msgbytes[i] = '<'
|
msgbytes[i] = '<'
|
||||||
msgbytes[i+2] = '>'
|
msgbytes[i+2] = '>'
|
||||||
has_s = true
|
hasS = true
|
||||||
}
|
}
|
||||||
i += 2
|
i += 2
|
||||||
}
|
}
|
||||||
@ -287,27 +291,27 @@ func bbcode_full_parse(msg string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// There's an unclosed tag in there somewhere x.x
|
// There's an unclosed tag in there somewhere x.x
|
||||||
if has_i || has_u || has_b || has_s {
|
if hasI || hasU || hasB || hasS {
|
||||||
close_under := []byte("</u>")
|
closeUnder := []byte("</u>")
|
||||||
close_italic := []byte("</i>")
|
closeItalic := []byte("</i>")
|
||||||
close_bold := []byte("</b>")
|
closeBold := []byte("</b>")
|
||||||
close_strike := []byte("</s>")
|
closeStrike := []byte("</s>")
|
||||||
if has_i {
|
if hasI {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_italic...)
|
msgbytes = append(bytes.TrimSpace(msgbytes), closeItalic...)
|
||||||
}
|
}
|
||||||
if has_u {
|
if hasU {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_under...)
|
msgbytes = append(bytes.TrimSpace(msgbytes), closeUnder...)
|
||||||
}
|
}
|
||||||
if has_b {
|
if hasB {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_bold...)
|
msgbytes = append(bytes.TrimSpace(msgbytes), closeBold...)
|
||||||
}
|
}
|
||||||
if has_s {
|
if hasS {
|
||||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_strike...)
|
msgbytes = append(bytes.TrimSpace(msgbytes), closeStrike...)
|
||||||
}
|
}
|
||||||
msgbytes = append(msgbytes,space_gap...)
|
msgbytes = append(msgbytes, spaceGap...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if complex_bbc {
|
if complexBbc {
|
||||||
i := 0
|
i := 0
|
||||||
var start, lastTag int
|
var start, lastTag int
|
||||||
var outbytes []byte
|
var outbytes []byte
|
||||||
@ -322,21 +326,21 @@ func bbcode_full_parse(msg string) string {
|
|||||||
start = i + 5
|
start = i + 5
|
||||||
outbytes = append(outbytes, msgbytes[lastTag:i]...)
|
outbytes = append(outbytes, msgbytes[lastTag:i]...)
|
||||||
i = start
|
i = start
|
||||||
i += partial_url_bytes_len(msgbytes[start:])
|
i += partialURLBytesLen(msgbytes[start:])
|
||||||
//log.Print("Partial Bytes:",string(msgbytes[start:]))
|
//log.Print("Partial Bytes:",string(msgbytes[start:]))
|
||||||
//log.Print("-----")
|
//log.Print("-----")
|
||||||
if !bytes.Equal(msgbytes[i:i+6], []byte("[/url]")) {
|
if !bytes.Equal(msgbytes[i:i+6], []byte("[/url]")) {
|
||||||
//log.Print("Invalid Bytes:",string(msgbytes[i:i+6]))
|
//log.Print("Invalid Bytes:",string(msgbytes[i:i+6]))
|
||||||
//log.Print("-----")
|
//log.Print("-----")
|
||||||
outbytes = append(outbytes, invalid_url...)
|
outbytes = append(outbytes, invalidURL...)
|
||||||
goto MainLoop
|
goto MainLoop
|
||||||
}
|
}
|
||||||
|
|
||||||
outbytes = append(outbytes, url_open...)
|
outbytes = append(outbytes, urlOpen...)
|
||||||
outbytes = append(outbytes, msgbytes[start:i]...)
|
outbytes = append(outbytes, msgbytes[start:i]...)
|
||||||
outbytes = append(outbytes, url_open2...)
|
outbytes = append(outbytes, urlOpen2...)
|
||||||
outbytes = append(outbytes, msgbytes[start:i]...)
|
outbytes = append(outbytes, msgbytes[start:i]...)
|
||||||
outbytes = append(outbytes, url_close...)
|
outbytes = append(outbytes, urlClose...)
|
||||||
i += 6
|
i += 6
|
||||||
lastTag = i
|
lastTag = i
|
||||||
}
|
}
|
||||||
@ -348,25 +352,25 @@ func bbcode_full_parse(msg string) string {
|
|||||||
for ; ; i++ {
|
for ; ; i++ {
|
||||||
if msgbytes[i] == '[' {
|
if msgbytes[i] == '[' {
|
||||||
if !bytes.Equal(msgbytes[i+1:i+7], []byte("/rand]")) {
|
if !bytes.Equal(msgbytes[i+1:i+7], []byte("/rand]")) {
|
||||||
outbytes = append(outbytes, bbcode_missing_tag...)
|
outbytes = append(outbytes, bbcodeMissingTag...)
|
||||||
goto OuterComplex
|
goto OuterComplex
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
} else if (len(msgbytes) - 1) < (i + 10) {
|
} else if (len(msgbytes) - 1) < (i + 10) {
|
||||||
outbytes = append(outbytes, bbcode_missing_tag...)
|
outbytes = append(outbytes, bbcodeMissingTag...)
|
||||||
goto OuterComplex
|
goto OuterComplex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
number, err := strconv.ParseInt(string(msgbytes[start:i]), 10, 64)
|
number, err := strconv.ParseInt(string(msgbytes[start:i]), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
outbytes = append(outbytes, bbcode_invalid_number...)
|
outbytes = append(outbytes, bbcodeInvalidNumber...)
|
||||||
goto MainLoop
|
goto MainLoop
|
||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: Add support for negative numbers?
|
// TO-DO: Add support for negative numbers?
|
||||||
if number < 0 {
|
if number < 0 {
|
||||||
outbytes = append(outbytes, bbcode_no_negative...)
|
outbytes = append(outbytes, bbcodeNoNegative...)
|
||||||
goto MainLoop
|
goto MainLoop
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,9 +405,9 @@ func bbcode_full_parse(msg string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>")
|
//msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>")
|
||||||
msg = bbcode_url_label.ReplaceAllString(msg,"<a href='$1$2//$3' rel='nofollow'>$4</i>")
|
msg = bbcodeURLLabel.ReplaceAllString(msg, "<a href='$1$2//$3' rel='nofollow'>$4</i>")
|
||||||
msg = bbcode_quotes.ReplaceAllString(msg,"<span class='postQuote'>$1</span>")
|
msg = bbcodeQuotes.ReplaceAllString(msg, "<span class='postQuote'>$1</span>")
|
||||||
msg = bbcode_code.ReplaceAllString(msg,"<span class='codequotes'>$1</span>")
|
msg = bbcodeCode.ReplaceAllString(msg, "<span class='codequotes'>$1</span>")
|
||||||
} else {
|
} else {
|
||||||
msg = string(msgbytes[0 : len(msgbytes)-10])
|
msg = string(msgbytes[0 : len(msgbytes)-10])
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
plugins["helloworld"] = NewPlugin("helloworld","Hello World","Azareal","http://github.com/Azareal","","","",init_helloworld,nil,deactivate_helloworld,nil,nil)
|
plugins["helloworld"] = NewPlugin("helloworld", "Hello World", "Azareal", "http://github.com/Azareal", "", "", "", initHelloworld, nil, deactivateHelloworld, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// init_helloworld is separate from init() as we don't want the plugin to run if the plugin is disabled
|
// init_helloworld is separate from init() as we don't want the plugin to run if the plugin is disabled
|
||||||
func init_helloworld() error {
|
func initHelloworld() error {
|
||||||
plugins["helloworld"].AddHook("rrow_assign", helloworld_reply)
|
plugins["helloworld"].AddHook("rrow_assign", helloworldReply)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deactivate_helloworld() {
|
func deactivateHelloworld() {
|
||||||
plugins["helloworld"].RemoveHook("rrow_assign", helloworld_reply)
|
plugins["helloworld"].RemoveHook("rrow_assign", helloworldReply)
|
||||||
}
|
}
|
||||||
|
|
||||||
func helloworld_reply(data interface{}) interface{} {
|
func helloworldReply(data interface{}) interface{} {
|
||||||
reply := data.(*Reply)
|
reply := data.(*Reply)
|
||||||
reply.Content = "Hello World!"
|
reply.Content = "Hello World!"
|
||||||
reply.ContentHtml = "Hello World!"
|
reply.ContentHtml = "Hello World!"
|
||||||
|
@ -4,73 +4,72 @@ package main
|
|||||||
import "regexp"
|
import "regexp"
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
||||||
var markdown_max_depth int = 25 // How deep the parser will go when parsing Markdown strings
|
var markdownMaxDepth int = 25 // How deep the parser will go when parsing Markdown strings
|
||||||
var markdown_unclosed_element []byte
|
var markdownUnclosedElement []byte
|
||||||
|
|
||||||
var markdown_bold_tag_open, markdown_bold_tag_close []byte
|
var markdownBoldTagOpen, markdownBoldTagClose []byte
|
||||||
var markdown_italic_tag_open, markdown_italic_tag_close []byte
|
var markdownItalicTagOpen, markdownItalicTagClose []byte
|
||||||
var markdown_underline_tag_open, markdown_underline_tag_close []byte
|
var markdownUnderlineTagOpen, markdownUnderlineTagClose []byte
|
||||||
var markdown_strike_tag_open, markdown_strike_tag_close []byte
|
var markdownStrikeTagOpen, markdownStrikeTagClose []byte
|
||||||
|
|
||||||
var markdown_bold_italic *regexp.Regexp
|
var markdownBoldItalic *regexp.Regexp
|
||||||
var markdown_bold *regexp.Regexp
|
var markdownBold *regexp.Regexp
|
||||||
var markdown_italic *regexp.Regexp
|
var markdownItalic *regexp.Regexp
|
||||||
var markdown_strike *regexp.Regexp
|
var markdownStrike *regexp.Regexp
|
||||||
var markdown_underline *regexp.Regexp
|
var markdownUnderline *regexp.Regexp
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
plugins["markdown"] = NewPlugin("markdown","Markdown","Azareal","http://github.com/Azareal","","","",init_markdown,nil,deactivate_markdown,nil,nil)
|
plugins["markdown"] = NewPlugin("markdown", "Markdown", "Azareal", "http://github.com/Azareal", "", "", "", initMarkdown, nil, deactivateMarkdown, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init_markdown() error {
|
func initMarkdown() error {
|
||||||
//plugins["markdown"].AddHook("parse_assign", markdown_regex_parse)
|
//plugins["markdown"].AddHook("parse_assign", markdownRegexParse)
|
||||||
plugins["markdown"].AddHook("parse_assign", markdown_parse)
|
plugins["markdown"].AddHook("parse_assign", markdownParse)
|
||||||
|
|
||||||
markdown_unclosed_element = []byte("<span style='color: red;'>[Unclosed Element]</span>")
|
markdownUnclosedElement = []byte("<span style='color: red;'>[Unclosed Element]</span>")
|
||||||
|
|
||||||
markdown_bold_tag_open = []byte("<b>")
|
markdownBoldTagOpen = []byte("<b>")
|
||||||
markdown_bold_tag_close = []byte("</b>")
|
markdownBoldTagClose = []byte("</b>")
|
||||||
markdown_italic_tag_open = []byte("<i>")
|
markdownItalicTagOpen = []byte("<i>")
|
||||||
markdown_italic_tag_close = []byte("</i>")
|
markdownItalicTagClose = []byte("</i>")
|
||||||
markdown_underline_tag_open = []byte("<u>")
|
markdownUnderlineTagOpen = []byte("<u>")
|
||||||
markdown_underline_tag_close = []byte("</u>")
|
markdownUnderlineTagClose = []byte("</u>")
|
||||||
markdown_strike_tag_open = []byte("<s>")
|
markdownStrikeTagOpen = []byte("<s>")
|
||||||
markdown_strike_tag_close = []byte("</s>")
|
markdownStrikeTagClose = []byte("</s>")
|
||||||
|
|
||||||
markdown_bold_italic = regexp.MustCompile(`\*\*\*(.*)\*\*\*`)
|
markdownBoldItalic = regexp.MustCompile(`\*\*\*(.*)\*\*\*`)
|
||||||
markdown_bold = regexp.MustCompile(`\*\*(.*)\*\*`)
|
markdownBold = regexp.MustCompile(`\*\*(.*)\*\*`)
|
||||||
markdown_italic = regexp.MustCompile(`\*(.*)\*`)
|
markdownItalic = regexp.MustCompile(`\*(.*)\*`)
|
||||||
//markdown_strike = regexp.MustCompile(`\~\~(.*)\~\~`)
|
//markdownStrike = regexp.MustCompile(`\~\~(.*)\~\~`)
|
||||||
markdown_strike = regexp.MustCompile(`\~(.*)\~`)
|
markdownStrike = regexp.MustCompile(`\~(.*)\~`)
|
||||||
//markdown_underline = regexp.MustCompile(`\_\_(.*)\_\_`)
|
//markdown_underline = regexp.MustCompile(`\_\_(.*)\_\_`)
|
||||||
markdown_underline = regexp.MustCompile(`\_(.*)\_`)
|
markdownUnderline = regexp.MustCompile(`\_(.*)\_`)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deactivate_markdown() {
|
func deactivateMarkdown() {
|
||||||
//plugins["markdown"].RemoveHook("parse_assign", markdown_regex_parse)
|
//plugins["markdown"].RemoveHook("parse_assign", markdownRegexParse)
|
||||||
plugins["markdown"].RemoveHook("parse_assign", markdown_parse)
|
plugins["markdown"].RemoveHook("parse_assign", markdownParse)
|
||||||
}
|
}
|
||||||
|
|
||||||
func markdown_regex_parse(msg string) string {
|
func markdownRegexParse(msg string) string {
|
||||||
msg = markdown_bold_italic.ReplaceAllString(msg,"<i><b>$1</b></i>")
|
msg = markdownBoldItalic.ReplaceAllString(msg, "<i><b>$1</b></i>")
|
||||||
msg = markdown_bold.ReplaceAllString(msg,"<b>$1</b>")
|
msg = markdownBold.ReplaceAllString(msg, "<b>$1</b>")
|
||||||
msg = markdown_italic.ReplaceAllString(msg,"<i>$1</i>")
|
msg = markdownItalic.ReplaceAllString(msg, "<i>$1</i>")
|
||||||
msg = markdown_strike.ReplaceAllString(msg,"<s>$1</s>")
|
msg = markdownStrike.ReplaceAllString(msg, "<s>$1</s>")
|
||||||
msg = markdown_underline.ReplaceAllString(msg,"<u>$1</u>")
|
msg = markdownUnderline.ReplaceAllString(msg, "<u>$1</u>")
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// An adapter for the parser, so that the parser can call itself recursively.
|
// An adapter for the parser, so that the parser can call itself recursively.
|
||||||
// This is less for the simple Markdown elements like bold and italics and more for the really complicated ones I plan on adding at some point.
|
// This is less for the simple Markdown elements like bold and italics and more for the really complicated ones I plan on adding at some point.
|
||||||
func markdown_parse(msg string) string {
|
func markdownParse(msg string) string {
|
||||||
return strings.TrimSpace(_markdown_parse(msg + " ",0))
|
return strings.TrimSpace(_markdownParse(msg+" ", 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Under Construction!
|
// Under Construction!
|
||||||
func _markdown_parse(msg string, n int) string {
|
func _markdownParse(msg string, n int) string {
|
||||||
if n > markdown_max_depth {
|
if n > markdownMaxDepth {
|
||||||
return "<span style='color: red;'>[Markdown Error: Overflowed the max depth of 20]</span>"
|
return "<span style='color: red;'>[Markdown Error: Overflowed the max depth of 20]</span>"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +86,7 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
//log.Print("--OUTER MARKDOWN LOOP END--")
|
//log.Print("--OUTER MARKDOWN LOOP END--")
|
||||||
//log.Print(" ")*/
|
//log.Print(" ")*/
|
||||||
|
|
||||||
switch(msg[index]) {
|
switch msg[index] {
|
||||||
case '_':
|
case '_':
|
||||||
var startIndex int = index
|
var startIndex int = index
|
||||||
if (index + 1) >= len(msg) {
|
if (index + 1) >= len(msg) {
|
||||||
@ -95,7 +94,7 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
index++
|
index++
|
||||||
index = markdown_skip_until_char(msg, index, '_')
|
index = markdownSkipUntilChar(msg, index, '_')
|
||||||
if (index-(startIndex+1)) < 2 || index >= len(msg) {
|
if (index-(startIndex+1)) < 2 || index >= len(msg) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -105,9 +104,9 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
index++
|
index++
|
||||||
|
|
||||||
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
||||||
outbytes = append(outbytes, markdown_underline_tag_open...)
|
outbytes = append(outbytes, markdownUnderlineTagOpen...)
|
||||||
outbytes = append(outbytes, msg[sIndex:lIndex]...)
|
outbytes = append(outbytes, msg[sIndex:lIndex]...)
|
||||||
outbytes = append(outbytes, markdown_underline_tag_close...)
|
outbytes = append(outbytes, markdownUnderlineTagClose...)
|
||||||
|
|
||||||
lastElement = index
|
lastElement = index
|
||||||
index--
|
index--
|
||||||
@ -118,7 +117,7 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
index++
|
index++
|
||||||
index = markdown_skip_until_char(msg, index, '~')
|
index = markdownSkipUntilChar(msg, index, '~')
|
||||||
if (index-(startIndex+1)) < 2 || index >= len(msg) {
|
if (index-(startIndex+1)) < 2 || index >= len(msg) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -128,9 +127,9 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
index++
|
index++
|
||||||
|
|
||||||
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
||||||
outbytes = append(outbytes, markdown_strike_tag_open...)
|
outbytes = append(outbytes, markdownStrikeTagOpen...)
|
||||||
outbytes = append(outbytes, msg[sIndex:lIndex]...)
|
outbytes = append(outbytes, msg[sIndex:lIndex]...)
|
||||||
outbytes = append(outbytes, markdown_strike_tag_close...)
|
outbytes = append(outbytes, markdownStrikeTagClose...)
|
||||||
|
|
||||||
lastElement = index
|
lastElement = index
|
||||||
index--
|
index--
|
||||||
@ -186,7 +185,7 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
//log.Print("preskip msg[index]",msg[index])
|
//log.Print("preskip msg[index]",msg[index])
|
||||||
//log.Print("preskip string(msg[index])",string(msg[index]))
|
//log.Print("preskip string(msg[index])",string(msg[index]))
|
||||||
|
|
||||||
index = markdown_skip_until_asterisk(msg,index)
|
index = markdownSkipUntilAsterisk(msg, index)
|
||||||
|
|
||||||
if index >= len(msg) {
|
if index >= len(msg) {
|
||||||
break
|
break
|
||||||
@ -203,7 +202,7 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
if (index + 3) >= len(msg) {
|
if (index + 3) >= len(msg) {
|
||||||
//log.Print("unclosed markdown element @ exit element")
|
//log.Print("unclosed markdown element @ exit element")
|
||||||
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
||||||
outbytes = append(outbytes, markdown_unclosed_element...)
|
outbytes = append(outbytes, markdownUnclosedElement...)
|
||||||
lastElement = startIndex
|
lastElement = startIndex
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -214,7 +213,7 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
if (index + 2) >= len(msg) {
|
if (index + 2) >= len(msg) {
|
||||||
//log.Print("true unclosed markdown element @ exit element")
|
//log.Print("true unclosed markdown element @ exit element")
|
||||||
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
||||||
outbytes = append(outbytes, markdown_unclosed_element...)
|
outbytes = append(outbytes, markdownUnclosedElement...)
|
||||||
lastElement = startIndex
|
lastElement = startIndex
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -225,7 +224,7 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
if (index + 1) >= len(msg) {
|
if (index + 1) >= len(msg) {
|
||||||
//log.Print("true unclosed markdown element @ exit element")
|
//log.Print("true unclosed markdown element @ exit element")
|
||||||
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
||||||
outbytes = append(outbytes, markdown_unclosed_element...)
|
outbytes = append(outbytes, markdownUnclosedElement...)
|
||||||
lastElement = startIndex
|
lastElement = startIndex
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -239,7 +238,7 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
if lIndex <= sIndex {
|
if lIndex <= sIndex {
|
||||||
//log.Print("unclosed markdown element @ lIndex <= sIndex")
|
//log.Print("unclosed markdown element @ lIndex <= sIndex")
|
||||||
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
||||||
outbytes = append(outbytes, markdown_unclosed_element...)
|
outbytes = append(outbytes, markdownUnclosedElement...)
|
||||||
lastElement = startIndex
|
lastElement = startIndex
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -247,7 +246,7 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
if sIndex < 0 || lIndex < 0 {
|
if sIndex < 0 || lIndex < 0 {
|
||||||
//log.Print("unclosed markdown element @ sIndex < 0 || lIndex < 0")
|
//log.Print("unclosed markdown element @ sIndex < 0 || lIndex < 0")
|
||||||
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
||||||
outbytes = append(outbytes, markdown_unclosed_element...)
|
outbytes = append(outbytes, markdownUnclosedElement...)
|
||||||
lastElement = startIndex
|
lastElement = startIndex
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -269,19 +268,19 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
outbytes = append(outbytes, msg[lastElement:startIndex]...)
|
||||||
|
|
||||||
if bold {
|
if bold {
|
||||||
outbytes = append(outbytes, markdown_bold_tag_open...)
|
outbytes = append(outbytes, markdownBoldTagOpen...)
|
||||||
}
|
}
|
||||||
if italic {
|
if italic {
|
||||||
outbytes = append(outbytes, markdown_italic_tag_open...)
|
outbytes = append(outbytes, markdownItalicTagOpen...)
|
||||||
}
|
}
|
||||||
|
|
||||||
outbytes = append(outbytes, msg[sIndex:lIndex]...)
|
outbytes = append(outbytes, msg[sIndex:lIndex]...)
|
||||||
|
|
||||||
if italic {
|
if italic {
|
||||||
outbytes = append(outbytes, markdown_italic_tag_close...)
|
outbytes = append(outbytes, markdownItalicTagClose...)
|
||||||
}
|
}
|
||||||
if bold {
|
if bold {
|
||||||
outbytes = append(outbytes, markdown_bold_tag_close...)
|
outbytes = append(outbytes, markdownBoldTagClose...)
|
||||||
}
|
}
|
||||||
|
|
||||||
lastElement = index
|
lastElement = index
|
||||||
@ -303,7 +302,7 @@ func _markdown_parse(msg string, n int) string {
|
|||||||
return string(outbytes)
|
return string(outbytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func markdown_find_char(data string ,index int ,char byte) bool {
|
func markdownFindChar(data string, index int, char byte) bool {
|
||||||
for ; index < len(data); index++ {
|
for ; index < len(data); index++ {
|
||||||
item := data[index]
|
item := data[index]
|
||||||
if item > 32 {
|
if item > 32 {
|
||||||
@ -313,7 +312,7 @@ func markdown_find_char(data string ,index int ,char byte) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func markdown_skip_until_char(data string, index int, char byte) int {
|
func markdownSkipUntilChar(data string, index int, char byte) int {
|
||||||
for ; index < len(data); index++ {
|
for ; index < len(data); index++ {
|
||||||
if data[index] == char {
|
if data[index] == char {
|
||||||
break
|
break
|
||||||
@ -322,22 +321,23 @@ func markdown_skip_until_char(data string, index int, char byte) int {
|
|||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
|
|
||||||
func markdown_skip_until_asterisk(data string, index int) int {
|
func markdownSkipUntilAsterisk(data string, index int) int {
|
||||||
SwitchLoop:
|
SwitchLoop:
|
||||||
for ; index < len(data); index++ {
|
for ; index < len(data); index++ {
|
||||||
switch(data[index]) {
|
switch data[index] {
|
||||||
case 10:
|
case 10:
|
||||||
if ((index+1) < len(data)) && markdown_find_char(data,index,'*') {
|
if ((index + 1) < len(data)) && markdownFindChar(data, index, '*') {
|
||||||
index = markdown_skip_list(data,index)
|
index = markdownSkipList(data, index)
|
||||||
}
|
}
|
||||||
case '*': break SwitchLoop
|
case '*':
|
||||||
|
break SwitchLoop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
|
|
||||||
// plugin_markdown doesn't support lists yet, but I want it to be easy to have nested lists when we do have them
|
// plugin_markdown doesn't support lists yet, but I want it to be easy to have nested lists when we do have them
|
||||||
func markdown_skip_list(data string, index int) int {
|
func markdownSkipList(data string, index int) int {
|
||||||
var lastNewline int
|
var lastNewline int
|
||||||
var datalen int = len(data)
|
var datalen int = len(data)
|
||||||
|
|
||||||
|
@ -26,12 +26,12 @@ func init() {
|
|||||||
|
|
||||||
That Uninstallation field which is currently unused is for not only deactivating this plugin, but for purging any data associated with it such a new tables or data produced by the end-user.
|
That Uninstallation field which is currently unused is for not only deactivating this plugin, but for purging any data associated with it such a new tables or data produced by the end-user.
|
||||||
*/
|
*/
|
||||||
plugins["skeleton"] = NewPlugin("skeleton","Skeleton","Azareal","","","","",init_skeleton, activate_skeleton, deactivate_skeleton,nil,nil)
|
plugins["skeleton"] = NewPlugin("skeleton", "Skeleton", "Azareal", "", "", "", "", initSkeleton, activateSkeleton, deactivateSkeleton, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init_skeleton() error { return nil; }
|
func initSkeleton() error { return nil }
|
||||||
|
|
||||||
// Any errors encountered while trying to activate the plugin are reported back to the admin and the activation is aborted
|
// Any errors encountered while trying to activate the plugin are reported back to the admin and the activation is aborted
|
||||||
func activate_skeleton() error { return nil; }
|
func activateSkeleton() error { return nil }
|
||||||
|
|
||||||
func deactivate_skeleton() {}
|
func deactivateSkeleton() {}
|
||||||
|
@ -3,31 +3,32 @@ package main
|
|||||||
import (
|
import (
|
||||||
//"fmt"
|
//"fmt"
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
|
||||||
"strconv"
|
|
||||||
"errors"
|
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"html"
|
"html"
|
||||||
"html/template"
|
"html/template"
|
||||||
"database/sql"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"./query_gen/lib"
|
"./query_gen/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
var socialgroups_list_stmt *sql.Stmt
|
var socialgroupsListStmt *sql.Stmt
|
||||||
var socialgroups_member_list_stmt *sql.Stmt
|
var socialgroupsMemberListStmt *sql.Stmt
|
||||||
var socialgroups_member_list_join_stmt *sql.Stmt
|
var socialgroupsMemberListJoinStmt *sql.Stmt
|
||||||
var socialgroups_get_member_stmt *sql.Stmt
|
var socialgroupsGetMemberStmt *sql.Stmt
|
||||||
var socialgroups_get_group_stmt *sql.Stmt
|
var socialgroupsGetGroupStmt *sql.Stmt
|
||||||
var socialgroups_create_group_stmt *sql.Stmt
|
var socialgroupsCreateGroupStmt *sql.Stmt
|
||||||
var socialgroups_attach_forum_stmt *sql.Stmt
|
var socialgroupsAttachForumStmt *sql.Stmt
|
||||||
var socialgroups_unattach_forum_stmt *sql.Stmt
|
var socialgroupsUnattachForumStmt *sql.Stmt
|
||||||
var socialgroups_add_member_stmt *sql.Stmt
|
var socialgroupsAddMemberStmt *sql.Stmt
|
||||||
|
|
||||||
// TO-DO: Add a better way of splitting up giant plugins like this
|
// TO-DO: Add a better way of splitting up giant plugins like this
|
||||||
type SocialGroup struct
|
|
||||||
{
|
// SocialGroup is a struct representing a social group
|
||||||
|
type SocialGroup struct {
|
||||||
ID int
|
ID int
|
||||||
Link string
|
Link string
|
||||||
Name string
|
Name string
|
||||||
@ -50,42 +51,37 @@ type SocialGroup struct
|
|||||||
ExtData ExtData
|
ExtData ExtData
|
||||||
}
|
}
|
||||||
|
|
||||||
type SocialGroupPage struct
|
type SocialGroupPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
ItemList []*TopicsRow
|
ItemList []*TopicsRow
|
||||||
Forum Forum
|
Forum Forum
|
||||||
SocialGroup SocialGroup
|
SocialGroup *SocialGroup
|
||||||
Page int
|
Page int
|
||||||
LastPage int
|
LastPage int
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SocialGroupListPage struct
|
// SocialGroupListPage is a page struct for constructing a list of every social group
|
||||||
{
|
type SocialGroupListPage struct {
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
GroupList []SocialGroup
|
GroupList []*SocialGroup
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SocialGroupMemberListPage struct
|
type SocialGroupMemberListPage struct {
|
||||||
{
|
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header HeaderVars
|
Header *HeaderVars
|
||||||
ItemList []SocialGroupMember
|
ItemList []SocialGroupMember
|
||||||
SocialGroup SocialGroup
|
SocialGroup *SocialGroup
|
||||||
Page int
|
Page int
|
||||||
LastPage int
|
LastPage int
|
||||||
ExtData ExtData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SocialGroupMember struct
|
// SocialGroupMember is a struct representing a specific member of a group, not to be confused with the global User struct.
|
||||||
{
|
type SocialGroupMember struct {
|
||||||
Link string
|
Link string
|
||||||
Rank int /* 0: Member. 1: Mod. 2: Admin. */
|
Rank int /* 0: Member. 1: Mod. 2: Admin. */
|
||||||
RankString string /* Member, Mod, Admin, Owner */
|
RankString string /* Member, Mod, Admin, Owner */
|
||||||
@ -96,58 +92,59 @@ type SocialGroupMember struct
|
|||||||
User User
|
User User
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TO-DO: Add a plugin interface instead of having a bunch of argument to AddPlugin?
|
||||||
func init() {
|
func init() {
|
||||||
plugins["socialgroups"] = NewPlugin("socialgroups","Social Groups","Azareal","http://github.com/Azareal","","","",init_socialgroups,nil,deactivate_socialgroups,install_socialgroups,nil)
|
plugins["socialgroups"] = NewPlugin("socialgroups", "Social Groups", "Azareal", "http://github.com/Azareal", "", "", "", initSocialgroups, nil, deactivateSocialgroups, installSocialgroups, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init_socialgroups() (err error) {
|
func initSocialgroups() (err error) {
|
||||||
plugins["socialgroups"].AddHook("intercept_build_widgets", socialgroups_widgets)
|
plugins["socialgroups"].AddHook("intercept_build_widgets", socialgroupsWidgets)
|
||||||
plugins["socialgroups"].AddHook("trow_assign", socialgroups_trow_assign)
|
plugins["socialgroups"].AddHook("trow_assign", socialgroupsTrowAssign)
|
||||||
plugins["socialgroups"].AddHook("topic_create_pre_loop", socialgroups_topic_create_pre_loop)
|
plugins["socialgroups"].AddHook("topic_create_pre_loop", socialgroupsTopicCreatePreLoop)
|
||||||
plugins["socialgroups"].AddHook("pre_render_view_forum", socialgroups_pre_render_view_forum)
|
plugins["socialgroups"].AddHook("pre_render_view_forum", socialgroupsPreRenderViewForum)
|
||||||
plugins["socialgroups"].AddHook("simple_forum_check_pre_perms", socialgroups_forum_check)
|
plugins["socialgroups"].AddHook("simple_forum_check_pre_perms", socialgroupsForumCheck)
|
||||||
plugins["socialgroups"].AddHook("forum_check_pre_perms", socialgroups_forum_check)
|
plugins["socialgroups"].AddHook("forum_check_pre_perms", socialgroupsForumCheck)
|
||||||
// TO-DO: Auto-grant this perm to admins upon installation?
|
// TO-DO: Auto-grant this perm to admins upon installation?
|
||||||
register_plugin_perm("CreateSocialGroup")
|
registerPluginPerm("CreateSocialGroup")
|
||||||
router.HandleFunc("/groups/", socialgroups_group_list)
|
router.HandleFunc("/groups/", socialgroupsGroupList)
|
||||||
router.HandleFunc("/group/", socialgroups_view_group)
|
router.HandleFunc("/group/", socialgroupsViewGroup)
|
||||||
router.HandleFunc("/group/create/", socialgroups_create_group)
|
router.HandleFunc("/group/create/", socialgroupsCreateGroup)
|
||||||
router.HandleFunc("/group/create/submit/", socialgroups_create_group_submit)
|
router.HandleFunc("/group/create/submit/", socialgroupsCreateGroupSubmit)
|
||||||
router.HandleFunc("/group/members/", socialgroups_member_list)
|
router.HandleFunc("/group/members/", socialgroupsMemberList)
|
||||||
|
|
||||||
socialgroups_list_stmt, err = qgen.Builder.SimpleSelect("socialgroups","sgid, name, desc, active, privacy, joinable, owner, memberCount, createdAt, lastUpdateTime","","","")
|
socialgroupsListStmt, err = qgen.Builder.SimpleSelect("socialgroups", "sgid, name, desc, active, privacy, joinable, owner, memberCount, createdAt, lastUpdateTime", "", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
socialgroups_get_group_stmt, err = qgen.Builder.SimpleSelect("socialgroups","name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime","sgid = ?","","")
|
socialgroupsGetGroupStmt, err = qgen.Builder.SimpleSelect("socialgroups", "name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime", "sgid = ?", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
socialgroups_member_list_stmt, err = qgen.Builder.SimpleSelect("socialgroups_members","sgid, uid, rank, posts, joinedAt","","","")
|
socialgroupsMemberListStmt, err = qgen.Builder.SimpleSelect("socialgroups_members", "sgid, uid, rank, posts, joinedAt", "", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
socialgroups_member_list_join_stmt, err = qgen.Builder.SimpleLeftJoin("socialgroups_members","users","users.uid, socialgroups_members.rank, socialgroups_members.posts, socialgroups_members.joinedAt, users.name, users.avatar","socialgroups_members.uid = users.uid","socialgroups_members.sgid = ?","socialgroups_members.rank DESC, socialgroups_members.joinedat ASC","")
|
socialgroupsMemberListJoinStmt, err = qgen.Builder.SimpleLeftJoin("socialgroups_members", "users", "users.uid, socialgroups_members.rank, socialgroups_members.posts, socialgroups_members.joinedAt, users.name, users.avatar", "socialgroups_members.uid = users.uid", "socialgroups_members.sgid = ?", "socialgroups_members.rank DESC, socialgroups_members.joinedat ASC", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
socialgroups_get_member_stmt, err = qgen.Builder.SimpleSelect("socialgroups_members","rank, posts, joinedAt","sgid = ? AND uid = ?","","")
|
socialgroupsGetMemberStmt, err = qgen.Builder.SimpleSelect("socialgroups_members", "rank, posts, joinedAt", "sgid = ? AND uid = ?", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
socialgroups_create_group_stmt, err = qgen.Builder.SimpleInsert("socialgroups","name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime","?,?,?,?,1,?,1,?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()")
|
socialgroupsCreateGroupStmt, err = qgen.Builder.SimpleInsert("socialgroups", "name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime", "?,?,?,?,1,?,1,?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
socialgroups_attach_forum_stmt, err = qgen.Builder.SimpleUpdate("forums","parentID = ?, parentType = 'socialgroup'","fid = ?")
|
socialgroupsAttachForumStmt, err = qgen.Builder.SimpleUpdate("forums", "parentID = ?, parentType = 'socialgroup'", "fid = ?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
socialgroups_unattach_forum_stmt, err = qgen.Builder.SimpleUpdate("forums","parentID = 0, parentType = ''","fid = ?")
|
socialgroupsUnattachForumStmt, err = qgen.Builder.SimpleUpdate("forums", "parentID = 0, parentType = ''", "fid = ?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
socialgroups_add_member_stmt, err = qgen.Builder.SimpleInsert("socialgroups_members","sgid, uid, rank, posts, joinedAt","?,?,?,0,UTC_TIMESTAMP()")
|
socialgroupsAddMemberStmt, err = qgen.Builder.SimpleInsert("socialgroups_members", "sgid, uid, rank, posts, joinedAt", "?,?,?,0,UTC_TIMESTAMP()")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -155,32 +152,32 @@ func init_socialgroups() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deactivate_socialgroups() {
|
func deactivateSocialgroups() {
|
||||||
plugins["socialgroups"].RemoveHook("intercept_build_widgets", socialgroups_widgets)
|
plugins["socialgroups"].RemoveHook("intercept_build_widgets", socialgroupsWidgets)
|
||||||
plugins["socialgroups"].RemoveHook("trow_assign", socialgroups_trow_assign)
|
plugins["socialgroups"].RemoveHook("trow_assign", socialgroupsTrowAssign)
|
||||||
plugins["socialgroups"].RemoveHook("topic_create_pre_loop", socialgroups_topic_create_pre_loop)
|
plugins["socialgroups"].RemoveHook("topic_create_pre_loop", socialgroupsTopicCreatePreLoop)
|
||||||
plugins["socialgroups"].RemoveHook("pre_render_view_forum", socialgroups_pre_render_view_forum)
|
plugins["socialgroups"].RemoveHook("pre_render_view_forum", socialgroupsPreRenderViewForum)
|
||||||
plugins["socialgroups"].RemoveHook("simple_forum_check_pre_perms", socialgroups_forum_check)
|
plugins["socialgroups"].RemoveHook("simple_forum_check_pre_perms", socialgroupsForumCheck)
|
||||||
plugins["socialgroups"].RemoveHook("forum_check_pre_perms", socialgroups_forum_check)
|
plugins["socialgroups"].RemoveHook("forum_check_pre_perms", socialgroupsForumCheck)
|
||||||
deregister_plugin_perm("CreateSocialGroup")
|
deregisterPluginPerm("CreateSocialGroup")
|
||||||
_ = router.RemoveFunc("/groups/")
|
_ = router.RemoveFunc("/groups/")
|
||||||
_ = router.RemoveFunc("/group/")
|
_ = router.RemoveFunc("/group/")
|
||||||
_ = router.RemoveFunc("/group/create/")
|
_ = router.RemoveFunc("/group/create/")
|
||||||
_ = router.RemoveFunc("/group/create/submit/")
|
_ = router.RemoveFunc("/group/create/submit/")
|
||||||
_ = socialgroups_list_stmt.Close()
|
_ = socialgroupsListStmt.Close()
|
||||||
_ = socialgroups_member_list_stmt.Close()
|
_ = socialgroupsMemberListStmt.Close()
|
||||||
_ = socialgroups_member_list_join_stmt.Close()
|
_ = socialgroupsMemberListJoinStmt.Close()
|
||||||
_ = socialgroups_get_member_stmt.Close()
|
_ = socialgroupsGetMemberStmt.Close()
|
||||||
_ = socialgroups_get_group_stmt.Close()
|
_ = socialgroupsGetGroupStmt.Close()
|
||||||
_ = socialgroups_create_group_stmt.Close()
|
_ = socialgroupsCreateGroupStmt.Close()
|
||||||
_ = socialgroups_attach_forum_stmt.Close()
|
_ = socialgroupsAttachForumStmt.Close()
|
||||||
_ = socialgroups_unattach_forum_stmt.Close()
|
_ = socialgroupsUnattachForumStmt.Close()
|
||||||
_ = socialgroups_add_member_stmt.Close()
|
_ = socialgroupsAddMemberStmt.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: Stop accessing the query builder directly and add a feature in Gosora which is more easily reversed, if an error comes up during the installation process
|
// TO-DO: Stop accessing the query builder directly and add a feature in Gosora which is more easily reversed, if an error comes up during the installation process
|
||||||
func install_socialgroups() error {
|
func installSocialgroups() error {
|
||||||
sg_table_stmt, err := qgen.Builder.CreateTable("socialgroups","utf8mb4","utf8mb4_general_ci",
|
sgTableStmt, err := qgen.Builder.CreateTable("socialgroups", "utf8mb4", "utf8mb4_general_ci",
|
||||||
[]qgen.DB_Table_Column{
|
[]qgen.DB_Table_Column{
|
||||||
qgen.DB_Table_Column{"sgid", "int", 0, false, true, ""},
|
qgen.DB_Table_Column{"sgid", "int", 0, false, true, ""},
|
||||||
qgen.DB_Table_Column{"name", "varchar", 100, false, false, ""},
|
qgen.DB_Table_Column{"name", "varchar", 100, false, false, ""},
|
||||||
@ -204,12 +201,12 @@ func install_socialgroups() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = sg_table_stmt.Exec()
|
_, err = sgTableStmt.Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sg_members_table_stmt, err := qgen.Builder.CreateTable("socialgroups_members","","",
|
sgMembersTableStmt, err := qgen.Builder.CreateTable("socialgroups_members", "", "",
|
||||||
[]qgen.DB_Table_Column{
|
[]qgen.DB_Table_Column{
|
||||||
qgen.DB_Table_Column{"sgid", "int", 0, false, false, ""},
|
qgen.DB_Table_Column{"sgid", "int", 0, false, false, ""},
|
||||||
qgen.DB_Table_Column{"uid", "int", 0, false, false, ""},
|
qgen.DB_Table_Column{"uid", "int", 0, false, false, ""},
|
||||||
@ -223,20 +220,20 @@ func install_socialgroups() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = sg_members_table_stmt.Exec()
|
_, err = sgMembersTableStmt.Exec()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO; Implement an uninstallation system into Gosora. And a better installation system.
|
// TO-DO; Implement an uninstallation system into Gosora. And a better installation system.
|
||||||
func uninstall_socialgroups() error {
|
func uninstallSocialgroups() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: Do this properly via the widget system
|
// TO-DO: Do this properly via the widget system
|
||||||
func socialgroups_common_area_widgets(headerVars *HeaderVars) {
|
func socialgroupsCommonAreaWidgets(headerVars *HeaderVars) {
|
||||||
// TO-DO: Hot Groups? Featured Groups? Official Groups?
|
// TO-DO: Hot Groups? Featured Groups? Official Groups?
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
var menu WidgetMenu = WidgetMenu{"Social Groups",[]WidgetMenuItem{
|
var menu = WidgetMenu{"Social Groups", []WidgetMenuItem{
|
||||||
WidgetMenuItem{"Create Group", "/group/create/", false},
|
WidgetMenuItem{"Create Group", "/group/create/", false},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -255,10 +252,10 @@ func socialgroups_common_area_widgets(headerVars *HeaderVars) {
|
|||||||
|
|
||||||
// TO-DO: Do this properly via the widget system
|
// TO-DO: Do this properly via the widget system
|
||||||
// TO-DO: Make a better more customisable group widget system
|
// TO-DO: Make a better more customisable group widget system
|
||||||
func socialgroups_group_widgets(headerVars *HeaderVars, sgItem SocialGroup) (success bool) {
|
func socialgroupsGroupWidgets(headerVars *HeaderVars, sgItem *SocialGroup) (success bool) {
|
||||||
return false // Disabled until the next commit
|
return false // Disabled until the next commit
|
||||||
|
|
||||||
var b bytes.Buffer
|
/*var b bytes.Buffer
|
||||||
var menu WidgetMenu = WidgetMenu{"Group Options", []WidgetMenuItem{
|
var menu WidgetMenu = WidgetMenu{"Group Options", []WidgetMenuItem{
|
||||||
WidgetMenuItem{"Join", "/group/join/" + strconv.Itoa(sgItem.ID), false},
|
WidgetMenuItem{"Join", "/group/join/" + strconv.Itoa(sgItem.ID), false},
|
||||||
WidgetMenuItem{"Members", "/group/members/" + strconv.Itoa(sgItem.ID), false},
|
WidgetMenuItem{"Members", "/group/members/" + strconv.Itoa(sgItem.ID), false},
|
||||||
@ -277,35 +274,35 @@ func socialgroups_group_widgets(headerVars *HeaderVars, sgItem SocialGroup) (suc
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Custom Pages
|
Custom Pages
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func socialgroups_group_list(w http.ResponseWriter, r *http.Request, user User) {
|
func socialgroupsGroupList(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
headerVars, ok := SessionCheck(w, r, &user)
|
headerVars, ok := SessionCheck(w, r, &user)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
socialgroups_common_area_widgets(&headerVars)
|
socialgroupsCommonAreaWidgets(headerVars)
|
||||||
|
|
||||||
rows, err := socialgroups_list_stmt.Query()
|
rows, err := socialgroupsListStmt.Query()
|
||||||
if err != nil && err != ErrNoRows {
|
if err != nil && err != ErrNoRows {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var sgList []SocialGroup
|
var sgList []*SocialGroup
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
sgItem := SocialGroup{ID:0}
|
sgItem := &SocialGroup{ID: 0}
|
||||||
err := rows.Scan(&sgItem.ID, &sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
|
err := rows.Scan(&sgItem.ID, &sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sgItem.Link = socialgroups_build_group_url(name_to_slug(sgItem.Name),sgItem.ID)
|
sgItem.Link = socialgroupsBuildGroupURL(nameToSlug(sgItem.Name), sgItem.ID)
|
||||||
sgList = append(sgList, sgItem)
|
sgList = append(sgList, sgItem)
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
err = rows.Err()
|
||||||
@ -315,20 +312,20 @@ func socialgroups_group_list(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
}
|
}
|
||||||
rows.Close()
|
rows.Close()
|
||||||
|
|
||||||
pi := SocialGroupListPage{"Group List",user,headerVars,sgList,extData}
|
pi := SocialGroupListPage{"Group List", user, headerVars, sgList}
|
||||||
err = templates.ExecuteTemplate(w, "socialgroups_group_list.html", pi)
|
err = templates.ExecuteTemplate(w, "socialgroups_group_list.html", pi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func socialgroups_get_group(sgid int) (sgItem SocialGroup, err error) {
|
func socialgroupsGetGroup(sgid int) (sgItem *SocialGroup, err error) {
|
||||||
sgItem = SocialGroup{ID:sgid}
|
sgItem = &SocialGroup{ID: sgid}
|
||||||
err = socialgroups_get_group_stmt.QueryRow(sgid).Scan(&sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &sgItem.MainForumID, &sgItem.Backdrop, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
|
err = socialgroupsGetGroupStmt.QueryRow(sgid).Scan(&sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &sgItem.MainForumID, &sgItem.Backdrop, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
|
||||||
return sgItem, err
|
return sgItem, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func socialgroups_view_group(w http.ResponseWriter, r *http.Request, user User) {
|
func socialgroupsViewGroup(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
// SEO URLs...
|
// SEO URLs...
|
||||||
halves := strings.Split(r.URL.Path[len("/group/"):], ".")
|
halves := strings.Split(r.URL.Path[len("/group/"):], ".")
|
||||||
if len(halves) < 2 {
|
if len(halves) < 2 {
|
||||||
@ -340,7 +337,7 @@ func socialgroups_view_group(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sgItem, err := socialgroups_get_group(sgid)
|
sgItem, err := socialgroupsGetGroup(sgid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalError("Bad group", w, r, user)
|
LocalError("Bad group", w, r, user)
|
||||||
return
|
return
|
||||||
@ -350,11 +347,11 @@ func socialgroups_view_group(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Re-route the request to route_forums
|
// Re-route the request to route_forums
|
||||||
var ctx context.Context = context.WithValue(r.Context(),"socialgroups_current_group",sgItem)
|
var ctx = context.WithValue(r.Context(), "socialgroups_current_group", sgItem)
|
||||||
route_forum(w, r.WithContext(ctx), user, strconv.Itoa(sgItem.MainForumID))
|
route_forum(w, r.WithContext(ctx), user, strconv.Itoa(sgItem.MainForumID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func socialgroups_create_group(w http.ResponseWriter, r *http.Request, user User) {
|
func socialgroupsCreateGroup(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
headerVars, ok := SessionCheck(w, r, &user)
|
headerVars, ok := SessionCheck(w, r, &user)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
@ -364,7 +361,7 @@ func socialgroups_create_group(w http.ResponseWriter, r *http.Request, user User
|
|||||||
NoPermissions(w, r, user)
|
NoPermissions(w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
socialgroups_common_area_widgets(&headerVars)
|
socialgroupsCommonAreaWidgets(headerVars)
|
||||||
|
|
||||||
pi := Page{"Create Group", user, headerVars, tList, nil}
|
pi := Page{"Create Group", user, headerVars, tList, nil}
|
||||||
err := templates.ExecuteTemplate(w, "socialgroups_create_group.html", pi)
|
err := templates.ExecuteTemplate(w, "socialgroups_create_group.html", pi)
|
||||||
@ -373,61 +370,65 @@ func socialgroups_create_group(w http.ResponseWriter, r *http.Request, user User
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func socialgroups_create_group_submit(w http.ResponseWriter, r *http.Request, user User) {
|
func socialgroupsCreateGroupSubmit(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
// TO-DO: Add an approval queue mode for group creation
|
// TO-DO: Add an approval queue mode for group creation
|
||||||
if !user.Loggedin || !user.PluginPerms["CreateSocialGroup"] {
|
if !user.Loggedin || !user.PluginPerms["CreateSocialGroup"] {
|
||||||
NoPermissions(w, r, user)
|
NoPermissions(w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var group_active bool = true
|
var groupActive = true
|
||||||
var group_name string = html.EscapeString(r.PostFormValue("group_name"))
|
var groupName = html.EscapeString(r.PostFormValue("group_name"))
|
||||||
var group_desc string = html.EscapeString(r.PostFormValue("group_desc"))
|
var groupDesc = html.EscapeString(r.PostFormValue("group_desc"))
|
||||||
var gprivacy string = r.PostFormValue("group_privacy")
|
var gprivacy = r.PostFormValue("group_privacy")
|
||||||
|
|
||||||
var group_privacy int
|
var groupPrivacy int
|
||||||
switch(gprivacy) {
|
switch gprivacy {
|
||||||
case "0": group_privacy = 0 // Public
|
case "0":
|
||||||
case "1": group_privacy = 1 // Protected
|
groupPrivacy = 0 // Public
|
||||||
case "2": group_privacy = 2 // private
|
case "1":
|
||||||
default: group_privacy = 0
|
groupPrivacy = 1 // Protected
|
||||||
|
case "2":
|
||||||
|
groupPrivacy = 2 // private
|
||||||
|
default:
|
||||||
|
groupPrivacy = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the backing forum
|
// Create the backing forum
|
||||||
fid, err := fstore.CreateForum(group_name,"",true,"")
|
fid, err := fstore.CreateForum(groupName, "", true, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := socialgroups_create_group_stmt.Exec(group_name, group_desc, group_active, group_privacy, user.ID, fid)
|
res, err := socialgroupsCreateGroupStmt.Exec(groupName, groupDesc, groupActive, groupPrivacy, user.ID, fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lastId, err := res.LastInsertId()
|
lastID, err := res.LastInsertId()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the main backing forum to the forum list
|
// Add the main backing forum to the forum list
|
||||||
err = socialgroups_attach_forum(int(lastId),fid)
|
err = socialgroupsAttachForum(int(lastID), fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = socialgroups_add_member_stmt.Exec(lastId,user.ID,2)
|
_, err = socialgroupsAddMemberStmt.Exec(lastID, user.ID, 2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(w,r,socialgroups_build_group_url(name_to_slug(group_name),int(lastId)), http.StatusSeeOther)
|
http.Redirect(w, r, socialgroupsBuildGroupURL(nameToSlug(groupName), int(lastID)), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
func socialgroups_member_list(w http.ResponseWriter, r *http.Request, user User) {
|
func socialgroupsMemberList(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
headerVars, ok := SessionCheck(w, r, &user)
|
headerVars, ok := SessionCheck(w, r, &user)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
@ -444,18 +445,18 @@ func socialgroups_member_list(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var sgItem SocialGroup = SocialGroup{ID:sgid}
|
var sgItem = &SocialGroup{ID: sgid}
|
||||||
var mainForum int // Unused
|
var mainForum int // Unused
|
||||||
err = socialgroups_get_group_stmt.QueryRow(sgid).Scan(&sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &mainForum, &sgItem.Backdrop, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
|
err = socialgroupsGetGroupStmt.QueryRow(sgid).Scan(&sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &mainForum, &sgItem.Backdrop, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalError("Bad group", w, r, user)
|
LocalError("Bad group", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sgItem.Link = socialgroups_build_group_url(name_to_slug(sgItem.Name),sgItem.ID)
|
sgItem.Link = socialgroupsBuildGroupURL(nameToSlug(sgItem.Name), sgItem.ID)
|
||||||
|
|
||||||
socialgroups_group_widgets(&headerVars, sgItem)
|
socialgroupsGroupWidgets(headerVars, sgItem)
|
||||||
|
|
||||||
rows, err := socialgroups_member_list_join_stmt.Query(sgid)
|
rows, err := socialgroupsMemberListJoinStmt.Query(sgid)
|
||||||
if err != nil && err != ErrNoRows {
|
if err != nil && err != ErrNoRows {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
@ -469,7 +470,7 @@ func socialgroups_member_list(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sgMember.Link = build_profile_url(name_to_slug(sgMember.User.Name),sgMember.User.ID)
|
sgMember.Link = buildProfileURL(nameToSlug(sgMember.User.Name), sgMember.User.ID)
|
||||||
if sgMember.User.Avatar != "" {
|
if sgMember.User.Avatar != "" {
|
||||||
if sgMember.User.Avatar[0] == '.' {
|
if sgMember.User.Avatar[0] == '.' {
|
||||||
sgMember.User.Avatar = "/uploads/avatar_" + strconv.Itoa(sgMember.User.ID) + sgMember.User.Avatar
|
sgMember.User.Avatar = "/uploads/avatar_" + strconv.Itoa(sgMember.User.ID) + sgMember.User.Avatar
|
||||||
@ -477,14 +478,17 @@ func socialgroups_member_list(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
} else {
|
} else {
|
||||||
sgMember.User.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(sgMember.User.ID), 1)
|
sgMember.User.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(sgMember.User.ID), 1)
|
||||||
}
|
}
|
||||||
sgMember.JoinedAt, _ = relative_time(sgMember.JoinedAt)
|
sgMember.JoinedAt, _ = relativeTime(sgMember.JoinedAt)
|
||||||
if sgItem.Owner == sgMember.User.ID {
|
if sgItem.Owner == sgMember.User.ID {
|
||||||
sgMember.RankString = "Owner"
|
sgMember.RankString = "Owner"
|
||||||
} else {
|
} else {
|
||||||
switch(sgMember.Rank) {
|
switch sgMember.Rank {
|
||||||
case 0: sgMember.RankString = "Member"
|
case 0:
|
||||||
case 1: sgMember.RankString = "Mod"
|
sgMember.RankString = "Member"
|
||||||
case 2: sgMember.RankString = "Admin"
|
case 1:
|
||||||
|
sgMember.RankString = "Mod"
|
||||||
|
case 2:
|
||||||
|
sgMember.RankString = "Admin"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sgMembers = append(sgMembers, sgMember)
|
sgMembers = append(sgMembers, sgMember)
|
||||||
@ -496,10 +500,10 @@ func socialgroups_member_list(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
}
|
}
|
||||||
rows.Close()
|
rows.Close()
|
||||||
|
|
||||||
pi := SocialGroupMemberListPage{"Group Member List",user,headerVars,sgMembers,sgItem,0,0,extData}
|
pi := SocialGroupMemberListPage{"Group Member List", user, headerVars, sgMembers, sgItem, 0, 0}
|
||||||
// A plugin with plugins. Pluginception!
|
// A plugin with plugins. Pluginception!
|
||||||
if pre_render_hooks["pre_render_socialgroups_member_list"] != nil {
|
if preRenderHooks["pre_render_socialgroups_member_list"] != nil {
|
||||||
if run_pre_render_hook("pre_render_socialgroups_member_list", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_socialgroups_member_list", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -509,17 +513,17 @@ func socialgroups_member_list(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func socialgroups_attach_forum(sgid int, fid int) error {
|
func socialgroupsAttachForum(sgid int, fid int) error {
|
||||||
_, err := socialgroups_attach_forum_stmt.Exec(sgid,fid)
|
_, err := socialgroupsAttachForumStmt.Exec(sgid, fid)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func socialgroups_unattach_forum(fid int) error {
|
func socialgroupsUnattachForum(fid int) error {
|
||||||
_, err := socialgroups_attach_forum_stmt.Exec(fid)
|
_, err := socialgroupsAttachForumStmt.Exec(fid)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func socialgroups_build_group_url(slug string, id int) string {
|
func socialgroupsBuildGroupURL(slug string, id int) string {
|
||||||
if slug == "" {
|
if slug == "" {
|
||||||
return "/group/" + slug + "." + strconv.Itoa(id)
|
return "/group/" + slug + "." + strconv.Itoa(id)
|
||||||
}
|
}
|
||||||
@ -530,13 +534,13 @@ func socialgroups_build_group_url(slug string, id int) string {
|
|||||||
Hooks
|
Hooks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func socialgroups_pre_render_view_forum(w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) {
|
func socialgroupsPreRenderViewForum(w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) {
|
||||||
pi := data.(*ForumPage)
|
pi := data.(*ForumPage)
|
||||||
if pi.Header.ExtData.items != nil {
|
if pi.Header.ExtData.items != nil {
|
||||||
if sgData, ok := pi.Header.ExtData.items["socialgroups_current_group"]; ok {
|
if sgData, ok := pi.Header.ExtData.items["socialgroups_current_group"]; ok {
|
||||||
sgItem := sgData.(SocialGroup)
|
sgItem := sgData.(*SocialGroup)
|
||||||
|
|
||||||
sgpi := SocialGroupPage{pi.Title,pi.CurrentUser,pi.Header,pi.ItemList,pi.Forum,sgItem,pi.Page,pi.LastPage,pi.ExtData}
|
sgpi := SocialGroupPage{pi.Title, pi.CurrentUser, pi.Header, pi.ItemList, pi.Forum, sgItem, pi.Page, pi.LastPage}
|
||||||
err := templates.ExecuteTemplate(w, "socialgroups_view_group.html", sgpi)
|
err := templates.ExecuteTemplate(w, "socialgroups_view_group.html", sgpi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError(err)
|
LogError(err)
|
||||||
@ -548,20 +552,20 @@ func socialgroups_pre_render_view_forum(w http.ResponseWriter, r *http.Request,
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func socialgroups_trow_assign(args ...interface{}) interface{} {
|
func socialgroupsTrowAssign(args ...interface{}) interface{} {
|
||||||
var forum *Forum = args[1].(*Forum)
|
var forum = args[1].(*Forum)
|
||||||
if forum.ParentType == "socialgroup" {
|
if forum.ParentType == "socialgroup" {
|
||||||
var topicItem *TopicsRow = args[0].(*TopicsRow)
|
var topicItem = args[0].(*TopicsRow)
|
||||||
topicItem.ForumLink = "/group/" + strings.TrimPrefix(topicItem.ForumLink,get_forum_url_prefix())
|
topicItem.ForumLink = "/group/" + strings.TrimPrefix(topicItem.ForumLink, getForumURLPrefix())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: It would be nice, if you could select one of the boards in the group from that drop-down rather than just the one you got linked from
|
// TO-DO: It would be nice, if you could select one of the boards in the group from that drop-down rather than just the one you got linked from
|
||||||
func socialgroups_topic_create_pre_loop(args ...interface{}) interface{} {
|
func socialgroupsTopicCreatePreLoop(args ...interface{}) interface{} {
|
||||||
var fid int = args[2].(int)
|
var fid = args[2].(int)
|
||||||
if fstore.DirtyGet(fid).ParentType == "socialgroup" {
|
if fstore.DirtyGet(fid).ParentType == "socialgroup" {
|
||||||
var strictmode *bool = args[5].(*bool)
|
var strictmode = args[5].(*bool)
|
||||||
*strictmode = true
|
*strictmode = true
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -569,19 +573,19 @@ func socialgroups_topic_create_pre_loop(args ...interface{}) interface{} {
|
|||||||
|
|
||||||
// TO-DO: Add privacy options
|
// TO-DO: Add privacy options
|
||||||
// TO-DO: Add support for multiple boards and add per-board simplified permissions
|
// TO-DO: Add support for multiple boards and add per-board simplified permissions
|
||||||
// TO-DO: Take is_js into account for routes which expect JSON responses
|
// TO-DO: Take isJs into account for routes which expect JSON responses
|
||||||
func socialgroups_forum_check(args ...interface{}) (skip interface{}) {
|
func socialgroupsForumCheck(args ...interface{}) (skip interface{}) {
|
||||||
var r = args[1].(*http.Request)
|
var r = args[1].(*http.Request)
|
||||||
var fid *int = args[3].(*int)
|
var fid = args[3].(*int)
|
||||||
var forum *Forum = fstore.DirtyGet(*fid)
|
var forum = fstore.DirtyGet(*fid)
|
||||||
|
|
||||||
if forum.ParentType == "socialgroup" {
|
if forum.ParentType == "socialgroup" {
|
||||||
var err error
|
var err error
|
||||||
var w = args[0].(http.ResponseWriter)
|
var w = args[0].(http.ResponseWriter)
|
||||||
var success *bool = args[4].(*bool)
|
var success = args[4].(*bool)
|
||||||
sgItem, ok := r.Context().Value("socialgroups_current_group").(SocialGroup)
|
sgItem, ok := r.Context().Value("socialgroups_current_group").(*SocialGroup)
|
||||||
if !ok {
|
if !ok {
|
||||||
sgItem, err = socialgroups_get_group(forum.ParentID)
|
sgItem, err = socialgroupsGetGroup(forum.ParentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(errors.New("Unable to find the parent group for a forum"), w)
|
InternalError(errors.New("Unable to find the parent group for a forum"), w)
|
||||||
*success = false
|
*success = false
|
||||||
@ -595,7 +599,7 @@ func socialgroups_forum_check(args ...interface{}) (skip interface{}) {
|
|||||||
r = r.WithContext(context.WithValue(r.Context(), "socialgroups_current_group", sgItem))
|
r = r.WithContext(context.WithValue(r.Context(), "socialgroups_current_group", sgItem))
|
||||||
}
|
}
|
||||||
|
|
||||||
var user *User = args[2].(*User)
|
var user = args[2].(*User)
|
||||||
var rank int
|
var rank int
|
||||||
var posts int
|
var posts int
|
||||||
var joinedAt string
|
var joinedAt string
|
||||||
@ -604,10 +608,10 @@ func socialgroups_forum_check(args ...interface{}) (skip interface{}) {
|
|||||||
|
|
||||||
// Clear the default group permissions
|
// Clear the default group permissions
|
||||||
// TO-DO: Do this more efficiently, doing it quick and dirty for now to get this out quickly
|
// TO-DO: Do this more efficiently, doing it quick and dirty for now to get this out quickly
|
||||||
override_forum_perms(&user.Perms, false)
|
overrideForumPerms(&user.Perms, false)
|
||||||
user.Perms.ViewTopic = true
|
user.Perms.ViewTopic = true
|
||||||
|
|
||||||
err = socialgroups_get_member_stmt.QueryRow(sgItem.ID,user.ID).Scan(&rank,&posts,&joinedAt)
|
err = socialgroupsGetMemberStmt.QueryRow(sgItem.ID, user.ID).Scan(&rank, &posts, &joinedAt)
|
||||||
if err != nil && err != ErrNoRows {
|
if err != nil && err != ErrNoRows {
|
||||||
*success = false
|
*success = false
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
@ -623,13 +627,13 @@ func socialgroups_forum_check(args ...interface{}) (skip interface{}) {
|
|||||||
|
|
||||||
// Basic permissions for members, more complicated permissions coming in the next commit!
|
// Basic permissions for members, more complicated permissions coming in the next commit!
|
||||||
if sgItem.Owner == user.ID {
|
if sgItem.Owner == user.ID {
|
||||||
override_forum_perms(&user.Perms,true)
|
overrideForumPerms(&user.Perms, true)
|
||||||
} else if rank == 0 {
|
} else if rank == 0 {
|
||||||
user.Perms.LikeItem = true
|
user.Perms.LikeItem = true
|
||||||
user.Perms.CreateTopic = true
|
user.Perms.CreateTopic = true
|
||||||
user.Perms.CreateReply = true
|
user.Perms.CreateReply = true
|
||||||
} else {
|
} else {
|
||||||
override_forum_perms(&user.Perms,true)
|
overrideForumPerms(&user.Perms, true)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -639,19 +643,19 @@ func socialgroups_forum_check(args ...interface{}) (skip interface{}) {
|
|||||||
|
|
||||||
// TO-DO: Override redirects? I don't think this is needed quite yet
|
// TO-DO: Override redirects? I don't think this is needed quite yet
|
||||||
|
|
||||||
func socialgroups_widgets(args ...interface{}) interface{} {
|
func socialgroupsWidgets(args ...interface{}) interface{} {
|
||||||
var zone string = args[0].(string)
|
var zone = args[0].(string)
|
||||||
var headerVars *HeaderVars = args[2].(*HeaderVars)
|
var headerVars = args[2].(*HeaderVars)
|
||||||
var request *http.Request = args[3].(*http.Request)
|
var request = args[3].(*http.Request)
|
||||||
|
|
||||||
if zone != "view_forum" {
|
if zone != "view_forum" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var forum *Forum = args[1].(*Forum)
|
var forum = args[1].(*Forum)
|
||||||
if forum.ParentType == "socialgroup" {
|
if forum.ParentType == "socialgroup" {
|
||||||
// This is why I hate using contexts, all the daisy chains and interface casts x.x
|
// This is why I hate using contexts, all the daisy chains and interface casts x.x
|
||||||
sgItem, ok := request.Context().Value("socialgroups_current_group").(SocialGroup)
|
sgItem, ok := request.Context().Value("socialgroups_current_group").(*SocialGroup)
|
||||||
if !ok {
|
if !ok {
|
||||||
LogError(errors.New("Unable to find a parent group in the context data"))
|
LogError(errors.New("Unable to find a parent group in the context data"))
|
||||||
return false
|
return false
|
||||||
@ -662,7 +666,7 @@ func socialgroups_widgets(args ...interface{}) interface{} {
|
|||||||
}
|
}
|
||||||
headerVars.ExtData.items["socialgroups_current_group"] = sgItem
|
headerVars.ExtData.items["socialgroups_current_group"] = sgItem
|
||||||
|
|
||||||
return socialgroups_group_widgets(headerVars,sgItem)
|
return socialgroupsGroupWidgets(headerVars, sgItem)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,7 @@ import "testing"
|
|||||||
// TO-DO: Replace the soft tabs with hard ones
|
// TO-DO: Replace the soft tabs with hard ones
|
||||||
// go test -v
|
// go test -v
|
||||||
|
|
||||||
type ME_Pair struct
|
type ME_Pair struct {
|
||||||
{
|
|
||||||
Msg string
|
Msg string
|
||||||
Expects string
|
Expects string
|
||||||
}
|
}
|
||||||
@ -46,10 +45,10 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
msgList = addMEPair(msgList, "[quote][b]h[/b][/quote]", "<span class='postQuote'><b>h</b></span>")
|
msgList = addMEPair(msgList, "[quote][b]h[/b][/quote]", "<span class='postQuote'><b>h</b></span>")
|
||||||
msgList = addMEPair(msgList, "[quote][b][/b][/quote]", "<span class='postQuote'><b></b></span>")
|
msgList = addMEPair(msgList, "[quote][b][/b][/quote]", "<span class='postQuote'><b></b></span>")
|
||||||
|
|
||||||
t.Log("Testing bbcode_full_parse")
|
t.Log("Testing bbcodeFullParse")
|
||||||
for _, item := range msgList {
|
for _, item := range msgList {
|
||||||
t.Log("Testing string '" + item.Msg + "'")
|
t.Log("Testing string '" + item.Msg + "'")
|
||||||
res = bbcode_full_parse(item.Msg)
|
res = bbcodeFullParse(item.Msg)
|
||||||
if res != item.Expects {
|
if res != item.Expects {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected:", item.Expects)
|
t.Error("Expected:", item.Expects)
|
||||||
@ -62,7 +61,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
msg = "[rand][/rand]"
|
msg = "[rand][/rand]"
|
||||||
expects = "<span style='color: red;'>[Invalid Number]</span>[rand][/rand]"
|
expects = "<span style='color: red;'>[Invalid Number]</span>[rand][/rand]"
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
if res != expects {
|
if res != expects {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected:", expects)
|
t.Error("Expected:", expects)
|
||||||
@ -71,7 +70,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
msg = "[rand]-1[/rand]"
|
msg = "[rand]-1[/rand]"
|
||||||
expects = "<span style='color: red;'>[No Negative Numbers]</span>[rand]-1[/rand]"
|
expects = "<span style='color: red;'>[No Negative Numbers]</span>[rand]-1[/rand]"
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
if res != expects {
|
if res != expects {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected:", expects)
|
t.Error("Expected:", expects)
|
||||||
@ -80,7 +79,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
msg = "[rand]-01[/rand]"
|
msg = "[rand]-01[/rand]"
|
||||||
expects = "<span style='color: red;'>[No Negative Numbers]</span>[rand]-01[/rand]"
|
expects = "<span style='color: red;'>[No Negative Numbers]</span>[rand]-01[/rand]"
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
if res != expects {
|
if res != expects {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected:", expects)
|
t.Error("Expected:", expects)
|
||||||
@ -89,7 +88,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
msg = "[rand]NaN[/rand]"
|
msg = "[rand]NaN[/rand]"
|
||||||
expects = "<span style='color: red;'>[Invalid Number]</span>[rand]NaN[/rand]"
|
expects = "<span style='color: red;'>[Invalid Number]</span>[rand]NaN[/rand]"
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
if res != expects {
|
if res != expects {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected:", expects)
|
t.Error("Expected:", expects)
|
||||||
@ -98,7 +97,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
msg = "[rand]Inf[/rand]"
|
msg = "[rand]Inf[/rand]"
|
||||||
expects = "<span style='color: red;'>[Invalid Number]</span>[rand]Inf[/rand]"
|
expects = "<span style='color: red;'>[Invalid Number]</span>[rand]Inf[/rand]"
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
if res != expects {
|
if res != expects {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected:", expects)
|
t.Error("Expected:", expects)
|
||||||
@ -107,7 +106,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
msg = "[rand]+[/rand]"
|
msg = "[rand]+[/rand]"
|
||||||
expects = "<span style='color: red;'>[Invalid Number]</span>[rand]+[/rand]"
|
expects = "<span style='color: red;'>[Invalid Number]</span>[rand]+[/rand]"
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
if res != expects {
|
if res != expects {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected:", expects)
|
t.Error("Expected:", expects)
|
||||||
@ -116,7 +115,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
msg = "[rand]1+1[/rand]"
|
msg = "[rand]1+1[/rand]"
|
||||||
expects = "<span style='color: red;'>[Invalid Number]</span>[rand]1+1[/rand]"
|
expects = "<span style='color: red;'>[Invalid Number]</span>[rand]1+1[/rand]"
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
if res != expects {
|
if res != expects {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected:", expects)
|
t.Error("Expected:", expects)
|
||||||
@ -125,7 +124,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
var conv int
|
var conv int
|
||||||
msg = "[rand]1[/rand]"
|
msg = "[rand]1[/rand]"
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
conv, err = strconv.Atoi(res)
|
conv, err = strconv.Atoi(res)
|
||||||
if err != nil || (conv > 1 || conv < 0) {
|
if err != nil || (conv > 1 || conv < 0) {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
@ -134,7 +133,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
|
|
||||||
msg = "[rand]0[/rand]"
|
msg = "[rand]0[/rand]"
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
conv, err = strconv.Atoi(res)
|
conv, err = strconv.Atoi(res)
|
||||||
if err != nil || conv != 0 {
|
if err != nil || conv != 0 {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
@ -143,7 +142,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
|
|
||||||
msg = "[rand]2147483647[/rand]" // Signed 32-bit MAX
|
msg = "[rand]2147483647[/rand]" // Signed 32-bit MAX
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
conv, err = strconv.Atoi(res)
|
conv, err = strconv.Atoi(res)
|
||||||
if err != nil || (conv > 2147483647 || conv < 0) {
|
if err != nil || (conv > 2147483647 || conv < 0) {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
@ -152,7 +151,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
|
|
||||||
msg = "[rand]9223372036854775807[/rand]" // Signed 64-bit MAX
|
msg = "[rand]9223372036854775807[/rand]" // Signed 64-bit MAX
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
conv, err = strconv.Atoi(res)
|
conv, err = strconv.Atoi(res)
|
||||||
if err != nil || (conv > 9223372036854775807 || conv < 0) {
|
if err != nil || (conv > 9223372036854775807 || conv < 0) {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
@ -162,7 +161,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
// Note: conv is commented out in these two, as these numbers overflow int
|
// Note: conv is commented out in these two, as these numbers overflow int
|
||||||
msg = "[rand]18446744073709551615[/rand]" // Unsigned 64-bit MAX
|
msg = "[rand]18446744073709551615[/rand]" // Unsigned 64-bit MAX
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
conv, err = strconv.Atoi(res)
|
conv, err = strconv.Atoi(res)
|
||||||
if err != nil || ( /*conv > 18446744073709551615 || */ conv < 0) {
|
if err != nil || ( /*conv > 18446744073709551615 || */ conv < 0) {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
@ -170,7 +169,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
}
|
}
|
||||||
msg = "[rand]170141183460469231731687303715884105727[/rand]" // Signed 128-bit MAX
|
msg = "[rand]170141183460469231731687303715884105727[/rand]" // Signed 128-bit MAX
|
||||||
t.Log("Testing string '" + msg + "'")
|
t.Log("Testing string '" + msg + "'")
|
||||||
res = bbcode_full_parse(msg)
|
res = bbcodeFullParse(msg)
|
||||||
conv, err = strconv.Atoi(res)
|
conv, err = strconv.Atoi(res)
|
||||||
if err != nil || ( /*conv > 170141183460469231731687303715884105727 || */ conv < 0) {
|
if err != nil || ( /*conv > 170141183460469231731687303715884105727 || */ conv < 0) {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
@ -180,7 +179,7 @@ func TestBBCodeRender(t *testing.T) {
|
|||||||
t.Log("Testing bbcode_regex_parse")
|
t.Log("Testing bbcode_regex_parse")
|
||||||
for _, item := range msgList {
|
for _, item := range msgList {
|
||||||
t.Log("Testing string '" + item.Msg + "'")
|
t.Log("Testing string '" + item.Msg + "'")
|
||||||
res = bbcode_regex_parse(item.Msg)
|
res = bbcodeRegexParse(item.Msg)
|
||||||
if res != item.Expects {
|
if res != item.Expects {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected:", item.Expects)
|
t.Error("Expected:", item.Expects)
|
||||||
@ -222,7 +221,7 @@ func TestMarkdownRender(t *testing.T) {
|
|||||||
|
|
||||||
for _, item := range msgList {
|
for _, item := range msgList {
|
||||||
t.Log("Testing string '" + item.Msg + "'")
|
t.Log("Testing string '" + item.Msg + "'")
|
||||||
res = markdown_parse(item.Msg)
|
res = markdownParse(item.Msg)
|
||||||
if res != item.Expects {
|
if res != item.Expects {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
t.Error("Expected:", item.Expects)
|
t.Error("Expected:", item.Expects)
|
||||||
|
@ -250,7 +250,7 @@ $(document).ready(function(){
|
|||||||
|
|
||||||
var form_action = $(this).closest('a').attr("href");
|
var form_action = $(this).closest('a').attr("href");
|
||||||
//console.log("Form Action: " + form_action);
|
//console.log("Form Action: " + form_action);
|
||||||
$.ajax({ url: form_action, type: "POST", dataType: "json", data: { is_js: "1", edit_item: newContent }
|
$.ajax({ url: form_action, type: "POST", dataType: "json", data: { isJs: "1", edit_item: newContent }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -276,7 +276,7 @@ $(document).ready(function(){
|
|||||||
url: form_action + "?session=" + session,
|
url: form_action + "?session=" + session,
|
||||||
type: "POST",
|
type: "POST",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
data: {is_js: "1",edit_item: newContent}
|
data: {isJs: "1",edit_item: newContent}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -325,7 +325,7 @@ $(document).ready(function(){
|
|||||||
{
|
{
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
//console.log("running .submit_edit event");
|
//console.log("running .submit_edit event");
|
||||||
var out_data = {is_js: "1"}
|
var out_data = {isJs: "1"}
|
||||||
var block_parent = $(this).closest('.editable_parent');
|
var block_parent = $(this).closest('.editable_parent');
|
||||||
var block = block_parent.find('.editable_block').each(function(){
|
var block = block_parent.find('.editable_block').each(function(){
|
||||||
var field_name = this.getAttribute("data-field");
|
var field_name = this.getAttribute("data-field");
|
||||||
|
@ -7,8 +7,7 @@ func init() {
|
|||||||
Install = &installer{instructions: []DB_Install_Instruction{}}
|
Install = &installer{instructions: []DB_Install_Instruction{}}
|
||||||
}
|
}
|
||||||
|
|
||||||
type DB_Install_Instruction struct
|
type DB_Install_Instruction struct {
|
||||||
{
|
|
||||||
Table string
|
Table string
|
||||||
Contents string
|
Contents string
|
||||||
Type string
|
Type string
|
||||||
@ -16,8 +15,7 @@ type DB_Install_Instruction struct
|
|||||||
|
|
||||||
// A set of wrappers around the generator methods, so we can use this in the installer
|
// A set of wrappers around the generator methods, so we can use this in the installer
|
||||||
// TO-DO: Re-implement the query generation, query builder and installer adapters as layers on-top of a query text adapter
|
// TO-DO: Re-implement the query generation, query builder and installer adapters as layers on-top of a query text adapter
|
||||||
type installer struct
|
type installer struct {
|
||||||
{
|
|
||||||
adapter DB_Adapter
|
adapter DB_Adapter
|
||||||
instructions []DB_Install_Instruction
|
instructions []DB_Install_Instruction
|
||||||
}
|
}
|
||||||
@ -49,7 +47,7 @@ func (install *installer) Write() error {
|
|||||||
// We can't escape backticks, so we have to dump it out a file at a time
|
// We can't escape backticks, so we have to dump it out a file at a time
|
||||||
for _, instr := range install.instructions {
|
for _, instr := range install.instructions {
|
||||||
if instr.Type == "create-table" {
|
if instr.Type == "create-table" {
|
||||||
err := write_file("./schema/" + install.adapter.GetName() + "/query_" + instr.Table + ".sql", instr.Contents)
|
err := writeFile("./schema/"+install.adapter.GetName()+"/query_"+instr.Table+".sql", instr.Contents)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -57,5 +55,5 @@ func (install *installer) Write() error {
|
|||||||
inserts += instr.Contents + "\n"
|
inserts += instr.Contents + "\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return write_file("./schema/" + install.adapter.GetName() + "/inserts.sql", inserts)
|
return writeFile("./schema/"+install.adapter.GetName()+"/inserts.sql", inserts)
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,7 @@ func init() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mysql_Adapter struct
|
type Mysql_Adapter struct {
|
||||||
{
|
|
||||||
Name string
|
Name string
|
||||||
Buffer map[string]DB_Stmt
|
Buffer map[string]DB_Stmt
|
||||||
BufferOrder []string // Map iteration order is random, so we need this to track the order, so we don't get huge diffs every commit
|
BufferOrder []string // Map iteration order is random, so we need this to track the order, so we don't get huge diffs every commit
|
||||||
@ -42,7 +41,7 @@ func (adapter *Mysql_Adapter) CreateTable(name string, table string, charset str
|
|||||||
return "", errors.New("You can't have a table with no columns")
|
return "", errors.New("You can't have a table with no columns")
|
||||||
}
|
}
|
||||||
|
|
||||||
var querystr string = "CREATE TABLE `" + table + "` ("
|
var querystr = "CREATE TABLE `" + table + "` ("
|
||||||
for _, column := range columns {
|
for _, column := range columns {
|
||||||
// Make it easier to support Cassandra in the future
|
// Make it easier to support Cassandra in the future
|
||||||
if column.Type == "createdAt" {
|
if column.Type == "createdAt" {
|
||||||
@ -58,7 +57,7 @@ func (adapter *Mysql_Adapter) CreateTable(name string, table string, charset str
|
|||||||
// TO-DO: Exclude the other variants of text like mediumtext and longtext too
|
// TO-DO: Exclude the other variants of text like mediumtext and longtext too
|
||||||
if column.Default != "" && column.Type != "text" {
|
if column.Default != "" && column.Type != "text" {
|
||||||
end = " DEFAULT "
|
end = " DEFAULT "
|
||||||
if adapter.stringy_type(column.Type) && column.Default != "''" {
|
if adapter.stringyType(column.Type) && column.Default != "''" {
|
||||||
end += "'" + column.Default + "'"
|
end += "'" + column.Default + "'"
|
||||||
} else {
|
} else {
|
||||||
end += column.Default
|
end += column.Default
|
||||||
@ -100,7 +99,7 @@ func (adapter *Mysql_Adapter) CreateTable(name string, table string, charset str
|
|||||||
querystr += " COLLATE " + collation
|
querystr += " COLLATE " + collation
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter.push_statement(name,"create-table",querystr + ";")
|
adapter.pushStatement(name, "create-table", querystr+";")
|
||||||
return querystr + ";", nil
|
return querystr + ";", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +117,7 @@ func (adapter *Mysql_Adapter) SimpleInsert(name string, table string, columns st
|
|||||||
return "", errors.New("No input data found for SimpleInsert")
|
return "", errors.New("No input data found for SimpleInsert")
|
||||||
}
|
}
|
||||||
|
|
||||||
var querystr string = "INSERT INTO `" + table + "`("
|
var querystr = "INSERT INTO `" + table + "`("
|
||||||
|
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
for _, column := range _process_columns(columns) {
|
for _, column := range _process_columns(columns) {
|
||||||
@ -133,12 +132,12 @@ func (adapter *Mysql_Adapter) SimpleInsert(name string, table string, columns st
|
|||||||
querystr = querystr[0 : len(querystr)-1]
|
querystr = querystr[0 : len(querystr)-1]
|
||||||
|
|
||||||
querystr += ") VALUES ("
|
querystr += ") VALUES ("
|
||||||
for _, field := range _process_fields(fields) {
|
for _, field := range _processFields(fields) {
|
||||||
querystr += field.Name + ","
|
querystr += field.Name + ","
|
||||||
}
|
}
|
||||||
querystr = querystr[0 : len(querystr)-1]
|
querystr = querystr[0 : len(querystr)-1]
|
||||||
|
|
||||||
adapter.push_statement(name,"insert",querystr + ")")
|
adapter.pushStatement(name, "insert", querystr+")")
|
||||||
return querystr + ")", nil
|
return querystr + ")", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +155,7 @@ func (adapter *Mysql_Adapter) SimpleReplace(name string, table string, columns s
|
|||||||
return "", errors.New("No input data found for SimpleInsert")
|
return "", errors.New("No input data found for SimpleInsert")
|
||||||
}
|
}
|
||||||
|
|
||||||
var querystr string = "REPLACE INTO `" + table + "`("
|
var querystr = "REPLACE INTO `" + table + "`("
|
||||||
|
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
for _, column := range _process_columns(columns) {
|
for _, column := range _process_columns(columns) {
|
||||||
@ -170,12 +169,12 @@ func (adapter *Mysql_Adapter) SimpleReplace(name string, table string, columns s
|
|||||||
querystr = querystr[0 : len(querystr)-1]
|
querystr = querystr[0 : len(querystr)-1]
|
||||||
|
|
||||||
querystr += ") VALUES ("
|
querystr += ") VALUES ("
|
||||||
for _, field := range _process_fields(fields) {
|
for _, field := range _processFields(fields) {
|
||||||
querystr += field.Name + ","
|
querystr += field.Name + ","
|
||||||
}
|
}
|
||||||
querystr = querystr[0 : len(querystr)-1]
|
querystr = querystr[0 : len(querystr)-1]
|
||||||
|
|
||||||
adapter.push_statement(name,"replace",querystr + ")")
|
adapter.pushStatement(name, "replace", querystr+")")
|
||||||
return querystr + ")", nil
|
return querystr + ")", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,13 +189,13 @@ func (adapter *Mysql_Adapter) SimpleUpdate(name string, table string, set string
|
|||||||
return "", errors.New("You need to set data in this update statement")
|
return "", errors.New("You need to set data in this update statement")
|
||||||
}
|
}
|
||||||
|
|
||||||
var querystr string = "UPDATE `" + table + "` SET "
|
var querystr = "UPDATE `" + table + "` SET "
|
||||||
for _, item := range _process_set(set) {
|
for _, item := range _process_set(set) {
|
||||||
querystr += "`" + item.Column + "` ="
|
querystr += "`" + item.Column + "` ="
|
||||||
for _, token := range item.Expr {
|
for _, token := range item.Expr {
|
||||||
switch(token.Type) {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute":
|
case "function", "operator", "number", "substitute":
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "column":
|
case "column":
|
||||||
querystr += " `" + token.Contents + "`"
|
querystr += " `" + token.Contents + "`"
|
||||||
case "string":
|
case "string":
|
||||||
@ -212,11 +211,11 @@ func (adapter *Mysql_Adapter) SimpleUpdate(name string, table string, set string
|
|||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
if len(where) != 0 {
|
if len(where) != 0 {
|
||||||
querystr += " WHERE"
|
querystr += " WHERE"
|
||||||
for _, loc := range _process_where(where) {
|
for _, loc := range _processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch(token.Type) {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute":
|
case "function", "operator", "number", "substitute":
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "column":
|
case "column":
|
||||||
querystr += " `" + token.Contents + "`"
|
querystr += " `" + token.Contents + "`"
|
||||||
case "string":
|
case "string":
|
||||||
@ -230,7 +229,7 @@ func (adapter *Mysql_Adapter) SimpleUpdate(name string, table string, set string
|
|||||||
querystr = querystr[0 : len(querystr)-4]
|
querystr = querystr[0 : len(querystr)-4]
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter.push_statement(name,"update",querystr)
|
adapter.pushStatement(name, "update", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,14 +244,14 @@ func (adapter *Mysql_Adapter) SimpleDelete(name string, table string, where stri
|
|||||||
return "", errors.New("You need to specify what data you want to delete")
|
return "", errors.New("You need to specify what data you want to delete")
|
||||||
}
|
}
|
||||||
|
|
||||||
var querystr string = "DELETE FROM `" + table + "` WHERE"
|
var querystr = "DELETE FROM `" + table + "` WHERE"
|
||||||
|
|
||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
for _, loc := range _process_where(where) {
|
for _, loc := range _processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch(token.Type) {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute":
|
case "function", "operator", "number", "substitute":
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "column":
|
case "column":
|
||||||
querystr += " `" + token.Contents + "`"
|
querystr += " `" + token.Contents + "`"
|
||||||
case "string":
|
case "string":
|
||||||
@ -265,7 +264,7 @@ func (adapter *Mysql_Adapter) SimpleDelete(name string, table string, where stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
querystr = strings.TrimSpace(querystr[0 : len(querystr)-4])
|
querystr = strings.TrimSpace(querystr[0 : len(querystr)-4])
|
||||||
adapter.push_statement(name,"delete",querystr)
|
adapter.pushStatement(name, "delete", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,7 +276,7 @@ func (adapter *Mysql_Adapter) Purge(name string, table string) (string, error) {
|
|||||||
if table == "" {
|
if table == "" {
|
||||||
return "", errors.New("You need a name for this table")
|
return "", errors.New("You need a name for this table")
|
||||||
}
|
}
|
||||||
adapter.push_statement(name,"purge","DELETE FROM `" + table + "`")
|
adapter.pushStatement(name, "purge", "DELETE FROM `"+table+"`")
|
||||||
return "DELETE FROM `" + table + "`", nil
|
return "DELETE FROM `" + table + "`", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,9 +292,9 @@ func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Slice up the user friendly strings into something easier to process
|
// Slice up the user friendly strings into something easier to process
|
||||||
var colslice []string = strings.Split(strings.TrimSpace(columns),",")
|
var colslice = strings.Split(strings.TrimSpace(columns), ",")
|
||||||
|
|
||||||
var querystr string = "SELECT "
|
var querystr = "SELECT "
|
||||||
|
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
for _, column := range colslice {
|
for _, column := range colslice {
|
||||||
@ -309,11 +308,11 @@ func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns st
|
|||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
if len(where) != 0 {
|
if len(where) != 0 {
|
||||||
querystr += " WHERE"
|
querystr += " WHERE"
|
||||||
for _, loc := range _process_where(where) {
|
for _, loc := range _processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch(token.Type) {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute":
|
case "function", "operator", "number", "substitute":
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "column":
|
case "column":
|
||||||
querystr += " `" + token.Contents + "`"
|
querystr += " `" + token.Contents + "`"
|
||||||
case "string":
|
case "string":
|
||||||
@ -340,7 +339,7 @@ func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns st
|
|||||||
}
|
}
|
||||||
|
|
||||||
querystr = strings.TrimSpace(querystr)
|
querystr = strings.TrimSpace(querystr)
|
||||||
adapter.push_statement(name,"select",querystr)
|
adapter.pushStatement(name, "select", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +360,7 @@ func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2
|
|||||||
return "", errors.New("No joiners found for SimpleLeftJoin")
|
return "", errors.New("No joiners found for SimpleLeftJoin")
|
||||||
}
|
}
|
||||||
|
|
||||||
var querystr string = "SELECT "
|
var querystr = "SELECT "
|
||||||
|
|
||||||
for _, column := range _process_columns(columns) {
|
for _, column := range _process_columns(columns) {
|
||||||
var source, alias string
|
var source, alias string
|
||||||
@ -385,7 +384,7 @@ func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2
|
|||||||
querystr = querystr[0 : len(querystr)-1]
|
querystr = querystr[0 : len(querystr)-1]
|
||||||
|
|
||||||
querystr += " FROM `" + table1 + "` LEFT JOIN `" + table2 + "` ON "
|
querystr += " FROM `" + table1 + "` LEFT JOIN `" + table2 + "` ON "
|
||||||
for _, joiner := range _process_joiner(joiners) {
|
for _, joiner := range _processJoiner(joiners) {
|
||||||
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
|
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
|
||||||
}
|
}
|
||||||
// Remove the trailing AND
|
// Remove the trailing AND
|
||||||
@ -394,11 +393,11 @@ func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2
|
|||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
if len(where) != 0 {
|
if len(where) != 0 {
|
||||||
querystr += " WHERE"
|
querystr += " WHERE"
|
||||||
for _, loc := range _process_where(where) {
|
for _, loc := range _processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch(token.Type) {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute":
|
case "function", "operator", "number", "substitute":
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "column":
|
case "column":
|
||||||
halves := strings.Split(token.Contents, ".")
|
halves := strings.Split(token.Contents, ".")
|
||||||
if len(halves) == 2 {
|
if len(halves) == 2 {
|
||||||
@ -430,7 +429,7 @@ func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2
|
|||||||
}
|
}
|
||||||
|
|
||||||
querystr = strings.TrimSpace(querystr)
|
querystr = strings.TrimSpace(querystr)
|
||||||
adapter.push_statement(name,"select",querystr)
|
adapter.pushStatement(name, "select", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,7 +450,7 @@ func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2
|
|||||||
return "", errors.New("No joiners found for SimpleInnerJoin")
|
return "", errors.New("No joiners found for SimpleInnerJoin")
|
||||||
}
|
}
|
||||||
|
|
||||||
var querystr string = "SELECT "
|
var querystr = "SELECT "
|
||||||
|
|
||||||
for _, column := range _process_columns(columns) {
|
for _, column := range _process_columns(columns) {
|
||||||
var source, alias string
|
var source, alias string
|
||||||
@ -475,7 +474,7 @@ func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2
|
|||||||
querystr = querystr[0 : len(querystr)-1]
|
querystr = querystr[0 : len(querystr)-1]
|
||||||
|
|
||||||
querystr += " FROM `" + table1 + "` INNER JOIN `" + table2 + "` ON "
|
querystr += " FROM `" + table1 + "` INNER JOIN `" + table2 + "` ON "
|
||||||
for _, joiner := range _process_joiner(joiners) {
|
for _, joiner := range _processJoiner(joiners) {
|
||||||
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
|
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
|
||||||
}
|
}
|
||||||
// Remove the trailing AND
|
// Remove the trailing AND
|
||||||
@ -484,11 +483,11 @@ func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2
|
|||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
if len(where) != 0 {
|
if len(where) != 0 {
|
||||||
querystr += " WHERE"
|
querystr += " WHERE"
|
||||||
for _, loc := range _process_where(where) {
|
for _, loc := range _processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch(token.Type) {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute":
|
case "function", "operator", "number", "substitute":
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "column":
|
case "column":
|
||||||
halves := strings.Split(token.Contents, ".")
|
halves := strings.Split(token.Contents, ".")
|
||||||
if len(halves) == 2 {
|
if len(halves) == 2 {
|
||||||
@ -520,14 +519,14 @@ func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2
|
|||||||
}
|
}
|
||||||
|
|
||||||
querystr = strings.TrimSpace(querystr)
|
querystr = strings.TrimSpace(querystr)
|
||||||
adapter.push_statement(name,"select",querystr)
|
adapter.pushStatement(name, "select", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *Mysql_Adapter) SimpleInsertSelect(name string, ins DB_Insert, sel DB_Select) (string, error) {
|
func (adapter *Mysql_Adapter) SimpleInsertSelect(name string, ins DB_Insert, sel DB_Select) (string, error) {
|
||||||
/* Insert Portion */
|
/* Insert Portion */
|
||||||
|
|
||||||
var querystr string = "INSERT INTO `" + ins.Table + "`("
|
var querystr = "INSERT INTO `" + ins.Table + "`("
|
||||||
|
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
for _, column := range _process_columns(ins.Columns) {
|
for _, column := range _process_columns(ins.Columns) {
|
||||||
@ -563,11 +562,11 @@ func (adapter *Mysql_Adapter) SimpleInsertSelect(name string, ins DB_Insert, sel
|
|||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
if len(sel.Where) != 0 {
|
if len(sel.Where) != 0 {
|
||||||
querystr += " WHERE"
|
querystr += " WHERE"
|
||||||
for _, loc := range _process_where(sel.Where) {
|
for _, loc := range _processWhere(sel.Where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch(token.Type) {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute":
|
case "function", "operator", "number", "substitute":
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "column":
|
case "column":
|
||||||
querystr += " `" + token.Contents + "`"
|
querystr += " `" + token.Contents + "`"
|
||||||
case "string":
|
case "string":
|
||||||
@ -594,14 +593,14 @@ func (adapter *Mysql_Adapter) SimpleInsertSelect(name string, ins DB_Insert, sel
|
|||||||
}
|
}
|
||||||
|
|
||||||
querystr = strings.TrimSpace(querystr)
|
querystr = strings.TrimSpace(querystr)
|
||||||
adapter.push_statement(name,"insert",querystr)
|
adapter.pushStatement(name, "insert", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *Mysql_Adapter) SimpleInsertLeftJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
|
func (adapter *Mysql_Adapter) SimpleInsertLeftJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
|
||||||
/* Insert Portion */
|
/* Insert Portion */
|
||||||
|
|
||||||
var querystr string = "INSERT INTO `" + ins.Table + "`("
|
var querystr = "INSERT INTO `" + ins.Table + "`("
|
||||||
|
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
for _, column := range _process_columns(ins.Columns) {
|
for _, column := range _process_columns(ins.Columns) {
|
||||||
@ -635,7 +634,7 @@ func (adapter *Mysql_Adapter) SimpleInsertLeftJoin(name string, ins DB_Insert, s
|
|||||||
querystr = querystr[0 : len(querystr)-1]
|
querystr = querystr[0 : len(querystr)-1]
|
||||||
|
|
||||||
querystr += " FROM `" + sel.Table1 + "` LEFT JOIN `" + sel.Table2 + "` ON "
|
querystr += " FROM `" + sel.Table1 + "` LEFT JOIN `" + sel.Table2 + "` ON "
|
||||||
for _, joiner := range _process_joiner(sel.Joiners) {
|
for _, joiner := range _processJoiner(sel.Joiners) {
|
||||||
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
|
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
|
||||||
}
|
}
|
||||||
querystr = querystr[0 : len(querystr)-4]
|
querystr = querystr[0 : len(querystr)-4]
|
||||||
@ -643,11 +642,11 @@ func (adapter *Mysql_Adapter) SimpleInsertLeftJoin(name string, ins DB_Insert, s
|
|||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
if len(sel.Where) != 0 {
|
if len(sel.Where) != 0 {
|
||||||
querystr += " WHERE"
|
querystr += " WHERE"
|
||||||
for _, loc := range _process_where(sel.Where) {
|
for _, loc := range _processWhere(sel.Where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch(token.Type) {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute":
|
case "function", "operator", "number", "substitute":
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "column":
|
case "column":
|
||||||
halves := strings.Split(token.Contents, ".")
|
halves := strings.Split(token.Contents, ".")
|
||||||
if len(halves) == 2 {
|
if len(halves) == 2 {
|
||||||
@ -679,14 +678,14 @@ func (adapter *Mysql_Adapter) SimpleInsertLeftJoin(name string, ins DB_Insert, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
querystr = strings.TrimSpace(querystr)
|
querystr = strings.TrimSpace(querystr)
|
||||||
adapter.push_statement(name,"insert",querystr)
|
adapter.pushStatement(name, "insert", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *Mysql_Adapter) SimpleInsertInnerJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
|
func (adapter *Mysql_Adapter) SimpleInsertInnerJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
|
||||||
/* Insert Portion */
|
/* Insert Portion */
|
||||||
|
|
||||||
var querystr string = "INSERT INTO `" + ins.Table + "`("
|
var querystr = "INSERT INTO `" + ins.Table + "`("
|
||||||
|
|
||||||
// Escape the column names, just in case we've used a reserved keyword
|
// Escape the column names, just in case we've used a reserved keyword
|
||||||
for _, column := range _process_columns(ins.Columns) {
|
for _, column := range _process_columns(ins.Columns) {
|
||||||
@ -720,7 +719,7 @@ func (adapter *Mysql_Adapter) SimpleInsertInnerJoin(name string, ins DB_Insert,
|
|||||||
querystr = querystr[0 : len(querystr)-1]
|
querystr = querystr[0 : len(querystr)-1]
|
||||||
|
|
||||||
querystr += " FROM `" + sel.Table1 + "` INNER JOIN `" + sel.Table2 + "` ON "
|
querystr += " FROM `" + sel.Table1 + "` INNER JOIN `" + sel.Table2 + "` ON "
|
||||||
for _, joiner := range _process_joiner(sel.Joiners) {
|
for _, joiner := range _processJoiner(sel.Joiners) {
|
||||||
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
|
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
|
||||||
}
|
}
|
||||||
querystr = querystr[0 : len(querystr)-4]
|
querystr = querystr[0 : len(querystr)-4]
|
||||||
@ -728,11 +727,11 @@ func (adapter *Mysql_Adapter) SimpleInsertInnerJoin(name string, ins DB_Insert,
|
|||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
if len(sel.Where) != 0 {
|
if len(sel.Where) != 0 {
|
||||||
querystr += " WHERE"
|
querystr += " WHERE"
|
||||||
for _, loc := range _process_where(sel.Where) {
|
for _, loc := range _processWhere(sel.Where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch(token.Type) {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute":
|
case "function", "operator", "number", "substitute":
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "column":
|
case "column":
|
||||||
halves := strings.Split(token.Contents, ".")
|
halves := strings.Split(token.Contents, ".")
|
||||||
if len(halves) == 2 {
|
if len(halves) == 2 {
|
||||||
@ -764,7 +763,7 @@ func (adapter *Mysql_Adapter) SimpleInsertInnerJoin(name string, ins DB_Insert,
|
|||||||
}
|
}
|
||||||
|
|
||||||
querystr = strings.TrimSpace(querystr)
|
querystr = strings.TrimSpace(querystr)
|
||||||
adapter.push_statement(name,"insert",querystr)
|
adapter.pushStatement(name, "insert", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -776,7 +775,7 @@ func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where strin
|
|||||||
return "", errors.New("You need a name for this table")
|
return "", errors.New("You need a name for this table")
|
||||||
}
|
}
|
||||||
|
|
||||||
var querystr string = "SELECT COUNT(*) AS `count` FROM `" + table + "`"
|
var querystr = "SELECT COUNT(*) AS `count` FROM `" + table + "`"
|
||||||
|
|
||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
if len(where) != 0 {
|
if len(where) != 0 {
|
||||||
@ -784,11 +783,11 @@ func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where strin
|
|||||||
//fmt.Println("SimpleCount:",name)
|
//fmt.Println("SimpleCount:",name)
|
||||||
//fmt.Println("where:",where)
|
//fmt.Println("where:",where)
|
||||||
//fmt.Println("_process_where:",_process_where(where))
|
//fmt.Println("_process_where:",_process_where(where))
|
||||||
for _, loc := range _process_where(where) {
|
for _, loc := range _processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch(token.Type) {
|
switch token.Type {
|
||||||
case "function", "operator", "number", "substitute":
|
case "function", "operator", "number", "substitute":
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "column":
|
case "column":
|
||||||
querystr += " `" + token.Contents + "`"
|
querystr += " `" + token.Contents + "`"
|
||||||
case "string":
|
case "string":
|
||||||
@ -807,7 +806,7 @@ func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
querystr = strings.TrimSpace(querystr)
|
querystr = strings.TrimSpace(querystr)
|
||||||
adapter.push_statement(name,"select",querystr)
|
adapter.pushStatement(name, "select", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -837,7 +836,9 @@ package main
|
|||||||
import "log"
|
import "log"
|
||||||
import "database/sql"
|
import "database/sql"
|
||||||
|
|
||||||
|
// nolint
|
||||||
` + stmts + `
|
` + stmts + `
|
||||||
|
// nolint
|
||||||
func _gen_mysql() (err error) {
|
func _gen_mysql() (err error) {
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Building the generated statements")
|
log.Print("Building the generated statements")
|
||||||
@ -846,16 +847,16 @@ func _gen_mysql() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
return write_file("./gen_mysql.go", out)
|
return writeFile("./gen_mysql.go", out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal methods, not exposed in the interface
|
// Internal methods, not exposed in the interface
|
||||||
func (adapter *Mysql_Adapter) push_statement(name string, stype string, querystr string) {
|
func (adapter *Mysql_Adapter) pushStatement(name string, stype string, querystr string) {
|
||||||
adapter.Buffer[name] = DB_Stmt{querystr, stype}
|
adapter.Buffer[name] = DB_Stmt{querystr, stype}
|
||||||
adapter.BufferOrder = append(adapter.BufferOrder, name)
|
adapter.BufferOrder = append(adapter.BufferOrder, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *Mysql_Adapter) stringy_type(ctype string) bool {
|
func (adapter *Mysql_Adapter) stringyType(ctype string) bool {
|
||||||
ctype = strings.ToLower(ctype)
|
ctype = strings.ToLower(ctype)
|
||||||
return ctype == "varchar" || ctype == "tinytext" || ctype == "text" || ctype == "mediumtext" || ctype == "longtext" || ctype == "char" || ctype == "datetime" || ctype == "timestamp" || ctype == "time" || ctype == "date"
|
return ctype == "varchar" || ctype == "tinytext" || ctype == "text" || ctype == "mediumtext" || ctype == "longtext" || ctype == "char" || ctype == "datetime" || ctype == "timestamp" || ctype == "time" || ctype == "date"
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,7 @@ func init() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Pgsql_Adapter struct
|
type Pgsql_Adapter struct {
|
||||||
{
|
|
||||||
Name string
|
Name string
|
||||||
Buffer map[string]DB_Stmt
|
Buffer map[string]DB_Stmt
|
||||||
BufferOrder []string // Map iteration order is random, so we need this to track the order, so we don't get huge diffs every commit
|
BufferOrder []string // Map iteration order is random, so we need this to track the order, so we don't get huge diffs every commit
|
||||||
@ -43,7 +42,7 @@ func (adapter *Pgsql_Adapter) CreateTable(name string, table string, charset str
|
|||||||
return "", errors.New("You can't have a table with no columns")
|
return "", errors.New("You can't have a table with no columns")
|
||||||
}
|
}
|
||||||
|
|
||||||
var querystr string = "CREATE TABLE `" + table + "` ("
|
var querystr = "CREATE TABLE `" + table + "` ("
|
||||||
for _, column := range columns {
|
for _, column := range columns {
|
||||||
if column.Auto_Increment {
|
if column.Auto_Increment {
|
||||||
column.Type = "serial"
|
column.Type = "serial"
|
||||||
@ -61,7 +60,7 @@ func (adapter *Pgsql_Adapter) CreateTable(name string, table string, charset str
|
|||||||
var end string
|
var end string
|
||||||
if column.Default != "" {
|
if column.Default != "" {
|
||||||
end = " DEFAULT "
|
end = " DEFAULT "
|
||||||
if adapter.stringy_type(column.Type) && column.Default != "''" {
|
if adapter.stringyType(column.Type) && column.Default != "''" {
|
||||||
end += "'" + column.Default + "'"
|
end += "'" + column.Default + "'"
|
||||||
} else {
|
} else {
|
||||||
end += column.Default
|
end += column.Default
|
||||||
@ -90,7 +89,7 @@ func (adapter *Pgsql_Adapter) CreateTable(name string, table string, charset str
|
|||||||
}
|
}
|
||||||
|
|
||||||
querystr = querystr[0:len(querystr)-1] + "\n);"
|
querystr = querystr[0:len(querystr)-1] + "\n);"
|
||||||
adapter.push_statement(name,"create-table",querystr)
|
adapter.pushStatement(name, "create-table", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,19 +138,19 @@ func (adapter *Pgsql_Adapter) SimpleUpdate(name string, table string, set string
|
|||||||
if set == "" {
|
if set == "" {
|
||||||
return "", errors.New("You need to set data in this update statement")
|
return "", errors.New("You need to set data in this update statement")
|
||||||
}
|
}
|
||||||
var querystr string = "UPDATE `" + table + "` SET "
|
var querystr = "UPDATE `" + table + "` SET "
|
||||||
for _, item := range _process_set(set) {
|
for _, item := range _process_set(set) {
|
||||||
querystr += "`" + item.Column + "` ="
|
querystr += "`" + item.Column + "` ="
|
||||||
for _, token := range item.Expr {
|
for _, token := range item.Expr {
|
||||||
switch(token.Type) {
|
switch token.Type {
|
||||||
case "function":
|
case "function":
|
||||||
// TO-DO: Write a more sophisticated function parser on the utils side.
|
// TO-DO: Write a more sophisticated function parser on the utils side.
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "LOCALTIMESTAMP()"
|
token.Contents = "LOCALTIMESTAMP()"
|
||||||
}
|
}
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "operator", "number", "substitute":
|
case "operator", "number", "substitute":
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "column":
|
case "column":
|
||||||
querystr += " `" + token.Contents + "`"
|
querystr += " `" + token.Contents + "`"
|
||||||
case "string":
|
case "string":
|
||||||
@ -167,17 +166,17 @@ func (adapter *Pgsql_Adapter) SimpleUpdate(name string, table string, set string
|
|||||||
// Add support for BETWEEN x.x
|
// Add support for BETWEEN x.x
|
||||||
if len(where) != 0 {
|
if len(where) != 0 {
|
||||||
querystr += " WHERE"
|
querystr += " WHERE"
|
||||||
for _, loc := range _process_where(where) {
|
for _, loc := range _processWhere(where) {
|
||||||
for _, token := range loc.Expr {
|
for _, token := range loc.Expr {
|
||||||
switch(token.Type) {
|
switch token.Type {
|
||||||
case "function":
|
case "function":
|
||||||
// TO-DO: Write a more sophisticated function parser on the utils side. What's the situation in regards to case sensitivity?
|
// TO-DO: Write a more sophisticated function parser on the utils side. What's the situation in regards to case sensitivity?
|
||||||
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
if strings.ToUpper(token.Contents) == "UTC_TIMESTAMP()" {
|
||||||
token.Contents = "LOCALTIMESTAMP()"
|
token.Contents = "LOCALTIMESTAMP()"
|
||||||
}
|
}
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "operator", "number", "substitute":
|
case "operator", "number", "substitute":
|
||||||
querystr += " " + token.Contents + ""
|
querystr += " " + token.Contents
|
||||||
case "column":
|
case "column":
|
||||||
querystr += " `" + token.Contents + "`"
|
querystr += " `" + token.Contents + "`"
|
||||||
case "string":
|
case "string":
|
||||||
@ -191,7 +190,7 @@ func (adapter *Pgsql_Adapter) SimpleUpdate(name string, table string, set string
|
|||||||
querystr = querystr[0 : len(querystr)-4]
|
querystr = querystr[0 : len(querystr)-4]
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter.push_statement(name,"update",querystr)
|
adapter.pushStatement(name, "update", querystr)
|
||||||
return querystr, nil
|
return querystr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +325,9 @@ package main
|
|||||||
import "log"
|
import "log"
|
||||||
import "database/sql"
|
import "database/sql"
|
||||||
|
|
||||||
|
// nolint
|
||||||
` + stmts + `
|
` + stmts + `
|
||||||
|
// nolint
|
||||||
func _gen_pgsql() (err error) {
|
func _gen_pgsql() (err error) {
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Building the generated statements")
|
log.Print("Building the generated statements")
|
||||||
@ -335,16 +336,16 @@ func _gen_pgsql() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
return write_file("./gen_pgsql.go", out)
|
return writeFile("./gen_pgsql.go", out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal methods, not exposed in the interface
|
// Internal methods, not exposed in the interface
|
||||||
func (adapter *Pgsql_Adapter) push_statement(name string, stype string, querystr string) {
|
func (adapter *Pgsql_Adapter) pushStatement(name string, stype string, querystr string) {
|
||||||
adapter.Buffer[name] = DB_Stmt{querystr, stype}
|
adapter.Buffer[name] = DB_Stmt{querystr, stype}
|
||||||
adapter.BufferOrder = append(adapter.BufferOrder, name)
|
adapter.BufferOrder = append(adapter.BufferOrder, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adapter *Pgsql_Adapter) stringy_type(ctype string) bool {
|
func (adapter *Pgsql_Adapter) stringyType(ctype string) bool {
|
||||||
ctype = strings.ToLower(ctype)
|
ctype = strings.ToLower(ctype)
|
||||||
return ctype == "char" || ctype == "varchar" || ctype == "timestamp" || ctype == "text"
|
return ctype == "char" || ctype == "varchar" || ctype == "timestamp" || ctype == "text"
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ func _process_orderby(orderstr string) (order []DB_Order) {
|
|||||||
return order
|
return order
|
||||||
}
|
}
|
||||||
|
|
||||||
func _process_joiner(joinstr string) (joiner []DB_Joiner) {
|
func _processJoiner(joinstr string) (joiner []DB_Joiner) {
|
||||||
if joinstr == "" {
|
if joinstr == "" {
|
||||||
return joiner
|
return joiner
|
||||||
}
|
}
|
||||||
@ -68,10 +68,9 @@ func _process_joiner(joinstr string) (joiner []DB_Joiner) {
|
|||||||
var parseOffset int
|
var parseOffset int
|
||||||
var left, right string
|
var left, right string
|
||||||
|
|
||||||
left, parseOffset = _get_identifier(segment, parseOffset)
|
left, parseOffset = _getIdentifier(segment, parseOffset)
|
||||||
outjoin.Operator, parseOffset = _get_operator(segment, parseOffset + 1)
|
outjoin.Operator, parseOffset = _getOperator(segment, parseOffset+1)
|
||||||
right, parseOffset = _get_identifier(segment, parseOffset + 1)
|
right, parseOffset = _getIdentifier(segment, parseOffset+1)
|
||||||
|
|
||||||
|
|
||||||
left_column := strings.Split(left, ".")
|
left_column := strings.Split(left, ".")
|
||||||
right_column := strings.Split(right, ".")
|
right_column := strings.Split(right, ".")
|
||||||
@ -85,7 +84,7 @@ func _process_joiner(joinstr string) (joiner []DB_Joiner) {
|
|||||||
return joiner
|
return joiner
|
||||||
}
|
}
|
||||||
|
|
||||||
func _process_where(wherestr string) (where []DB_Where) {
|
func _processWhere(wherestr string) (where []DB_Where) {
|
||||||
if wherestr == "" {
|
if wherestr == "" {
|
||||||
return where
|
return where
|
||||||
}
|
}
|
||||||
@ -99,10 +98,10 @@ func _process_where(wherestr string) (where []DB_Where) {
|
|||||||
for i := 0; i < len(segment); i++ {
|
for i := 0; i < len(segment); i++ {
|
||||||
char := segment[i]
|
char := segment[i]
|
||||||
//fmt.Println("optype",optype)
|
//fmt.Println("optype",optype)
|
||||||
switch(optype) {
|
switch optype {
|
||||||
case 0: // unknown
|
case 0: // unknown
|
||||||
//fmt.Println("case 0:",char,string(char))
|
//fmt.Println("case 0:",char,string(char))
|
||||||
if ('0' <= char && char <= '9') {
|
if '0' <= char && char <= '9' {
|
||||||
optype = 1
|
optype = 1
|
||||||
buffer = string(char)
|
buffer = string(char)
|
||||||
} else if ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_' {
|
} else if ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_' {
|
||||||
@ -119,7 +118,7 @@ func _process_where(wherestr string) (where []DB_Where) {
|
|||||||
tmp_where.Expr = append(tmp_where.Expr, DB_Token{"?", "substitute"})
|
tmp_where.Expr = append(tmp_where.Expr, DB_Token{"?", "substitute"})
|
||||||
}
|
}
|
||||||
case 1: // number
|
case 1: // number
|
||||||
if ('0' <= char && char <= '9') {
|
if '0' <= char && char <= '9' {
|
||||||
buffer += string(char)
|
buffer += string(char)
|
||||||
} else {
|
} else {
|
||||||
optype = 0
|
optype = 0
|
||||||
@ -140,17 +139,17 @@ func _process_where(wherestr string) (where []DB_Where) {
|
|||||||
tmp_where.Expr = append(tmp_where.Expr, DB_Token{buffer, "column"})
|
tmp_where.Expr = append(tmp_where.Expr, DB_Token{buffer, "column"})
|
||||||
}
|
}
|
||||||
case 3: // function
|
case 3: // function
|
||||||
var pre_i int = i
|
var preI = i
|
||||||
//fmt.Println("buffer",buffer)
|
//fmt.Println("buffer",buffer)
|
||||||
//fmt.Println("len(halves)",len(halves[1]))
|
//fmt.Println("len(halves)",len(halves[1]))
|
||||||
//fmt.Println("pre_i",string(halves[1][pre_i]))
|
//fmt.Println("preI",string(halves[1][preI]))
|
||||||
//fmt.Println("msg prior to pre_i",halves[1][0:pre_i])
|
//fmt.Println("msg prior to preI",halves[1][0:preI])
|
||||||
i = _skip_function_call(segment,i-1)
|
i = _skipFunctionCall(segment, i-1)
|
||||||
//fmt.Println("i",i)
|
//fmt.Println("i",i)
|
||||||
//fmt.Println("msg prior to i-1",halves[1][0:i-1])
|
//fmt.Println("msg prior to i-1",halves[1][0:i-1])
|
||||||
//fmt.Println("string(i-1)",string(halves[1][i-1]))
|
//fmt.Println("string(i-1)",string(halves[1][i-1]))
|
||||||
//fmt.Println("string(i)",string(halves[1][i]))
|
//fmt.Println("string(i)",string(halves[1][i]))
|
||||||
buffer += segment[pre_i:i] + string(segment[i])
|
buffer += segment[preI:i] + string(segment[i])
|
||||||
//fmt.Println("Expr:",buffer)
|
//fmt.Println("Expr:",buffer)
|
||||||
tmp_where.Expr = append(tmp_where.Expr, DB_Token{buffer, "function"})
|
tmp_where.Expr = append(tmp_where.Expr, DB_Token{buffer, "function"})
|
||||||
optype = 0
|
optype = 0
|
||||||
@ -189,18 +188,18 @@ func _process_set(setstr string) (setter []DB_Setter) {
|
|||||||
// First pass, splitting the string by commas while ignoring the innards of functions
|
// First pass, splitting the string by commas while ignoring the innards of functions
|
||||||
var setset []string
|
var setset []string
|
||||||
var buffer string
|
var buffer string
|
||||||
var last_item int
|
var lastItem int
|
||||||
setstr += ","
|
setstr += ","
|
||||||
for i := 0; i < len(setstr); i++ {
|
for i := 0; i < len(setstr); i++ {
|
||||||
if setstr[i] == '(' {
|
if setstr[i] == '(' {
|
||||||
i = _skip_function_call(setstr,i-1)
|
i = _skipFunctionCall(setstr, i-1)
|
||||||
setset = append(setset,setstr[last_item:i+1])
|
setset = append(setset, setstr[lastItem:i+1])
|
||||||
buffer = ""
|
buffer = ""
|
||||||
last_item = i + 2
|
lastItem = i + 2
|
||||||
} else if setstr[i] == ',' && buffer != "" {
|
} else if setstr[i] == ',' && buffer != "" {
|
||||||
setset = append(setset, buffer)
|
setset = append(setset, buffer)
|
||||||
buffer = ""
|
buffer = ""
|
||||||
last_item = i + 1
|
lastItem = i + 1
|
||||||
} else if (setstr[i] > 32) && setstr[i] != ',' && setstr[i] != ')' {
|
} else if (setstr[i] > 32) && setstr[i] != ',' && setstr[i] != ')' {
|
||||||
buffer += string(setstr[i])
|
buffer += string(setstr[i])
|
||||||
}
|
}
|
||||||
@ -222,9 +221,9 @@ func _process_set(setstr string) (setter []DB_Setter) {
|
|||||||
for i := 0; i < len(halves[1]); i++ {
|
for i := 0; i < len(halves[1]); i++ {
|
||||||
char := halves[1][i]
|
char := halves[1][i]
|
||||||
//fmt.Println("optype",optype)
|
//fmt.Println("optype",optype)
|
||||||
switch(optype) {
|
switch optype {
|
||||||
case 0: // unknown
|
case 0: // unknown
|
||||||
if ('0' <= char && char <= '9') {
|
if '0' <= char && char <= '9' {
|
||||||
optype = 1
|
optype = 1
|
||||||
buffer = string(char)
|
buffer = string(char)
|
||||||
} else if ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_' {
|
} else if ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_' {
|
||||||
@ -241,7 +240,7 @@ func _process_set(setstr string) (setter []DB_Setter) {
|
|||||||
tmp_setter.Expr = append(tmp_setter.Expr, DB_Token{"?", "substitute"})
|
tmp_setter.Expr = append(tmp_setter.Expr, DB_Token{"?", "substitute"})
|
||||||
}
|
}
|
||||||
case 1: // number
|
case 1: // number
|
||||||
if ('0' <= char && char <= '9') {
|
if '0' <= char && char <= '9' {
|
||||||
buffer += string(char)
|
buffer += string(char)
|
||||||
} else {
|
} else {
|
||||||
optype = 0
|
optype = 0
|
||||||
@ -262,17 +261,17 @@ func _process_set(setstr string) (setter []DB_Setter) {
|
|||||||
tmp_setter.Expr = append(tmp_setter.Expr, DB_Token{buffer, "column"})
|
tmp_setter.Expr = append(tmp_setter.Expr, DB_Token{buffer, "column"})
|
||||||
}
|
}
|
||||||
case 3: // function
|
case 3: // function
|
||||||
var pre_i int = i
|
var preI = i
|
||||||
//fmt.Println("buffer",buffer)
|
//fmt.Println("buffer",buffer)
|
||||||
//fmt.Println("len(halves)",len(halves[1]))
|
//fmt.Println("len(halves)",len(halves[1]))
|
||||||
//fmt.Println("pre_i",string(halves[1][pre_i]))
|
//fmt.Println("preI",string(halves[1][preI]))
|
||||||
//fmt.Println("msg prior to pre_i",halves[1][0:pre_i])
|
//fmt.Println("msg prior to preI",halves[1][0:preI])
|
||||||
i = _skip_function_call(halves[1],i-1)
|
i = _skipFunctionCall(halves[1], i-1)
|
||||||
//fmt.Println("i",i)
|
//fmt.Println("i",i)
|
||||||
//fmt.Println("msg prior to i-1",halves[1][0:i-1])
|
//fmt.Println("msg prior to i-1",halves[1][0:i-1])
|
||||||
//fmt.Println("string(i-1)",string(halves[1][i-1]))
|
//fmt.Println("string(i-1)",string(halves[1][i-1]))
|
||||||
//fmt.Println("string(i)",string(halves[1][i]))
|
//fmt.Println("string(i)",string(halves[1][i]))
|
||||||
buffer += halves[1][pre_i:i] + string(halves[1][i])
|
buffer += halves[1][preI:i] + string(halves[1][i])
|
||||||
//fmt.Println("Expr:",buffer)
|
//fmt.Println("Expr:",buffer)
|
||||||
tmp_setter.Expr = append(tmp_setter.Expr, DB_Token{buffer, "function"})
|
tmp_setter.Expr = append(tmp_setter.Expr, DB_Token{buffer, "function"})
|
||||||
optype = 0
|
optype = 0
|
||||||
@ -303,7 +302,7 @@ func _process_set(setstr string) (setter []DB_Setter) {
|
|||||||
return setter
|
return setter
|
||||||
}
|
}
|
||||||
|
|
||||||
func _process_limit(limitstr string) (limiter DB_Limit) {
|
func _processLimit(limitstr string) (limiter DB_Limit) {
|
||||||
halves := strings.Split(limitstr, ",")
|
halves := strings.Split(limitstr, ",")
|
||||||
if len(halves) == 2 {
|
if len(halves) == 2 {
|
||||||
limiter.Offset = halves[0]
|
limiter.Offset = halves[0]
|
||||||
@ -322,23 +321,23 @@ func _is_op_rune(char rune) bool {
|
|||||||
return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/'
|
return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
func _process_fields(fieldstr string) (fields []DB_Field) {
|
func _processFields(fieldstr string) (fields []DB_Field) {
|
||||||
if fieldstr == "" {
|
if fieldstr == "" {
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
var buffer string
|
var buffer string
|
||||||
var last_item int
|
var lastItem int
|
||||||
fieldstr += ","
|
fieldstr += ","
|
||||||
for i := 0; i < len(fieldstr); i++ {
|
for i := 0; i < len(fieldstr); i++ {
|
||||||
if fieldstr[i] == '(' {
|
if fieldstr[i] == '(' {
|
||||||
i = _skip_function_call(fieldstr,i-1)
|
i = _skipFunctionCall(fieldstr, i-1)
|
||||||
fields = append(fields,DB_Field{Name:fieldstr[last_item:i+1],Type:_get_identifier_type(fieldstr[last_item:i+1])})
|
fields = append(fields, DB_Field{Name: fieldstr[lastItem : i+1], Type: _getIdentifierType(fieldstr[lastItem : i+1])})
|
||||||
buffer = ""
|
buffer = ""
|
||||||
last_item = i + 2
|
lastItem = i + 2
|
||||||
} else if fieldstr[i] == ',' && buffer != "" {
|
} else if fieldstr[i] == ',' && buffer != "" {
|
||||||
fields = append(fields,DB_Field{Name:buffer,Type:_get_identifier_type(buffer)})
|
fields = append(fields, DB_Field{Name: buffer, Type: _getIdentifierType(buffer)})
|
||||||
buffer = ""
|
buffer = ""
|
||||||
last_item = i + 1
|
lastItem = i + 1
|
||||||
} else if (fieldstr[i] > 32) && fieldstr[i] != ',' && fieldstr[i] != ')' {
|
} else if (fieldstr[i] > 32) && fieldstr[i] != ',' && fieldstr[i] != ')' {
|
||||||
buffer += string(fieldstr[i])
|
buffer += string(fieldstr[i])
|
||||||
}
|
}
|
||||||
@ -346,7 +345,7 @@ func _process_fields(fieldstr string) (fields []DB_Field) {
|
|||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
func _get_identifier_type(identifier string) string {
|
func _getIdentifierType(identifier string) string {
|
||||||
if ('a' <= identifier[0] && identifier[0] <= 'z') || ('A' <= identifier[0] && identifier[0] <= 'Z') {
|
if ('a' <= identifier[0] && identifier[0] <= 'z') || ('A' <= identifier[0] && identifier[0] <= 'Z') {
|
||||||
if identifier[len(identifier)-1] == ')' {
|
if identifier[len(identifier)-1] == ')' {
|
||||||
return "function"
|
return "function"
|
||||||
@ -359,12 +358,12 @@ func _get_identifier_type(identifier string) string {
|
|||||||
return "literal"
|
return "literal"
|
||||||
}
|
}
|
||||||
|
|
||||||
func _get_identifier(segment string, startOffset int) (out string, i int) {
|
func _getIdentifier(segment string, startOffset int) (out string, i int) {
|
||||||
segment = strings.TrimSpace(segment)
|
segment = strings.TrimSpace(segment)
|
||||||
segment += " " // Avoid overflow bugs with slicing
|
segment += " " // Avoid overflow bugs with slicing
|
||||||
for i = startOffset; i < len(segment); i++ {
|
for i = startOffset; i < len(segment); i++ {
|
||||||
if segment[i] == '(' {
|
if segment[i] == '(' {
|
||||||
i = _skip_function_call(segment,i)
|
i = _skipFunctionCall(segment, i)
|
||||||
return strings.TrimSpace(segment[startOffset:i]), (i - 1)
|
return strings.TrimSpace(segment[startOffset:i]), (i - 1)
|
||||||
}
|
}
|
||||||
if (segment[i] == ' ' || _is_op_byte(segment[i])) && i != startOffset {
|
if (segment[i] == ' ' || _is_op_byte(segment[i])) && i != startOffset {
|
||||||
@ -374,7 +373,7 @@ func _get_identifier(segment string, startOffset int) (out string, i int) {
|
|||||||
return strings.TrimSpace(segment[startOffset:]), (i - 1)
|
return strings.TrimSpace(segment[startOffset:]), (i - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _get_operator(segment string, startOffset int) (out string, i int) {
|
func _getOperator(segment string, startOffset int) (out string, i int) {
|
||||||
segment = strings.TrimSpace(segment)
|
segment = strings.TrimSpace(segment)
|
||||||
segment += " " // Avoid overflow bugs with slicing
|
segment += " " // Avoid overflow bugs with slicing
|
||||||
for i = startOffset; i < len(segment); i++ {
|
for i = startOffset; i < len(segment); i++ {
|
||||||
@ -385,15 +384,15 @@ func _get_operator(segment string, startOffset int) (out string, i int) {
|
|||||||
return strings.TrimSpace(segment[startOffset:]), (i - 1)
|
return strings.TrimSpace(segment[startOffset:]), (i - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _skip_function_call(data string, index int) int {
|
func _skipFunctionCall(data string, index int) int {
|
||||||
var brace_count int
|
var braceCount int
|
||||||
for ; index < len(data); index++ {
|
for ; index < len(data); index++ {
|
||||||
char := data[index]
|
char := data[index]
|
||||||
if char == '(' {
|
if char == '(' {
|
||||||
brace_count++
|
braceCount++
|
||||||
} else if char == ')' {
|
} else if char == ')' {
|
||||||
brace_count--
|
braceCount--
|
||||||
if brace_count == 0 {
|
if braceCount == 0 {
|
||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,7 +400,7 @@ func _skip_function_call(data string, index int) int {
|
|||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
|
|
||||||
func write_file(name string, content string) (err error) {
|
func writeFile(name string, content string) (err error) {
|
||||||
f, err := os.Create(name)
|
f, err := os.Create(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -410,7 +409,9 @@ func write_file(name string, content string) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
f.Sync()
|
err = f.Sync()
|
||||||
f.Close()
|
if err != nil {
|
||||||
return
|
return err
|
||||||
|
}
|
||||||
|
return f.Close()
|
||||||
}
|
}
|
||||||
|
22
reply.go
22
reply.go
@ -1,4 +1,9 @@
|
|||||||
/* Copyright Azareal 2016 - 2017 */
|
/*
|
||||||
|
*
|
||||||
|
* Reply Resources File
|
||||||
|
* Copyright Azareal 2016 - 2018
|
||||||
|
*
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
// Should we add a reply store to centralise all the reply logic? Would this cover profile replies too or would that be seperate?
|
// Should we add a reply store to centralise all the reply logic? Would this cover profile replies too or would that be seperate?
|
||||||
@ -24,15 +29,14 @@ type Reply struct /* Should probably rename this to ReplyUser and rename ReplySh
|
|||||||
URLPrefix string
|
URLPrefix string
|
||||||
URLName string
|
URLName string
|
||||||
Level int
|
Level int
|
||||||
IpAddress string
|
IPAddress string
|
||||||
Liked bool
|
Liked bool
|
||||||
LikeCount int
|
LikeCount int
|
||||||
ActionType string
|
ActionType string
|
||||||
ActionIcon string
|
ActionIcon string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReplyShort struct
|
type ReplyShort struct {
|
||||||
{
|
|
||||||
ID int
|
ID int
|
||||||
ParentID int
|
ParentID int
|
||||||
Content string
|
Content string
|
||||||
@ -42,19 +46,19 @@ type ReplyShort struct
|
|||||||
LastEdit int
|
LastEdit int
|
||||||
LastEditBy int
|
LastEditBy int
|
||||||
ContentLines int
|
ContentLines int
|
||||||
IpAddress string
|
IPAddress string
|
||||||
Liked bool
|
Liked bool
|
||||||
LikeCount int
|
LikeCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
func get_reply(id int) (*ReplyShort, error) {
|
func getReply(id int) (*ReplyShort, error) {
|
||||||
reply := ReplyShort{ID: id}
|
reply := ReplyShort{ID: id}
|
||||||
err := get_reply_stmt.QueryRow(id).Scan(&reply.ParentID, &reply.Content, &reply.CreatedBy, &reply.CreatedAt, &reply.LastEdit, &reply.LastEditBy, &reply.IpAddress, &reply.LikeCount)
|
err := get_reply_stmt.QueryRow(id).Scan(&reply.ParentID, &reply.Content, &reply.CreatedBy, &reply.CreatedAt, &reply.LastEdit, &reply.LastEditBy, &reply.IPAddress, &reply.LikeCount)
|
||||||
return &reply, err
|
return &reply, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func get_user_reply(id int) (*ReplyShort, error) {
|
func getUserReply(id int) (*ReplyShort, error) {
|
||||||
reply := ReplyShort{ID: id}
|
reply := ReplyShort{ID: id}
|
||||||
err := get_user_reply_stmt.QueryRow(id).Scan(&reply.ParentID, &reply.Content, &reply.CreatedBy, &reply.CreatedAt, &reply.LastEdit, &reply.LastEditBy, &reply.IpAddress)
|
err := get_user_reply_stmt.QueryRow(id).Scan(&reply.ParentID, &reply.Content, &reply.CreatedBy, &reply.CreatedAt, &reply.LastEdit, &reply.LastEditBy, &reply.IPAddress)
|
||||||
return &reply, err
|
return &reply, err
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ func routes() {
|
|||||||
Route{"route_panel_word_filters_delete_submit", "/panel/settings/word-filters/delete/submit/", "", []string{"extra_data"}},
|
Route{"route_panel_word_filters_delete_submit", "/panel/settings/word-filters/delete/submit/", "", []string{"extra_data"}},
|
||||||
|
|
||||||
Route{"route_panel_themes", "/panel/themes/", "", []string{}},
|
Route{"route_panel_themes", "/panel/themes/", "", []string{}},
|
||||||
Route{"route_panel_themes_default","/panel/themes/default/","",[]string{"extra_data"}},
|
Route{"route_panel_themes_set_default", "/panel/themes/default/", "", []string{"extra_data"}},
|
||||||
|
|
||||||
Route{"route_panel_plugins", "/panel/plugins/", "", []string{}},
|
Route{"route_panel_plugins", "/panel/plugins/", "", []string{}},
|
||||||
Route{"route_panel_plugins_activate", "/panel/plugins/activate/", "", []string{"extra_data"}},
|
Route{"route_panel_plugins_activate", "/panel/plugins/activate/", "", []string{"extra_data"}},
|
||||||
|
355
routes.go
355
routes.go
@ -1,33 +1,38 @@
|
|||||||
/* Copyright Azareal 2016 - 2017 */
|
/*
|
||||||
|
*
|
||||||
|
* Gosora Route Handlers
|
||||||
|
* Copyright Azareal 2016 - 2018
|
||||||
|
*
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
//"fmt"
|
//"fmt"
|
||||||
"strconv"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"regexp"
|
"html"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"html"
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"./query_gen/lib"
|
"./query_gen/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A blank list to fill out that parameter in Page for routes which don't use it
|
// A blank list to fill out that parameter in Page for routes which don't use it
|
||||||
var tList []interface{}
|
var tList []interface{}
|
||||||
var nList []string
|
|
||||||
var hvars HeaderVars
|
//var nList []string
|
||||||
var extData ExtData
|
var hvars *HeaderVars // We might need to rethink this now that it's a pointer
|
||||||
var success_json_bytes []byte = []byte(`{"success":"1"}`)
|
var successJSONBytes = []byte(`{"success":"1"}`)
|
||||||
var cacheControlMaxAge string = "max-age=" + strconv.Itoa(day)
|
var cacheControlMaxAge = "max-age=" + strconv.Itoa(day)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
hvars.Site = site
|
hvars = &HeaderVars{Site: site}
|
||||||
}
|
}
|
||||||
|
|
||||||
type HttpsRedirect struct {
|
type HttpsRedirect struct {
|
||||||
@ -44,7 +49,7 @@ func (red *HttpsRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
// GET functions
|
// GET functions
|
||||||
func route_static(w http.ResponseWriter, r *http.Request) {
|
func route_static(w http.ResponseWriter, r *http.Request) {
|
||||||
//log.Print("Outputting static file '" + r.URL.Path + "'")
|
//log.Print("Outputting static file '" + r.URL.Path + "'")
|
||||||
file, ok := static_files[r.URL.Path]
|
file, ok := staticFiles[r.URL.Path]
|
||||||
if !ok {
|
if !ok {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
return
|
return
|
||||||
@ -89,7 +94,7 @@ func route_fstatic(w http.ResponseWriter, r *http.Request){
|
|||||||
// TO-DO: Add a sitemap
|
// TO-DO: Add a sitemap
|
||||||
// TO-DO: Add an API so that plugins can register disallowed areas. E.g. /groups/join for plugin_socialgroups
|
// TO-DO: Add an API so that plugins can register disallowed areas. E.g. /groups/join for plugin_socialgroups
|
||||||
func route_robots_txt(w http.ResponseWriter, r *http.Request) {
|
func route_robots_txt(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Write([]byte(`User-agent: *
|
_, _ = w.Write([]byte(`User-agent: *
|
||||||
Disallow: /panel/
|
Disallow: /panel/
|
||||||
Disallow: /topics/create/
|
Disallow: /topics/create/
|
||||||
Disallow: /user/edit/
|
Disallow: /user/edit/
|
||||||
@ -102,11 +107,11 @@ func route_overview(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
BuildWidgets("overview",nil,&headerVars,r)
|
BuildWidgets("overview", nil, headerVars, r)
|
||||||
|
|
||||||
pi := Page{"Overview", user, headerVars, tList, nil}
|
pi := Page{"Overview", user, headerVars, tList, nil}
|
||||||
if pre_render_hooks["pre_render_overview"] != nil {
|
if preRenderHooks["pre_render_overview"] != nil {
|
||||||
if run_pre_render_hook("pre_render_overview", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_overview", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,11 +133,11 @@ func route_custom_page(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
NotFound(w, r)
|
NotFound(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
BuildWidgets("custom_page",name,&headerVars,r)
|
BuildWidgets("custom_page", name, headerVars, r)
|
||||||
|
|
||||||
pi := Page{"Page", user, headerVars, tList, nil}
|
pi := Page{"Page", user, headerVars, tList, nil}
|
||||||
if pre_render_hooks["pre_render_custom_page"] != nil {
|
if preRenderHooks["pre_render_custom_page"] != nil {
|
||||||
if run_pre_render_hook("pre_render_custom_page", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_custom_page", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,7 +154,7 @@ func route_topics(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
BuildWidgets("topics",nil,&headerVars,r)
|
BuildWidgets("topics", nil, headerVars, r)
|
||||||
|
|
||||||
var qlist string
|
var qlist string
|
||||||
var fidList []interface{}
|
var fidList []interface{}
|
||||||
@ -177,16 +182,16 @@ func route_topics(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
var reqUserList map[int]bool = make(map[int]bool)
|
var reqUserList = make(map[int]bool)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
topicItem := TopicsRow{ID: 0}
|
topicItem := TopicsRow{ID: 0}
|
||||||
err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.Is_Closed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.LastReplyBy, &topicItem.ParentID, &topicItem.PostCount, &topicItem.LikeCount)
|
err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.IsClosed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.LastReplyBy, &topicItem.ParentID, &topicItem.PostCount, &topicItem.LikeCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
topicItem.Link = build_topic_url(name_to_slug(topicItem.Title),topicItem.ID)
|
topicItem.Link = buildTopicURL(nameToSlug(topicItem.Title), topicItem.ID)
|
||||||
|
|
||||||
forum := fstore.DirtyGet(topicItem.ParentID)
|
forum := fstore.DirtyGet(topicItem.ParentID)
|
||||||
if topicItem.ParentID >= 0 {
|
if topicItem.ParentID >= 0 {
|
||||||
@ -197,17 +202,17 @@ func route_topics(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
//topicItem.ForumLink = ""
|
//topicItem.ForumLink = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
/*topicItem.CreatedAt, err = relative_time(topicItem.CreatedAt)
|
/*topicItem.CreatedAt, err = relativeTime(topicItem.CreatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
replyItem.CreatedAt = ""
|
replyItem.CreatedAt = ""
|
||||||
}*/
|
}*/
|
||||||
topicItem.LastReplyAt, err = relative_time(topicItem.LastReplyAt)
|
topicItem.LastReplyAt, err = relativeTime(topicItem.LastReplyAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hooks["topics_topic_row_assign"] != nil {
|
if vhooks["topics_topic_row_assign"] != nil {
|
||||||
run_vhook("topics_topic_row_assign", &topicItem, &forum)
|
runVhook("topics_topic_row_assign", &topicItem, &forum)
|
||||||
}
|
}
|
||||||
topicList = append(topicList, &topicItem)
|
topicList = append(topicList, &topicItem)
|
||||||
reqUserList[topicItem.CreatedBy] = true
|
reqUserList[topicItem.CreatedBy] = true
|
||||||
@ -220,9 +225,9 @@ func route_topics(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert the user ID map to a slice, then bulk load the users
|
// Convert the user ID map to a slice, then bulk load the users
|
||||||
var idSlice []int = make([]int,len(reqUserList))
|
var idSlice = make([]int, len(reqUserList))
|
||||||
var i int
|
var i int
|
||||||
for userID, _ := range reqUserList {
|
for userID := range reqUserList {
|
||||||
idSlice[i] = userID
|
idSlice[i] = userID
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
@ -241,19 +246,13 @@ func route_topics(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
topicItem.LastUser = userList[topicItem.LastReplyBy]
|
topicItem.LastUser = userList[topicItem.LastReplyBy]
|
||||||
}
|
}
|
||||||
|
|
||||||
pi := TopicsPage{"Topic List",user,headerVars,topicList,extData}
|
pi := TopicsPage{"Topic List", user, headerVars, topicList}
|
||||||
if pre_render_hooks["pre_render_topic_list"] != nil {
|
if preRenderHooks["pre_render_topic_list"] != nil {
|
||||||
if run_pre_render_hook("pre_render_topic_list", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_topic_list", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RunThemeTemplate(headerVars.ThemeName, "topics", pi, w)
|
||||||
// TO-DO: Is there a more type-safe way of doing this?
|
|
||||||
//RunThemeTemplate(defaultTheme,"topics",pi,w)
|
|
||||||
//RunTemplate(GetThemeTemplate(defaultTheme,"topics"),pi,w)
|
|
||||||
//GetThemeTemplate(defaultTheme,"topics").(func(TopicsPage,http.ResponseWriter))(pi,w)
|
|
||||||
//GetThemeTemplate(defaultTheme,"topics").Execute(pi,w)
|
|
||||||
template_topics_handle(pi,w)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func route_forum(w http.ResponseWriter, r *http.Request, user User, sfid string) {
|
func route_forum(w http.ResponseWriter, r *http.Request, user User, sfid string) {
|
||||||
@ -290,15 +289,15 @@ func route_forum(w http.ResponseWriter, r *http.Request, user User, sfid string)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildWidgets("view_forum",forum,&headerVars,r)
|
BuildWidgets("view_forum", forum, headerVars, r)
|
||||||
|
|
||||||
// Calculate the offset
|
// Calculate the offset
|
||||||
var offset int
|
var offset int
|
||||||
last_page := int(forum.TopicCount / config.ItemsPerPage) + 1
|
lastPage := (forum.TopicCount / config.ItemsPerPage) + 1
|
||||||
if page > 1 {
|
if page > 1 {
|
||||||
offset = (config.ItemsPerPage * page) - config.ItemsPerPage
|
offset = (config.ItemsPerPage * page) - config.ItemsPerPage
|
||||||
} else if page == -1 {
|
} else if page == -1 {
|
||||||
page = last_page
|
page = lastPage
|
||||||
offset = (config.ItemsPerPage * page) - config.ItemsPerPage
|
offset = (config.ItemsPerPage * page) - config.ItemsPerPage
|
||||||
} else {
|
} else {
|
||||||
page = 1
|
page = 1
|
||||||
@ -312,23 +311,23 @@ func route_forum(w http.ResponseWriter, r *http.Request, user User, sfid string)
|
|||||||
|
|
||||||
// TO-DO: Use something other than TopicsRow as we don't need to store the forum name and link on each and every topic item?
|
// TO-DO: Use something other than TopicsRow as we don't need to store the forum name and link on each and every topic item?
|
||||||
var topicList []*TopicsRow
|
var topicList []*TopicsRow
|
||||||
var reqUserList map[int]bool = make(map[int]bool)
|
var reqUserList = make(map[int]bool)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var topicItem TopicsRow = TopicsRow{ID: 0}
|
var topicItem = TopicsRow{ID: 0}
|
||||||
err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.Is_Closed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.LastReplyBy, &topicItem.ParentID, &topicItem.PostCount, &topicItem.LikeCount)
|
err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.IsClosed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.LastReplyBy, &topicItem.ParentID, &topicItem.PostCount, &topicItem.LikeCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
topicItem.Link = build_topic_url(name_to_slug(topicItem.Title),topicItem.ID)
|
topicItem.Link = buildTopicURL(nameToSlug(topicItem.Title), topicItem.ID)
|
||||||
topicItem.LastReplyAt, err = relative_time(topicItem.LastReplyAt)
|
topicItem.LastReplyAt, err = relativeTime(topicItem.LastReplyAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hooks["forum_trow_assign"] != nil {
|
if vhooks["forum_trow_assign"] != nil {
|
||||||
run_vhook("forum_trow_assign", &topicItem, &forum)
|
runVhook("forum_trow_assign", &topicItem, &forum)
|
||||||
}
|
}
|
||||||
topicList = append(topicList, &topicItem)
|
topicList = append(topicList, &topicItem)
|
||||||
reqUserList[topicItem.CreatedBy] = true
|
reqUserList[topicItem.CreatedBy] = true
|
||||||
@ -341,9 +340,9 @@ func route_forum(w http.ResponseWriter, r *http.Request, user User, sfid string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert the user ID map to a slice, then bulk load the users
|
// Convert the user ID map to a slice, then bulk load the users
|
||||||
var idSlice []int = make([]int,len(reqUserList))
|
var idSlice = make([]int, len(reqUserList))
|
||||||
var i int
|
var i int
|
||||||
for userID, _ := range reqUserList {
|
for userID := range reqUserList {
|
||||||
idSlice[i] = userID
|
idSlice[i] = userID
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
@ -362,14 +361,13 @@ func route_forum(w http.ResponseWriter, r *http.Request, user User, sfid string)
|
|||||||
topicItem.LastUser = userList[topicItem.LastReplyBy]
|
topicItem.LastUser = userList[topicItem.LastReplyBy]
|
||||||
}
|
}
|
||||||
|
|
||||||
pi := ForumPage{forum.Name,user,headerVars,topicList,*forum,page,last_page,extData}
|
pi := ForumPage{forum.Name, user, headerVars, topicList, *forum, page, lastPage}
|
||||||
if pre_render_hooks["pre_render_view_forum"] != nil {
|
if preRenderHooks["pre_render_view_forum"] != nil {
|
||||||
if run_pre_render_hook("pre_render_view_forum", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_view_forum", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RunThemeTemplate(headerVars.ThemeName, "forum", pi, w)
|
||||||
template_forum_handle(pi,w)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func route_forums(w http.ResponseWriter, r *http.Request, user User) {
|
func route_forums(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
@ -377,12 +375,12 @@ func route_forums(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
BuildWidgets("forums",nil,&headerVars,r)
|
BuildWidgets("forums", nil, headerVars, r)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var forumList []Forum
|
var forumList []Forum
|
||||||
var canSee []int
|
var canSee []int
|
||||||
if user.Is_Super_Admin {
|
if user.IsSuperAdmin {
|
||||||
canSee, err = fstore.GetAllIDs()
|
canSee, err = fstore.GetAllIDs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
@ -397,10 +395,10 @@ func route_forums(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
|
|
||||||
for _, fid := range canSee {
|
for _, fid := range canSee {
|
||||||
//log.Print(forums[fid])
|
//log.Print(forums[fid])
|
||||||
var forum Forum = *fstore.DirtyGet(fid)
|
var forum = *fstore.DirtyGet(fid)
|
||||||
if forum.Active && forum.Name != "" && forum.ParentID == 0 {
|
if forum.Active && forum.Name != "" && forum.ParentID == 0 {
|
||||||
if forum.LastTopicID != 0 {
|
if forum.LastTopicID != 0 {
|
||||||
forum.LastTopicTime, err = relative_time(forum.LastTopicTime)
|
forum.LastTopicTime, err = relativeTime(forum.LastTopicTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
}
|
}
|
||||||
@ -409,20 +407,19 @@ func route_forums(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
forum.LastTopicTime = ""
|
forum.LastTopicTime = ""
|
||||||
}
|
}
|
||||||
if hooks["forums_frow_assign"] != nil {
|
if hooks["forums_frow_assign"] != nil {
|
||||||
run_hook("forums_frow_assign", &forum)
|
runHook("forums_frow_assign", &forum)
|
||||||
}
|
}
|
||||||
forumList = append(forumList, forum)
|
forumList = append(forumList, forum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pi := ForumsPage{"Forum List",user,headerVars,forumList,extData}
|
pi := ForumsPage{"Forum List", user, headerVars, forumList}
|
||||||
if pre_render_hooks["pre_render_forum_list"] != nil {
|
if preRenderHooks["pre_render_forum_list"] != nil {
|
||||||
if run_pre_render_hook("pre_render_forum_list", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_forum_list", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RunThemeTemplate(headerVars.ThemeName, "forums", pi, w)
|
||||||
template_forums_handle(pi,w)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func route_topic_id(w http.ResponseWriter, r *http.Request, user User) {
|
func route_topic_id(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
@ -445,7 +442,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the topic...
|
// Get the topic...
|
||||||
topic, err := get_topicuser(tid)
|
topic, err := getTopicuser(tid)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
NotFound(w, r)
|
NotFound(w, r)
|
||||||
return
|
return
|
||||||
@ -465,18 +462,18 @@ func route_topic_id(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildWidgets("view_topic",&topic,&headerVars,r)
|
BuildWidgets("view_topic", &topic, headerVars, r)
|
||||||
|
|
||||||
topic.Content = parse_message(topic.Content)
|
topic.Content = parseMessage(topic.Content)
|
||||||
topic.ContentLines = strings.Count(topic.Content, "\n")
|
topic.ContentLines = strings.Count(topic.Content, "\n")
|
||||||
|
|
||||||
// We don't want users posting in locked topics...
|
// We don't want users posting in locked topics...
|
||||||
if topic.Is_Closed && !user.Is_Mod {
|
if topic.IsClosed && !user.IsMod {
|
||||||
user.Perms.CreateReply = false
|
user.Perms.CreateReply = false
|
||||||
}
|
}
|
||||||
|
|
||||||
topic.Tag = groups[topic.Group].Tag
|
topic.Tag = groups[topic.Group].Tag
|
||||||
if groups[topic.Group].Is_Mod || groups[topic.Group].Is_Admin {
|
if groups[topic.Group].IsMod || groups[topic.Group].IsAdmin {
|
||||||
topic.ClassName = config.StaffCss
|
topic.ClassName = config.StaffCss
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,17 +488,17 @@ func route_topic_id(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
topic.CreatedAt, err = relative_time(topic.CreatedAt)
|
topic.CreatedAt, err = relativeTime(topic.CreatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
topic.CreatedAt = ""
|
topic.CreatedAt = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the offset
|
// Calculate the offset
|
||||||
last_page := int(topic.PostCount / config.ItemsPerPage) + 1
|
lastPage := (topic.PostCount / config.ItemsPerPage) + 1
|
||||||
if page > 1 {
|
if page > 1 {
|
||||||
offset = (config.ItemsPerPage * page) - config.ItemsPerPage
|
offset = (config.ItemsPerPage * page) - config.ItemsPerPage
|
||||||
} else if page == -1 {
|
} else if page == -1 {
|
||||||
page = last_page
|
page = lastPage
|
||||||
offset = (config.ItemsPerPage * page) - config.ItemsPerPage
|
offset = (config.ItemsPerPage * page) - config.ItemsPerPage
|
||||||
} else {
|
} else {
|
||||||
page = 1
|
page = 1
|
||||||
@ -520,18 +517,18 @@ func route_topic_id(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
|
|
||||||
replyItem := Reply{ClassName: ""}
|
replyItem := Reply{ClassName: ""}
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &replyItem.Group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IpAddress, &replyItem.LikeCount, &replyItem.ActionType)
|
err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &replyItem.Group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IPAddress, &replyItem.LikeCount, &replyItem.ActionType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
replyItem.UserLink = build_profile_url(name_to_slug(replyItem.CreatedByName),replyItem.CreatedBy)
|
replyItem.UserLink = buildProfileURL(nameToSlug(replyItem.CreatedByName), replyItem.CreatedBy)
|
||||||
replyItem.ParentID = topic.ID
|
replyItem.ParentID = topic.ID
|
||||||
replyItem.ContentHtml = parse_message(replyItem.Content)
|
replyItem.ContentHtml = parseMessage(replyItem.Content)
|
||||||
replyItem.ContentLines = strings.Count(replyItem.Content, "\n")
|
replyItem.ContentLines = strings.Count(replyItem.Content, "\n")
|
||||||
|
|
||||||
if groups[replyItem.Group].Is_Mod || groups[replyItem.Group].Is_Admin {
|
if groups[replyItem.Group].IsMod || groups[replyItem.Group].IsAdmin {
|
||||||
replyItem.ClassName = config.StaffCss
|
replyItem.ClassName = config.StaffCss
|
||||||
} else {
|
} else {
|
||||||
replyItem.ClassName = ""
|
replyItem.ClassName = ""
|
||||||
@ -558,14 +555,14 @@ func route_topic_id(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
replyItem.CreatedAt, err = relative_time(replyItem.CreatedAt)
|
replyItem.CreatedAt, err = relativeTime(replyItem.CreatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
replyItem.CreatedAt = ""
|
replyItem.CreatedAt = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// We really shouldn't have inline HTML, we should do something about this...
|
// We really shouldn't have inline HTML, we should do something about this...
|
||||||
if replyItem.ActionType != "" {
|
if replyItem.ActionType != "" {
|
||||||
switch(replyItem.ActionType) {
|
switch replyItem.ActionType {
|
||||||
case "lock":
|
case "lock":
|
||||||
replyItem.ActionType = "This topic has been locked by <a href='" + replyItem.UserLink + "'>" + replyItem.CreatedByName + "</a>"
|
replyItem.ActionType = "This topic has been locked by <a href='" + replyItem.UserLink + "'>" + replyItem.CreatedByName + "</a>"
|
||||||
replyItem.ActionIcon = "🔒︎"
|
replyItem.ActionIcon = "🔒︎"
|
||||||
@ -587,7 +584,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
|
|
||||||
// TO-DO: Rename this to topic_rrow_assign
|
// TO-DO: Rename this to topic_rrow_assign
|
||||||
if hooks["rrow_assign"] != nil {
|
if hooks["rrow_assign"] != nil {
|
||||||
run_hook("rrow_assign", &replyItem)
|
runHook("rrow_assign", &replyItem)
|
||||||
}
|
}
|
||||||
replyList = append(replyList, replyItem)
|
replyList = append(replyList, replyItem)
|
||||||
}
|
}
|
||||||
@ -597,14 +594,13 @@ func route_topic_id(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tpage := TopicPage{topic.Title,user,headerVars,replyList,topic,page,last_page,extData}
|
tpage := TopicPage{topic.Title, user, headerVars, replyList, topic, page, lastPage}
|
||||||
if pre_render_hooks["pre_render_view_topic"] != nil {
|
if preRenderHooks["pre_render_view_topic"] != nil {
|
||||||
if run_pre_render_hook("pre_render_view_topic", w, r, &user, &tpage) {
|
if runPreRenderHook("pre_render_view_topic", w, r, &user, &tpage) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RunThemeTemplate(headerVars.ThemeName, "topic", tpage, w)
|
||||||
template_topic_handle(tpage,w)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func route_profile(w http.ResponseWriter, r *http.Request, user User) {
|
func route_profile(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
@ -632,7 +628,7 @@ func route_profile(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
|
|
||||||
var puser *User
|
var puser *User
|
||||||
if pid == user.ID {
|
if pid == user.ID {
|
||||||
user.Is_Mod = true
|
user.IsMod = true
|
||||||
puser = &user
|
puser = &user
|
||||||
} else {
|
} else {
|
||||||
// Fetch the user data
|
// Fetch the user data
|
||||||
@ -662,7 +658,7 @@ func route_profile(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
}
|
}
|
||||||
|
|
||||||
replyLines = strings.Count(replyContent, "\n")
|
replyLines = strings.Count(replyContent, "\n")
|
||||||
if groups[replyGroup].Is_Mod || groups[replyGroup].Is_Admin {
|
if groups[replyGroup].IsMod || groups[replyGroup].IsAdmin {
|
||||||
replyClassName = config.StaffCss
|
replyClassName = config.StaffCss
|
||||||
} else {
|
} else {
|
||||||
replyClassName = ""
|
replyClassName = ""
|
||||||
@ -688,7 +684,7 @@ func route_profile(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
|
|
||||||
// TO-DO: Add a hook here
|
// TO-DO: Add a hook here
|
||||||
|
|
||||||
replyList = append(replyList, Reply{rid,puser.ID,replyContent,parse_message(replyContent),replyCreatedBy,build_profile_url(name_to_slug(replyCreatedByName),replyCreatedBy),replyCreatedByName,replyGroup,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyClassName,replyLines,replyTag,"","","",0,"",replyLiked,replyLikeCount,"",""})
|
replyList = append(replyList, Reply{rid, puser.ID, replyContent, parseMessage(replyContent), replyCreatedBy, buildProfileURL(nameToSlug(replyCreatedByName), replyCreatedBy), replyCreatedByName, replyGroup, replyCreatedAt, replyLastEdit, replyLastEditBy, replyAvatar, replyClassName, replyLines, replyTag, "", "", "", 0, "", replyLiked, replyLikeCount, "", ""})
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
err = rows.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -696,9 +692,9 @@ func route_profile(w http.ResponseWriter, r *http.Request, user User){
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ppage := ProfilePage{puser.Name + "'s Profile",user,headerVars,replyList,*puser,extData}
|
ppage := ProfilePage{puser.Name + "'s Profile", user, headerVars, replyList, *puser}
|
||||||
if pre_render_hooks["pre_render_profile"] != nil {
|
if preRenderHooks["pre_render_profile"] != nil {
|
||||||
if run_pre_render_hook("pre_render_profile", w, r, &user, &ppage) {
|
if runPreRenderHook("pre_render_profile", w, r, &user, &ppage) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -726,18 +722,18 @@ func route_topic_create(w http.ResponseWriter, r *http.Request, user User, sfid
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildWidgets("create_topic",nil,&headerVars,r)
|
BuildWidgets("create_topic", nil, headerVars, r)
|
||||||
|
|
||||||
// Lock this to the forum being linked?
|
// Lock this to the forum being linked?
|
||||||
// Should we always put it in strictmode when it's linked from another forum? Well, the user might end up changing their mind on what forum they want to post in and it would be a hassle, if they had to switch pages, even if it is a single click for many (exc. mobile)
|
// Should we always put it in strictmode when it's linked from another forum? Well, the user might end up changing their mind on what forum they want to post in and it would be a hassle, if they had to switch pages, even if it is a single click for many (exc. mobile)
|
||||||
var strictmode bool
|
var strictmode bool
|
||||||
if vhooks["topic_create_pre_loop"] != nil {
|
if vhooks["topic_create_pre_loop"] != nil {
|
||||||
run_vhook("topic_create_pre_loop", w, r, fid, &headerVars, &user, &strictmode)
|
runVhook("topic_create_pre_loop", w, r, fid, &headerVars, &user, &strictmode)
|
||||||
}
|
}
|
||||||
|
|
||||||
var forumList []Forum
|
var forumList []Forum
|
||||||
var canSee []int
|
var canSee []int
|
||||||
if user.Is_Super_Admin {
|
if user.IsSuperAdmin {
|
||||||
canSee, err = fstore.GetAllIDs()
|
canSee, err = fstore.GetAllIDs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
@ -761,7 +757,7 @@ func route_topic_create(w http.ResponseWriter, r *http.Request, user User, sfid
|
|||||||
fcopy := *forum
|
fcopy := *forum
|
||||||
if hooks["topic_create_frow_assign"] != nil {
|
if hooks["topic_create_frow_assign"] != nil {
|
||||||
// TO-DO: Add the skip feature to all the other row based hooks?
|
// TO-DO: Add the skip feature to all the other row based hooks?
|
||||||
if run_hook("topic_create_frow_assign", &fcopy).(bool) {
|
if runHook("topic_create_frow_assign", &fcopy).(bool) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -769,9 +765,9 @@ func route_topic_create(w http.ResponseWriter, r *http.Request, user User, sfid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctpage := CreateTopicPage{"Create Topic",user,headerVars,forumList,fid,extData}
|
ctpage := CreateTopicPage{"Create Topic", user, headerVars, forumList, fid}
|
||||||
if pre_render_hooks["pre_render_create_topic"] != nil {
|
if preRenderHooks["pre_render_create_topic"] != nil {
|
||||||
if run_pre_render_hook("pre_render_create_topic", w, r, &user, &ctpage) {
|
if runPreRenderHook("pre_render_create_topic", w, r, &user, &ctpage) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -793,7 +789,8 @@ func route_topic_create_submit(w http.ResponseWriter, r *http.Request, user User
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := SimpleForumSessionCheck(w,r,&user,fid)
|
// TO-DO: Add hooks to make use of headerLite
|
||||||
|
_, ok := SimpleForumSessionCheck(w, r, &user, fid)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -803,20 +800,20 @@ func route_topic_create_submit(w http.ResponseWriter, r *http.Request, user User
|
|||||||
}
|
}
|
||||||
|
|
||||||
topic_name := html.EscapeString(r.PostFormValue("topic-name"))
|
topic_name := html.EscapeString(r.PostFormValue("topic-name"))
|
||||||
content := html.EscapeString(preparse_message(r.PostFormValue("topic-content")))
|
content := html.EscapeString(preparseMessage(r.PostFormValue("topic-content")))
|
||||||
ipaddress, _, err := net.SplitHostPort(r.RemoteAddr)
|
ipaddress, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalError("Bad IP", w, r, user)
|
LocalError("Bad IP", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
wcount := word_count(content)
|
wcount := wordCount(content)
|
||||||
res, err := create_topic_stmt.Exec(fid,topic_name,content,parse_message(content),user.ID,ipaddress,wcount,user.ID)
|
res, err := create_topic_stmt.Exec(fid, topic_name, content, parseMessage(content), user.ID, ipaddress, wcount, user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lastId, err := res.LastInsertId()
|
lastID, err := res.LastInsertId()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
@ -828,20 +825,20 @@ func route_topic_create_submit(w http.ResponseWriter, r *http.Request, user User
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = add_subscription_stmt.Exec(user.ID,lastId,"topic")
|
_, err = add_subscription_stmt.Exec(user.ID, lastID, "topic")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(w,r,"/topic/" + strconv.FormatInt(lastId,10), http.StatusSeeOther)
|
http.Redirect(w, r, "/topic/"+strconv.FormatInt(lastID, 10), http.StatusSeeOther)
|
||||||
err = increase_post_user_stats(wcount, user.ID, true, user)
|
err = increase_post_user_stats(wcount, user.ID, true, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = fstore.UpdateLastTopic(topic_name,int(lastId),user.Name,user.ID,time.Now().Format("2006-01-02 15:04:05"),fid)
|
err = fstore.UpdateLastTopic(topic_name, int(lastID), user.Name, user.ID, time.Now().Format("2006-01-02 15:04:05"), fid)
|
||||||
if err != nil && err != ErrNoRows {
|
if err != nil && err != ErrNoRows {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
}
|
}
|
||||||
@ -868,7 +865,8 @@ func route_create_reply(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := SimpleForumSessionCheck(w,r,&user,topic.ParentID)
|
// TO-DO: Add hooks to make use of headerLite
|
||||||
|
_, ok := SimpleForumSessionCheck(w, r, &user, topic.ParentID)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -877,15 +875,15 @@ func route_create_reply(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content := preparse_message(html.EscapeString(r.PostFormValue("reply-content")))
|
content := preparseMessage(html.EscapeString(r.PostFormValue("reply-content")))
|
||||||
ipaddress, _, err := net.SplitHostPort(r.RemoteAddr)
|
ipaddress, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalError("Bad IP", w, r, user)
|
LocalError("Bad IP", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
wcount := word_count(content)
|
wcount := wordCount(content)
|
||||||
_, err = create_reply_stmt.Exec(tid,content,parse_message(content),ipaddress,wcount,user.ID)
|
_, err = create_reply_stmt.Exec(tid, content, parseMessage(content), ipaddress, wcount, user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
@ -907,21 +905,21 @@ func route_create_reply(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lastId, err := res.LastInsertId()
|
lastID, err := res.LastInsertId()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = notify_watchers_stmt.Exec(lastId)
|
_, err = notify_watchers_stmt.Exec(lastID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alert the subscribers about this post without blocking this post from being posted
|
// Alert the subscribers about this post without blocking this post from being posted
|
||||||
if enable_websockets {
|
if enableWebsockets {
|
||||||
go notify_watchers(lastId)
|
go notifyWatchers(lastID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload the topic...
|
// Reload the topic...
|
||||||
@ -964,7 +962,8 @@ func route_like_topic(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := SimpleForumSessionCheck(w,r,&user,topic.ParentID)
|
// TO-DO: Add hooks to make use of headerLite
|
||||||
|
_, ok := SimpleForumSessionCheck(w, r, &user, topic.ParentID)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1014,20 +1013,20 @@ func route_like_topic(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lastId, err := res.LastInsertId()
|
lastID, err := res.LastInsertId()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = notify_one_stmt.Exec(topic.CreatedBy,lastId)
|
_, err = notify_one_stmt.Exec(topic.CreatedBy, lastID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Live alerts, if the poster is online and WebSockets is enabled
|
// Live alerts, if the poster is online and WebSockets is enabled
|
||||||
_ = ws_hub.push_alert(topic.CreatedBy,int(lastId),"like","topic",user.ID,topic.CreatedBy,tid)
|
_ = wsHub.pushAlert(topic.CreatedBy, int(lastID), "like", "topic", user.ID, topic.CreatedBy, tid)
|
||||||
|
|
||||||
// Reload the topic...
|
// Reload the topic...
|
||||||
err = topics.Load(tid)
|
err = topics.Load(tid)
|
||||||
@ -1055,7 +1054,7 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
reply, err := get_reply(rid)
|
reply, err := getReply(rid)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
PreError("You can't like something which doesn't exist!", w, r)
|
PreError("You can't like something which doesn't exist!", w, r)
|
||||||
return
|
return
|
||||||
@ -1074,7 +1073,8 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := SimpleForumSessionCheck(w,r,&user,fid)
|
// TO-DO: Add hooks to make use of headerLite
|
||||||
|
_, ok := SimpleForumSessionCheck(w, r, &user, fid)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1124,20 +1124,20 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request, user User)
|
|||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lastId, err := res.LastInsertId()
|
lastID, err := res.LastInsertId()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = notify_one_stmt.Exec(reply.CreatedBy,lastId)
|
_, err = notify_one_stmt.Exec(reply.CreatedBy, lastID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Live alerts, if the poster is online and WebSockets is enabled
|
// Live alerts, if the poster is online and WebSockets is enabled
|
||||||
_ = ws_hub.push_alert(reply.CreatedBy,int(lastId),"like","post",user.ID,reply.CreatedBy,rid)
|
_ = wsHub.pushAlert(reply.CreatedBy, int(lastID), "like", "post", user.ID, reply.CreatedBy, rid)
|
||||||
|
|
||||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(reply.ParentID), http.StatusSeeOther)
|
http.Redirect(w, r, "/topic/"+strconv.Itoa(reply.ParentID), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
@ -1165,7 +1165,7 @@ func route_profile_reply_create(w http.ResponseWriter, r *http.Request, user Use
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = create_profile_reply_stmt.Exec(uid,html.EscapeString(preparse_message(r.PostFormValue("reply-content"))),parse_message(html.EscapeString(preparse_message(r.PostFormValue("reply-content")))),user.ID,ipaddress)
|
_, err = create_profile_reply_stmt.Exec(uid, html.EscapeString(preparseMessage(r.PostFormValue("reply-content"))), parseMessage(html.EscapeString(preparseMessage(r.PostFormValue("reply-content")))), user.ID, ipaddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
@ -1189,7 +1189,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, user User, site
|
|||||||
LoginRequired(w, r, user)
|
LoginRequired(w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if user.Is_Banned {
|
if user.IsBanned {
|
||||||
Banned(w, r, user)
|
Banned(w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1215,7 +1215,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, user User, site
|
|||||||
var fid int = 1
|
var fid int = 1
|
||||||
var title, content string
|
var title, content string
|
||||||
if item_type == "reply" {
|
if item_type == "reply" {
|
||||||
reply, err := get_reply(item_id)
|
reply, err := getReply(item_id)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
LocalError("We were unable to find the reported post", w, r, user)
|
LocalError("We were unable to find the reported post", w, r, user)
|
||||||
return
|
return
|
||||||
@ -1236,7 +1236,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, user User, site
|
|||||||
title = "Reply: " + topic.Title
|
title = "Reply: " + topic.Title
|
||||||
content = reply.Content + "\n\nOriginal Post: #rid-" + strconv.Itoa(item_id)
|
content = reply.Content + "\n\nOriginal Post: #rid-" + strconv.Itoa(item_id)
|
||||||
} else if item_type == "user-reply" {
|
} else if item_type == "user-reply" {
|
||||||
user_reply, err := get_user_reply(item_id)
|
userReply, err := getUserReply(item_id)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
LocalError("We weren't able to find the reported post", w, r, user)
|
LocalError("We weren't able to find the reported post", w, r, user)
|
||||||
return
|
return
|
||||||
@ -1245,7 +1245,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, user User, site
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = get_user_name_stmt.QueryRow(user_reply.ParentID).Scan(&title)
|
err = get_user_name_stmt.QueryRow(userReply.ParentID).Scan(&title)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
LocalError("We weren't able to find the profile the reported post is supposed to be on", w, r, user)
|
LocalError("We weren't able to find the profile the reported post is supposed to be on", w, r, user)
|
||||||
return
|
return
|
||||||
@ -1254,7 +1254,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, user User, site
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
title = "Profile: " + title
|
title = "Profile: " + title
|
||||||
content = user_reply.Content + "\n\nOriginal Post: @" + strconv.Itoa(user_reply.ParentID)
|
content = userReply.Content + "\n\nOriginal Post: @" + strconv.Itoa(userReply.ParentID)
|
||||||
} else if item_type == "topic" {
|
} else if item_type == "topic" {
|
||||||
err = get_topic_basic_stmt.QueryRow(item_id).Scan(&title, &content)
|
err = get_topic_basic_stmt.QueryRow(item_id).Scan(&title, &content)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
@ -1268,7 +1268,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, user User, site
|
|||||||
content = content + "\n\nOriginal Post: #tid-" + strconv.Itoa(item_id)
|
content = content + "\n\nOriginal Post: #tid-" + strconv.Itoa(item_id)
|
||||||
} else {
|
} else {
|
||||||
if vhooks["report_preassign"] != nil {
|
if vhooks["report_preassign"] != nil {
|
||||||
run_vhook_noreturn("report_preassign", &item_id, &item_type)
|
runVhookNoreturn("report_preassign", &item_id, &item_type)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Don't try to guess the type
|
// Don't try to guess the type
|
||||||
@ -1295,13 +1295,13 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, user User, site
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := create_report_stmt.Exec(title,content,parse_message(content),user.ID,item_type + "_" + strconv.Itoa(item_id))
|
res, err := create_report_stmt.Exec(title, content, parseMessage(content), user.ID, item_type+"_"+strconv.Itoa(item_id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lastId, err := res.LastInsertId()
|
lastID, err := res.LastInsertId()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
@ -1312,13 +1312,13 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, user User, site
|
|||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = fstore.UpdateLastTopic(title,int(lastId),user.Name,user.ID,time.Now().Format("2006-01-02 15:04:05"),fid)
|
err = fstore.UpdateLastTopic(title, int(lastID), user.Name, user.ID, time.Now().Format("2006-01-02 15:04:05"), fid)
|
||||||
if err != nil && err != ErrNoRows {
|
if err != nil && err != ErrNoRows {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(w,r,"/topic/" + strconv.FormatInt(lastId, 10), http.StatusSeeOther)
|
http.Redirect(w, r, "/topic/"+strconv.FormatInt(lastID, 10), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
func route_account_own_edit_critical(w http.ResponseWriter, r *http.Request, user User) {
|
func route_account_own_edit_critical(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
@ -1332,8 +1332,8 @@ func route_account_own_edit_critical(w http.ResponseWriter, r *http.Request, use
|
|||||||
}
|
}
|
||||||
|
|
||||||
pi := Page{"Edit Password", user, headerVars, tList, nil}
|
pi := Page{"Edit Password", user, headerVars, tList, nil}
|
||||||
if pre_render_hooks["pre_render_account_own_edit_critical"] != nil {
|
if preRenderHooks["pre_render_account_own_edit_critical"] != nil {
|
||||||
if run_pre_render_hook("pre_render_account_own_edit_critical", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_account_own_edit_critical", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1356,12 +1356,12 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var real_password, salt string
|
var realPassword, salt string
|
||||||
current_password := r.PostFormValue("account-current-password")
|
currentPassword := r.PostFormValue("account-current-password")
|
||||||
new_password := r.PostFormValue("account-new-password")
|
newPassword := r.PostFormValue("account-new-password")
|
||||||
confirm_password := r.PostFormValue("account-confirm-password")
|
confirmPassword := r.PostFormValue("account-confirm-password")
|
||||||
|
|
||||||
err = get_password_stmt.QueryRow(user.ID).Scan(&real_password, &salt)
|
err = get_password_stmt.QueryRow(user.ID).Scan(&realPassword, &salt)
|
||||||
if err == ErrNoRows {
|
if err == ErrNoRows {
|
||||||
LocalError("Your account no longer exists.", w, r, user)
|
LocalError("Your account no longer exists.", w, r, user)
|
||||||
return
|
return
|
||||||
@ -1370,7 +1370,7 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = CheckPassword(real_password,current_password,salt)
|
err = CheckPassword(realPassword, currentPassword, salt)
|
||||||
if err == ErrMismatchedHashAndPassword {
|
if err == ErrMismatchedHashAndPassword {
|
||||||
LocalError("That's not the correct password.", w, r, user)
|
LocalError("That's not the correct password.", w, r, user)
|
||||||
return
|
return
|
||||||
@ -1378,19 +1378,19 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
|
|||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if new_password != confirm_password {
|
if newPassword != confirmPassword {
|
||||||
LocalError("The two passwords don't match.", w, r, user)
|
LocalError("The two passwords don't match.", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
SetPassword(user.ID, new_password)
|
SetPassword(user.ID, newPassword)
|
||||||
|
|
||||||
// Log the user out as a safety precaution
|
// Log the user out as a safety precaution
|
||||||
auth.ForceLogout(user.ID)
|
auth.ForceLogout(user.ID)
|
||||||
|
|
||||||
headerVars.NoticeList = append(headerVars.NoticeList, "Your password was successfully updated")
|
headerVars.NoticeList = append(headerVars.NoticeList, "Your password was successfully updated")
|
||||||
pi := Page{"Edit Password", user, headerVars, tList, nil}
|
pi := Page{"Edit Password", user, headerVars, tList, nil}
|
||||||
if pre_render_hooks["pre_render_account_own_edit_critical"] != nil {
|
if preRenderHooks["pre_render_account_own_edit_critical"] != nil {
|
||||||
if run_pre_render_hook("pre_render_account_own_edit_critical", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_account_own_edit_critical", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1407,8 +1407,8 @@ func route_account_own_edit_avatar(w http.ResponseWriter, r *http.Request, user
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
pi := Page{"Edit Avatar", user, headerVars, tList, nil}
|
pi := Page{"Edit Avatar", user, headerVars, tList, nil}
|
||||||
if pre_render_hooks["pre_render_account_own_edit_avatar"] != nil {
|
if preRenderHooks["pre_render_account_own_edit_avatar"] != nil {
|
||||||
if run_pre_render_hook("pre_render_account_own_edit_avatar", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_account_own_edit_avatar", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1441,7 +1441,7 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
|
|||||||
var ext string
|
var ext string
|
||||||
for _, fheaders := range r.MultipartForm.File {
|
for _, fheaders := range r.MultipartForm.File {
|
||||||
for _, hdr := range fheaders {
|
for _, hdr := range fheaders {
|
||||||
infile, err := hdr.Open();
|
infile, err := hdr.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalError("Upload failed", w, r, user)
|
LocalError("Upload failed", w, r, user)
|
||||||
return
|
return
|
||||||
@ -1476,14 +1476,14 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
|
|||||||
ext = strings.ToLower(ext)
|
ext = strings.ToLower(ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
outfile, err := os.Create("./uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext);
|
outfile, err := os.Create("./uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalError("Upload failed [File Creation Failed]", w, r, user)
|
LocalError("Upload failed [File Creation Failed]", w, r, user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer outfile.Close()
|
defer outfile.Close()
|
||||||
|
|
||||||
_, err = io.Copy(outfile, infile);
|
_, err = io.Copy(outfile, infile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalError("Upload failed [Copy Failed]", w, r, user)
|
LocalError("Upload failed [Copy Failed]", w, r, user)
|
||||||
return
|
return
|
||||||
@ -1505,8 +1505,8 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
|
|||||||
|
|
||||||
headerVars.NoticeList = append(headerVars.NoticeList, "Your avatar was successfully updated")
|
headerVars.NoticeList = append(headerVars.NoticeList, "Your avatar was successfully updated")
|
||||||
pi := Page{"Edit Avatar", user, headerVars, tList, nil}
|
pi := Page{"Edit Avatar", user, headerVars, tList, nil}
|
||||||
if pre_render_hooks["pre_render_account_own_edit_avatar"] != nil {
|
if preRenderHooks["pre_render_account_own_edit_avatar"] != nil {
|
||||||
if run_pre_render_hook("pre_render_account_own_edit_avatar", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_account_own_edit_avatar", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1523,8 +1523,8 @@ func route_account_own_edit_username(w http.ResponseWriter, r *http.Request, use
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
pi := Page{"Edit Username", user, headerVars, tList, user.Name}
|
pi := Page{"Edit Username", user, headerVars, tList, user.Name}
|
||||||
if pre_render_hooks["pre_render_account_own_edit_username"] != nil {
|
if preRenderHooks["pre_render_account_own_edit_username"] != nil {
|
||||||
if run_pre_render_hook("pre_render_account_own_edit_username", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_account_own_edit_username", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1562,8 +1562,8 @@ func route_account_own_edit_username_submit(w http.ResponseWriter, r *http.Reque
|
|||||||
|
|
||||||
headerVars.NoticeList = append(headerVars.NoticeList, "Your username was successfully updated")
|
headerVars.NoticeList = append(headerVars.NoticeList, "Your username was successfully updated")
|
||||||
pi := Page{"Edit Username", user, headerVars, tList, nil}
|
pi := Page{"Edit Username", user, headerVars, tList, nil}
|
||||||
if pre_render_hooks["pre_render_account_own_edit_username"] != nil {
|
if preRenderHooks["pre_render_account_own_edit_username"] != nil {
|
||||||
if run_pre_render_hook("pre_render_account_own_edit_username", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_account_own_edit_username", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1617,8 +1617,8 @@ func route_account_own_edit_email(w http.ResponseWriter, r *http.Request, user U
|
|||||||
headerVars.NoticeList = append(headerVars.NoticeList, "The mail system is currently disabled.")
|
headerVars.NoticeList = append(headerVars.NoticeList, "The mail system is currently disabled.")
|
||||||
}
|
}
|
||||||
pi := Page{"Email Manager", user, headerVars, emailList, nil}
|
pi := Page{"Email Manager", user, headerVars, emailList, nil}
|
||||||
if pre_render_hooks["pre_render_account_own_edit_email"] != nil {
|
if preRenderHooks["pre_render_account_own_edit_email"] != nil {
|
||||||
if run_pre_render_hook("pre_render_account_own_edit_email", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_account_own_edit_email", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1696,8 +1696,8 @@ func route_account_own_edit_email_token_submit(w http.ResponseWriter, r *http.Re
|
|||||||
}
|
}
|
||||||
headerVars.NoticeList = append(headerVars.NoticeList, "Your email was successfully verified")
|
headerVars.NoticeList = append(headerVars.NoticeList, "Your email was successfully verified")
|
||||||
pi := Page{"Email Manager", user, headerVars, emailList, nil}
|
pi := Page{"Email Manager", user, headerVars, emailList, nil}
|
||||||
if pre_render_hooks["pre_render_account_own_edit_email"] != nil {
|
if preRenderHooks["pre_render_account_own_edit_email"] != nil {
|
||||||
if run_pre_render_hook("pre_render_account_own_edit_email", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_account_own_edit_email", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1723,8 +1723,8 @@ func route_login(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
pi := Page{"Login", user, headerVars, tList, nil}
|
pi := Page{"Login", user, headerVars, tList, nil}
|
||||||
if pre_render_hooks["pre_render_login"] != nil {
|
if preRenderHooks["pre_render_login"] != nil {
|
||||||
if run_pre_render_hook("pre_render_login", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_login", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1770,7 +1770,7 @@ func route_login_submit(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auth.SetCookies(w, uid, session)
|
auth.SetCookies(w, uid, session)
|
||||||
if user.Is_Admin {
|
if user.IsAdmin {
|
||||||
// Is this error check reundant? We already check for the error in PreRoute for the same IP
|
// Is this error check reundant? We already check for the error in PreRoute for the same IP
|
||||||
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1792,8 +1792,8 @@ func route_register(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
pi := Page{"Registration", user, headerVars, tList, nil}
|
pi := Page{"Registration", user, headerVars, tList, nil}
|
||||||
if pre_render_hooks["pre_render_register"] != nil {
|
if preRenderHooks["pre_render_register"] != nil {
|
||||||
if run_pre_render_hook("pre_render_register", w, r, &user, &pi) {
|
if runPreRenderHook("pre_render_register", w, r, &user, &pi) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1836,7 +1836,7 @@ func route_register_submit(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = weak_password(password)
|
err = weakPassword(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalError(err.Error(), w, r, user)
|
LocalError(err.Error(), w, r, user)
|
||||||
return
|
return
|
||||||
@ -1861,7 +1861,7 @@ func route_register_submit(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uid, err := users.CreateUser(username, password, email, group, active)
|
uid, err := users.CreateUser(username, password, email, group, active)
|
||||||
if err == err_account_exists {
|
if err == errAccountExists {
|
||||||
LocalError("This username isn't available. Try another.", w, r, user)
|
LocalError("This username isn't available. Try another.", w, r, user)
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@ -1899,7 +1899,8 @@ func route_register_submit(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: We don't need support XML here to support sitemaps, we could handle those elsewhere
|
// TO-DO: We don't need support XML here to support sitemaps, we could handle those elsewhere
|
||||||
var phrase_login_alerts []byte = []byte(`{"msgs":[{"msg":"Login to see your alerts","path":"/accounts/login"}]}`)
|
var phrase_login_alerts = []byte(`{"msgs":[{"msg":"Login to see your alerts","path":"/accounts/login"}]}`)
|
||||||
|
|
||||||
func route_api(w http.ResponseWriter, r *http.Request, user User) {
|
func route_api(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
err := r.ParseForm()
|
err := r.ParseForm()
|
||||||
@ -1915,7 +1916,7 @@ func route_api(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module := r.FormValue("module")
|
module := r.FormValue("module")
|
||||||
switch(module) {
|
switch module {
|
||||||
case "dismiss-alert":
|
case "dismiss-alert":
|
||||||
asid, err := strconv.Atoi(r.FormValue("asid"))
|
asid, err := strconv.Atoi(r.FormValue("asid"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1935,7 +1936,7 @@ func route_api(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var msglist, event, elementType string
|
var msglist, event, elementType string
|
||||||
var asid, actor_id, targetUser_id, elementID int
|
var asid, actorID, targetUserID, elementID int
|
||||||
var msgCount int
|
var msgCount int
|
||||||
|
|
||||||
err = get_activity_count_by_watcher_stmt.QueryRow(user.ID).Scan(&msgCount)
|
err = get_activity_count_by_watcher_stmt.QueryRow(user.ID).Scan(&msgCount)
|
||||||
@ -1955,12 +1956,12 @@ func route_api(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
err = rows.Scan(&asid,&actor_id,&targetUser_id,&event,&elementType,&elementID)
|
err = rows.Scan(&asid, &actorID, &targetUserID, &event, &elementType, &elementID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalErrorJS(err, w, r)
|
InternalErrorJS(err, w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res, err := build_alert(asid, event, elementType, actor_id, targetUser_id, elementID, user)
|
res, err := buildAlert(asid, event, elementType, actorID, targetUserID, elementID, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LocalErrorJS(err.Error(), w, r)
|
LocalErrorJS(err.Error(), w, r)
|
||||||
return
|
return
|
||||||
@ -1977,7 +1978,7 @@ func route_api(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
if len(msglist) != 0 {
|
if len(msglist) != 0 {
|
||||||
msglist = msglist[0 : len(msglist)-1]
|
msglist = msglist[0 : len(msglist)-1]
|
||||||
}
|
}
|
||||||
w.Write([]byte(`{"msgs":[` + msglist + `],"msgCount":` + strconv.Itoa(msgCount) + `}`))
|
_, _ = w.Write([]byte(`{"msgs":[` + msglist + `],"msgCount":` + strconv.Itoa(msgCount) + `}`))
|
||||||
//log.Print(`{"msgs":[` + msglist + `],"msgCount":` + strconv.Itoa(msgCount) + `}`)
|
//log.Print(`{"msgs":[` + msglist + `],"msgCount":` + strconv.Itoa(msgCount) + `}`)
|
||||||
//case "topics":
|
//case "topics":
|
||||||
//case "forums":
|
//case "forums":
|
||||||
|
13
setting.go
13
setting.go
@ -1,22 +1,21 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "strconv"
|
import "strconv"
|
||||||
import "strings"
|
import "strings"
|
||||||
import "sync/atomic"
|
import "sync/atomic"
|
||||||
|
|
||||||
// TO-DO: Move this into the phrase system
|
// SettingBox is a map type specifically for holding the various settings admins set to toggle features on and off or to otherwise alter Gosora's behaviour from the Control Panel
|
||||||
var settingLabels map[string]string
|
|
||||||
type SettingBox map[string]interface{}
|
type SettingBox map[string]interface{}
|
||||||
|
|
||||||
var settingBox atomic.Value // An atomic value pointing to a SettingBox
|
var settingBox atomic.Value // An atomic value pointing to a SettingBox
|
||||||
|
|
||||||
type OptionLabel struct
|
type OptionLabel struct {
|
||||||
{
|
|
||||||
Label string
|
Label string
|
||||||
Value int
|
Value int
|
||||||
Selected bool
|
Selected bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Setting struct
|
type Setting struct {
|
||||||
{
|
|
||||||
Name string
|
Name string
|
||||||
Content string
|
Content string
|
||||||
Type string
|
Type string
|
||||||
@ -24,8 +23,6 @@ type Setting struct
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
settingLabels = make(map[string]string)
|
|
||||||
settingLabels["activation_type"] = "Activate All,Email Activation,Admin Approval"
|
|
||||||
settingBox.Store(SettingBox(make(map[string]interface{})))
|
settingBox.Store(SettingBox(make(map[string]interface{})))
|
||||||
//settingBox.Store(make(map[string]interface{}))
|
//settingBox.Store(make(map[string]interface{}))
|
||||||
}
|
}
|
||||||
|
2
tasks.go
2
tasks.go
@ -2,7 +2,7 @@ package main
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
func handle_expired_scheduled_groups() error {
|
func handleExpiredScheduledGroups() error {
|
||||||
rows, err := get_expired_scheduled_groups_stmt.Query()
|
rows, err := get_expired_scheduled_groups_stmt.Query()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -6,63 +6,68 @@ package main
|
|||||||
import "net/http"
|
import "net/http"
|
||||||
import "strconv"
|
import "strconv"
|
||||||
|
|
||||||
|
// nolint
|
||||||
func init() {
|
func init() {
|
||||||
template_forum_handle = template_forum
|
template_forum_handle = template_forum
|
||||||
//o_template_forum_handle = template_forum
|
//o_template_forum_handle = template_forum
|
||||||
ctemplates = append(ctemplates,"forum")
|
ctemplates = append(ctemplates,"forum")
|
||||||
tmpl_ptr_map["forum"] = &template_forum_handle
|
tmplPtrMap["forum"] = &template_forum_handle
|
||||||
tmpl_ptr_map["o_forum"] = template_forum
|
tmplPtrMap["o_forum"] = template_forum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
func template_forum(tmpl_forum_vars ForumPage, w http.ResponseWriter) {
|
func template_forum(tmpl_forum_vars ForumPage, w http.ResponseWriter) {
|
||||||
w.Write(header_0)
|
w.Write(header_0)
|
||||||
w.Write([]byte(tmpl_forum_vars.Title))
|
w.Write([]byte(tmpl_forum_vars.Title))
|
||||||
w.Write(header_1)
|
w.Write(header_1)
|
||||||
|
w.Write([]byte(tmpl_forum_vars.Header.ThemeName))
|
||||||
|
w.Write(header_2)
|
||||||
if len(tmpl_forum_vars.Header.Stylesheets) != 0 {
|
if len(tmpl_forum_vars.Header.Stylesheets) != 0 {
|
||||||
for _, item := range tmpl_forum_vars.Header.Stylesheets {
|
for _, item := range tmpl_forum_vars.Header.Stylesheets {
|
||||||
w.Write(header_2)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_3)
|
w.Write(header_3)
|
||||||
}
|
w.Write([]byte(item))
|
||||||
}
|
|
||||||
w.Write(header_4)
|
w.Write(header_4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.Write(header_5)
|
||||||
if len(tmpl_forum_vars.Header.Scripts) != 0 {
|
if len(tmpl_forum_vars.Header.Scripts) != 0 {
|
||||||
for _, item := range tmpl_forum_vars.Header.Scripts {
|
for _, item := range tmpl_forum_vars.Header.Scripts {
|
||||||
w.Write(header_5)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_6)
|
w.Write(header_6)
|
||||||
}
|
w.Write([]byte(item))
|
||||||
}
|
|
||||||
w.Write(header_7)
|
w.Write(header_7)
|
||||||
w.Write([]byte(tmpl_forum_vars.CurrentUser.Session))
|
}
|
||||||
|
}
|
||||||
w.Write(header_8)
|
w.Write(header_8)
|
||||||
if !tmpl_forum_vars.CurrentUser.Is_Super_Mod {
|
|
||||||
w.Write(header_9)
|
|
||||||
}
|
|
||||||
w.Write(header_10)
|
|
||||||
w.Write(menu_0)
|
|
||||||
w.Write([]byte(tmpl_forum_vars.Header.Site.Name))
|
|
||||||
w.Write(menu_1)
|
|
||||||
if tmpl_forum_vars.CurrentUser.Loggedin {
|
|
||||||
w.Write(menu_2)
|
|
||||||
w.Write([]byte(tmpl_forum_vars.CurrentUser.Link))
|
|
||||||
w.Write(menu_3)
|
|
||||||
w.Write([]byte(tmpl_forum_vars.CurrentUser.Session))
|
w.Write([]byte(tmpl_forum_vars.CurrentUser.Session))
|
||||||
w.Write(menu_4)
|
w.Write(header_9)
|
||||||
} else {
|
if !tmpl_forum_vars.CurrentUser.IsSuperMod {
|
||||||
w.Write(menu_5)
|
w.Write(header_10)
|
||||||
}
|
}
|
||||||
w.Write(menu_6)
|
|
||||||
w.Write(header_11)
|
w.Write(header_11)
|
||||||
if tmpl_forum_vars.Header.Widgets.RightSidebar != "" {
|
w.Write(menu_0)
|
||||||
w.Write(header_12)
|
w.Write(menu_1)
|
||||||
|
w.Write([]byte(tmpl_forum_vars.Header.Site.Name))
|
||||||
|
w.Write(menu_2)
|
||||||
|
if tmpl_forum_vars.CurrentUser.Loggedin {
|
||||||
|
w.Write(menu_3)
|
||||||
|
w.Write([]byte(tmpl_forum_vars.CurrentUser.Link))
|
||||||
|
w.Write(menu_4)
|
||||||
|
w.Write([]byte(tmpl_forum_vars.CurrentUser.Session))
|
||||||
|
w.Write(menu_5)
|
||||||
|
} else {
|
||||||
|
w.Write(menu_6)
|
||||||
}
|
}
|
||||||
|
w.Write(menu_7)
|
||||||
|
w.Write(header_12)
|
||||||
|
if tmpl_forum_vars.Header.Widgets.RightSidebar != "" {
|
||||||
w.Write(header_13)
|
w.Write(header_13)
|
||||||
|
}
|
||||||
|
w.Write(header_14)
|
||||||
if len(tmpl_forum_vars.Header.NoticeList) != 0 {
|
if len(tmpl_forum_vars.Header.NoticeList) != 0 {
|
||||||
for _, item := range tmpl_forum_vars.Header.NoticeList {
|
for _, item := range tmpl_forum_vars.Header.NoticeList {
|
||||||
w.Write(header_14)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_15)
|
w.Write(header_15)
|
||||||
|
w.Write([]byte(item))
|
||||||
|
w.Write(header_16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if tmpl_forum_vars.Page > 1 {
|
if tmpl_forum_vars.Page > 1 {
|
||||||
@ -107,7 +112,7 @@ w.Write(forum_17)
|
|||||||
if item.Sticky {
|
if item.Sticky {
|
||||||
w.Write(forum_18)
|
w.Write(forum_18)
|
||||||
} else {
|
} else {
|
||||||
if item.Is_Closed {
|
if item.IsClosed {
|
||||||
w.Write(forum_19)
|
w.Write(forum_19)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,7 +135,7 @@ w.Write([]byte(item.Creator.Link))
|
|||||||
w.Write(forum_28)
|
w.Write(forum_28)
|
||||||
w.Write([]byte(item.Creator.Name))
|
w.Write([]byte(item.Creator.Name))
|
||||||
w.Write(forum_29)
|
w.Write(forum_29)
|
||||||
if item.Is_Closed {
|
if item.IsClosed {
|
||||||
w.Write(forum_30)
|
w.Write(forum_30)
|
||||||
}
|
}
|
||||||
if item.Sticky {
|
if item.Sticky {
|
||||||
|
@ -5,63 +5,68 @@
|
|||||||
package main
|
package main
|
||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
||||||
|
// nolint
|
||||||
func init() {
|
func init() {
|
||||||
template_forums_handle = template_forums
|
template_forums_handle = template_forums
|
||||||
//o_template_forums_handle = template_forums
|
//o_template_forums_handle = template_forums
|
||||||
ctemplates = append(ctemplates,"forums")
|
ctemplates = append(ctemplates,"forums")
|
||||||
tmpl_ptr_map["forums"] = &template_forums_handle
|
tmplPtrMap["forums"] = &template_forums_handle
|
||||||
tmpl_ptr_map["o_forums"] = template_forums
|
tmplPtrMap["o_forums"] = template_forums
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
func template_forums(tmpl_forums_vars ForumsPage, w http.ResponseWriter) {
|
func template_forums(tmpl_forums_vars ForumsPage, w http.ResponseWriter) {
|
||||||
w.Write(header_0)
|
w.Write(header_0)
|
||||||
w.Write([]byte(tmpl_forums_vars.Title))
|
w.Write([]byte(tmpl_forums_vars.Title))
|
||||||
w.Write(header_1)
|
w.Write(header_1)
|
||||||
|
w.Write([]byte(tmpl_forums_vars.Header.ThemeName))
|
||||||
|
w.Write(header_2)
|
||||||
if len(tmpl_forums_vars.Header.Stylesheets) != 0 {
|
if len(tmpl_forums_vars.Header.Stylesheets) != 0 {
|
||||||
for _, item := range tmpl_forums_vars.Header.Stylesheets {
|
for _, item := range tmpl_forums_vars.Header.Stylesheets {
|
||||||
w.Write(header_2)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_3)
|
w.Write(header_3)
|
||||||
}
|
w.Write([]byte(item))
|
||||||
}
|
|
||||||
w.Write(header_4)
|
w.Write(header_4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.Write(header_5)
|
||||||
if len(tmpl_forums_vars.Header.Scripts) != 0 {
|
if len(tmpl_forums_vars.Header.Scripts) != 0 {
|
||||||
for _, item := range tmpl_forums_vars.Header.Scripts {
|
for _, item := range tmpl_forums_vars.Header.Scripts {
|
||||||
w.Write(header_5)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_6)
|
w.Write(header_6)
|
||||||
}
|
w.Write([]byte(item))
|
||||||
}
|
|
||||||
w.Write(header_7)
|
w.Write(header_7)
|
||||||
w.Write([]byte(tmpl_forums_vars.CurrentUser.Session))
|
}
|
||||||
|
}
|
||||||
w.Write(header_8)
|
w.Write(header_8)
|
||||||
if !tmpl_forums_vars.CurrentUser.Is_Super_Mod {
|
|
||||||
w.Write(header_9)
|
|
||||||
}
|
|
||||||
w.Write(header_10)
|
|
||||||
w.Write(menu_0)
|
|
||||||
w.Write([]byte(tmpl_forums_vars.Header.Site.Name))
|
|
||||||
w.Write(menu_1)
|
|
||||||
if tmpl_forums_vars.CurrentUser.Loggedin {
|
|
||||||
w.Write(menu_2)
|
|
||||||
w.Write([]byte(tmpl_forums_vars.CurrentUser.Link))
|
|
||||||
w.Write(menu_3)
|
|
||||||
w.Write([]byte(tmpl_forums_vars.CurrentUser.Session))
|
w.Write([]byte(tmpl_forums_vars.CurrentUser.Session))
|
||||||
w.Write(menu_4)
|
w.Write(header_9)
|
||||||
} else {
|
if !tmpl_forums_vars.CurrentUser.IsSuperMod {
|
||||||
w.Write(menu_5)
|
w.Write(header_10)
|
||||||
}
|
}
|
||||||
w.Write(menu_6)
|
|
||||||
w.Write(header_11)
|
w.Write(header_11)
|
||||||
if tmpl_forums_vars.Header.Widgets.RightSidebar != "" {
|
w.Write(menu_0)
|
||||||
w.Write(header_12)
|
w.Write(menu_1)
|
||||||
|
w.Write([]byte(tmpl_forums_vars.Header.Site.Name))
|
||||||
|
w.Write(menu_2)
|
||||||
|
if tmpl_forums_vars.CurrentUser.Loggedin {
|
||||||
|
w.Write(menu_3)
|
||||||
|
w.Write([]byte(tmpl_forums_vars.CurrentUser.Link))
|
||||||
|
w.Write(menu_4)
|
||||||
|
w.Write([]byte(tmpl_forums_vars.CurrentUser.Session))
|
||||||
|
w.Write(menu_5)
|
||||||
|
} else {
|
||||||
|
w.Write(menu_6)
|
||||||
}
|
}
|
||||||
|
w.Write(menu_7)
|
||||||
|
w.Write(header_12)
|
||||||
|
if tmpl_forums_vars.Header.Widgets.RightSidebar != "" {
|
||||||
w.Write(header_13)
|
w.Write(header_13)
|
||||||
|
}
|
||||||
|
w.Write(header_14)
|
||||||
if len(tmpl_forums_vars.Header.NoticeList) != 0 {
|
if len(tmpl_forums_vars.Header.NoticeList) != 0 {
|
||||||
for _, item := range tmpl_forums_vars.Header.NoticeList {
|
for _, item := range tmpl_forums_vars.Header.NoticeList {
|
||||||
w.Write(header_14)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_15)
|
w.Write(header_15)
|
||||||
|
w.Write([]byte(item))
|
||||||
|
w.Write(header_16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Write(forums_0)
|
w.Write(forums_0)
|
||||||
|
@ -75,13 +75,13 @@ var template_create_topic_handle func(CreateTopicPage,http.ResponseWriter) = fun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func compile_templates() error {
|
func compileTemplates() error {
|
||||||
var c CTemplateSet
|
var c CTemplateSet
|
||||||
user := User{62,build_profile_url("fake-user",62),"Fake User","compiler@localhost",0,false,false,false,false,false,false,GuestPerms,make(map[string]bool),"",false,"","","","","",0,0,"0.0.0.0.0",0}
|
user := User{62, buildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0}
|
||||||
// TO-DO: Do a more accurate level calculation for this?
|
// TO-DO: Do a more accurate level calculation for this?
|
||||||
user2 := User{1,build_profile_url("admin-alice",1),"Admin Alice","alice@localhost",1,true,true,true,true,false,false,AllPerms,make(map[string]bool),"",true,"","","","","",58,1000,"127.0.0.1",0}
|
user2 := User{1, buildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", "", "", "", "", 58, 1000, "127.0.0.1", 0}
|
||||||
user3 := User{2,build_profile_url("admin-fred",62),"Admin Fred","fred@localhost",1,true,true,true,true,false,false,AllPerms,make(map[string]bool),"",true,"","","","","",42,900,"::1",0}
|
user3 := User{2, buildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", "", "", "", "", 42, 900, "::1", 0}
|
||||||
headerVars := HeaderVars{
|
headerVars := &HeaderVars{
|
||||||
Site: site,
|
Site: site,
|
||||||
NoticeList: []string{"test"},
|
NoticeList: []string{"test"},
|
||||||
Stylesheets: []string{"panel"},
|
Stylesheets: []string{"panel"},
|
||||||
@ -93,24 +93,24 @@ func compile_templates() error {
|
|||||||
|
|
||||||
log.Print("Compiling the templates")
|
log.Print("Compiling the templates")
|
||||||
|
|
||||||
topic := TopicUser{1,"blah","Blah","Hey there!",0,false,false,"Date","Date",0,"","127.0.0.1",0,1,"classname","weird-data",build_profile_url("fake-user",62),"Fake User",config.DefaultGroup,"",0,"","","","",58,false}
|
topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, "Date", "Date", 0, "", "127.0.0.1", 0, 1, "classname", "weird-data", buildProfileURL("fake-user", 62), "Fake User", config.DefaultGroup, "", 0, "", "", "", "", 58, false}
|
||||||
var replyList []Reply
|
var replyList []Reply
|
||||||
replyList = append(replyList, Reply{0, 0, "Yo!", "Yo!", 0, "alice", "Alice", config.DefaultGroup, "", 0, 0, "", "", 0, "", "", "", "", 0, "127.0.0.1", false, 1, "", ""})
|
replyList = append(replyList, Reply{0, 0, "Yo!", "Yo!", 0, "alice", "Alice", config.DefaultGroup, "", 0, 0, "", "", 0, "", "", "", "", 0, "127.0.0.1", false, 1, "", ""})
|
||||||
|
|
||||||
var varList map[string]VarItem = make(map[string]VarItem)
|
var varList map[string]VarItem = make(map[string]VarItem)
|
||||||
tpage := TopicPage{"Title",user,headerVars,replyList,topic,1,1,extData}
|
tpage := TopicPage{"Title", user, headerVars, replyList, topic, 1, 1}
|
||||||
topic_id_tmpl, err := c.compile_template("topic.html","templates/","TopicPage", tpage, varList)
|
topic_id_tmpl, err := c.compileTemplate("topic.html", "templates/", "TopicPage", tpage, varList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
topic_id_alt_tmpl, err := c.compile_template("topic_alt.html","templates/","TopicPage", tpage, varList)
|
topic_id_alt_tmpl, err := c.compileTemplate("topic_alt.html", "templates/", "TopicPage", tpage, varList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
varList = make(map[string]VarItem)
|
varList = make(map[string]VarItem)
|
||||||
ppage := ProfilePage{"User 526",user,headerVars,replyList,user,extData}
|
ppage := ProfilePage{"User 526", user, headerVars, replyList, user}
|
||||||
profile_tmpl, err := c.compile_template("profile.html","templates/","ProfilePage", ppage, varList)
|
profile_tmpl, err := c.compileTemplate("profile.html", "templates/", "ProfilePage", ppage, varList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -127,16 +127,16 @@ func compile_templates() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
varList = make(map[string]VarItem)
|
varList = make(map[string]VarItem)
|
||||||
forums_page := ForumsPage{"Forum List",user,headerVars,forumList,extData}
|
forums_page := ForumsPage{"Forum List", user, headerVars, forumList}
|
||||||
forums_tmpl, err := c.compile_template("forums.html","templates/","ForumsPage",forums_page,varList)
|
forums_tmpl, err := c.compileTemplate("forums.html", "templates/", "ForumsPage", forums_page, varList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var topicsList []*TopicsRow
|
var topicsList []*TopicsRow
|
||||||
topicsList = append(topicsList, &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, "Date", "Date", user3.ID, 1, "", "127.0.0.1", 0, 1, "classname", "", &user2, "", 0, &user3, "General", "/forum/general.2"})
|
topicsList = append(topicsList, &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, "Date", "Date", user3.ID, 1, "", "127.0.0.1", 0, 1, "classname", "", &user2, "", 0, &user3, "General", "/forum/general.2"})
|
||||||
topics_page := TopicsPage{"Topic List",user,headerVars,topicsList,extData}
|
topics_page := TopicsPage{"Topic List", user, headerVars, topicsList}
|
||||||
topics_tmpl, err := c.compile_template("topics.html","templates/","TopicsPage",topics_page,varList)
|
topics_tmpl, err := c.compileTemplate("topics.html", "templates/", "TopicsPage", topics_page, varList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -144,21 +144,21 @@ func compile_templates() error {
|
|||||||
//var topicList []TopicUser
|
//var topicList []TopicUser
|
||||||
//topicList = append(topicList,TopicUser{1,"topic-title","Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"classname","","admin-fred","Admin Fred",config.DefaultGroup,"",0,"","","","",58,false})
|
//topicList = append(topicList,TopicUser{1,"topic-title","Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"classname","","admin-fred","Admin Fred",config.DefaultGroup,"",0,"","","","",58,false})
|
||||||
forum_item := Forum{1, "general", "General Forum", "Where the general stuff happens", true, "all", 0, "", 0, "", "", 0, "", 0, ""}
|
forum_item := Forum{1, "general", "General Forum", "Where the general stuff happens", true, "all", 0, "", 0, "", "", 0, "", 0, ""}
|
||||||
forum_page := ForumPage{"General Forum",user,headerVars,topicsList,forum_item,1,1,extData}
|
forum_page := ForumPage{"General Forum", user, headerVars, topicsList, forum_item, 1, 1}
|
||||||
forum_tmpl, err := c.compile_template("forum.html","templates/","ForumPage",forum_page,varList)
|
forum_tmpl, err := c.compileTemplate("forum.html", "templates/", "ForumPage", forum_page, varList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Writing the templates")
|
log.Print("Writing the templates")
|
||||||
go write_template("topic", topic_id_tmpl)
|
go writeTemplate("topic", topic_id_tmpl)
|
||||||
go write_template("topic_alt", topic_id_alt_tmpl)
|
go writeTemplate("topic_alt", topic_id_alt_tmpl)
|
||||||
go write_template("profile", profile_tmpl)
|
go writeTemplate("profile", profile_tmpl)
|
||||||
go write_template("forums", forums_tmpl)
|
go writeTemplate("forums", forums_tmpl)
|
||||||
go write_template("topics", topics_tmpl)
|
go writeTemplate("topics", topics_tmpl)
|
||||||
go write_template("forum", forum_tmpl)
|
go writeTemplate("forum", forum_tmpl)
|
||||||
go func() {
|
go func() {
|
||||||
err := write_file("./template_list.go","package main\n\n" + c.FragOut)
|
err := writeFile("./template_list.go", "package main\n\n// nolint\n"+c.FragOut)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -167,18 +167,18 @@ func compile_templates() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func write_template(name string, content string) {
|
func writeTemplate(name string, content string) {
|
||||||
err := write_file("./template_" + name + ".go", content)
|
err := writeFile("./template_"+name+".go", content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func init_templates() {
|
func initTemplates() {
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Initialising the template system")
|
log.Print("Initialising the template system")
|
||||||
}
|
}
|
||||||
compile_templates()
|
compileTemplates()
|
||||||
|
|
||||||
// TO-DO: Add support for 64-bit integers
|
// TO-DO: Add support for 64-bit integers
|
||||||
// TO-DO: Add support for floats
|
// TO-DO: Add support for floats
|
||||||
@ -187,10 +187,12 @@ func init_templates() {
|
|||||||
var left_int int
|
var left_int int
|
||||||
var right_int int
|
var right_int int
|
||||||
switch left := left.(type) {
|
switch left := left.(type) {
|
||||||
case uint, uint8, uint16, int, int32: left_int = left.(int)
|
case uint, uint8, uint16, int, int32:
|
||||||
|
left_int = left.(int)
|
||||||
}
|
}
|
||||||
switch right := right.(type) {
|
switch right := right.(type) {
|
||||||
case uint, uint8, uint16, int, int32: right_int = right.(int)
|
case uint, uint8, uint16, int, int32:
|
||||||
|
right_int = right.(int)
|
||||||
}
|
}
|
||||||
return left_int + right_int
|
return left_int + right_int
|
||||||
}
|
}
|
||||||
@ -199,10 +201,12 @@ func init_templates() {
|
|||||||
var left_int int
|
var left_int int
|
||||||
var right_int int
|
var right_int int
|
||||||
switch left := left.(type) {
|
switch left := left.(type) {
|
||||||
case uint, uint8, uint16, int, int32: left_int = left.(int)
|
case uint, uint8, uint16, int, int32:
|
||||||
|
left_int = left.(int)
|
||||||
}
|
}
|
||||||
switch right := right.(type) {
|
switch right := right.(type) {
|
||||||
case uint, uint8, uint16, int, int32: right_int = right.(int)
|
case uint, uint8, uint16, int, int32:
|
||||||
|
right_int = right.(int)
|
||||||
}
|
}
|
||||||
return left_int - right_int
|
return left_int - right_int
|
||||||
}
|
}
|
||||||
@ -211,10 +215,12 @@ func init_templates() {
|
|||||||
var left_int int
|
var left_int int
|
||||||
var right_int int
|
var right_int int
|
||||||
switch left := left.(type) {
|
switch left := left.(type) {
|
||||||
case uint, uint8, uint16, int, int32: left_int = left.(int)
|
case uint, uint8, uint16, int, int32:
|
||||||
|
left_int = left.(int)
|
||||||
}
|
}
|
||||||
switch right := right.(type) {
|
switch right := right.(type) {
|
||||||
case uint, uint8, uint16, int, int32: right_int = right.(int)
|
case uint, uint8, uint16, int, int32:
|
||||||
|
right_int = right.(int)
|
||||||
}
|
}
|
||||||
return left_int * right_int
|
return left_int * right_int
|
||||||
}
|
}
|
||||||
@ -223,10 +229,12 @@ func init_templates() {
|
|||||||
var left_int int
|
var left_int int
|
||||||
var right_int int
|
var right_int int
|
||||||
switch left := left.(type) {
|
switch left := left.(type) {
|
||||||
case uint, uint8, uint16, int, int32: left_int = left.(int)
|
case uint, uint8, uint16, int, int32:
|
||||||
|
left_int = left.(int)
|
||||||
}
|
}
|
||||||
switch right := right.(type) {
|
switch right := right.(type) {
|
||||||
case uint, uint8, uint16, int, int32: right_int = right.(int)
|
case uint, uint8, uint16, int, int32:
|
||||||
|
right_int = right.(int)
|
||||||
}
|
}
|
||||||
if left_int == 0 || right_int == 0 {
|
if left_int == 0 || right_int == 0 {
|
||||||
return 0
|
return 0
|
||||||
|
697
template_list.go
697
template_list.go
File diff suppressed because it is too large
Load Diff
@ -6,63 +6,68 @@ package main
|
|||||||
import "net/http"
|
import "net/http"
|
||||||
import "strconv"
|
import "strconv"
|
||||||
|
|
||||||
|
// nolint
|
||||||
func init() {
|
func init() {
|
||||||
template_profile_handle = template_profile
|
template_profile_handle = template_profile
|
||||||
//o_template_profile_handle = template_profile
|
//o_template_profile_handle = template_profile
|
||||||
ctemplates = append(ctemplates,"profile")
|
ctemplates = append(ctemplates,"profile")
|
||||||
tmpl_ptr_map["profile"] = &template_profile_handle
|
tmplPtrMap["profile"] = &template_profile_handle
|
||||||
tmpl_ptr_map["o_profile"] = template_profile
|
tmplPtrMap["o_profile"] = template_profile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
func template_profile(tmpl_profile_vars ProfilePage, w http.ResponseWriter) {
|
func template_profile(tmpl_profile_vars ProfilePage, w http.ResponseWriter) {
|
||||||
w.Write(header_0)
|
w.Write(header_0)
|
||||||
w.Write([]byte(tmpl_profile_vars.Title))
|
w.Write([]byte(tmpl_profile_vars.Title))
|
||||||
w.Write(header_1)
|
w.Write(header_1)
|
||||||
|
w.Write([]byte(tmpl_profile_vars.Header.ThemeName))
|
||||||
|
w.Write(header_2)
|
||||||
if len(tmpl_profile_vars.Header.Stylesheets) != 0 {
|
if len(tmpl_profile_vars.Header.Stylesheets) != 0 {
|
||||||
for _, item := range tmpl_profile_vars.Header.Stylesheets {
|
for _, item := range tmpl_profile_vars.Header.Stylesheets {
|
||||||
w.Write(header_2)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_3)
|
w.Write(header_3)
|
||||||
}
|
w.Write([]byte(item))
|
||||||
}
|
|
||||||
w.Write(header_4)
|
w.Write(header_4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.Write(header_5)
|
||||||
if len(tmpl_profile_vars.Header.Scripts) != 0 {
|
if len(tmpl_profile_vars.Header.Scripts) != 0 {
|
||||||
for _, item := range tmpl_profile_vars.Header.Scripts {
|
for _, item := range tmpl_profile_vars.Header.Scripts {
|
||||||
w.Write(header_5)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_6)
|
w.Write(header_6)
|
||||||
}
|
w.Write([]byte(item))
|
||||||
}
|
|
||||||
w.Write(header_7)
|
w.Write(header_7)
|
||||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
}
|
||||||
|
}
|
||||||
w.Write(header_8)
|
w.Write(header_8)
|
||||||
if !tmpl_profile_vars.CurrentUser.Is_Super_Mod {
|
|
||||||
w.Write(header_9)
|
|
||||||
}
|
|
||||||
w.Write(header_10)
|
|
||||||
w.Write(menu_0)
|
|
||||||
w.Write([]byte(tmpl_profile_vars.Header.Site.Name))
|
|
||||||
w.Write(menu_1)
|
|
||||||
if tmpl_profile_vars.CurrentUser.Loggedin {
|
|
||||||
w.Write(menu_2)
|
|
||||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Link))
|
|
||||||
w.Write(menu_3)
|
|
||||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
||||||
w.Write(menu_4)
|
w.Write(header_9)
|
||||||
} else {
|
if !tmpl_profile_vars.CurrentUser.IsSuperMod {
|
||||||
w.Write(menu_5)
|
w.Write(header_10)
|
||||||
}
|
}
|
||||||
w.Write(menu_6)
|
|
||||||
w.Write(header_11)
|
w.Write(header_11)
|
||||||
if tmpl_profile_vars.Header.Widgets.RightSidebar != "" {
|
w.Write(menu_0)
|
||||||
w.Write(header_12)
|
w.Write(menu_1)
|
||||||
|
w.Write([]byte(tmpl_profile_vars.Header.Site.Name))
|
||||||
|
w.Write(menu_2)
|
||||||
|
if tmpl_profile_vars.CurrentUser.Loggedin {
|
||||||
|
w.Write(menu_3)
|
||||||
|
w.Write([]byte(tmpl_profile_vars.CurrentUser.Link))
|
||||||
|
w.Write(menu_4)
|
||||||
|
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
||||||
|
w.Write(menu_5)
|
||||||
|
} else {
|
||||||
|
w.Write(menu_6)
|
||||||
}
|
}
|
||||||
|
w.Write(menu_7)
|
||||||
|
w.Write(header_12)
|
||||||
|
if tmpl_profile_vars.Header.Widgets.RightSidebar != "" {
|
||||||
w.Write(header_13)
|
w.Write(header_13)
|
||||||
|
}
|
||||||
|
w.Write(header_14)
|
||||||
if len(tmpl_profile_vars.Header.NoticeList) != 0 {
|
if len(tmpl_profile_vars.Header.NoticeList) != 0 {
|
||||||
for _, item := range tmpl_profile_vars.Header.NoticeList {
|
for _, item := range tmpl_profile_vars.Header.NoticeList {
|
||||||
w.Write(header_14)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_15)
|
w.Write(header_15)
|
||||||
|
w.Write([]byte(item))
|
||||||
|
w.Write(header_16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Write(profile_0)
|
w.Write(profile_0)
|
||||||
@ -76,9 +81,9 @@ w.Write([]byte(tmpl_profile_vars.ProfileOwner.Tag))
|
|||||||
w.Write(profile_4)
|
w.Write(profile_4)
|
||||||
}
|
}
|
||||||
w.Write(profile_5)
|
w.Write(profile_5)
|
||||||
if tmpl_profile_vars.CurrentUser.Is_Super_Mod && !tmpl_profile_vars.ProfileOwner.Is_Super_Mod {
|
if tmpl_profile_vars.CurrentUser.IsSuperMod && !tmpl_profile_vars.ProfileOwner.IsSuperMod {
|
||||||
w.Write(profile_6)
|
w.Write(profile_6)
|
||||||
if tmpl_profile_vars.ProfileOwner.Is_Banned {
|
if tmpl_profile_vars.ProfileOwner.IsBanned {
|
||||||
w.Write(profile_7)
|
w.Write(profile_7)
|
||||||
w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID)))
|
w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID)))
|
||||||
w.Write(profile_8)
|
w.Write(profile_8)
|
||||||
@ -124,7 +129,7 @@ w.Write([]byte(item.UserLink))
|
|||||||
w.Write(profile_28)
|
w.Write(profile_28)
|
||||||
w.Write([]byte(item.CreatedByName))
|
w.Write([]byte(item.CreatedByName))
|
||||||
w.Write(profile_29)
|
w.Write(profile_29)
|
||||||
if tmpl_profile_vars.CurrentUser.Is_Mod {
|
if tmpl_profile_vars.CurrentUser.IsMod {
|
||||||
w.Write(profile_30)
|
w.Write(profile_30)
|
||||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||||
w.Write(profile_31)
|
w.Write(profile_31)
|
||||||
@ -145,7 +150,7 @@ w.Write(profile_38)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Write(profile_39)
|
w.Write(profile_39)
|
||||||
if !tmpl_profile_vars.CurrentUser.Is_Banned {
|
if !tmpl_profile_vars.CurrentUser.IsBanned {
|
||||||
w.Write(profile_40)
|
w.Write(profile_40)
|
||||||
w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID)))
|
w.Write([]byte(strconv.Itoa(tmpl_profile_vars.ProfileOwner.ID)))
|
||||||
w.Write(profile_41)
|
w.Write(profile_41)
|
||||||
|
@ -6,63 +6,68 @@ package main
|
|||||||
import "net/http"
|
import "net/http"
|
||||||
import "strconv"
|
import "strconv"
|
||||||
|
|
||||||
|
// nolint
|
||||||
func init() {
|
func init() {
|
||||||
template_topic_handle = template_topic
|
template_topic_handle = template_topic
|
||||||
//o_template_topic_handle = template_topic
|
//o_template_topic_handle = template_topic
|
||||||
ctemplates = append(ctemplates,"topic")
|
ctemplates = append(ctemplates,"topic")
|
||||||
tmpl_ptr_map["topic"] = &template_topic_handle
|
tmplPtrMap["topic"] = &template_topic_handle
|
||||||
tmpl_ptr_map["o_topic"] = template_topic
|
tmplPtrMap["o_topic"] = template_topic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
func template_topic(tmpl_topic_vars TopicPage, w http.ResponseWriter) {
|
func template_topic(tmpl_topic_vars TopicPage, w http.ResponseWriter) {
|
||||||
w.Write(header_0)
|
w.Write(header_0)
|
||||||
w.Write([]byte(tmpl_topic_vars.Title))
|
w.Write([]byte(tmpl_topic_vars.Title))
|
||||||
w.Write(header_1)
|
w.Write(header_1)
|
||||||
|
w.Write([]byte(tmpl_topic_vars.Header.ThemeName))
|
||||||
|
w.Write(header_2)
|
||||||
if len(tmpl_topic_vars.Header.Stylesheets) != 0 {
|
if len(tmpl_topic_vars.Header.Stylesheets) != 0 {
|
||||||
for _, item := range tmpl_topic_vars.Header.Stylesheets {
|
for _, item := range tmpl_topic_vars.Header.Stylesheets {
|
||||||
w.Write(header_2)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_3)
|
w.Write(header_3)
|
||||||
}
|
w.Write([]byte(item))
|
||||||
}
|
|
||||||
w.Write(header_4)
|
w.Write(header_4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.Write(header_5)
|
||||||
if len(tmpl_topic_vars.Header.Scripts) != 0 {
|
if len(tmpl_topic_vars.Header.Scripts) != 0 {
|
||||||
for _, item := range tmpl_topic_vars.Header.Scripts {
|
for _, item := range tmpl_topic_vars.Header.Scripts {
|
||||||
w.Write(header_5)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_6)
|
w.Write(header_6)
|
||||||
}
|
w.Write([]byte(item))
|
||||||
}
|
|
||||||
w.Write(header_7)
|
w.Write(header_7)
|
||||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
}
|
||||||
|
}
|
||||||
w.Write(header_8)
|
w.Write(header_8)
|
||||||
if !tmpl_topic_vars.CurrentUser.Is_Super_Mod {
|
|
||||||
w.Write(header_9)
|
|
||||||
}
|
|
||||||
w.Write(header_10)
|
|
||||||
w.Write(menu_0)
|
|
||||||
w.Write([]byte(tmpl_topic_vars.Header.Site.Name))
|
|
||||||
w.Write(menu_1)
|
|
||||||
if tmpl_topic_vars.CurrentUser.Loggedin {
|
|
||||||
w.Write(menu_2)
|
|
||||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Link))
|
|
||||||
w.Write(menu_3)
|
|
||||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||||
w.Write(menu_4)
|
w.Write(header_9)
|
||||||
} else {
|
if !tmpl_topic_vars.CurrentUser.IsSuperMod {
|
||||||
w.Write(menu_5)
|
w.Write(header_10)
|
||||||
}
|
}
|
||||||
w.Write(menu_6)
|
|
||||||
w.Write(header_11)
|
w.Write(header_11)
|
||||||
if tmpl_topic_vars.Header.Widgets.RightSidebar != "" {
|
w.Write(menu_0)
|
||||||
w.Write(header_12)
|
w.Write(menu_1)
|
||||||
|
w.Write([]byte(tmpl_topic_vars.Header.Site.Name))
|
||||||
|
w.Write(menu_2)
|
||||||
|
if tmpl_topic_vars.CurrentUser.Loggedin {
|
||||||
|
w.Write(menu_3)
|
||||||
|
w.Write([]byte(tmpl_topic_vars.CurrentUser.Link))
|
||||||
|
w.Write(menu_4)
|
||||||
|
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||||
|
w.Write(menu_5)
|
||||||
|
} else {
|
||||||
|
w.Write(menu_6)
|
||||||
}
|
}
|
||||||
|
w.Write(menu_7)
|
||||||
|
w.Write(header_12)
|
||||||
|
if tmpl_topic_vars.Header.Widgets.RightSidebar != "" {
|
||||||
w.Write(header_13)
|
w.Write(header_13)
|
||||||
|
}
|
||||||
|
w.Write(header_14)
|
||||||
if len(tmpl_topic_vars.Header.NoticeList) != 0 {
|
if len(tmpl_topic_vars.Header.NoticeList) != 0 {
|
||||||
for _, item := range tmpl_topic_vars.Header.NoticeList {
|
for _, item := range tmpl_topic_vars.Header.NoticeList {
|
||||||
w.Write(header_14)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_15)
|
w.Write(header_15)
|
||||||
|
w.Write([]byte(item))
|
||||||
|
w.Write(header_16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Write(topic_0)
|
w.Write(topic_0)
|
||||||
@ -90,14 +95,14 @@ w.Write(topic_10)
|
|||||||
if tmpl_topic_vars.Topic.Sticky {
|
if tmpl_topic_vars.Topic.Sticky {
|
||||||
w.Write(topic_11)
|
w.Write(topic_11)
|
||||||
} else {
|
} else {
|
||||||
if tmpl_topic_vars.Topic.Is_Closed {
|
if tmpl_topic_vars.Topic.IsClosed {
|
||||||
w.Write(topic_12)
|
w.Write(topic_12)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Write(topic_13)
|
w.Write(topic_13)
|
||||||
w.Write([]byte(tmpl_topic_vars.Topic.Title))
|
w.Write([]byte(tmpl_topic_vars.Topic.Title))
|
||||||
w.Write(topic_14)
|
w.Write(topic_14)
|
||||||
if tmpl_topic_vars.Topic.Is_Closed {
|
if tmpl_topic_vars.Topic.IsClosed {
|
||||||
w.Write(topic_15)
|
w.Write(topic_15)
|
||||||
}
|
}
|
||||||
if tmpl_topic_vars.CurrentUser.Perms.EditTopic {
|
if tmpl_topic_vars.CurrentUser.Perms.EditTopic {
|
||||||
@ -160,103 +165,113 @@ w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
|||||||
w.Write(topic_42)
|
w.Write(topic_42)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if tmpl_topic_vars.CurrentUser.Perms.ViewIPs {
|
||||||
w.Write(topic_43)
|
w.Write(topic_43)
|
||||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
w.Write([]byte(tmpl_topic_vars.Topic.IPAddress))
|
||||||
w.Write(topic_44)
|
w.Write(topic_44)
|
||||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
}
|
||||||
w.Write(topic_45)
|
w.Write(topic_45)
|
||||||
if tmpl_topic_vars.Topic.LikeCount > 0 {
|
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
||||||
w.Write(topic_46)
|
w.Write(topic_46)
|
||||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.LikeCount)))
|
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||||
w.Write(topic_47)
|
w.Write(topic_47)
|
||||||
|
if tmpl_topic_vars.Topic.LikeCount > 0 {
|
||||||
|
w.Write(topic_48)
|
||||||
|
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.LikeCount)))
|
||||||
|
w.Write(topic_49)
|
||||||
}
|
}
|
||||||
if tmpl_topic_vars.Topic.Tag != "" {
|
if tmpl_topic_vars.Topic.Tag != "" {
|
||||||
w.Write(topic_48)
|
|
||||||
w.Write([]byte(tmpl_topic_vars.Topic.Tag))
|
|
||||||
w.Write(topic_49)
|
|
||||||
} else {
|
|
||||||
w.Write(topic_50)
|
w.Write(topic_50)
|
||||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.Level)))
|
w.Write([]byte(tmpl_topic_vars.Topic.Tag))
|
||||||
w.Write(topic_51)
|
w.Write(topic_51)
|
||||||
}
|
} else {
|
||||||
w.Write(topic_52)
|
w.Write(topic_52)
|
||||||
|
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.Level)))
|
||||||
|
w.Write(topic_53)
|
||||||
|
}
|
||||||
|
w.Write(topic_54)
|
||||||
if len(tmpl_topic_vars.ItemList) != 0 {
|
if len(tmpl_topic_vars.ItemList) != 0 {
|
||||||
for _, item := range tmpl_topic_vars.ItemList {
|
for _, item := range tmpl_topic_vars.ItemList {
|
||||||
if item.ActionType != "" {
|
if item.ActionType != "" {
|
||||||
w.Write(topic_53)
|
|
||||||
w.Write([]byte(item.ActionIcon))
|
|
||||||
w.Write(topic_54)
|
|
||||||
w.Write([]byte(item.ActionType))
|
|
||||||
w.Write(topic_55)
|
w.Write(topic_55)
|
||||||
} else {
|
w.Write([]byte(item.ActionIcon))
|
||||||
w.Write(topic_56)
|
w.Write(topic_56)
|
||||||
w.Write([]byte(item.ClassName))
|
w.Write([]byte(item.ActionType))
|
||||||
w.Write(topic_57)
|
w.Write(topic_57)
|
||||||
if item.Avatar != "" {
|
} else {
|
||||||
w.Write(topic_58)
|
w.Write(topic_58)
|
||||||
w.Write([]byte(item.Avatar))
|
w.Write([]byte(item.ClassName))
|
||||||
w.Write(topic_59)
|
w.Write(topic_59)
|
||||||
if item.ContentLines <= 5 {
|
if item.Avatar != "" {
|
||||||
w.Write(topic_60)
|
w.Write(topic_60)
|
||||||
}
|
w.Write([]byte(item.Avatar))
|
||||||
w.Write(topic_61)
|
w.Write(topic_61)
|
||||||
}
|
if item.ContentLines <= 5 {
|
||||||
w.Write(topic_62)
|
w.Write(topic_62)
|
||||||
w.Write([]byte(item.ContentHtml))
|
}
|
||||||
w.Write(topic_63)
|
w.Write(topic_63)
|
||||||
w.Write([]byte(item.UserLink))
|
}
|
||||||
w.Write(topic_64)
|
w.Write(topic_64)
|
||||||
w.Write([]byte(item.CreatedByName))
|
w.Write([]byte(item.ContentHtml))
|
||||||
w.Write(topic_65)
|
w.Write(topic_65)
|
||||||
if tmpl_topic_vars.CurrentUser.Perms.LikeItem {
|
w.Write([]byte(item.UserLink))
|
||||||
w.Write(topic_66)
|
w.Write(topic_66)
|
||||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
w.Write([]byte(item.CreatedByName))
|
||||||
w.Write(topic_67)
|
w.Write(topic_67)
|
||||||
if item.Liked {
|
if tmpl_topic_vars.CurrentUser.Perms.LikeItem {
|
||||||
w.Write(topic_68)
|
w.Write(topic_68)
|
||||||
}
|
|
||||||
w.Write(topic_69)
|
|
||||||
}
|
|
||||||
if tmpl_topic_vars.CurrentUser.Perms.EditReply {
|
|
||||||
w.Write(topic_70)
|
|
||||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||||
|
w.Write(topic_69)
|
||||||
|
if item.Liked {
|
||||||
|
w.Write(topic_70)
|
||||||
|
}
|
||||||
w.Write(topic_71)
|
w.Write(topic_71)
|
||||||
}
|
}
|
||||||
if tmpl_topic_vars.CurrentUser.Perms.DeleteReply {
|
if tmpl_topic_vars.CurrentUser.Perms.EditReply {
|
||||||
w.Write(topic_72)
|
w.Write(topic_72)
|
||||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||||
w.Write(topic_73)
|
w.Write(topic_73)
|
||||||
}
|
}
|
||||||
|
if tmpl_topic_vars.CurrentUser.Perms.DeleteReply {
|
||||||
w.Write(topic_74)
|
w.Write(topic_74)
|
||||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||||
w.Write(topic_75)
|
w.Write(topic_75)
|
||||||
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
|
||||||
w.Write(topic_76)
|
|
||||||
if item.LikeCount > 0 {
|
|
||||||
w.Write(topic_77)
|
|
||||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
|
||||||
w.Write(topic_78)
|
|
||||||
}
|
}
|
||||||
if item.Tag != "" {
|
if tmpl_topic_vars.CurrentUser.Perms.ViewIPs {
|
||||||
|
w.Write(topic_76)
|
||||||
|
w.Write([]byte(item.IPAddress))
|
||||||
|
w.Write(topic_77)
|
||||||
|
}
|
||||||
|
w.Write(topic_78)
|
||||||
|
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||||
w.Write(topic_79)
|
w.Write(topic_79)
|
||||||
w.Write([]byte(item.Tag))
|
w.Write([]byte(tmpl_topic_vars.CurrentUser.Session))
|
||||||
w.Write(topic_80)
|
w.Write(topic_80)
|
||||||
} else {
|
if item.LikeCount > 0 {
|
||||||
w.Write(topic_81)
|
w.Write(topic_81)
|
||||||
w.Write([]byte(strconv.Itoa(item.Level)))
|
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||||
w.Write(topic_82)
|
w.Write(topic_82)
|
||||||
}
|
}
|
||||||
|
if item.Tag != "" {
|
||||||
w.Write(topic_83)
|
w.Write(topic_83)
|
||||||
}
|
w.Write([]byte(item.Tag))
|
||||||
}
|
|
||||||
}
|
|
||||||
w.Write(topic_84)
|
w.Write(topic_84)
|
||||||
if tmpl_topic_vars.CurrentUser.Perms.CreateReply {
|
} else {
|
||||||
w.Write(topic_85)
|
w.Write(topic_85)
|
||||||
w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID)))
|
w.Write([]byte(strconv.Itoa(item.Level)))
|
||||||
w.Write(topic_86)
|
w.Write(topic_86)
|
||||||
}
|
}
|
||||||
w.Write(topic_87)
|
w.Write(topic_87)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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_91)
|
||||||
w.Write(footer_0)
|
w.Write(footer_0)
|
||||||
if tmpl_topic_vars.Header.Widgets.RightSidebar != "" {
|
if tmpl_topic_vars.Header.Widgets.RightSidebar != "" {
|
||||||
w.Write(footer_1)
|
w.Write(footer_1)
|
||||||
|
@ -6,63 +6,68 @@ package main
|
|||||||
import "net/http"
|
import "net/http"
|
||||||
import "strconv"
|
import "strconv"
|
||||||
|
|
||||||
|
// nolint
|
||||||
func init() {
|
func init() {
|
||||||
template_topic_alt_handle = template_topic_alt
|
template_topic_alt_handle = template_topic_alt
|
||||||
//o_template_topic_alt_handle = template_topic_alt
|
//o_template_topic_alt_handle = template_topic_alt
|
||||||
ctemplates = append(ctemplates,"topic_alt")
|
ctemplates = append(ctemplates,"topic_alt")
|
||||||
tmpl_ptr_map["topic_alt"] = &template_topic_alt_handle
|
tmplPtrMap["topic_alt"] = &template_topic_alt_handle
|
||||||
tmpl_ptr_map["o_topic_alt"] = template_topic_alt
|
tmplPtrMap["o_topic_alt"] = template_topic_alt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
func template_topic_alt(tmpl_topic_alt_vars TopicPage, w http.ResponseWriter) {
|
func template_topic_alt(tmpl_topic_alt_vars TopicPage, w http.ResponseWriter) {
|
||||||
w.Write(header_0)
|
w.Write(header_0)
|
||||||
w.Write([]byte(tmpl_topic_alt_vars.Title))
|
w.Write([]byte(tmpl_topic_alt_vars.Title))
|
||||||
w.Write(header_1)
|
w.Write(header_1)
|
||||||
|
w.Write([]byte(tmpl_topic_alt_vars.Header.ThemeName))
|
||||||
|
w.Write(header_2)
|
||||||
if len(tmpl_topic_alt_vars.Header.Stylesheets) != 0 {
|
if len(tmpl_topic_alt_vars.Header.Stylesheets) != 0 {
|
||||||
for _, item := range tmpl_topic_alt_vars.Header.Stylesheets {
|
for _, item := range tmpl_topic_alt_vars.Header.Stylesheets {
|
||||||
w.Write(header_2)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_3)
|
w.Write(header_3)
|
||||||
}
|
w.Write([]byte(item))
|
||||||
}
|
|
||||||
w.Write(header_4)
|
w.Write(header_4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.Write(header_5)
|
||||||
if len(tmpl_topic_alt_vars.Header.Scripts) != 0 {
|
if len(tmpl_topic_alt_vars.Header.Scripts) != 0 {
|
||||||
for _, item := range tmpl_topic_alt_vars.Header.Scripts {
|
for _, item := range tmpl_topic_alt_vars.Header.Scripts {
|
||||||
w.Write(header_5)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_6)
|
w.Write(header_6)
|
||||||
}
|
w.Write([]byte(item))
|
||||||
}
|
|
||||||
w.Write(header_7)
|
w.Write(header_7)
|
||||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
}
|
||||||
|
}
|
||||||
w.Write(header_8)
|
w.Write(header_8)
|
||||||
if !tmpl_topic_alt_vars.CurrentUser.Is_Super_Mod {
|
|
||||||
w.Write(header_9)
|
|
||||||
}
|
|
||||||
w.Write(header_10)
|
|
||||||
w.Write(menu_0)
|
|
||||||
w.Write([]byte(tmpl_topic_alt_vars.Header.Site.Name))
|
|
||||||
w.Write(menu_1)
|
|
||||||
if tmpl_topic_alt_vars.CurrentUser.Loggedin {
|
|
||||||
w.Write(menu_2)
|
|
||||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Link))
|
|
||||||
w.Write(menu_3)
|
|
||||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||||
w.Write(menu_4)
|
w.Write(header_9)
|
||||||
} else {
|
if !tmpl_topic_alt_vars.CurrentUser.IsSuperMod {
|
||||||
w.Write(menu_5)
|
w.Write(header_10)
|
||||||
}
|
}
|
||||||
w.Write(menu_6)
|
|
||||||
w.Write(header_11)
|
w.Write(header_11)
|
||||||
if tmpl_topic_alt_vars.Header.Widgets.RightSidebar != "" {
|
w.Write(menu_0)
|
||||||
w.Write(header_12)
|
w.Write(menu_1)
|
||||||
|
w.Write([]byte(tmpl_topic_alt_vars.Header.Site.Name))
|
||||||
|
w.Write(menu_2)
|
||||||
|
if tmpl_topic_alt_vars.CurrentUser.Loggedin {
|
||||||
|
w.Write(menu_3)
|
||||||
|
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Link))
|
||||||
|
w.Write(menu_4)
|
||||||
|
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||||
|
w.Write(menu_5)
|
||||||
|
} else {
|
||||||
|
w.Write(menu_6)
|
||||||
}
|
}
|
||||||
|
w.Write(menu_7)
|
||||||
|
w.Write(header_12)
|
||||||
|
if tmpl_topic_alt_vars.Header.Widgets.RightSidebar != "" {
|
||||||
w.Write(header_13)
|
w.Write(header_13)
|
||||||
|
}
|
||||||
|
w.Write(header_14)
|
||||||
if len(tmpl_topic_alt_vars.Header.NoticeList) != 0 {
|
if len(tmpl_topic_alt_vars.Header.NoticeList) != 0 {
|
||||||
for _, item := range tmpl_topic_alt_vars.Header.NoticeList {
|
for _, item := range tmpl_topic_alt_vars.Header.NoticeList {
|
||||||
w.Write(header_14)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_15)
|
w.Write(header_15)
|
||||||
|
w.Write([]byte(item))
|
||||||
|
w.Write(header_16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if tmpl_topic_alt_vars.Page > 1 {
|
if tmpl_topic_alt_vars.Page > 1 {
|
||||||
@ -89,14 +94,14 @@ w.Write(topic_alt_9)
|
|||||||
if tmpl_topic_alt_vars.Topic.Sticky {
|
if tmpl_topic_alt_vars.Topic.Sticky {
|
||||||
w.Write(topic_alt_10)
|
w.Write(topic_alt_10)
|
||||||
} else {
|
} else {
|
||||||
if tmpl_topic_alt_vars.Topic.Is_Closed {
|
if tmpl_topic_alt_vars.Topic.IsClosed {
|
||||||
w.Write(topic_alt_11)
|
w.Write(topic_alt_11)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Write(topic_alt_12)
|
w.Write(topic_alt_12)
|
||||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Title))
|
w.Write([]byte(tmpl_topic_alt_vars.Topic.Title))
|
||||||
w.Write(topic_alt_13)
|
w.Write(topic_alt_13)
|
||||||
if tmpl_topic_alt_vars.Topic.Is_Closed {
|
if tmpl_topic_alt_vars.Topic.IsClosed {
|
||||||
w.Write(topic_alt_14)
|
w.Write(topic_alt_14)
|
||||||
}
|
}
|
||||||
if tmpl_topic_alt_vars.CurrentUser.Perms.EditTopic {
|
if tmpl_topic_alt_vars.CurrentUser.Perms.EditTopic {
|
||||||
@ -163,7 +168,7 @@ w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
|||||||
w.Write(topic_alt_42)
|
w.Write(topic_alt_42)
|
||||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||||
w.Write(topic_alt_43)
|
w.Write(topic_alt_43)
|
||||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.IpAddress))
|
w.Write([]byte(tmpl_topic_alt_vars.Topic.IPAddress))
|
||||||
w.Write(topic_alt_44)
|
w.Write(topic_alt_44)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,7 +241,7 @@ w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
|||||||
w.Write(topic_alt_76)
|
w.Write(topic_alt_76)
|
||||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||||
w.Write(topic_alt_77)
|
w.Write(topic_alt_77)
|
||||||
w.Write([]byte(item.IpAddress))
|
w.Write([]byte(item.IPAddress))
|
||||||
w.Write(topic_alt_78)
|
w.Write(topic_alt_78)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,66 +3,71 @@
|
|||||||
// Code generated by Gosora. More below:
|
// Code generated by Gosora. More below:
|
||||||
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
|
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
|
||||||
package main
|
package main
|
||||||
import "net/http"
|
|
||||||
import "strconv"
|
import "strconv"
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// nolint
|
||||||
func init() {
|
func init() {
|
||||||
template_topics_handle = template_topics
|
template_topics_handle = template_topics
|
||||||
//o_template_topics_handle = template_topics
|
//o_template_topics_handle = template_topics
|
||||||
ctemplates = append(ctemplates,"topics")
|
ctemplates = append(ctemplates,"topics")
|
||||||
tmpl_ptr_map["topics"] = &template_topics_handle
|
tmplPtrMap["topics"] = &template_topics_handle
|
||||||
tmpl_ptr_map["o_topics"] = template_topics
|
tmplPtrMap["o_topics"] = template_topics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
func template_topics(tmpl_topics_vars TopicsPage, w http.ResponseWriter) {
|
func template_topics(tmpl_topics_vars TopicsPage, w http.ResponseWriter) {
|
||||||
w.Write(header_0)
|
w.Write(header_0)
|
||||||
w.Write([]byte(tmpl_topics_vars.Title))
|
w.Write([]byte(tmpl_topics_vars.Title))
|
||||||
w.Write(header_1)
|
w.Write(header_1)
|
||||||
|
w.Write([]byte(tmpl_topics_vars.Header.ThemeName))
|
||||||
|
w.Write(header_2)
|
||||||
if len(tmpl_topics_vars.Header.Stylesheets) != 0 {
|
if len(tmpl_topics_vars.Header.Stylesheets) != 0 {
|
||||||
for _, item := range tmpl_topics_vars.Header.Stylesheets {
|
for _, item := range tmpl_topics_vars.Header.Stylesheets {
|
||||||
w.Write(header_2)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_3)
|
w.Write(header_3)
|
||||||
}
|
w.Write([]byte(item))
|
||||||
}
|
|
||||||
w.Write(header_4)
|
w.Write(header_4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.Write(header_5)
|
||||||
if len(tmpl_topics_vars.Header.Scripts) != 0 {
|
if len(tmpl_topics_vars.Header.Scripts) != 0 {
|
||||||
for _, item := range tmpl_topics_vars.Header.Scripts {
|
for _, item := range tmpl_topics_vars.Header.Scripts {
|
||||||
w.Write(header_5)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_6)
|
w.Write(header_6)
|
||||||
}
|
w.Write([]byte(item))
|
||||||
}
|
|
||||||
w.Write(header_7)
|
w.Write(header_7)
|
||||||
w.Write([]byte(tmpl_topics_vars.CurrentUser.Session))
|
}
|
||||||
|
}
|
||||||
w.Write(header_8)
|
w.Write(header_8)
|
||||||
if !tmpl_topics_vars.CurrentUser.Is_Super_Mod {
|
|
||||||
w.Write(header_9)
|
|
||||||
}
|
|
||||||
w.Write(header_10)
|
|
||||||
w.Write(menu_0)
|
|
||||||
w.Write([]byte(tmpl_topics_vars.Header.Site.Name))
|
|
||||||
w.Write(menu_1)
|
|
||||||
if tmpl_topics_vars.CurrentUser.Loggedin {
|
|
||||||
w.Write(menu_2)
|
|
||||||
w.Write([]byte(tmpl_topics_vars.CurrentUser.Link))
|
|
||||||
w.Write(menu_3)
|
|
||||||
w.Write([]byte(tmpl_topics_vars.CurrentUser.Session))
|
w.Write([]byte(tmpl_topics_vars.CurrentUser.Session))
|
||||||
w.Write(menu_4)
|
w.Write(header_9)
|
||||||
} else {
|
if !tmpl_topics_vars.CurrentUser.IsSuperMod {
|
||||||
w.Write(menu_5)
|
w.Write(header_10)
|
||||||
}
|
}
|
||||||
w.Write(menu_6)
|
|
||||||
w.Write(header_11)
|
w.Write(header_11)
|
||||||
if tmpl_topics_vars.Header.Widgets.RightSidebar != "" {
|
w.Write(menu_0)
|
||||||
w.Write(header_12)
|
w.Write(menu_1)
|
||||||
|
w.Write([]byte(tmpl_topics_vars.Header.Site.Name))
|
||||||
|
w.Write(menu_2)
|
||||||
|
if tmpl_topics_vars.CurrentUser.Loggedin {
|
||||||
|
w.Write(menu_3)
|
||||||
|
w.Write([]byte(tmpl_topics_vars.CurrentUser.Link))
|
||||||
|
w.Write(menu_4)
|
||||||
|
w.Write([]byte(tmpl_topics_vars.CurrentUser.Session))
|
||||||
|
w.Write(menu_5)
|
||||||
|
} else {
|
||||||
|
w.Write(menu_6)
|
||||||
}
|
}
|
||||||
|
w.Write(menu_7)
|
||||||
|
w.Write(header_12)
|
||||||
|
if tmpl_topics_vars.Header.Widgets.RightSidebar != "" {
|
||||||
w.Write(header_13)
|
w.Write(header_13)
|
||||||
|
}
|
||||||
|
w.Write(header_14)
|
||||||
if len(tmpl_topics_vars.Header.NoticeList) != 0 {
|
if len(tmpl_topics_vars.Header.NoticeList) != 0 {
|
||||||
for _, item := range tmpl_topics_vars.Header.NoticeList {
|
for _, item := range tmpl_topics_vars.Header.NoticeList {
|
||||||
w.Write(header_14)
|
|
||||||
w.Write([]byte(item))
|
|
||||||
w.Write(header_15)
|
w.Write(header_15)
|
||||||
|
w.Write([]byte(item))
|
||||||
|
w.Write(header_16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Write(topics_0)
|
w.Write(topics_0)
|
||||||
@ -72,7 +77,7 @@ w.Write(topics_1)
|
|||||||
if item.Sticky {
|
if item.Sticky {
|
||||||
w.Write(topics_2)
|
w.Write(topics_2)
|
||||||
} else {
|
} else {
|
||||||
if item.Is_Closed {
|
if item.IsClosed {
|
||||||
w.Write(topics_3)
|
w.Write(topics_3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,7 +108,7 @@ w.Write([]byte(item.Creator.Link))
|
|||||||
w.Write(topics_16)
|
w.Write(topics_16)
|
||||||
w.Write([]byte(item.Creator.Name))
|
w.Write([]byte(item.Creator.Name))
|
||||||
w.Write(topics_17)
|
w.Write(topics_17)
|
||||||
if item.Is_Closed {
|
if item.IsClosed {
|
||||||
w.Write(topics_18)
|
w.Write(topics_18)
|
||||||
}
|
}
|
||||||
if item.Sticky {
|
if item.Sticky {
|
||||||
|
231
templates.go
231
templates.go
@ -1,43 +1,35 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"fmt"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
"fmt"
|
||||||
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
//"regexp"
|
//"regexp"
|
||||||
"reflect"
|
|
||||||
"path/filepath"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"text/template/parse"
|
"text/template/parse"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TO-DO: Turn this file into a library
|
// TO-DO: Turn this file into a library
|
||||||
var ctemplates []string
|
var ctemplates []string
|
||||||
var tmpl_ptr_map map[string]interface{} = make(map[string]interface{})
|
var tmplPtrMap = make(map[string]interface{})
|
||||||
var text_overlap_list map[string]int
|
var textOverlapList = make(map[string]int)
|
||||||
|
|
||||||
func init() {
|
// nolint
|
||||||
text_overlap_list = make(map[string]int)
|
type VarItem struct {
|
||||||
}
|
|
||||||
|
|
||||||
type VarItem struct
|
|
||||||
{
|
|
||||||
Name string
|
Name string
|
||||||
Destination string
|
Destination string
|
||||||
Type string
|
Type string
|
||||||
}
|
}
|
||||||
|
type VarItemReflect struct {
|
||||||
type VarItemReflect struct
|
|
||||||
{
|
|
||||||
Name string
|
Name string
|
||||||
Destination string
|
Destination string
|
||||||
Value reflect.Value
|
Value reflect.Value
|
||||||
}
|
}
|
||||||
|
type CTemplateSet struct {
|
||||||
type CTemplateSet struct
|
|
||||||
{
|
|
||||||
tlist map[string]*parse.Tree
|
tlist map[string]*parse.Tree
|
||||||
dir string
|
dir string
|
||||||
funcMap map[string]interface{}
|
funcMap map[string]interface{}
|
||||||
@ -58,7 +50,7 @@ type CTemplateSet struct
|
|||||||
expectsInt interface{}
|
expectsInt interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_template(name string, dir string, expects string, expectsInt interface{}, varList map[string]VarItem) (out string, err error) {
|
func (c *CTemplateSet) compileTemplate(name string, dir string, expects string, expectsInt interface{}, varList map[string]VarItem) (out string, err error) {
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
fmt.Println("Compiling template '" + name + "'")
|
fmt.Println("Compiling template '" + name + "'")
|
||||||
}
|
}
|
||||||
@ -102,7 +94,7 @@ func (c *CTemplateSet) compile_template(name string, dir string, expects string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
tree := parse.New(name, c.funcMap)
|
tree := parse.New(name, c.funcMap)
|
||||||
var treeSet map[string]*parse.Tree = make(map[string]*parse.Tree)
|
var treeSet = make(map[string]*parse.Tree)
|
||||||
tree, err = tree.Parse(content, "{{", "}}", treeSet, c.funcMap)
|
tree, err = tree.Parse(content, "{{", "}}", treeSet, c.funcMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -145,7 +137,7 @@ func (c *CTemplateSet) compile_template(name string, dir string, expects string,
|
|||||||
if treeLength != (index + 1) {
|
if treeLength != (index + 1) {
|
||||||
c.nextNode = subtree.Root.Nodes[index+1].Type()
|
c.nextNode = subtree.Root.Nodes[index+1].Type()
|
||||||
}
|
}
|
||||||
out += c.compile_switch(varholder, holdreflect, fname, node)
|
out += c.compileSwitch(varholder, holdreflect, fname, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
var importList string
|
var importList string
|
||||||
@ -162,8 +154,8 @@ func (c *CTemplateSet) compile_template(name string, dir string, expects string,
|
|||||||
|
|
||||||
fout := "// +build !no_templategen\n\n// Code generated by Gosora. More below:\n/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */\n"
|
fout := "// +build !no_templategen\n\n// Code generated by Gosora. More below:\n/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */\n"
|
||||||
fout += "package main\n" + importList + c.pVarList + "\n"
|
fout += "package main\n" + importList + c.pVarList + "\n"
|
||||||
fout += "func init() {\n\ttemplate_" + fname +"_handle = template_" + fname + "\n\t//o_template_" + fname +"_handle = template_" + fname + "\n\tctemplates = append(ctemplates,\"" + fname + "\")\n\ttmpl_ptr_map[\"" + fname + "\"] = &template_" + fname + "_handle\n\ttmpl_ptr_map[\"o_" + fname + "\"] = template_" + fname + "\n}\n\n"
|
fout += "// nolint\nfunc init() {\n\ttemplate_" + fname + "_handle = template_" + fname + "\n\t//o_template_" + fname + "_handle = template_" + fname + "\n\tctemplates = append(ctemplates,\"" + fname + "\")\n\ttmplPtrMap[\"" + fname + "\"] = &template_" + fname + "_handle\n\ttmplPtrMap[\"o_" + fname + "\"] = template_" + fname + "\n}\n\n"
|
||||||
fout += "func template_" + fname + "(tmpl_" + fname + "_vars " + expects + ", w http.ResponseWriter) {\n" + varString + out + "}\n"
|
fout += "// nolint\nfunc template_" + fname + "(tmpl_" + fname + "_vars " + expects + ", w http.ResponseWriter) {\n" + varString + out + "}\n"
|
||||||
|
|
||||||
fout = strings.Replace(fout, `))
|
fout = strings.Replace(fout, `))
|
||||||
w.Write([]byte(`, " + ", -1)
|
w.Write([]byte(`, " + ", -1)
|
||||||
@ -186,9 +178,9 @@ w.Write([]byte(`," + ",-1)
|
|||||||
return fout, nil
|
return fout, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_switch(varholder string, holdreflect reflect.Value, template_name string, node interface{}) (out string) {
|
func (c *CTemplateSet) compileSwitch(varholder string, holdreflect reflect.Value, templateName string, node interface{}) (out string) {
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("in compile_switch")
|
fmt.Println("in compileSwitch")
|
||||||
}
|
}
|
||||||
switch node := node.(type) {
|
switch node := node.(type) {
|
||||||
case *parse.ActionNode:
|
case *parse.ActionNode:
|
||||||
@ -199,7 +191,7 @@ func (c *CTemplateSet) compile_switch(varholder string, holdreflect reflect.Valu
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
for _, cmd := range node.Pipe.Cmds {
|
for _, cmd := range node.Pipe.Cmds {
|
||||||
out += c.compile_subswitch(varholder, holdreflect, template_name, cmd)
|
out += c.compileSubswitch(varholder, holdreflect, templateName, cmd)
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
case *parse.IfNode:
|
case *parse.IfNode:
|
||||||
@ -214,9 +206,9 @@ func (c *CTemplateSet) compile_switch(varholder string, holdreflect reflect.Valu
|
|||||||
fmt.Println("If Node Bit:", cmd)
|
fmt.Println("If Node Bit:", cmd)
|
||||||
fmt.Println("If Node Bit Type:", reflect.ValueOf(cmd).Type().Name())
|
fmt.Println("If Node Bit Type:", reflect.ValueOf(cmd).Type().Name())
|
||||||
}
|
}
|
||||||
expr += c.compile_varswitch(varholder, holdreflect, template_name, cmd)
|
expr += c.compileVarswitch(varholder, holdreflect, templateName, cmd)
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("If Node Expression Step:",c.compile_varswitch(varholder, holdreflect, template_name, cmd))
|
fmt.Println("If Node Expression Step:", c.compileVarswitch(varholder, holdreflect, templateName, cmd))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,19 +223,19 @@ func (c *CTemplateSet) compile_switch(varholder string, holdreflect reflect.Valu
|
|||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("Selected Branch 1")
|
fmt.Println("Selected Branch 1")
|
||||||
}
|
}
|
||||||
return "if " + expr + " {\n" + c.compile_switch(varholder, holdreflect, template_name, node.List) + "}\n"
|
return "if " + expr + " {\n" + c.compileSwitch(varholder, holdreflect, templateName, node.List) + "}\n"
|
||||||
} else {
|
}
|
||||||
|
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("Selected Branch 2")
|
fmt.Println("Selected Branch 2")
|
||||||
}
|
}
|
||||||
return "if " + expr + " {\n" + c.compile_switch(varholder, holdreflect, template_name, node.List) + "} else {\n" + c.compile_switch(varholder, holdreflect, template_name, node.ElseList) + "}\n"
|
return "if " + expr + " {\n" + c.compileSwitch(varholder, holdreflect, templateName, node.List) + "} else {\n" + c.compileSwitch(varholder, holdreflect, templateName, node.ElseList) + "}\n"
|
||||||
}
|
|
||||||
case *parse.ListNode:
|
case *parse.ListNode:
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("List Node")
|
fmt.Println("List Node")
|
||||||
}
|
}
|
||||||
for _, subnode := range node.Nodes {
|
for _, subnode := range node.Nodes {
|
||||||
out += c.compile_switch(varholder, holdreflect, template_name, subnode)
|
out += c.compileSwitch(varholder, holdreflect, templateName, subnode)
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
case *parse.RangeNode:
|
case *parse.RangeNode:
|
||||||
@ -257,7 +249,7 @@ func (c *CTemplateSet) compile_switch(varholder string, holdreflect reflect.Valu
|
|||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("Range Bit:", cmd)
|
fmt.Println("Range Bit:", cmd)
|
||||||
}
|
}
|
||||||
out, outVal = c.compile_reflectswitch(varholder, holdreflect, template_name, cmd)
|
out, outVal = c.compileReflectswitch(varholder, holdreflect, templateName, cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
@ -273,28 +265,28 @@ func (c *CTemplateSet) compile_switch(varholder string, holdreflect reflect.Valu
|
|||||||
}
|
}
|
||||||
|
|
||||||
if node.ElseList != nil {
|
if node.ElseList != nil {
|
||||||
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c.compile_switch("item", item, template_name, node.List) + "}\n} else {\n" + c.compile_switch("item", item, template_name, node.ElseList) + "}\n"
|
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c.compileSwitch("item", item, templateName, node.List) + "}\n} else {\n" + c.compileSwitch("item", item, templateName, node.ElseList) + "}\n"
|
||||||
} else {
|
} else {
|
||||||
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c.compile_switch("item", item, template_name, node.List) + "}\n}"
|
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c.compileSwitch("item", item, templateName, node.List) + "}\n}"
|
||||||
}
|
}
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
if outVal.Len() == 0 {
|
if outVal.Len() == 0 {
|
||||||
panic("The sample data needs at-least one or more elements for the slices. We're looking into removing this requirement at some point!")
|
panic("The sample data needs at-least one or more elements for the slices. We're looking into removing this requirement at some point!")
|
||||||
}
|
}
|
||||||
item := outVal.Index(0)
|
item := outVal.Index(0)
|
||||||
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c.compile_switch("item", item, template_name, node.List) + "}\n}"
|
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c.compileSwitch("item", item, templateName, node.List) + "}\n}"
|
||||||
case reflect.Invalid:
|
case reflect.Invalid:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.ElseList != nil {
|
if node.ElseList != nil {
|
||||||
out += " else {\n" + c.compile_switch(varholder, holdreflect, template_name, node.ElseList) + "}\n"
|
out += " else {\n" + c.compileSwitch(varholder, holdreflect, templateName, node.ElseList) + "}\n"
|
||||||
} else {
|
} else {
|
||||||
out += "\n"
|
out += "\n"
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
case *parse.TemplateNode:
|
case *parse.TemplateNode:
|
||||||
return c.compile_subtemplate(varholder, holdreflect, node)
|
return c.compileSubtemplate(varholder, holdreflect, node)
|
||||||
case *parse.TextNode:
|
case *parse.TextNode:
|
||||||
c.previousNode = c.currentNode
|
c.previousNode = c.currentNode
|
||||||
c.currentNode = node.Type()
|
c.currentNode = node.Type()
|
||||||
@ -302,26 +294,26 @@ func (c *CTemplateSet) compile_switch(varholder string, holdreflect reflect.Valu
|
|||||||
tmpText := bytes.TrimSpace(node.Text)
|
tmpText := bytes.TrimSpace(node.Text)
|
||||||
if len(tmpText) == 0 {
|
if len(tmpText) == 0 {
|
||||||
return ""
|
return ""
|
||||||
} else {
|
}
|
||||||
|
|
||||||
//return "w.Write([]byte(`" + string(node.Text) + "`))\n"
|
//return "w.Write([]byte(`" + string(node.Text) + "`))\n"
|
||||||
fragment_name := template_name + "_" + strconv.Itoa(c.FragmentCursor[template_name])
|
fragmentName := templateName + "_" + strconv.Itoa(c.FragmentCursor[templateName])
|
||||||
_, ok := c.Fragments[fragment_name]
|
_, ok := c.Fragments[fragmentName]
|
||||||
if !ok {
|
if !ok {
|
||||||
c.Fragments[fragment_name] = len(node.Text)
|
c.Fragments[fragmentName] = len(node.Text)
|
||||||
c.FragOut += "var " + fragment_name + " []byte = []byte(`" + string(node.Text) + "`)\n"
|
c.FragOut += "var " + fragmentName + " = []byte(`" + string(node.Text) + "`)\n"
|
||||||
}
|
|
||||||
c.FragmentCursor[template_name] = c.FragmentCursor[template_name] + 1
|
|
||||||
return "w.Write(" + fragment_name + ")\n"
|
|
||||||
}
|
}
|
||||||
|
c.FragmentCursor[templateName] = c.FragmentCursor[templateName] + 1
|
||||||
|
return "w.Write(" + fragmentName + ")\n"
|
||||||
default:
|
default:
|
||||||
panic("Unknown Node in main switch")
|
panic("Unknown Node in main switch")
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_subswitch(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string) {
|
func (c *CTemplateSet) compileSubswitch(varholder string, holdreflect reflect.Value, templateName string, node *parse.CommandNode) (out string) {
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("in compile_subswitch")
|
fmt.Println("in compileSubswitch")
|
||||||
}
|
}
|
||||||
firstWord := node.Args[0]
|
firstWord := node.Args[0]
|
||||||
switch n := firstWord.(type) {
|
switch n := firstWord.(type) {
|
||||||
@ -383,7 +375,7 @@ func (c *CTemplateSet) compile_subswitch(varholder string, holdreflect reflect.V
|
|||||||
fmt.Println("End Cycle")
|
fmt.Println("End Cycle")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out = c.compile_varsub(varholder + varbit, cur)
|
out = c.compileVarsub(varholder+varbit, cur)
|
||||||
|
|
||||||
for _, varItem := range c.varList {
|
for _, varItem := range c.varList {
|
||||||
if strings.HasPrefix(out, varItem.Destination) {
|
if strings.HasPrefix(out, varItem.Destination) {
|
||||||
@ -395,7 +387,7 @@ func (c *CTemplateSet) compile_subswitch(varholder string, holdreflect reflect.V
|
|||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("Dot Node:", node.String())
|
fmt.Println("Dot Node:", node.String())
|
||||||
}
|
}
|
||||||
return c.compile_varsub(varholder, holdreflect)
|
return c.compileVarsub(varholder, holdreflect)
|
||||||
case *parse.NilNode:
|
case *parse.NilNode:
|
||||||
panic("Nil is not a command x.x")
|
panic("Nil is not a command x.x")
|
||||||
case *parse.VariableNode:
|
case *parse.VariableNode:
|
||||||
@ -403,8 +395,8 @@ func (c *CTemplateSet) compile_subswitch(varholder string, holdreflect reflect.V
|
|||||||
fmt.Println("Variable Node:", n.String())
|
fmt.Println("Variable Node:", n.String())
|
||||||
fmt.Println(n.Ident)
|
fmt.Println(n.Ident)
|
||||||
}
|
}
|
||||||
varname, reflectVal := c.compile_if_varsub(n.String(), varholder, template_name, holdreflect)
|
varname, reflectVal := c.compileIfVarsub(n.String(), varholder, templateName, holdreflect)
|
||||||
return c.compile_varsub(varname, reflectVal)
|
return c.compileVarsub(varname, reflectVal)
|
||||||
case *parse.StringNode:
|
case *parse.StringNode:
|
||||||
return n.Quoted
|
return n.Quoted
|
||||||
case *parse.IdentifierNode:
|
case *parse.IdentifierNode:
|
||||||
@ -412,16 +404,15 @@ func (c *CTemplateSet) compile_subswitch(varholder string, holdreflect reflect.V
|
|||||||
fmt.Println("Identifier Node:", node)
|
fmt.Println("Identifier Node:", node)
|
||||||
fmt.Println("Identifier Node Args:", node.Args)
|
fmt.Println("Identifier Node Args:", node.Args)
|
||||||
}
|
}
|
||||||
return c.compile_varsub(c.compile_identswitch(varholder, holdreflect, template_name, node))
|
return c.compileVarsub(c.compileIdentswitch(varholder, holdreflect, templateName, node))
|
||||||
default:
|
default:
|
||||||
fmt.Println("Unknown Kind:", reflect.ValueOf(firstWord).Elem().Kind())
|
fmt.Println("Unknown Kind:", reflect.ValueOf(firstWord).Elem().Kind())
|
||||||
fmt.Println("Unknown Type:", reflect.ValueOf(firstWord).Elem().Type().Name())
|
fmt.Println("Unknown Type:", reflect.ValueOf(firstWord).Elem().Type().Name())
|
||||||
panic("I don't know what node this is")
|
panic("I don't know what node this is")
|
||||||
}
|
}
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_varswitch(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string) {
|
func (c *CTemplateSet) compileVarswitch(varholder string, holdreflect reflect.Value, templateName string, node *parse.CommandNode) (out string) {
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("in compile_varswitch")
|
fmt.Println("in compile_varswitch")
|
||||||
}
|
}
|
||||||
@ -436,7 +427,7 @@ func (c *CTemplateSet) compile_varswitch(varholder string, holdreflect reflect.V
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
|
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
|
||||||
return c.compile_boolsub(n.String(), varholder, template_name, holdreflect)
|
return c.compileBoolsub(n.String(), varholder, templateName, holdreflect)
|
||||||
case *parse.ChainNode:
|
case *parse.ChainNode:
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("Chain Node:", n.Node)
|
fmt.Println("Chain Node:", n.Node)
|
||||||
@ -448,7 +439,7 @@ func (c *CTemplateSet) compile_varswitch(varholder string, holdreflect reflect.V
|
|||||||
fmt.Println("Identifier Node:", node)
|
fmt.Println("Identifier Node:", node)
|
||||||
fmt.Println("Identifier Node Args:", node.Args)
|
fmt.Println("Identifier Node Args:", node.Args)
|
||||||
}
|
}
|
||||||
return c.compile_identswitch_n(varholder, holdreflect, template_name, node)
|
return c.compileIdentswitchN(varholder, holdreflect, templateName, node)
|
||||||
case *parse.DotNode:
|
case *parse.DotNode:
|
||||||
return varholder
|
return varholder
|
||||||
case *parse.VariableNode:
|
case *parse.VariableNode:
|
||||||
@ -456,7 +447,7 @@ func (c *CTemplateSet) compile_varswitch(varholder string, holdreflect reflect.V
|
|||||||
fmt.Println("Variable Node:", n.String())
|
fmt.Println("Variable Node:", n.String())
|
||||||
fmt.Println("Variable Node Identifier:", n.Ident)
|
fmt.Println("Variable Node Identifier:", n.Ident)
|
||||||
}
|
}
|
||||||
out, _ = c.compile_if_varsub(n.String(), varholder, template_name, holdreflect)
|
out, _ = c.compileIfVarsub(n.String(), varholder, templateName, holdreflect)
|
||||||
return out
|
return out
|
||||||
case *parse.NilNode:
|
case *parse.NilNode:
|
||||||
panic("Nil is not a command x.x")
|
panic("Nil is not a command x.x")
|
||||||
@ -466,7 +457,7 @@ func (c *CTemplateSet) compile_varswitch(varholder string, holdreflect reflect.V
|
|||||||
fmt.Println(n)
|
fmt.Println(n)
|
||||||
fmt.Println("Args:", node.Args)
|
fmt.Println("Args:", node.Args)
|
||||||
}
|
}
|
||||||
out += c.compile_identswitch_n(varholder, holdreflect, template_name, node)
|
out += c.compileIdentswitchN(varholder, holdreflect, templateName, node)
|
||||||
|
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("Out:", out)
|
fmt.Println("Out:", out)
|
||||||
@ -480,17 +471,17 @@ func (c *CTemplateSet) compile_varswitch(varholder string, holdreflect reflect.V
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_identswitch_n(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string) {
|
func (c *CTemplateSet) compileIdentswitchN(varholder string, holdreflect reflect.Value, templateName string, node *parse.CommandNode) (out string) {
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("in compile_identswitch_n")
|
fmt.Println("in compile_identswitch_n")
|
||||||
}
|
}
|
||||||
out, _ = c.compile_identswitch(varholder, holdreflect, template_name, node)
|
out, _ = c.compileIdentswitch(varholder, holdreflect, templateName, node)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_identswitch(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string, val reflect.Value) {
|
func (c *CTemplateSet) compileIdentswitch(varholder string, holdreflect reflect.Value, templateName string, node *parse.CommandNode) (out string, val reflect.Value) {
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("in compile_identswitch")
|
fmt.Println("in compileIdentswitch")
|
||||||
}
|
}
|
||||||
|
|
||||||
//var outbuf map[int]string
|
//var outbuf map[int]string
|
||||||
@ -511,21 +502,19 @@ func (c *CTemplateSet) compile_identswitch(varholder string, holdreflect reflect
|
|||||||
if pos == 0 {
|
if pos == 0 {
|
||||||
fmt.Println("pos:", pos)
|
fmt.Println("pos:", pos)
|
||||||
panic("or is missing a left operand")
|
panic("or is missing a left operand")
|
||||||
return out, val
|
|
||||||
}
|
}
|
||||||
if len(node.Args) <= pos {
|
if len(node.Args) <= pos {
|
||||||
fmt.Println("post pos:", pos)
|
fmt.Println("post pos:", pos)
|
||||||
fmt.Println("len(node.Args):", len(node.Args))
|
fmt.Println("len(node.Args):", len(node.Args))
|
||||||
panic("or is missing a right operand")
|
panic("or is missing a right operand")
|
||||||
return out, val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
left := c.compile_boolsub(node.Args[pos - 1].String(), varholder, template_name, holdreflect)
|
left := c.compileBoolsub(node.Args[pos-1].String(), varholder, templateName, holdreflect)
|
||||||
_, funcExists := c.funcMap[node.Args[pos+1].String()]
|
_, funcExists := c.funcMap[node.Args[pos+1].String()]
|
||||||
|
|
||||||
var right string
|
var right string
|
||||||
if !funcExists {
|
if !funcExists {
|
||||||
right = c.compile_boolsub(node.Args[pos + 1].String(), varholder, template_name, holdreflect)
|
right = c.compileBoolsub(node.Args[pos+1].String(), varholder, templateName, holdreflect)
|
||||||
}
|
}
|
||||||
|
|
||||||
out += left + " || " + right
|
out += left + " || " + right
|
||||||
@ -550,21 +539,19 @@ func (c *CTemplateSet) compile_identswitch(varholder string, holdreflect reflect
|
|||||||
if pos == 0 {
|
if pos == 0 {
|
||||||
fmt.Println("pos:", pos)
|
fmt.Println("pos:", pos)
|
||||||
panic("and is missing a left operand")
|
panic("and is missing a left operand")
|
||||||
return out, val
|
|
||||||
}
|
}
|
||||||
if len(node.Args) <= pos {
|
if len(node.Args) <= pos {
|
||||||
fmt.Println("post pos:", pos)
|
fmt.Println("post pos:", pos)
|
||||||
fmt.Println("len(node.Args):", len(node.Args))
|
fmt.Println("len(node.Args):", len(node.Args))
|
||||||
panic("and is missing a right operand")
|
panic("and is missing a right operand")
|
||||||
return out, val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
left := c.compile_boolsub(node.Args[pos - 1].String(), varholder, template_name, holdreflect)
|
left := c.compileBoolsub(node.Args[pos-1].String(), varholder, templateName, holdreflect)
|
||||||
_, funcExists := c.funcMap[node.Args[pos+1].String()]
|
_, funcExists := c.funcMap[node.Args[pos+1].String()]
|
||||||
|
|
||||||
var right string
|
var right string
|
||||||
if !funcExists {
|
if !funcExists {
|
||||||
right = c.compile_boolsub(node.Args[pos + 1].String(), varholder, template_name, holdreflect)
|
right = c.compileBoolsub(node.Args[pos+1].String(), varholder, templateName, holdreflect)
|
||||||
}
|
}
|
||||||
|
|
||||||
out += left + " && " + right
|
out += left + " && " + right
|
||||||
@ -583,50 +570,50 @@ func (c *CTemplateSet) compile_identswitch(varholder string, holdreflect reflect
|
|||||||
fmt.Println("len(node.Args):", len(node.Args))
|
fmt.Println("len(node.Args):", len(node.Args))
|
||||||
}
|
}
|
||||||
case "le":
|
case "le":
|
||||||
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " <= " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
|
out += c.compileIfVarsubN(node.Args[pos+1].String(), varholder, templateName, holdreflect) + " <= " + c.compileIfVarsubN(node.Args[pos+2].String(), varholder, templateName, holdreflect)
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("node.Args[pos + 1]", node.Args[pos+1])
|
fmt.Println("node.Args[pos + 1]", node.Args[pos+1])
|
||||||
fmt.Println("node.Args[pos + 2]", node.Args[pos+2])
|
fmt.Println("node.Args[pos + 2]", node.Args[pos+2])
|
||||||
}
|
}
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "lt":
|
case "lt":
|
||||||
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " < " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
|
out += c.compileIfVarsubN(node.Args[pos+1].String(), varholder, templateName, holdreflect) + " < " + c.compileIfVarsubN(node.Args[pos+2].String(), varholder, templateName, holdreflect)
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("node.Args[pos + 1]", node.Args[pos+1])
|
fmt.Println("node.Args[pos + 1]", node.Args[pos+1])
|
||||||
fmt.Println("node.Args[pos + 2]", node.Args[pos+2])
|
fmt.Println("node.Args[pos + 2]", node.Args[pos+2])
|
||||||
}
|
}
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "gt":
|
case "gt":
|
||||||
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " > " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
|
out += c.compileIfVarsubN(node.Args[pos+1].String(), varholder, templateName, holdreflect) + " > " + c.compileIfVarsubN(node.Args[pos+2].String(), varholder, templateName, holdreflect)
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("node.Args[pos + 1]", node.Args[pos+1])
|
fmt.Println("node.Args[pos + 1]", node.Args[pos+1])
|
||||||
fmt.Println("node.Args[pos + 2]", node.Args[pos+2])
|
fmt.Println("node.Args[pos + 2]", node.Args[pos+2])
|
||||||
}
|
}
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "ge":
|
case "ge":
|
||||||
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " >= " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
|
out += c.compileIfVarsubN(node.Args[pos+1].String(), varholder, templateName, holdreflect) + " >= " + c.compileIfVarsubN(node.Args[pos+2].String(), varholder, templateName, holdreflect)
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("node.Args[pos + 1]", node.Args[pos+1])
|
fmt.Println("node.Args[pos + 1]", node.Args[pos+1])
|
||||||
fmt.Println("node.Args[pos + 2]", node.Args[pos+2])
|
fmt.Println("node.Args[pos + 2]", node.Args[pos+2])
|
||||||
}
|
}
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "eq":
|
case "eq":
|
||||||
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " == " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
|
out += c.compileIfVarsubN(node.Args[pos+1].String(), varholder, templateName, holdreflect) + " == " + c.compileIfVarsubN(node.Args[pos+2].String(), varholder, templateName, holdreflect)
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("node.Args[pos + 1]", node.Args[pos+1])
|
fmt.Println("node.Args[pos + 1]", node.Args[pos+1])
|
||||||
fmt.Println("node.Args[pos + 2]", node.Args[pos+2])
|
fmt.Println("node.Args[pos + 2]", node.Args[pos+2])
|
||||||
}
|
}
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "ne":
|
case "ne":
|
||||||
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " != " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
|
out += c.compileIfVarsubN(node.Args[pos+1].String(), varholder, templateName, holdreflect) + " != " + c.compileIfVarsubN(node.Args[pos+2].String(), varholder, templateName, holdreflect)
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("node.Args[pos + 1]", node.Args[pos+1])
|
fmt.Println("node.Args[pos + 1]", node.Args[pos+1])
|
||||||
fmt.Println("node.Args[pos + 2]", node.Args[pos+2])
|
fmt.Println("node.Args[pos + 2]", node.Args[pos+2])
|
||||||
}
|
}
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "add":
|
case "add":
|
||||||
param1, val2 := c.compile_if_varsub(node.Args[pos + 1].String(), varholder, template_name, holdreflect)
|
param1, val2 := c.compileIfVarsub(node.Args[pos+1].String(), varholder, templateName, holdreflect)
|
||||||
param2, val3 := c.compile_if_varsub(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
|
param2, val3 := c.compileIfVarsub(node.Args[pos+2].String(), varholder, templateName, holdreflect)
|
||||||
|
|
||||||
if val2.IsValid() {
|
if val2.IsValid() {
|
||||||
val = val2
|
val = val2
|
||||||
@ -645,8 +632,8 @@ func (c *CTemplateSet) compile_identswitch(varholder string, holdreflect reflect
|
|||||||
}
|
}
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "subtract":
|
case "subtract":
|
||||||
param1, val2 := c.compile_if_varsub(node.Args[pos + 1].String(), varholder, template_name, holdreflect)
|
param1, val2 := c.compileIfVarsub(node.Args[pos+1].String(), varholder, templateName, holdreflect)
|
||||||
param2, val3 := c.compile_if_varsub(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
|
param2, val3 := c.compileIfVarsub(node.Args[pos+2].String(), varholder, templateName, holdreflect)
|
||||||
|
|
||||||
if val2.IsValid() {
|
if val2.IsValid() {
|
||||||
val = val2
|
val = val2
|
||||||
@ -665,8 +652,8 @@ func (c *CTemplateSet) compile_identswitch(varholder string, holdreflect reflect
|
|||||||
}
|
}
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "divide":
|
case "divide":
|
||||||
param1, val2 := c.compile_if_varsub(node.Args[pos + 1].String(), varholder, template_name, holdreflect)
|
param1, val2 := c.compileIfVarsub(node.Args[pos+1].String(), varholder, templateName, holdreflect)
|
||||||
param2, val3 := c.compile_if_varsub(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
|
param2, val3 := c.compileIfVarsub(node.Args[pos+2].String(), varholder, templateName, holdreflect)
|
||||||
|
|
||||||
if val2.IsValid() {
|
if val2.IsValid() {
|
||||||
val = val2
|
val = val2
|
||||||
@ -685,8 +672,8 @@ func (c *CTemplateSet) compile_identswitch(varholder string, holdreflect reflect
|
|||||||
}
|
}
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "multiply":
|
case "multiply":
|
||||||
param1, val2 := c.compile_if_varsub(node.Args[pos + 1].String(), varholder, template_name, holdreflect)
|
param1, val2 := c.compileIfVarsub(node.Args[pos+1].String(), varholder, templateName, holdreflect)
|
||||||
param2, val3 := c.compile_if_varsub(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
|
param2, val3 := c.compileIfVarsub(node.Args[pos+2].String(), varholder, templateName, holdreflect)
|
||||||
|
|
||||||
if val2.IsValid() {
|
if val2.IsValid() {
|
||||||
val = val2
|
val = val2
|
||||||
@ -709,12 +696,12 @@ func (c *CTemplateSet) compile_identswitch(varholder string, holdreflect reflect
|
|||||||
fmt.Println("Variable!")
|
fmt.Println("Variable!")
|
||||||
}
|
}
|
||||||
if len(node.Args) > (pos + 1) {
|
if len(node.Args) > (pos + 1) {
|
||||||
next_node := node.Args[pos + 1].String()
|
nextNode := node.Args[pos+1].String()
|
||||||
if next_node == "or" || next_node == "and" {
|
if nextNode == "or" || nextNode == "and" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out += c.compile_if_varsub_n(id.String(), varholder, template_name, holdreflect)
|
out += c.compileIfVarsubN(id.String(), varholder, templateName, holdreflect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -724,9 +711,9 @@ func (c *CTemplateSet) compile_identswitch(varholder string, holdreflect reflect
|
|||||||
return out, val
|
return out, val
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_reflectswitch(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string, outVal reflect.Value) {
|
func (c *CTemplateSet) compileReflectswitch(varholder string, holdreflect reflect.Value, templateName string, node *parse.CommandNode) (out string, outVal reflect.Value) {
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("in compile_reflectswitch")
|
fmt.Println("in compileReflectswitch")
|
||||||
}
|
}
|
||||||
firstWord := node.Args[0]
|
firstWord := node.Args[0]
|
||||||
switch n := firstWord.(type) {
|
switch n := firstWord.(type) {
|
||||||
@ -738,7 +725,7 @@ func (c *CTemplateSet) compile_reflectswitch(varholder string, holdreflect refle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
|
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
|
||||||
return c.compile_if_varsub(n.String(), varholder, template_name, holdreflect)
|
return c.compileIfVarsub(n.String(), varholder, templateName, holdreflect)
|
||||||
case *parse.ChainNode:
|
case *parse.ChainNode:
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("Chain Node:", n.Node)
|
fmt.Println("Chain Node:", n.Node)
|
||||||
@ -755,17 +742,17 @@ func (c *CTemplateSet) compile_reflectswitch(varholder string, holdreflect refle
|
|||||||
return "", outVal
|
return "", outVal
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_if_varsub_n(varname string, varholder string, template_name string, cur reflect.Value) (out string) {
|
func (c *CTemplateSet) compileIfVarsubN(varname string, varholder string, templateName string, cur reflect.Value) (out string) {
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("in compile_if_varsub_n")
|
fmt.Println("in compileIfVarsubN")
|
||||||
}
|
}
|
||||||
out, _ = c.compile_if_varsub(varname, varholder, template_name, cur)
|
out, _ = c.compileIfVarsub(varname, varholder, templateName, cur)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_if_varsub(varname string, varholder string, template_name string, cur reflect.Value) (out string, val reflect.Value) {
|
func (c *CTemplateSet) compileIfVarsub(varname string, varholder string, templateName string, cur reflect.Value) (out string, val reflect.Value) {
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("in compile_if_varsub")
|
fmt.Println("in compileIfVarsub")
|
||||||
}
|
}
|
||||||
if varname[0] != '.' && varname[0] != '$' {
|
if varname[0] != '.' && varname[0] != '$' {
|
||||||
return varname, cur
|
return varname, cur
|
||||||
@ -775,9 +762,9 @@ func (c *CTemplateSet) compile_if_varsub(varname string, varholder string, templ
|
|||||||
if varname[0] == '$' {
|
if varname[0] == '$' {
|
||||||
var res VarItemReflect
|
var res VarItemReflect
|
||||||
if varname[1] == '.' {
|
if varname[1] == '.' {
|
||||||
res = c.localVars[template_name]["."]
|
res = c.localVars[templateName]["."]
|
||||||
} else {
|
} else {
|
||||||
res = c.localVars[template_name][strings.TrimPrefix(bits[0],"$")]
|
res = c.localVars[templateName][strings.TrimPrefix(bits[0], "$")]
|
||||||
}
|
}
|
||||||
out += res.Destination
|
out += res.Destination
|
||||||
cur = res.Value
|
cur = res.Value
|
||||||
@ -869,16 +856,19 @@ func (c *CTemplateSet) compile_if_varsub(varname string, varholder string, templ
|
|||||||
return out, cur
|
return out, cur
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_boolsub(varname string, varholder string, template_name string, val reflect.Value) string {
|
func (c *CTemplateSet) compileBoolsub(varname string, varholder string, templateName string, val reflect.Value) string {
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("in compile_boolsub")
|
fmt.Println("in compileBoolsub")
|
||||||
}
|
}
|
||||||
out, val := c.compile_if_varsub(varname, varholder, template_name, val)
|
out, val := c.compileIfVarsub(varname, varholder, templateName, val)
|
||||||
switch val.Kind() {
|
switch val.Kind() {
|
||||||
case reflect.Int: out += " > 0"
|
case reflect.Int:
|
||||||
|
out += " > 0"
|
||||||
case reflect.Bool: // Do nothing
|
case reflect.Bool: // Do nothing
|
||||||
case reflect.String: out += " != \"\""
|
case reflect.String:
|
||||||
case reflect.Int64: out += " > 0"
|
out += " != \"\""
|
||||||
|
case reflect.Int64:
|
||||||
|
out += " > 0"
|
||||||
default:
|
default:
|
||||||
fmt.Println("Variable Name:", varname)
|
fmt.Println("Variable Name:", varname)
|
||||||
fmt.Println("Variable Holder:", varholder)
|
fmt.Println("Variable Holder:", varholder)
|
||||||
@ -888,9 +878,9 @@ func (c *CTemplateSet) compile_boolsub(varname string, varholder string, templat
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_varsub(varname string, val reflect.Value) string {
|
func (c *CTemplateSet) compileVarsub(varname string, val reflect.Value) string {
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("in compile_varsub")
|
fmt.Println("in compileVarsub")
|
||||||
}
|
}
|
||||||
for _, varItem := range c.varList {
|
for _, varItem := range c.varList {
|
||||||
if strings.HasPrefix(varname, varItem.Destination) {
|
if strings.HasPrefix(varname, varItem.Destination) {
|
||||||
@ -918,9 +908,8 @@ func (c *CTemplateSet) compile_varsub(varname string, val reflect.Value) string
|
|||||||
case reflect.String:
|
case reflect.String:
|
||||||
if val.Type().Name() != "string" && !strings.HasPrefix(varname, "string(") {
|
if val.Type().Name() != "string" && !strings.HasPrefix(varname, "string(") {
|
||||||
return "w.Write([]byte(string(" + varname + ")))\n"
|
return "w.Write([]byte(string(" + varname + ")))\n"
|
||||||
} else {
|
|
||||||
return "w.Write([]byte(" + varname + "))\n"
|
|
||||||
}
|
}
|
||||||
|
return "w.Write([]byte(" + varname + "))\n"
|
||||||
case reflect.Int64:
|
case reflect.Int64:
|
||||||
c.importMap["strconv"] = "strconv"
|
c.importMap["strconv"] = "strconv"
|
||||||
return "w.Write([]byte(strconv.FormatInt(" + varname + ", 10)))"
|
return "w.Write([]byte(strconv.FormatInt(" + varname + ", 10)))"
|
||||||
@ -935,9 +924,9 @@ func (c *CTemplateSet) compile_varsub(varname string, val reflect.Value) string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_subtemplate(pvarholder string, pholdreflect reflect.Value, node *parse.TemplateNode) (out string) {
|
func (c *CTemplateSet) compileSubtemplate(pvarholder string, pholdreflect reflect.Value, node *parse.TemplateNode) (out string) {
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
fmt.Println("in compile_subtemplate")
|
fmt.Println("in compileSubtemplate")
|
||||||
fmt.Println("Template Node:", node.Name)
|
fmt.Println("Template Node:", node.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -956,7 +945,7 @@ func (c *CTemplateSet) compile_subtemplate(pvarholder string, pholdreflect refle
|
|||||||
panic("Nil is not a command x.x")
|
panic("Nil is not a command x.x")
|
||||||
default:
|
default:
|
||||||
out = "var " + varholder + " := false\n"
|
out = "var " + varholder + " := false\n"
|
||||||
out += c.compile_command(cmd)
|
out += c.compileCommand(cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -973,7 +962,7 @@ func (c *CTemplateSet) compile_subtemplate(pvarholder string, pholdreflect refle
|
|||||||
}
|
}
|
||||||
|
|
||||||
tree := parse.New(node.Name, c.funcMap)
|
tree := parse.New(node.Name, c.funcMap)
|
||||||
var treeSet map[string]*parse.Tree = make(map[string]*parse.Tree)
|
var treeSet = make(map[string]*parse.Tree)
|
||||||
tree, err = tree.Parse(content, "{{", "}}", treeSet, c.funcMap)
|
tree, err = tree.Parse(content, "{{", "}}", treeSet, c.funcMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -1000,14 +989,13 @@ func (c *CTemplateSet) compile_subtemplate(pvarholder string, pholdreflect refle
|
|||||||
if treeLength != (index + 1) {
|
if treeLength != (index + 1) {
|
||||||
c.nextNode = subtree.Root.Nodes[index+1].Type()
|
c.nextNode = subtree.Root.Nodes[index+1].Type()
|
||||||
}
|
}
|
||||||
out += c.compile_switch(varholder, holdreflect, fname, node)
|
out += c.compileSwitch(varholder, holdreflect, fname, node)
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compile_command(*parse.CommandNode) (out string) {
|
func (c *CTemplateSet) compileCommand(*parse.CommandNode) (out string) {
|
||||||
panic("Uh oh! Something went wrong!")
|
panic("Uh oh! Something went wrong!")
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: Write unit tests for this
|
// TO-DO: Write unit tests for this
|
||||||
@ -1023,7 +1011,7 @@ func minify(data string) string {
|
|||||||
// TO-DO: Strip comments
|
// TO-DO: Strip comments
|
||||||
// TO-DO: Handle CSS nested in <style> tags?
|
// TO-DO: Handle CSS nested in <style> tags?
|
||||||
// TO-DO: Write unit tests for this
|
// TO-DO: Write unit tests for this
|
||||||
func minify_html(data string) string {
|
func minifyHTML(data string) string {
|
||||||
return minify(data)
|
return minify(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1031,19 +1019,20 @@ func minify_html(data string) string {
|
|||||||
// TO-DO: Strip comments
|
// TO-DO: Strip comments
|
||||||
// TO-DO: Convert the rgb()s to hex codes?
|
// TO-DO: Convert the rgb()s to hex codes?
|
||||||
// TO-DO: Write unit tests for this
|
// TO-DO: Write unit tests for this
|
||||||
func minify_css(data string) string {
|
func minifyCSS(data string) string {
|
||||||
return minify(data)
|
return minify(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: Convert this to three character hex strings whenever possible?
|
// TO-DO: Convert this to three character hex strings whenever possible?
|
||||||
// TO-DO: Write unit tests for this
|
// TO-DO: Write unit tests for this
|
||||||
func rgb_to_hexstr(red int, green int, blue int) string {
|
// nolint
|
||||||
|
func rgbToHexstr(red int, green int, blue int) string {
|
||||||
return strconv.FormatInt(int64(red), 16) + strconv.FormatInt(int64(green), 16) + strconv.FormatInt(int64(blue), 16)
|
return strconv.FormatInt(int64(red), 16) + strconv.FormatInt(int64(green), 16) + strconv.FormatInt(int64(blue), 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// TO-DO: Write unit tests for this
|
// TO-DO: Write unit tests for this
|
||||||
func hexstr_to_rgb(hexstr string) (red int, blue int, green int, err error) {
|
func hexstrToRgb(hexstr string) (red int, blue int, green int, err error) {
|
||||||
// Strip the # at the start
|
// Strip the # at the start
|
||||||
if hexstr[0] == '#' {
|
if hexstr[0] == '#' {
|
||||||
hexstr = strings.TrimPrefix(hexstr,"#")
|
hexstr = strings.TrimPrefix(hexstr,"#")
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div id="forum_topic_list" class="rowblock topic_list">
|
<div id="forum_topic_list" class="rowblock topic_list">
|
||||||
{{range .ItemList}}<div class="rowitem topic_left passive datarow {{if .Sticky}}topic_sticky{{else if .Is_Closed}}topic_closed{{end}}" style="{{if .Creator.Avatar}}background-image: url({{.Creator.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}">
|
{{range .ItemList}}<div class="rowitem topic_left passive datarow {{if .Sticky}}topic_sticky{{else if .IsClosed}}topic_closed{{end}}" style="{{if .Creator.Avatar}}background-image: url({{.Creator.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}">
|
||||||
<span class="topic_inner_right rowsmall" style="float: right;">
|
<span class="topic_inner_right rowsmall" style="float: right;">
|
||||||
<span class="replyCount">{{.PostCount}} replies</span><br />
|
<span class="replyCount">{{.PostCount}} replies</span><br />
|
||||||
<span class="lastReplyAt">{{.LastReplyAt}}</span>
|
<span class="lastReplyAt">{{.LastReplyAt}}</span>
|
||||||
@ -25,8 +25,8 @@
|
|||||||
<span>
|
<span>
|
||||||
<a class="rowtopic" href="{{.Link}}">{{.Title}}</a>
|
<a class="rowtopic" href="{{.Link}}">{{.Title}}</a>
|
||||||
<br /><a class="rowsmall" href="{{.Creator.Link}}">Starter: {{.Creator.Name}}</a>
|
<br /><a class="rowsmall" href="{{.Creator.Link}}">Starter: {{.Creator.Name}}</a>
|
||||||
{{/** TO-DO: Avoid the double '|' when both .Is_Closed and .Sticky are set to true. We could probably do this with CSS **/}}
|
{{/** TO-DO: Avoid the double '|' when both .IsClosed and .Sticky are set to true. We could probably do this with CSS **/}}
|
||||||
{{if .Is_Closed}}<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎</span>{{end}}
|
{{if .IsClosed}}<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎</span>{{end}}
|
||||||
{{if .Sticky}}<span class="rowsmall topic_status_e topic_status_sticky" title="Status: Pinned"> | 📍︎</span>{{end}}
|
{{if .Sticky}}<span class="rowsmall topic_status_e topic_status_sticky" title="Status: Pinned"> | 📍︎</span>{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>{{.Title}}</title>
|
<title>{{.Title}}</title>
|
||||||
<link href="/static/main.css" rel="stylesheet" type="text/css">
|
<link href="/static/{{.Header.ThemeName}}/main.css" rel="stylesheet" type="text/css">
|
||||||
{{range .Header.Stylesheets}}
|
{{range .Header.Stylesheets}}
|
||||||
<link href="/static/{{.}}" rel="stylesheet" type="text/css">
|
<link href="/static/{{.}}" rel="stylesheet" type="text/css">
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -15,7 +15,7 @@
|
|||||||
<meta name="viewport" content="width=device-width,initial-scale = 1.0, maximum-scale=1.0,user-scalable=no" />
|
<meta name="viewport" content="width=device-width,initial-scale = 1.0, maximum-scale=1.0,user-scalable=no" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<style>{{if not .CurrentUser.Is_Super_Mod}}.supermod_only { display: none !important; }{{end}}</style>
|
<style>{{if not .CurrentUser.IsSuperMod}}.supermod_only { display: none !important; }{{end}}</style>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
{{template "menu.html" .}}
|
{{template "menu.html" .}}
|
||||||
<div id="back"><div id="main" {{if .Header.Widgets.RightSidebar}}class="shrink_main"{{end}}>
|
<div id="back"><div id="main" {{if .Header.Widgets.RightSidebar}}class="shrink_main"{{end}}>
|
||||||
|
18
templates/ip-search.html
Normal file
18
templates/ip-search.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{{template "header.html" . }}
|
||||||
|
<main>
|
||||||
|
|
||||||
|
<div class="rowblock opthead">
|
||||||
|
<div class="rowitem"><a>IP Search</a></div>
|
||||||
|
</div>
|
||||||
|
<div class="rowblock">
|
||||||
|
<div class="rowitem passive">Searching for {{.IP}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rowblock rowlist bgavatars">
|
||||||
|
{{range .ItemList}}<div class="rowitem" style="{{if .Avatar}}background-image: url('{{.Avatar}}');{{end}}">
|
||||||
|
<a href="{{.Link}}">{{.Name}}</a>
|
||||||
|
</div>
|
||||||
|
{{else}}<div class="rowitem passive">No users found.</div>{{end}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
{{template "footer.html" . }}
|
@ -1,7 +1,7 @@
|
|||||||
<nav class="nav">
|
<nav class="nav">
|
||||||
<div class="move_left">
|
<div class="move_left">
|
||||||
<div class="move_right">
|
<div class="move_right">
|
||||||
<ul>
|
<ul>{{/** Add a menu manager **/}}
|
||||||
<li class="menu_left menu_overview"><a href="/" rel="home">{{.Header.Site.Name}}</a></li>
|
<li class="menu_left menu_overview"><a href="/" rel="home">{{.Header.Site.Name}}</a></li>
|
||||||
<li class="menu_left menu_forums"><a href="/forums/">Forums</a></li>
|
<li class="menu_left menu_forums"><a href="/forums/">Forums</a></li>
|
||||||
<li class="menu_left menu_topics"><a href="/">Topics</a></li>
|
<li class="menu_left menu_topics"><a href="/">Topics</a></li>
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
<div class="rowitem passive">
|
<div class="rowitem passive">
|
||||||
<a href="/panel/logs/mod/">Logs</a>
|
<a href="/panel/logs/mod/">Logs</a>
|
||||||
</div>
|
</div>
|
||||||
{{if .CurrentUser.Is_Admin}}<div class="rowitem passive">
|
{{if .CurrentUser.IsAdmin}}<div class="rowitem passive">
|
||||||
<a href="/panel/debug/">Debug</a>
|
<a href="/panel/debug/">Debug</a>
|
||||||
</div>{{end}}
|
</div>{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,10 +10,10 @@
|
|||||||
<div class="rowitem editable_parent" style="{{if .Avatar}}background-image: url('{{.Avatar}}');{{end}}">
|
<div class="rowitem editable_parent" style="{{if .Avatar}}background-image: url('{{.Avatar}}');{{end}}">
|
||||||
<a {{if $.CurrentUser.Perms.EditUser}}href="/panel/users/edit/{{.ID}}?session={{$.CurrentUser.Session}} "{{end}}class="editable_block">{{.Name}}</a>
|
<a {{if $.CurrentUser.Perms.EditUser}}href="/panel/users/edit/{{.ID}}?session={{$.CurrentUser.Session}} "{{end}}class="editable_block">{{.Name}}</a>
|
||||||
<a href="/user/{{.ID}}" class="tag-mini">Profile</a>
|
<a href="/user/{{.ID}}" class="tag-mini">Profile</a>
|
||||||
{{if (.Tag) and (.Is_Super_Mod)}}<span style="float: right;"><span class="panel_tag" style="margin-left 4px;">{{.Tag}}</span></span>{{end}}
|
{{if (.Tag) and (.IsSuperMod)}}<span style="float: right;"><span class="panel_tag" style="margin-left 4px;">{{.Tag}}</span></span>{{end}}
|
||||||
|
|
||||||
<span class="panel_floater">
|
<span class="panel_floater">
|
||||||
{{if .Is_Banned}}<a href="/users/unban/{{.ID}}?session={{$.CurrentUser.Session}}" class="panel_tag panel_right_button ban_button">Unban</a>{{else if not .Is_Super_Mod}}<a href="/user/{{.ID}}#ban_user" class="panel_tag panel_right_button ban_button">Ban</a>{{end}}
|
{{if .IsBanned}}<a href="/users/unban/{{.ID}}?session={{$.CurrentUser.Session}}" class="panel_tag panel_right_button ban_button">Unban</a>{{else if not .IsSuperMod}}<a href="/user/{{.ID}}#ban_user" class="panel_tag panel_right_button ban_button">Ban</a>{{end}}
|
||||||
{{if not .Active}}<a href="/users/activate/{{.ID}}?session={{$.CurrentUser.Session}}" class="panel_tag panel_right_button">Activate</a>{{end}}
|
{{if not .Active}}<a href="/users/activate/{{.ID}}?session={{$.CurrentUser.Session}}" class="panel_tag panel_right_button">Activate</a>{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
<div class="rowitem passive">
|
<div class="rowitem passive">
|
||||||
<a class="profile_menu_item">Add Friend</a>
|
<a class="profile_menu_item">Add Friend</a>
|
||||||
</div>
|
</div>
|
||||||
{{if (.CurrentUser.Is_Super_Mod) and not (.ProfileOwner.Is_Super_Mod) }}<div class="rowitem passive">
|
{{if (.CurrentUser.IsSuperMod) and not (.ProfileOwner.IsSuperMod) }}<div class="rowitem passive">
|
||||||
{{if .ProfileOwner.Is_Banned }}<a href="/users/unban/{{.ProfileOwner.ID}}?session={{.CurrentUser.Session}}" class="profile_menu_item">Unban</a>
|
{{if .ProfileOwner.IsBanned }}<a href="/users/unban/{{.ProfileOwner.ID}}?session={{.CurrentUser.Session}}" class="profile_menu_item">Unban</a>
|
||||||
{{else}}<a href="#ban_user" class="profile_menu_item">Ban</a>{{end}}
|
{{else}}<a href="#ban_user" class="profile_menu_item">Ban</a>{{end}}
|
||||||
</div>{{end}}
|
</div>{{end}}
|
||||||
<div class="rowitem passive">
|
<div class="rowitem passive">
|
||||||
@ -73,7 +73,7 @@
|
|||||||
<span class="controls">
|
<span class="controls">
|
||||||
<a href="{{.UserLink}}" class="real_username username">{{.CreatedByName}}</a>
|
<a href="{{.UserLink}}" class="real_username username">{{.CreatedByName}}</a>
|
||||||
|
|
||||||
{{if $.CurrentUser.Is_Mod}}<a href="/profile/reply/edit/submit/{{.ID}}" class="mod_button" title="Edit Item"><button class="username edit_item edit_label"></button></a>
|
{{if $.CurrentUser.IsMod}}<a href="/profile/reply/edit/submit/{{.ID}}" class="mod_button" title="Edit Item"><button class="username edit_item edit_label"></button></a>
|
||||||
|
|
||||||
<a href="/profile/reply/delete/submit/{{.ID}}" class="mod_button" title="Delete Item"><button class="username delete_item trash_label"></button></a>{{end}}
|
<a href="/profile/reply/delete/submit/{{.ID}}" class="mod_button" title="Delete Item"><button class="username delete_item trash_label"></button></a>{{end}}
|
||||||
|
|
||||||
@ -84,7 +84,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}</div>
|
{{end}}</div>
|
||||||
|
|
||||||
{{if not .CurrentUser.Is_Banned}}
|
{{if not .CurrentUser.IsBanned}}
|
||||||
<form id="profile_comments_form" class="hash_hide" action="/profile/reply/create/" method="post">
|
<form id="profile_comments_form" class="hash_hide" action="/profile/reply/create/" method="post">
|
||||||
<input name="uid" value='{{.ProfileOwner.ID}}' type="hidden" />
|
<input name="uid" value='{{.ProfileOwner.ID}}' type="hidden" />
|
||||||
<div class="colstack_item topic_reply_form" style="border-top: none;">
|
<div class="colstack_item topic_reply_form" style="border-top: none;">
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<div style="clear: both;"></div>
|
<div style="clear: both;"></div>
|
||||||
</div>
|
</div>
|
||||||
<main id="forum_topic_list" class="rowblock topic_list" style="position: relative;z-index: 50;">
|
<main id="forum_topic_list" class="rowblock topic_list" style="position: relative;z-index: 50;">
|
||||||
{{range .ItemList}}<div class="rowitem topic_left passive datarow" style="{{if .Creator.Avatar}}background-image: url({{.Creator.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}{{if .Sticky}}background-color: #FFFFCC;{{else if .Is_Closed}}background-color: #eaeaea;{{end}}">
|
{{range .ItemList}}<div class="rowitem topic_left passive datarow" style="{{if .Creator.Avatar}}background-image: url({{.Creator.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}{{if .Sticky}}background-color: #FFFFCC;{{else if .IsClosed}}background-color: #eaeaea;{{end}}">
|
||||||
<span class="topic_inner_right rowsmall" style="float: right;">
|
<span class="topic_inner_right rowsmall" style="float: right;">
|
||||||
<span class="replyCount">{{.PostCount}} replies</span><br />
|
<span class="replyCount">{{.PostCount}} replies</span><br />
|
||||||
<span class="lastReplyAt">{{.LastReplyAt}}</span>
|
<span class="lastReplyAt">{{.LastReplyAt}}</span>
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<span>
|
<span>
|
||||||
<a class="rowtopic" href="{{.Link}}">{{.Title}}</a>
|
<a class="rowtopic" href="{{.Link}}">{{.Title}}</a>
|
||||||
<br /><a class="rowsmall" href="{{.Creator.Link}}">Starter: {{.Creator.Name}}</a>
|
<br /><a class="rowsmall" href="{{.Creator.Link}}">Starter: {{.Creator.Name}}</a>
|
||||||
{{if .Is_Closed}}<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎{{end}}</span>
|
{{if .IsClosed}}<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎{{end}}</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="rowitem topic_right passive datarow" style="{{if .LastUser.Avatar}}background-image: url({{.LastUser.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}">
|
<div class="rowitem topic_right passive datarow" style="{{if .LastUser.Avatar}}background-image: url({{.LastUser.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}">
|
||||||
|
@ -11,9 +11,9 @@
|
|||||||
<main>
|
<main>
|
||||||
|
|
||||||
<div class="rowblock rowhead topic_block">
|
<div class="rowblock rowhead topic_block">
|
||||||
<div class="rowitem topic_item{{if .Topic.Sticky}} topic_sticky_head{{else if .Topic.Is_Closed}} topic_closed_head{{end}}">
|
<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>
|
<h1 class='topic_name hide_on_edit'>{{.Topic.Title}}</h1>
|
||||||
{{if .Topic.Is_Closed}}<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' style="font-weight:normal;float: right;position:relative;top:-5px;">🔒︎</span>{{end}}
|
||||||
{{if .CurrentUser.Perms.EditTopic}}
|
{{if .CurrentUser.Perms.EditTopic}}
|
||||||
<input form='edit_topic_form' class='show_on_edit topic_name_input' name="topic_name" value='{{.Topic.Title}}' type="text" />
|
<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;'>
|
{{if .CurrentUser.Perms.CloseTopic}}<select form='edit_topic_form' name="topic_status" class='show_on_edit topic_status_input' style='float: right;'>
|
||||||
@ -41,6 +41,7 @@
|
|||||||
{{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.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.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.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>
|
<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>
|
||||||
|
|
||||||
{{if .Topic.LikeCount}}<a class="username hide_on_micro like_count">{{.Topic.LikeCount}}</a><a class="username hide_on_micro like_count_label" title="Like Count"></a>{{end}}
|
{{if .Topic.LikeCount}}<a class="username hide_on_micro like_count">{{.Topic.LikeCount}}</a><a class="username hide_on_micro like_count_label" title="Like Count"></a>{{end}}
|
||||||
@ -67,6 +68,7 @@
|
|||||||
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" class="mod_button" title="Edit Reply"><button class="username edit_item edit_label"></button></a>{{end}}
|
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" class="mod_button" title="Edit Reply"><button class="username edit_item edit_label"></button></a>{{end}}
|
||||||
|
|
||||||
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" class="mod_button" title="Delete Reply"><button class="username delete_item trash_label"></button></a>{{end}}
|
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" class="mod_button" title="Delete Reply"><button class="username delete_item trash_label"></button></a>{{end}}
|
||||||
|
{{if $.CurrentUser.Perms.ViewIPs}}<a class="mod_button" href='/users/ips/{{.IPAddress}}' style="font-weight:normal;" title="View IP"><button class="username ip_label"></button></a>{{end}}
|
||||||
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="mod_button report_item" title="Flag Reply"><button class="username report_item flag_label"></button></a>
|
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="mod_button report_item" title="Flag Reply"><button class="username report_item flag_label"></button></a>
|
||||||
|
|
||||||
{{if .LikeCount}}<a class="username hide_on_micro like_count">{{.LikeCount}}</a><a class="username hide_on_micro like_count_label" title="Like Count"></a>{{end}}
|
{{if .LikeCount}}<a class="username hide_on_micro like_count">{{.LikeCount}}</a><a class="username hide_on_micro like_count_label" title="Like Count"></a>{{end}}
|
||||||
|
@ -7,9 +7,9 @@
|
|||||||
|
|
||||||
<div class="rowblock rowhead topic_block">
|
<div class="rowblock rowhead topic_block">
|
||||||
<form action='/topic/edit/submit/{{.Topic.ID}}' method="post">
|
<form action='/topic/edit/submit/{{.Topic.ID}}' method="post">
|
||||||
<div class="rowitem topic_item{{if .Topic.Sticky}} topic_sticky_head{{else if .Topic.Is_Closed}} topic_closed_head{{end}}">
|
<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>
|
<h1 class='topic_name hide_on_edit'>{{.Topic.Title}}</h1>
|
||||||
{{if .Topic.Is_Closed}}<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' style="font-weight:normal;float: right;position:relative;top:-5px;">🔒︎</span>{{end}}
|
||||||
{{if .CurrentUser.Perms.EditTopic}}
|
{{if .CurrentUser.Perms.EditTopic}}
|
||||||
<input class='show_on_edit topic_name_input' name="topic_name" value='{{.Topic.Title}}' type="text" />
|
<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;'>
|
{{if .CurrentUser.Perms.CloseTopic}}<select name="topic_status" class='show_on_edit topic_status_input' style='float: right;'>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
{{if .CurrentUser.Perms.PinTopic}}
|
{{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}}
|
{{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>
|
<a href="/report/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}&type=topic" class="action_button report_item">Report</a>
|
||||||
{{if .CurrentUser.Perms.ViewIPs}}<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">{{.Topic.IpAddress}}</a>{{end}}
|
{{if .CurrentUser.Perms.ViewIPs}}<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">{{.Topic.IPAddress}}</a>{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="action_button action_button_right hide_on_mobile">{{.Topic.CreatedAt}}</a>
|
<a class="action_button action_button_right hide_on_mobile">{{.Topic.CreatedAt}}</a>
|
||||||
{{if .Topic.LikeCount}}<a class="action_button action_button_right hide_on_micro">{{.Topic.LikeCount}} up</a>{{end}}
|
{{if .Topic.LikeCount}}<a class="action_button action_button_right hide_on_micro">{{.Topic.LikeCount}} up</a>{{end}}
|
||||||
@ -68,7 +68,7 @@
|
|||||||
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" class="action_button edit_item">Edit</a>{{end}}
|
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" class="action_button edit_item">Edit</a>{{end}}
|
||||||
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" class="action_button delete_item">Delete</a>{{end}}
|
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" class="action_button delete_item">Delete</a>{{end}}
|
||||||
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="action_button report_item">Report</a>
|
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="action_button report_item">Report</a>
|
||||||
{{if $.CurrentUser.Perms.ViewIPs}}<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">{{.IpAddress}}</a>{{end}}
|
{{if $.CurrentUser.Perms.ViewIPs}}<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">{{.IPAddress}}</a>{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="action_button action_button_right hide_on_mobile">{{.CreatedAt}}</a>
|
<a class="action_button action_button_right hide_on_mobile">{{.CreatedAt}}</a>
|
||||||
{{if .LikeCount}}<a class="action_button action_button_right hide_on_micro">{{.LikeCount}} up</a>{{end}}
|
{{if .LikeCount}}<a class="action_button action_button_right hide_on_micro">{{.LikeCount}} up</a>{{end}}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<div class="rowitem"><h1>Topic List</h1></div>
|
<div class="rowitem"><h1>Topic List</h1></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="topic_list" class="rowblock topic_list">
|
<div id="topic_list" class="rowblock topic_list">
|
||||||
{{range .ItemList}}<div class="rowitem topic_left passive datarow {{if .Sticky}}topic_sticky{{else if .Is_Closed}}topic_closed{{end}}" style="{{if .Creator.Avatar}}background-image: url({{.Creator.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}">
|
{{range .ItemList}}<div class="rowitem topic_left passive datarow {{if .Sticky}}topic_sticky{{else if .IsClosed}}topic_closed{{end}}" style="{{if .Creator.Avatar}}background-image: url({{.Creator.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}">
|
||||||
<span class="topic_inner_right rowsmall" style="float: right;">
|
<span class="topic_inner_right rowsmall" style="float: right;">
|
||||||
<span class="replyCount">{{.PostCount}} replies</span><br />
|
<span class="replyCount">{{.PostCount}} replies</span><br />
|
||||||
<span class="lastReplyAt">{{.LastReplyAt}}</span>
|
<span class="lastReplyAt">{{.LastReplyAt}}</span>
|
||||||
@ -13,8 +13,8 @@
|
|||||||
<span>
|
<span>
|
||||||
<a class="rowtopic" href="{{.Link}}">{{.Title}}</a> {{if .ForumName}}<a class="rowsmall" href="{{.ForumLink}}">{{.ForumName}}</a>{{end}}
|
<a class="rowtopic" href="{{.Link}}">{{.Title}}</a> {{if .ForumName}}<a class="rowsmall" href="{{.ForumLink}}">{{.ForumName}}</a>{{end}}
|
||||||
<br /><a class="rowsmall" href="{{.Creator.Link}}">Starter: {{.Creator.Name}}</a>
|
<br /><a class="rowsmall" href="{{.Creator.Link}}">Starter: {{.Creator.Name}}</a>
|
||||||
{{/** TO-DO: Avoid the double '|' when both .Is_Closed and .Sticky are set to true. We could probably do this with CSS **/}}
|
{{/** TO-DO: Avoid the double '|' when both .IsClosed and .Sticky are set to true. We could probably do this with CSS **/}}
|
||||||
{{if .Is_Closed}}<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎</span>{{end}}
|
{{if .IsClosed}}<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎</span>{{end}}
|
||||||
{{if .Sticky}}<span class="rowsmall topic_status_e topic_status_sticky" title="Status: Pinned"> | 📍︎</span>{{end}}
|
{{if .Sticky}}<span class="rowsmall topic_status_e topic_status_sticky" title="Status: Pinned"> | 📍︎</span>{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
270
themes.go
270
themes.go
@ -3,26 +3,27 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
//"fmt"
|
//"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
|
||||||
"errors"
|
|
||||||
"mime"
|
|
||||||
"io/ioutil"
|
|
||||||
"path/filepath"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultTheme string
|
var defaultTheme string
|
||||||
var themes map[string]Theme = make(map[string]Theme)
|
var themes = make(map[string]Theme)
|
||||||
//var overriden_templates map[string]interface{} = make(map[string]interface{})
|
|
||||||
var overriden_templates map[string]bool = make(map[string]bool)
|
|
||||||
|
|
||||||
type Theme struct
|
//var overridenTemplates map[string]interface{} = make(map[string]interface{})
|
||||||
{
|
var overridenTemplates = make(map[string]bool)
|
||||||
|
|
||||||
|
type Theme struct {
|
||||||
Name string
|
Name string
|
||||||
FriendlyName string
|
FriendlyName string
|
||||||
Version string
|
Version string
|
||||||
@ -39,7 +40,7 @@ type Theme struct
|
|||||||
Settings map[string]ThemeSetting
|
Settings map[string]ThemeSetting
|
||||||
Templates []TemplateMapping
|
Templates []TemplateMapping
|
||||||
TemplatesMap map[string]string
|
TemplatesMap map[string]string
|
||||||
TmplPtr map[string]interface{} // Coming Soon
|
TmplPtr map[string]interface{}
|
||||||
Resources []ThemeResource
|
Resources []ThemeResource
|
||||||
ResourceTemplates *template.Template
|
ResourceTemplates *template.Template
|
||||||
|
|
||||||
@ -47,21 +48,18 @@ type Theme struct
|
|||||||
Active bool
|
Active bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ThemeSetting struct
|
type ThemeSetting struct {
|
||||||
{
|
|
||||||
FriendlyName string
|
FriendlyName string
|
||||||
Options []string
|
Options []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type TemplateMapping struct
|
type TemplateMapping struct {
|
||||||
{
|
|
||||||
Name string
|
Name string
|
||||||
Source string
|
Source string
|
||||||
//When string
|
//When string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ThemeResource struct
|
type ThemeResource struct {
|
||||||
{
|
|
||||||
Name string
|
Name string
|
||||||
Location string
|
Location string
|
||||||
}
|
}
|
||||||
@ -88,9 +86,11 @@ func LoadThemes() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
theme.TemplatesMap = make(map[string]string)
|
theme.TemplatesMap = make(map[string]string)
|
||||||
|
theme.TmplPtr = make(map[string]interface{})
|
||||||
if theme.Templates != nil {
|
if theme.Templates != nil {
|
||||||
for _, themeTmpl := range theme.Templates {
|
for _, themeTmpl := range theme.Templates {
|
||||||
theme.TemplatesMap[themeTmpl.Name] = themeTmpl.Source
|
theme.TemplatesMap[themeTmpl.Name] = themeTmpl.Source
|
||||||
|
theme.TmplPtr[themeTmpl.Name] = tmplPtrMap["o_"+themeTmpl.Source]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,24 +101,25 @@ func LoadThemes() error {
|
|||||||
log.Print("Loading the theme '" + theme.Name + "'")
|
log.Print("Loading the theme '" + theme.Name + "'")
|
||||||
theme.Active = true
|
theme.Active = true
|
||||||
defaultTheme = uname
|
defaultTheme = uname
|
||||||
add_theme_static_files(theme)
|
mapThemeTemplates(theme)
|
||||||
map_theme_templates(theme)
|
|
||||||
} else {
|
} else {
|
||||||
theme.Active = false
|
theme.Active = false
|
||||||
}
|
}
|
||||||
themes[uname] = theme
|
|
||||||
}
|
// It should be safe for us to load the files for all the themes in memory, as-long as the admin hasn't setup a ridiculous number of themes
|
||||||
err = rows.Err()
|
err = addThemeStaticFiles(theme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
themes[uname] = theme
|
||||||
|
}
|
||||||
|
return rows.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func init_themes() {
|
func initThemes() error {
|
||||||
themeFiles, err := ioutil.ReadDir("./themes")
|
themeFiles, err := ioutil.ReadDir("./themes")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, themeFile := range themeFiles {
|
for _, themeFile := range themeFiles {
|
||||||
@ -130,13 +131,13 @@ func init_themes() {
|
|||||||
log.Print("Adding theme '" + themeName + "'")
|
log.Print("Adding theme '" + themeName + "'")
|
||||||
themeFile, err := ioutil.ReadFile("./themes/" + themeName + "/theme.json")
|
themeFile, err := ioutil.ReadFile("./themes/" + themeName + "/theme.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var theme Theme
|
var theme Theme
|
||||||
err = json.Unmarshal(themeFile, &theme)
|
err = json.Unmarshal(themeFile, &theme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
theme.Active = false // Set this to false, just in case someone explicitly overrode this value in the JSON file
|
theme.Active = false // Set this to false, just in case someone explicitly overrode this value in the JSON file
|
||||||
@ -145,19 +146,20 @@ func init_themes() {
|
|||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Adding theme image")
|
log.Print("Adding theme image")
|
||||||
}
|
}
|
||||||
err = add_static_file("./themes/" + themeName + "/" + theme.FullImage, "./themes/" + themeName)
|
err = addStaticFile("./themes/"+themeName+"/"+theme.FullImage, "./themes/"+themeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
themes[theme.Name] = theme
|
themes[theme.Name] = theme
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func add_theme_static_files(theme Theme) {
|
func addThemeStaticFiles(theme Theme) error {
|
||||||
// TO-DO: Use a function instead of a closure to make this more testable? What about a function call inside the closure to take the theme variable into account?
|
// TO-DO: Use a function instead of a closure to make this more testable? What about a function call inside the closure to take the theme variable into account?
|
||||||
err := filepath.Walk("./themes/" + theme.Name + "/public", func(path string, f os.FileInfo, err error) error {
|
return filepath.Walk("./themes/"+theme.Name+"/public", func(path string, f os.FileInfo, err error) error {
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Attempting to add static file '" + path + "' for default theme '" + theme.Name + "'")
|
log.Print("Attempting to add static file '" + path + "' for default theme '" + theme.Name + "'")
|
||||||
}
|
}
|
||||||
@ -174,13 +176,13 @@ func add_theme_static_files(theme Theme) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ext string = filepath.Ext(path)
|
var ext = filepath.Ext(path)
|
||||||
//log.Print("path ",path)
|
//log.Print("path ",path)
|
||||||
//log.Print("ext ",ext)
|
//log.Print("ext ",ext)
|
||||||
if ext == ".css" && len(data) != 0 {
|
if ext == ".css" && len(data) != 0 {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
var pieces []string = strings.Split(path,"/")
|
var pieces = strings.Split(path, "/")
|
||||||
var filename string = pieces[len(pieces) - 1]
|
var filename = pieces[len(pieces)-1]
|
||||||
//log.Print("filename ", filename)
|
//log.Print("filename ", filename)
|
||||||
err = theme.ResourceTemplates.ExecuteTemplate(&b, filename, CssData{ComingSoon: "We don't have any data to pass you yet!"})
|
err = theme.ResourceTemplates.ExecuteTemplate(&b, filename, CssData{ComingSoon: "We don't have any data to pass you yet!"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -190,20 +192,17 @@ func add_theme_static_files(theme Theme) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
path = strings.TrimPrefix(path, "themes/"+theme.Name+"/public")
|
path = strings.TrimPrefix(path, "themes/"+theme.Name+"/public")
|
||||||
gzip_data := compress_bytes_gzip(data)
|
gzipData := compressBytesGzip(data)
|
||||||
static_files["/static" + path] = SFile{data,gzip_data,0,int64(len(data)),int64(len(gzip_data)),mime.TypeByExtension(ext),f,f.ModTime().UTC().Format(http.TimeFormat)}
|
staticFiles["/static/"+theme.Name+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}
|
||||||
|
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("Added the '" + path + "' static file for default theme " + theme.Name + ".")
|
log.Print("Added the '/" + theme.Name + path + "' static file for theme " + theme.Name + ".")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func map_theme_templates(theme Theme) {
|
func mapThemeTemplates(theme Theme) {
|
||||||
if theme.Templates != nil {
|
if theme.Templates != nil {
|
||||||
for _, themeTmpl := range theme.Templates {
|
for _, themeTmpl := range theme.Templates {
|
||||||
if themeTmpl.Name == "" {
|
if themeTmpl.Name == "" {
|
||||||
@ -215,76 +214,76 @@ func map_theme_templates(theme Theme) {
|
|||||||
|
|
||||||
// `go generate` is one possibility for letting plugins inject custom page structs, but it would simply add another step of compilation. It might be simpler than the current build process from the perspective of the administrator?
|
// `go generate` is one possibility for letting plugins inject custom page structs, but it would simply add another step of compilation. It might be simpler than the current build process from the perspective of the administrator?
|
||||||
|
|
||||||
dest_tmpl_ptr, ok := tmpl_ptr_map[themeTmpl.Name]
|
destTmplPtr, ok := tmplPtrMap[themeTmpl.Name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
source_tmpl_ptr, ok := tmpl_ptr_map[themeTmpl.Source]
|
sourceTmplPtr, ok := tmplPtrMap[themeTmpl.Source]
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatal("The source template doesn't exist!")
|
log.Fatal("The source template doesn't exist!")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch d_tmpl_ptr := dest_tmpl_ptr.(type) {
|
switch dTmplPtr := destTmplPtr.(type) {
|
||||||
case *func(TopicPage, http.ResponseWriter):
|
case *func(TopicPage, http.ResponseWriter):
|
||||||
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
|
switch sTmplPtr := sourceTmplPtr.(type) {
|
||||||
case *func(TopicPage, http.ResponseWriter):
|
case *func(TopicPage, http.ResponseWriter):
|
||||||
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
|
//overridenTemplates[themeTmpl.Name] = d_tmpl_ptr
|
||||||
overriden_templates[themeTmpl.Name] = true
|
overridenTemplates[themeTmpl.Name] = true
|
||||||
*d_tmpl_ptr = *s_tmpl_ptr
|
*dTmplPtr = *sTmplPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The source and destination templates are incompatible")
|
log.Fatal("The source and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
case *func(TopicsPage, http.ResponseWriter):
|
case *func(TopicsPage, http.ResponseWriter):
|
||||||
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
|
switch sTmplPtr := sourceTmplPtr.(type) {
|
||||||
case *func(TopicsPage, http.ResponseWriter):
|
case *func(TopicsPage, http.ResponseWriter):
|
||||||
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
|
//overridenTemplates[themeTmpl.Name] = d_tmpl_ptr
|
||||||
overriden_templates[themeTmpl.Name] = true
|
overridenTemplates[themeTmpl.Name] = true
|
||||||
*d_tmpl_ptr = *s_tmpl_ptr
|
*dTmplPtr = *sTmplPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The source and destination templates are incompatible")
|
log.Fatal("The source and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
case *func(ForumPage, http.ResponseWriter):
|
case *func(ForumPage, http.ResponseWriter):
|
||||||
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
|
switch sTmplPtr := sourceTmplPtr.(type) {
|
||||||
case *func(ForumPage, http.ResponseWriter):
|
case *func(ForumPage, http.ResponseWriter):
|
||||||
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
|
//overridenTemplates[themeTmpl.Name] = d_tmpl_ptr
|
||||||
overriden_templates[themeTmpl.Name] = true
|
overridenTemplates[themeTmpl.Name] = true
|
||||||
*d_tmpl_ptr = *s_tmpl_ptr
|
*dTmplPtr = *sTmplPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The source and destination templates are incompatible")
|
log.Fatal("The source and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
case *func(ForumsPage, http.ResponseWriter):
|
case *func(ForumsPage, http.ResponseWriter):
|
||||||
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
|
switch sTmplPtr := sourceTmplPtr.(type) {
|
||||||
case *func(ForumsPage, http.ResponseWriter):
|
case *func(ForumsPage, http.ResponseWriter):
|
||||||
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
|
//overridenTemplates[themeTmpl.Name] = d_tmpl_ptr
|
||||||
overriden_templates[themeTmpl.Name] = true
|
overridenTemplates[themeTmpl.Name] = true
|
||||||
*d_tmpl_ptr = *s_tmpl_ptr
|
*dTmplPtr = *sTmplPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The source and destination templates are incompatible")
|
log.Fatal("The source and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
case *func(ProfilePage, http.ResponseWriter):
|
case *func(ProfilePage, http.ResponseWriter):
|
||||||
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
|
switch sTmplPtr := sourceTmplPtr.(type) {
|
||||||
case *func(ProfilePage, http.ResponseWriter):
|
case *func(ProfilePage, http.ResponseWriter):
|
||||||
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
|
//overridenTemplates[themeTmpl.Name] = d_tmpl_ptr
|
||||||
overriden_templates[themeTmpl.Name] = true
|
overridenTemplates[themeTmpl.Name] = true
|
||||||
*d_tmpl_ptr = *s_tmpl_ptr
|
*dTmplPtr = *sTmplPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The source and destination templates are incompatible")
|
log.Fatal("The source and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
case *func(CreateTopicPage, http.ResponseWriter):
|
case *func(CreateTopicPage, http.ResponseWriter):
|
||||||
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
|
switch sTmplPtr := sourceTmplPtr.(type) {
|
||||||
case *func(CreateTopicPage, http.ResponseWriter):
|
case *func(CreateTopicPage, http.ResponseWriter):
|
||||||
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
|
//overridenTemplates[themeTmpl.Name] = d_tmpl_ptr
|
||||||
overriden_templates[themeTmpl.Name] = true
|
overridenTemplates[themeTmpl.Name] = true
|
||||||
*d_tmpl_ptr = *s_tmpl_ptr
|
*dTmplPtr = *sTmplPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The source and destination templates are incompatible")
|
log.Fatal("The source and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
case *func(Page, http.ResponseWriter):
|
case *func(Page, http.ResponseWriter):
|
||||||
switch s_tmpl_ptr := source_tmpl_ptr.(type) {
|
switch sTmplPtr := sourceTmplPtr.(type) {
|
||||||
case *func(Page, http.ResponseWriter):
|
case *func(Page, http.ResponseWriter):
|
||||||
//overriden_templates[themeTmpl.Name] = d_tmpl_ptr
|
//overridenTemplates[themeTmpl.Name] = d_tmpl_ptr
|
||||||
overriden_templates[themeTmpl.Name] = true
|
overridenTemplates[themeTmpl.Name] = true
|
||||||
*d_tmpl_ptr = *s_tmpl_ptr
|
*dTmplPtr = *sTmplPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The source and destination templates are incompatible")
|
log.Fatal("The source and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
@ -295,20 +294,20 @@ func map_theme_templates(theme Theme) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func reset_template_overrides() {
|
func resetTemplateOverrides() {
|
||||||
log.Print("Resetting the template overrides")
|
log.Print("Resetting the template overrides")
|
||||||
|
|
||||||
for name, _ := range overriden_templates {
|
for name := range overridenTemplates {
|
||||||
log.Print("Resetting '" + name + "' template override")
|
log.Print("Resetting '" + name + "' template override")
|
||||||
|
|
||||||
origin_pointer, ok := tmpl_ptr_map["o_" + name]
|
originPointer, ok := tmplPtrMap["o_"+name]
|
||||||
if !ok {
|
if !ok {
|
||||||
//log.Fatal("The origin template doesn't exist!")
|
//log.Fatal("The origin template doesn't exist!")
|
||||||
log.Print("The origin template doesn't exist!")
|
log.Print("The origin template doesn't exist!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dest_tmpl_ptr, ok := tmpl_ptr_map[name]
|
destTmplPtr, ok := tmplPtrMap[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
//log.Fatal("The destination template doesn't exist!")
|
//log.Fatal("The destination template doesn't exist!")
|
||||||
log.Print("The destination template doesn't exist!")
|
log.Print("The destination template doesn't exist!")
|
||||||
@ -316,53 +315,53 @@ func reset_template_overrides() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Not really a pointer, more of a function handle, an artifact from one of the earlier versions of themes.go
|
// Not really a pointer, more of a function handle, an artifact from one of the earlier versions of themes.go
|
||||||
switch o_ptr := origin_pointer.(type) {
|
switch oPtr := originPointer.(type) {
|
||||||
case func(TopicPage, http.ResponseWriter):
|
case func(TopicPage, http.ResponseWriter):
|
||||||
switch d_ptr := dest_tmpl_ptr.(type) {
|
switch dPtr := destTmplPtr.(type) {
|
||||||
case *func(TopicPage, http.ResponseWriter):
|
case *func(TopicPage, http.ResponseWriter):
|
||||||
*d_ptr = o_ptr
|
*dPtr = oPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The origin and destination templates are incompatible")
|
log.Fatal("The origin and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
case func(TopicsPage, http.ResponseWriter):
|
case func(TopicsPage, http.ResponseWriter):
|
||||||
switch d_ptr := dest_tmpl_ptr.(type) {
|
switch dPtr := destTmplPtr.(type) {
|
||||||
case *func(TopicsPage, http.ResponseWriter):
|
case *func(TopicsPage, http.ResponseWriter):
|
||||||
*d_ptr = o_ptr
|
*dPtr = oPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The origin and destination templates are incompatible")
|
log.Fatal("The origin and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
case func(ForumPage, http.ResponseWriter):
|
case func(ForumPage, http.ResponseWriter):
|
||||||
switch d_ptr := dest_tmpl_ptr.(type) {
|
switch dPtr := destTmplPtr.(type) {
|
||||||
case *func(ForumPage, http.ResponseWriter):
|
case *func(ForumPage, http.ResponseWriter):
|
||||||
*d_ptr = o_ptr
|
*dPtr = oPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The origin and destination templates are incompatible")
|
log.Fatal("The origin and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
case func(ForumsPage, http.ResponseWriter):
|
case func(ForumsPage, http.ResponseWriter):
|
||||||
switch d_ptr := dest_tmpl_ptr.(type) {
|
switch dPtr := destTmplPtr.(type) {
|
||||||
case *func(ForumsPage, http.ResponseWriter):
|
case *func(ForumsPage, http.ResponseWriter):
|
||||||
*d_ptr = o_ptr
|
*dPtr = oPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The origin and destination templates are incompatible")
|
log.Fatal("The origin and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
case func(ProfilePage, http.ResponseWriter):
|
case func(ProfilePage, http.ResponseWriter):
|
||||||
switch d_ptr := dest_tmpl_ptr.(type) {
|
switch dPtr := destTmplPtr.(type) {
|
||||||
case *func(ProfilePage, http.ResponseWriter):
|
case *func(ProfilePage, http.ResponseWriter):
|
||||||
*d_ptr = o_ptr
|
*dPtr = oPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The origin and destination templates are incompatible")
|
log.Fatal("The origin and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
case func(CreateTopicPage, http.ResponseWriter):
|
case func(CreateTopicPage, http.ResponseWriter):
|
||||||
switch d_ptr := dest_tmpl_ptr.(type) {
|
switch dPtr := destTmplPtr.(type) {
|
||||||
case *func(CreateTopicPage, http.ResponseWriter):
|
case *func(CreateTopicPage, http.ResponseWriter):
|
||||||
*d_ptr = o_ptr
|
*dPtr = oPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The origin and destination templates are incompatible")
|
log.Fatal("The origin and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
case func(Page, http.ResponseWriter):
|
case func(Page, http.ResponseWriter):
|
||||||
switch d_ptr := dest_tmpl_ptr.(type) {
|
switch dPtr := destTmplPtr.(type) {
|
||||||
case *func(Page, http.ResponseWriter):
|
case *func(Page, http.ResponseWriter):
|
||||||
*d_ptr = o_ptr
|
*dPtr = oPtr
|
||||||
default:
|
default:
|
||||||
log.Fatal("The origin and destination templates are incompatible")
|
log.Fatal("The origin and destination templates are incompatible")
|
||||||
}
|
}
|
||||||
@ -371,35 +370,94 @@ func reset_template_overrides() {
|
|||||||
}
|
}
|
||||||
log.Print("The template override was reset")
|
log.Print("The template override was reset")
|
||||||
}
|
}
|
||||||
overriden_templates = make(map[string]bool)
|
overridenTemplates = make(map[string]bool)
|
||||||
log.Print("All of the template overrides have been reset")
|
log.Print("All of the template overrides have been reset")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEW method of doing theme templates to allow one user to have a different theme to another. Under construction.
|
// NEW method of doing theme templates to allow one user to have a different theme to another. Under construction.
|
||||||
// TO-DO: Generate the type switch instead of writing it by hand
|
// TO-DO: Generate the type switch instead of writing it by hand
|
||||||
|
// TO-DO: Cut the number of types in half
|
||||||
func RunThemeTemplate(theme string, template string, pi interface{}, w http.ResponseWriter) {
|
func RunThemeTemplate(theme string, template string, pi interface{}, w http.ResponseWriter) {
|
||||||
switch tmpl := GetThemeTemplate(theme,template).(type) {
|
switch tmplO := GetThemeTemplate(theme, template).(type) {
|
||||||
case func(TopicPage,http.ResponseWriter): tmpl(pi.(TopicPage),w)
|
case *func(TopicPage, http.ResponseWriter):
|
||||||
case func(TopicsPage,http.ResponseWriter): tmpl(pi.(TopicsPage),w)
|
var tmpl = *tmplO
|
||||||
case func(ForumPage,http.ResponseWriter): tmpl(pi.(ForumPage),w)
|
tmpl(pi.(TopicPage), w)
|
||||||
case func(ForumsPage,http.ResponseWriter): tmpl(pi.(ForumsPage),w)
|
case *func(TopicsPage, http.ResponseWriter):
|
||||||
case func(ProfilePage,http.ResponseWriter): tmpl(pi.(ProfilePage),w)
|
var tmpl = *tmplO
|
||||||
case func(CreateTopicPage,http.ResponseWriter): tmpl(pi.(CreateTopicPage),w)
|
tmpl(pi.(TopicsPage), w)
|
||||||
case func(Page,http.ResponseWriter): tmpl(pi.(Page),w)
|
case *func(ForumPage, http.ResponseWriter):
|
||||||
default: LogError(errors.New("Unknown template type"))
|
var tmpl = *tmplO
|
||||||
|
tmpl(pi.(ForumPage), w)
|
||||||
|
case *func(ForumsPage, http.ResponseWriter):
|
||||||
|
var tmpl = *tmplO
|
||||||
|
tmpl(pi.(ForumsPage), w)
|
||||||
|
case *func(ProfilePage, http.ResponseWriter):
|
||||||
|
var tmpl = *tmplO
|
||||||
|
tmpl(pi.(ProfilePage), w)
|
||||||
|
case *func(CreateTopicPage, http.ResponseWriter):
|
||||||
|
var tmpl = *tmplO
|
||||||
|
tmpl(pi.(CreateTopicPage), w)
|
||||||
|
case *func(Page, http.ResponseWriter):
|
||||||
|
var tmpl = *tmplO
|
||||||
|
tmpl(pi.(Page), w)
|
||||||
|
case func(TopicPage, http.ResponseWriter):
|
||||||
|
tmplO(pi.(TopicPage), w)
|
||||||
|
case func(TopicsPage, http.ResponseWriter):
|
||||||
|
tmplO(pi.(TopicsPage), w)
|
||||||
|
case func(ForumPage, http.ResponseWriter):
|
||||||
|
tmplO(pi.(ForumPage), w)
|
||||||
|
case func(ForumsPage, http.ResponseWriter):
|
||||||
|
tmplO(pi.(ForumsPage), w)
|
||||||
|
case func(ProfilePage, http.ResponseWriter):
|
||||||
|
tmplO(pi.(ProfilePage), w)
|
||||||
|
case func(CreateTopicPage, http.ResponseWriter):
|
||||||
|
tmplO(pi.(CreateTopicPage), w)
|
||||||
|
case func(Page, http.ResponseWriter):
|
||||||
|
tmplO(pi.(Page), w)
|
||||||
|
case string:
|
||||||
|
mapping, ok := themes[defaultTheme].TemplatesMap[template]
|
||||||
|
if !ok {
|
||||||
|
mapping = template
|
||||||
|
}
|
||||||
|
err := templates.ExecuteTemplate(w, mapping+".html", pi)
|
||||||
|
if err != nil {
|
||||||
|
LogError(err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Print("theme ", theme)
|
||||||
|
log.Print("template ", template)
|
||||||
|
log.Print("pi ", pi)
|
||||||
|
log.Print("tmplO ", tmplO)
|
||||||
|
|
||||||
|
valueOf := reflect.ValueOf(tmplO)
|
||||||
|
log.Print("initial valueOf.Type()", valueOf.Type())
|
||||||
|
for valueOf.Kind() == reflect.Interface || valueOf.Kind() == reflect.Ptr {
|
||||||
|
valueOf = valueOf.Elem()
|
||||||
|
log.Print("valueOf.Elem().Type() ", valueOf.Type())
|
||||||
|
}
|
||||||
|
log.Print("deferenced valueOf.Type() ", valueOf.Type())
|
||||||
|
log.Print("valueOf.Kind() ", valueOf.Kind())
|
||||||
|
|
||||||
|
LogError(errors.New("Unknown template type"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetThemeTemplate attempts to get the template for a specific theme, otherwise it falls back on the default template pointer, which if absent will fallback onto the template interpreter
|
||||||
func GetThemeTemplate(theme string, template string) interface{} {
|
func GetThemeTemplate(theme string, template string) interface{} {
|
||||||
tmpl, ok := themes[theme].TmplPtr[template]
|
tmpl, ok := themes[theme].TmplPtr[template]
|
||||||
if !ok {
|
if ok {
|
||||||
return tmpl
|
return tmpl
|
||||||
}
|
}
|
||||||
return nil
|
tmpl, ok = tmplPtrMap[template]
|
||||||
|
if ok {
|
||||||
|
return tmpl
|
||||||
|
}
|
||||||
|
return template
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateThemeTemplate creates a theme template on the current default theme
|
||||||
func CreateThemeTemplate(theme string, name string) {
|
func CreateThemeTemplate(theme string, name string) {
|
||||||
themes[theme].TmplPtr[name] = func(pi ProfilePage, w http.ResponseWriter) {
|
themes[theme].TmplPtr[name] = func(pi Page, w http.ResponseWriter) {
|
||||||
mapping, ok := themes[defaultTheme].TemplatesMap[name]
|
mapping, ok := themes[defaultTheme].TemplatesMap[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
mapping = name
|
mapping = name
|
||||||
|
@ -247,6 +247,9 @@ a {
|
|||||||
.unpin_label:before {
|
.unpin_label:before {
|
||||||
content: "Unpin";
|
content: "Unpin";
|
||||||
}
|
}
|
||||||
|
.ip_label:before {
|
||||||
|
content: "IP";
|
||||||
|
}
|
||||||
.flag_label:before {
|
.flag_label:before {
|
||||||
content: "Flag";
|
content: "Flag";
|
||||||
}
|
}
|
||||||
|
@ -158,6 +158,9 @@ li a {
|
|||||||
.rowblock:empty {
|
.rowblock:empty {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.rowmenu {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
.rowsmall {
|
.rowsmall {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
@ -234,12 +237,15 @@ li a {
|
|||||||
.stat_red { background-color: #ffb2b2; border-color: #ffb2b2; }
|
.stat_red { background-color: #ffb2b2; border-color: #ffb2b2; }
|
||||||
.stat_disabled { background-color: lightgray; border-color: lightgray; }
|
.stat_disabled { background-color: lightgray; border-color: lightgray; }
|
||||||
|
|
||||||
.rowhead, .colstack_head {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
.rowhead .rowitem, .colstack_head .rowitem {
|
.rowhead .rowitem, .colstack_head .rowitem {
|
||||||
background-color: rgb(252,252,252);
|
background-color: rgb(252,252,252);
|
||||||
}
|
}
|
||||||
|
.rowhead h1, .colstack_head h1 {
|
||||||
|
-webkit-margin-before: 0;
|
||||||
|
-webkit-margin-after: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.rowitem {
|
.rowitem {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -465,6 +471,7 @@ button.username {
|
|||||||
.pin_label:before { content: "📌"; }
|
.pin_label:before { content: "📌"; }
|
||||||
.unpin_label:before { content: "📌"; }
|
.unpin_label:before { content: "📌"; }
|
||||||
.unpin_label { background-color: #D6FFD6; }
|
.unpin_label { background-color: #D6FFD6; }
|
||||||
|
.ip_label:before { content: "🔍"; }
|
||||||
.flag_label:before { content: "🚩"; }
|
.flag_label:before { content: "🚩"; }
|
||||||
.level_label:before { content: "👑"; }
|
.level_label:before { content: "👑"; }
|
||||||
.level_label { color: #505050; opacity:0.85; }
|
.level_label { color: #505050; opacity:0.85; }
|
||||||
@ -558,5 +565,33 @@ button.username {
|
|||||||
background-size: 128px;
|
background-size: 128px;
|
||||||
padding-left: 136px;
|
padding-left: 136px;
|
||||||
}
|
}
|
||||||
|
/* Profiles */
|
||||||
|
#profile_left_lane {
|
||||||
|
width: 220px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
#profile_left_lane .avatarRow {
|
||||||
|
overflow: hidden;
|
||||||
|
max-height: 220px;
|
||||||
|
}
|
||||||
|
#profile_left_lane .avatar {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
#profile_left_lane .username {
|
||||||
|
font-size: 14px;
|
||||||
|
display: block;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
#profile_left_lane .profileName {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
#profile_right_lane {
|
||||||
|
width: calc(100% - 245px);
|
||||||
|
}
|
||||||
|
.simple .user_tag {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
{{template "media.partial.css" }}
|
{{template "media.partial.css" }}
|
||||||
|
@ -71,3 +71,7 @@
|
|||||||
.perm_preset_can_moderate:before { content: "Can Moderate"; color: darkblue; }
|
.perm_preset_can_moderate:before { content: "Can Moderate"; color: darkblue; }
|
||||||
.perm_preset_custom:before { content: "Custom"; color: black; }
|
.perm_preset_custom:before { content: "Custom"; color: black; }
|
||||||
.perm_preset_default:before { content: "Default"; }
|
.perm_preset_default:before { content: "Default"; }
|
||||||
|
|
||||||
|
#panel_dashboard_right .colstack_head {
|
||||||
|
display: none;
|
||||||
|
}
|
58
topic.go
58
topic.go
@ -1,44 +1,43 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
//import "fmt"
|
//import "fmt"
|
||||||
import "strconv"
|
import "strconv"
|
||||||
import "html/template"
|
import "html/template"
|
||||||
|
|
||||||
type Topic struct
|
type Topic struct {
|
||||||
{
|
|
||||||
ID int
|
ID int
|
||||||
Link string
|
Link string
|
||||||
Title string
|
Title string
|
||||||
Content string
|
Content string
|
||||||
CreatedBy int
|
CreatedBy int
|
||||||
Is_Closed bool
|
IsClosed bool
|
||||||
Sticky bool
|
Sticky bool
|
||||||
CreatedAt string
|
CreatedAt string
|
||||||
LastReplyAt string
|
LastReplyAt string
|
||||||
//LastReplyBy int
|
//LastReplyBy int
|
||||||
ParentID int
|
ParentID int
|
||||||
Status string // Deprecated. Marked for removal.
|
Status string // Deprecated. Marked for removal.
|
||||||
IpAddress string
|
IPAddress string
|
||||||
PostCount int
|
PostCount int
|
||||||
LikeCount int
|
LikeCount int
|
||||||
ClassName string // CSS Class Name
|
ClassName string // CSS Class Name
|
||||||
Data string // Used for report metadata
|
Data string // Used for report metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
type TopicUser struct
|
type TopicUser struct {
|
||||||
{
|
|
||||||
ID int
|
ID int
|
||||||
Link string
|
Link string
|
||||||
Title string
|
Title string
|
||||||
Content string
|
Content string
|
||||||
CreatedBy int
|
CreatedBy int
|
||||||
Is_Closed bool
|
IsClosed bool
|
||||||
Sticky bool
|
Sticky bool
|
||||||
CreatedAt string
|
CreatedAt string
|
||||||
LastReplyAt string
|
LastReplyAt string
|
||||||
//LastReplyBy int
|
//LastReplyBy int
|
||||||
ParentID int
|
ParentID int
|
||||||
Status string // Deprecated. Marked for removal.
|
Status string // Deprecated. Marked for removal.
|
||||||
IpAddress string
|
IPAddress string
|
||||||
PostCount int
|
PostCount int
|
||||||
LikeCount int
|
LikeCount int
|
||||||
ClassName string
|
ClassName string
|
||||||
@ -57,28 +56,27 @@ type TopicUser struct
|
|||||||
Liked bool
|
Liked bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type TopicsRow struct
|
type TopicsRow struct {
|
||||||
{
|
|
||||||
ID int
|
ID int
|
||||||
Link string
|
Link string
|
||||||
Title string
|
Title string
|
||||||
Content string
|
Content string
|
||||||
CreatedBy int
|
CreatedBy int
|
||||||
Is_Closed bool
|
IsClosed bool
|
||||||
Sticky bool
|
Sticky bool
|
||||||
CreatedAt string
|
CreatedAt string
|
||||||
LastReplyAt string
|
LastReplyAt string
|
||||||
LastReplyBy int
|
LastReplyBy int
|
||||||
ParentID int
|
ParentID int
|
||||||
Status string // Deprecated. Marked for removal. -Is there anything we could use it for?
|
Status string // Deprecated. Marked for removal. -Is there anything we could use it for?
|
||||||
IpAddress string
|
IPAddress string
|
||||||
PostCount int
|
PostCount int
|
||||||
LikeCount int
|
LikeCount int
|
||||||
ClassName string
|
ClassName string
|
||||||
Data string // Used for report metadata
|
Data string // Used for report metadata
|
||||||
|
|
||||||
Creator *User
|
Creator *User
|
||||||
Css template.CSS
|
CSS template.CSS
|
||||||
ContentLines int
|
ContentLines int
|
||||||
LastUser *User
|
LastUser *User
|
||||||
|
|
||||||
@ -86,7 +84,7 @@ type TopicsRow struct
|
|||||||
ForumLink string
|
ForumLink string
|
||||||
}
|
}
|
||||||
|
|
||||||
func get_topicuser(tid int) (TopicUser,error) {
|
func getTopicuser(tid int) (TopicUser, error) {
|
||||||
if config.CacheTopicUser != CACHE_SQL {
|
if config.CacheTopicUser != CACHE_SQL {
|
||||||
topic, err := topics.Get(tid)
|
topic, err := topics.Get(tid)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -96,7 +94,7 @@ func get_topicuser(tid int) (TopicUser,error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We might be better off just passing seperate topic and user structs to the caller?
|
// We might be better off just passing seperate topic and user structs to the caller?
|
||||||
return copy_topic_to_topicuser(topic, user), nil
|
return copyTopicToTopicuser(topic, user), nil
|
||||||
} else if users.GetLength() < users.GetCapacity() {
|
} else if users.GetLength() < users.GetCapacity() {
|
||||||
topic, err = topics.CascadeGet(tid)
|
topic, err = topics.CascadeGet(tid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -106,23 +104,23 @@ func get_topicuser(tid int) (TopicUser,error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return TopicUser{ID: tid}, err
|
return TopicUser{ID: tid}, err
|
||||||
}
|
}
|
||||||
return copy_topic_to_topicuser(topic, user), nil
|
return copyTopicToTopicuser(topic, user), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tu := TopicUser{ID: tid}
|
tu := TopicUser{ID: tid}
|
||||||
err := get_topic_user_stmt.QueryRow(tid).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.Is_Closed, &tu.Sticky, &tu.ParentID, &tu.IpAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
err := get_topic_user_stmt.QueryRow(tid).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IPAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
||||||
tu.Link = build_topic_url(name_to_slug(tu.Title),tu.ID)
|
tu.Link = buildTopicURL(nameToSlug(tu.Title), tu.ID)
|
||||||
tu.UserLink = build_profile_url(name_to_slug(tu.CreatedByName),tu.CreatedBy)
|
tu.UserLink = buildProfileURL(nameToSlug(tu.CreatedByName), tu.CreatedBy)
|
||||||
|
|
||||||
the_topic := Topic{ID:tu.ID, Link:tu.Link, Title:tu.Title, Content:tu.Content, CreatedBy:tu.CreatedBy, Is_Closed:tu.Is_Closed, Sticky:tu.Sticky, CreatedAt:tu.CreatedAt, LastReplyAt:tu.LastReplyAt, ParentID:tu.ParentID, IpAddress:tu.IpAddress, PostCount:tu.PostCount, LikeCount:tu.LikeCount}
|
theTopic := Topic{ID: tu.ID, Link: tu.Link, Title: tu.Title, Content: tu.Content, CreatedBy: tu.CreatedBy, IsClosed: tu.IsClosed, Sticky: tu.Sticky, CreatedAt: tu.CreatedAt, LastReplyAt: tu.LastReplyAt, ParentID: tu.ParentID, IPAddress: tu.IPAddress, PostCount: tu.PostCount, LikeCount: tu.LikeCount}
|
||||||
//log.Printf("the_topic: %+v\n", the_topic)
|
//log.Printf("the_topic: %+v\n", the_topic)
|
||||||
tu.Tag = groups[tu.Group].Tag
|
tu.Tag = groups[tu.Group].Tag
|
||||||
topics.Add(&the_topic)
|
_ = topics.Add(&theTopic)
|
||||||
return tu, err
|
return tu, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func copy_topic_to_topicuser(topic *Topic, user *User) (tu TopicUser) {
|
func copyTopicToTopicuser(topic *Topic, user *User) (tu TopicUser) {
|
||||||
tu.UserLink = user.Link
|
tu.UserLink = user.Link
|
||||||
tu.CreatedByName = user.Name
|
tu.CreatedByName = user.Name
|
||||||
tu.Group = user.Group
|
tu.Group = user.Group
|
||||||
@ -136,12 +134,12 @@ func copy_topic_to_topicuser(topic *Topic, user *User) (tu TopicUser) {
|
|||||||
tu.Title = topic.Title
|
tu.Title = topic.Title
|
||||||
tu.Content = topic.Content
|
tu.Content = topic.Content
|
||||||
tu.CreatedBy = topic.CreatedBy
|
tu.CreatedBy = topic.CreatedBy
|
||||||
tu.Is_Closed = topic.Is_Closed
|
tu.IsClosed = topic.IsClosed
|
||||||
tu.Sticky = topic.Sticky
|
tu.Sticky = topic.Sticky
|
||||||
tu.CreatedAt = topic.CreatedAt
|
tu.CreatedAt = topic.CreatedAt
|
||||||
tu.LastReplyAt = topic.LastReplyAt
|
tu.LastReplyAt = topic.LastReplyAt
|
||||||
tu.ParentID = topic.ParentID
|
tu.ParentID = topic.ParentID
|
||||||
tu.IpAddress = topic.IpAddress
|
tu.IPAddress = topic.IPAddress
|
||||||
tu.PostCount = topic.PostCount
|
tu.PostCount = topic.PostCount
|
||||||
tu.LikeCount = topic.LikeCount
|
tu.LikeCount = topic.LikeCount
|
||||||
tu.Data = topic.Data
|
tu.Data = topic.Data
|
||||||
@ -149,20 +147,22 @@ func copy_topic_to_topicuser(topic *Topic, user *User) (tu TopicUser) {
|
|||||||
return tu
|
return tu
|
||||||
}
|
}
|
||||||
|
|
||||||
func get_topic_by_reply(rid int) (*Topic, error) {
|
func getTopicByReply(rid int) (*Topic, error) {
|
||||||
topic := Topic{ID: 0}
|
topic := Topic{ID: 0}
|
||||||
err := get_topic_by_reply_stmt.QueryRow(rid).Scan(&topic.ID, &topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
err := get_topic_by_reply_stmt.QueryRow(rid).Scan(&topic.ID, &topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
||||||
topic.Link = build_topic_url(name_to_slug(topic.Title),topic.ID)
|
topic.Link = buildTopicURL(nameToSlug(topic.Title), topic.ID)
|
||||||
return &topic, err
|
return &topic, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func build_topic_url(slug string, tid int) string {
|
func buildTopicURL(slug string, tid int) string {
|
||||||
if slug == "" {
|
if slug == "" {
|
||||||
return "/topic/" + strconv.Itoa(tid)
|
return "/topic/" + strconv.Itoa(tid)
|
||||||
}
|
}
|
||||||
return "/topic/" + slug + "." + strconv.Itoa(tid)
|
return "/topic/" + slug + "." + strconv.Itoa(tid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func get_topic_url_prefix() string {
|
// I don't care if it isn't used,, it will likely be in the future. Nolint.
|
||||||
|
// nolint
|
||||||
|
func getTopicURLPrefix() string {
|
||||||
return "/topic/"
|
return "/topic/"
|
||||||
}
|
}
|
||||||
|
@ -71,29 +71,29 @@ func (sts *MemoryTopicStore) CascadeGet(id int) (*Topic, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
topic = &Topic{ID: id}
|
topic = &Topic{ID: id}
|
||||||
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
topic.Link = build_topic_url(name_to_slug(topic.Title),id)
|
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
|
||||||
sts.Add(topic)
|
_ = sts.Add(topic)
|
||||||
}
|
}
|
||||||
return topic, err
|
return topic, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sts *MemoryTopicStore) BypassGet(id int) (*Topic, error) {
|
func (sts *MemoryTopicStore) BypassGet(id int) (*Topic, error) {
|
||||||
topic := &Topic{ID: id}
|
topic := &Topic{ID: id}
|
||||||
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
||||||
topic.Link = build_topic_url(name_to_slug(topic.Title),id)
|
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
|
||||||
return topic, err
|
return topic, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sts *MemoryTopicStore) Load(id int) error {
|
func (sts *MemoryTopicStore) Load(id int) error {
|
||||||
topic := &Topic{ID: id}
|
topic := &Topic{ID: id}
|
||||||
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
topic.Link = build_topic_url(name_to_slug(topic.Title),id)
|
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
|
||||||
sts.Set(topic)
|
_ = sts.Set(topic)
|
||||||
} else {
|
} else {
|
||||||
sts.Remove(id)
|
_ = sts.Remove(id)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -179,36 +179,36 @@ func NewSqlTopicStore() *SqlTopicStore {
|
|||||||
|
|
||||||
func (sts *SqlTopicStore) Get(id int) (*Topic, error) {
|
func (sts *SqlTopicStore) Get(id int) (*Topic, error) {
|
||||||
topic := Topic{ID: id}
|
topic := Topic{ID: id}
|
||||||
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
||||||
topic.Link = build_topic_url(name_to_slug(topic.Title),id)
|
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
|
||||||
return &topic, err
|
return &topic, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sts *SqlTopicStore) GetUnsafe(id int) (*Topic, error) {
|
func (sts *SqlTopicStore) GetUnsafe(id int) (*Topic, error) {
|
||||||
topic := Topic{ID: id}
|
topic := Topic{ID: id}
|
||||||
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
||||||
topic.Link = build_topic_url(name_to_slug(topic.Title),id)
|
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
|
||||||
return &topic, err
|
return &topic, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sts *SqlTopicStore) CascadeGet(id int) (*Topic, error) {
|
func (sts *SqlTopicStore) CascadeGet(id int) (*Topic, error) {
|
||||||
topic := Topic{ID: id}
|
topic := Topic{ID: id}
|
||||||
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
||||||
topic.Link = build_topic_url(name_to_slug(topic.Title),id)
|
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
|
||||||
return &topic, err
|
return &topic, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sts *SqlTopicStore) BypassGet(id int) (*Topic, error) {
|
func (sts *SqlTopicStore) BypassGet(id int) (*Topic, error) {
|
||||||
topic := &Topic{ID: id}
|
topic := &Topic{ID: id}
|
||||||
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
||||||
topic.Link = build_topic_url(name_to_slug(topic.Title),id)
|
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
|
||||||
return topic, err
|
return topic, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sts *SqlTopicStore) Load(id int) error {
|
func (sts *SqlTopicStore) Load(id int) error {
|
||||||
topic := Topic{ID: id}
|
topic := Topic{ID: id}
|
||||||
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
||||||
topic.Link = build_topic_url(name_to_slug(topic.Title),id)
|
topic.Link = buildTopicURL(nameToSlug(topic.Title), id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
175
user.go
175
user.go
@ -3,44 +3,46 @@ package main
|
|||||||
import (
|
import (
|
||||||
//"log"
|
//"log"
|
||||||
//"fmt"
|
//"fmt"
|
||||||
"strings"
|
"html/template"
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"html/template"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var guest_user User = User{ID:0,Link:"#",Group:6,Perms:GuestPerms}
|
var guestUser = User{ID: 0, Link: "#", Group: 6, Perms: GuestPerms}
|
||||||
|
|
||||||
var PreRoute func(http.ResponseWriter, *http.Request) (User, bool) = _pre_route
|
var PreRoute func(http.ResponseWriter, *http.Request) (User, bool) = _pre_route
|
||||||
|
|
||||||
// TO-DO: Are these even session checks anymore? We might need to rethink these names
|
// TO-DO: Are these even session checks anymore? We might need to rethink these names
|
||||||
var PanelSessionCheck func(http.ResponseWriter, *http.Request, *User) (HeaderVars,PanelStats,bool) = _panel_session_check
|
var PanelSessionCheck func(http.ResponseWriter, *http.Request, *User) (*HeaderVars, PanelStats, bool) = _panel_session_check
|
||||||
var SimplePanelSessionCheck func(http.ResponseWriter, *http.Request, *User) (HeaderLite,bool) = _simple_panel_session_check
|
var SimplePanelSessionCheck func(http.ResponseWriter, *http.Request, *User) (*HeaderLite, bool) = _simple_panel_session_check
|
||||||
var SimpleForumSessionCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (success bool) = _simple_forum_session_check
|
var SimpleForumSessionCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *HeaderLite, success bool) = _simple_forum_session_check
|
||||||
var ForumSessionCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars HeaderVars, success bool) = _forum_session_check
|
var ForumSessionCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *HeaderVars, success bool) = _forum_session_check
|
||||||
var SimpleSessionCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerLite HeaderLite, success bool) = _simple_session_check
|
var SimpleSessionCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, success bool) = _simple_session_check
|
||||||
var SessionCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars HeaderVars, success bool) = _session_check
|
var SessionCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, success bool) = _session_check
|
||||||
|
|
||||||
var CheckPassword func(real_password string, password string, salt string) (err error) = BcryptCheckPassword
|
//func(real_password string, password string, salt string) (err error)
|
||||||
var GeneratePassword func(password string) (hashed_password string, salt string, err error) = BcryptGeneratePassword
|
var CheckPassword = BcryptCheckPassword
|
||||||
|
|
||||||
type User struct
|
//func(password string) (hashed_password string, salt string, err error)
|
||||||
{
|
var GeneratePassword = BcryptGeneratePassword
|
||||||
|
|
||||||
|
type User struct {
|
||||||
ID int
|
ID int
|
||||||
Link string
|
Link string
|
||||||
Name string
|
Name string
|
||||||
Email string
|
Email string
|
||||||
Group int
|
Group int
|
||||||
Active bool
|
Active bool
|
||||||
Is_Mod bool
|
IsMod bool
|
||||||
Is_Super_Mod bool
|
IsSuperMod bool
|
||||||
Is_Admin bool
|
IsAdmin bool
|
||||||
Is_Super_Admin bool
|
IsSuperAdmin bool
|
||||||
Is_Banned bool
|
IsBanned bool
|
||||||
Perms Perms
|
Perms Perms
|
||||||
PluginPerms map[string]bool
|
PluginPerms map[string]bool
|
||||||
Session string
|
Session string
|
||||||
@ -52,12 +54,11 @@ type User struct
|
|||||||
Tag string
|
Tag string
|
||||||
Level int
|
Level int
|
||||||
Score int
|
Score int
|
||||||
Last_IP string
|
LastIP string
|
||||||
TempGroup int
|
TempGroup int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Email struct
|
type Email struct {
|
||||||
{
|
|
||||||
UserID int
|
UserID int
|
||||||
Email string
|
Email string
|
||||||
Validated bool
|
Validated bool
|
||||||
@ -111,8 +112,8 @@ func (user *User) RevertGroupUpdate() error {
|
|||||||
return users.Load(user.ID)
|
return users.Load(user.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BcryptCheckPassword(real_password string, password string, salt string) (err error) {
|
func BcryptCheckPassword(realPassword string, password string, salt string) (err error) {
|
||||||
return bcrypt.CompareHashAndPassword([]byte(real_password), []byte(password + salt))
|
return bcrypt.CompareHashAndPassword([]byte(realPassword), []byte(password+salt))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Investigate. Do we need the extra salt?
|
// Investigate. Do we need the extra salt?
|
||||||
@ -131,24 +132,21 @@ func BcryptGeneratePassword(password string) (hashed_password string, salt strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BcryptGeneratePasswordNoSalt(password string) (hash string, err error) {
|
func BcryptGeneratePasswordNoSalt(password string) (hash string, err error) {
|
||||||
hashed_password, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(hashed_password), nil
|
return string(hashedPassword), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetPassword(uid int, password string) error {
|
func SetPassword(uid int, password string) error {
|
||||||
hashed_password, salt, err := GeneratePassword(password)
|
hashedPassword, salt, err := GeneratePassword(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = set_password_stmt.Exec(hashed_password, salt, uid)
|
_, err = set_password_stmt.Exec(hashedPassword, salt, uid)
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SendValidationEmail(username string, email string, token string) bool {
|
func SendValidationEmail(username string, email string, token string) bool {
|
||||||
var schema string = "http"
|
var schema string = "http"
|
||||||
@ -165,7 +163,7 @@ func SendValidationEmail(username string, email string, token string) bool {
|
|||||||
// http.Request is for context.Context middleware. Mostly for plugin_socialgroups right now
|
// http.Request is for context.Context middleware. Mostly for plugin_socialgroups right now
|
||||||
func BuildWidgets(zone string, data interface{}, headerVars *HeaderVars, r *http.Request) {
|
func BuildWidgets(zone string, data interface{}, headerVars *HeaderVars, r *http.Request) {
|
||||||
if vhooks["intercept_build_widgets"] != nil {
|
if vhooks["intercept_build_widgets"] != nil {
|
||||||
if run_vhook("intercept_build_widgets", zone, data, headerVars, r).(bool) {
|
if runVhook("intercept_build_widgets", zone, data, headerVars, r).(bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,22 +184,22 @@ func BuildWidgets(zone string, data interface{}, headerVars *HeaderVars, r *http
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func _simple_forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fid int) (success bool) {
|
func _simple_forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *HeaderLite, success bool) {
|
||||||
if !fstore.Exists(fid) {
|
if !fstore.Exists(fid) {
|
||||||
PreError("The target forum doesn't exist.", w, r)
|
PreError("The target forum doesn't exist.", w, r)
|
||||||
return false
|
return nil, false
|
||||||
}
|
}
|
||||||
success = true
|
success = true
|
||||||
|
|
||||||
// Is there a better way of doing the skip AND the success flag on this hook like multiple returns?
|
// Is there a better way of doing the skip AND the success flag on this hook like multiple returns?
|
||||||
if vhooks["simple_forum_check_pre_perms"] != nil {
|
if vhooks["simple_forum_check_pre_perms"] != nil {
|
||||||
if run_vhook("simple_forum_check_pre_perms", w, r, user, &fid, &success).(bool) {
|
if runVhook("simple_forum_check_pre_perms", w, r, user, &fid, &success, &headerLite).(bool) {
|
||||||
return success
|
return headerLite, success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fperms := groups[user.Group].Forums[fid]
|
fperms := groups[user.Group].Forums[fid]
|
||||||
if fperms.Overrides && !user.Is_Super_Admin {
|
if fperms.Overrides && !user.IsSuperAdmin {
|
||||||
user.Perms.ViewTopic = fperms.ViewTopic
|
user.Perms.ViewTopic = fperms.ViewTopic
|
||||||
user.Perms.LikeItem = fperms.LikeItem
|
user.Perms.LikeItem = fperms.LikeItem
|
||||||
user.Perms.CreateTopic = fperms.CreateTopic
|
user.Perms.CreateTopic = fperms.CreateTopic
|
||||||
@ -219,10 +217,10 @@ func _simple_forum_session_check(w http.ResponseWriter, r *http.Request, user *U
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return headerLite, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func _forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars HeaderVars, success bool) {
|
func _forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *HeaderVars, success bool) {
|
||||||
headerVars, success = SessionCheck(w, r, user)
|
headerVars, success = SessionCheck(w, r, user)
|
||||||
if !fstore.Exists(fid) {
|
if !fstore.Exists(fid) {
|
||||||
NotFound(w, r)
|
NotFound(w, r)
|
||||||
@ -230,7 +228,7 @@ func _forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if vhooks["forum_check_pre_perms"] != nil {
|
if vhooks["forum_check_pre_perms"] != nil {
|
||||||
if run_vhook("forum_check_pre_perms", w, r, user, &fid, &success, &headerVars).(bool) {
|
if runVhook("forum_check_pre_perms", w, r, user, &fid, &success, &headerVars).(bool) {
|
||||||
return headerVars, success
|
return headerVars, success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,7 +236,7 @@ func _forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fi
|
|||||||
fperms := groups[user.Group].Forums[fid]
|
fperms := groups[user.Group].Forums[fid]
|
||||||
//log.Printf("user.Perms: %+v\n", user.Perms)
|
//log.Printf("user.Perms: %+v\n", user.Perms)
|
||||||
//log.Printf("fperms: %+v\n", fperms)
|
//log.Printf("fperms: %+v\n", fperms)
|
||||||
if fperms.Overrides && !user.Is_Super_Admin {
|
if fperms.Overrides && !user.IsSuperAdmin {
|
||||||
user.Perms.ViewTopic = fperms.ViewTopic
|
user.Perms.ViewTopic = fperms.ViewTopic
|
||||||
user.Perms.LikeItem = fperms.LikeItem
|
user.Perms.LikeItem = fperms.LikeItem
|
||||||
user.Perms.CreateTopic = fperms.CreateTopic
|
user.Perms.CreateTopic = fperms.CreateTopic
|
||||||
@ -260,15 +258,20 @@ func _forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Even if they have the right permissions, the control panel is only open to supermods+. There are many areas without subpermissions which assume that the current user is a supermod+ and admins are extremely unlikely to give these permissions to someone who isn't at-least a supermod to begin with
|
// Even if they have the right permissions, the control panel is only open to supermods+. There are many areas without subpermissions which assume that the current user is a supermod+ and admins are extremely unlikely to give these permissions to someone who isn't at-least a supermod to begin with
|
||||||
func _panel_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerVars HeaderVars, stats PanelStats, success bool) {
|
func _panel_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, stats PanelStats, success bool) {
|
||||||
headerVars.Site = site
|
headerVars = &HeaderVars{
|
||||||
headerVars.Settings = settingBox.Load().(SettingBox)
|
Site: site,
|
||||||
if !user.Is_Super_Mod {
|
Settings: settingBox.Load().(SettingBox),
|
||||||
|
ThemeName: defaultTheme, // TO-DO: Is this racey?
|
||||||
|
}
|
||||||
|
// TO-DO: We should probably initialise headerVars.ExtData
|
||||||
|
|
||||||
|
if !user.IsSuperMod {
|
||||||
NoPermissions(w, r, *user)
|
NoPermissions(w, r, *user)
|
||||||
return headerVars, stats, false
|
return headerVars, stats, false
|
||||||
}
|
}
|
||||||
|
|
||||||
headerVars.Stylesheets = append(headerVars.Stylesheets,"panel.css")
|
headerVars.Stylesheets = append(headerVars.Stylesheets, headerVars.ThemeName+"/panel.css")
|
||||||
if len(themes[defaultTheme].Resources) != 0 {
|
if len(themes[defaultTheme].Resources) != 0 {
|
||||||
rlist := themes[defaultTheme].Resources
|
rlist := themes[defaultTheme].Resources
|
||||||
for _, resource := range rlist {
|
for _, resource := range rlist {
|
||||||
@ -301,8 +304,8 @@ func _panel_session_check(w http.ResponseWriter, r *http.Request, user *User) (h
|
|||||||
|
|
||||||
pusher, ok := w.(http.Pusher)
|
pusher, ok := w.(http.Pusher)
|
||||||
if ok {
|
if ok {
|
||||||
pusher.Push("/static/main.css", nil)
|
pusher.Push("/static/"+headerVars.ThemeName+"/main.css", nil)
|
||||||
pusher.Push("/static/panel.css", nil)
|
pusher.Push("/static/"+headerVars.ThemeName+"/panel.css", nil)
|
||||||
pusher.Push("/static/global.js", nil)
|
pusher.Push("/static/global.js", nil)
|
||||||
pusher.Push("/static/jquery-3.1.1.min.js", nil)
|
pusher.Push("/static/jquery-3.1.1.min.js", nil)
|
||||||
// TO-DO: Push the theme CSS files
|
// TO-DO: Push the theme CSS files
|
||||||
@ -313,27 +316,35 @@ func _panel_session_check(w http.ResponseWriter, r *http.Request, user *User) (h
|
|||||||
return headerVars, stats, true
|
return headerVars, stats, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func _simple_panel_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerLite HeaderLite, success bool) {
|
func _simple_panel_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, success bool) {
|
||||||
if !user.Is_Super_Mod {
|
if !user.IsSuperMod {
|
||||||
NoPermissions(w, r, *user)
|
NoPermissions(w, r, *user)
|
||||||
return headerLite, false
|
return headerLite, false
|
||||||
}
|
}
|
||||||
headerLite.Site = site
|
headerLite = &HeaderLite{
|
||||||
headerLite.Settings = settingBox.Load().(SettingBox)
|
Site: site,
|
||||||
|
Settings: settingBox.Load().(SettingBox),
|
||||||
|
}
|
||||||
return headerLite, true
|
return headerLite, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimpleSessionCheck is back from the grave, yay :D
|
// SimpleSessionCheck is back from the grave, yay :D
|
||||||
func _simple_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerLite HeaderLite, success bool) {
|
func _simple_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, success bool) {
|
||||||
headerLite.Site = site
|
headerLite = &HeaderLite{
|
||||||
headerLite.Settings = settingBox.Load().(SettingBox)
|
Site: site,
|
||||||
|
Settings: settingBox.Load().(SettingBox),
|
||||||
|
}
|
||||||
return headerLite, true
|
return headerLite, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func _session_check(w http.ResponseWriter, r *http.Request, user *User) (headerVars HeaderVars, success bool) {
|
func _session_check(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, success bool) {
|
||||||
headerVars.Site = site
|
headerVars = &HeaderVars{
|
||||||
headerVars.Settings = settingBox.Load().(SettingBox)
|
Site: site,
|
||||||
if user.Is_Banned {
|
Settings: settingBox.Load().(SettingBox),
|
||||||
|
ThemeName: defaultTheme, // TO-DO: Is this racey?
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.IsBanned {
|
||||||
headerVars.NoticeList = append(headerVars.NoticeList, "Your account has been suspended. Some of your permissions may have been revoked.")
|
headerVars.NoticeList = append(headerVars.NoticeList, "Your account has been suspended. Some of your permissions may have been revoked.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,7 +367,7 @@ func _session_check(w http.ResponseWriter, r *http.Request, user *User) (headerV
|
|||||||
|
|
||||||
pusher, ok := w.(http.Pusher)
|
pusher, ok := w.(http.Pusher)
|
||||||
if ok {
|
if ok {
|
||||||
pusher.Push("/static/main.css", nil)
|
pusher.Push("/static/"+headerVars.ThemeName+"/main.css", nil)
|
||||||
pusher.Push("/static/global.js", nil)
|
pusher.Push("/static/global.js", nil)
|
||||||
pusher.Push("/static/jquery-3.1.1.min.js", nil)
|
pusher.Push("/static/jquery-3.1.1.min.js", nil)
|
||||||
// TO-DO: Push the theme CSS files
|
// TO-DO: Push the theme CSS files
|
||||||
@ -372,7 +383,7 @@ func _pre_route(w http.ResponseWriter, r *http.Request) (User,bool) {
|
|||||||
if halt {
|
if halt {
|
||||||
return *user, false
|
return *user, false
|
||||||
}
|
}
|
||||||
if user == &guest_user {
|
if user == &guestUser {
|
||||||
return *user, true
|
return *user, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,13 +392,13 @@ func _pre_route(w http.ResponseWriter, r *http.Request) (User,bool) {
|
|||||||
PreError("Bad IP", w, r)
|
PreError("Bad IP", w, r)
|
||||||
return *user, false
|
return *user, false
|
||||||
}
|
}
|
||||||
if host != user.Last_IP {
|
if host != user.LastIP {
|
||||||
_, err = update_last_ip_stmt.Exec(host, user.ID)
|
_, err = update_last_ip_stmt.Exec(host, user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(err, w)
|
InternalError(err, w)
|
||||||
return *user, false
|
return *user, false
|
||||||
}
|
}
|
||||||
user.Last_IP = host
|
user.LastIP = host
|
||||||
}
|
}
|
||||||
|
|
||||||
// TO-DO: Set the X-Frame-Options header
|
// TO-DO: Set the X-Frame-Options header
|
||||||
@ -405,20 +416,20 @@ func words_to_score(wcount int, topic bool) (score int) {
|
|||||||
if wcount >= settings["megapost_min_words"].(int) {
|
if wcount >= settings["megapost_min_words"].(int) {
|
||||||
score += 4
|
score += 4
|
||||||
} else if wcount >= settings["bigpost_min_words"].(int) {
|
} else if wcount >= settings["bigpost_min_words"].(int) {
|
||||||
score += 1
|
score++
|
||||||
}
|
}
|
||||||
return score
|
return score
|
||||||
}
|
}
|
||||||
|
|
||||||
func increase_post_user_stats(wcount int, uid int, topic bool, user User) error {
|
func increase_post_user_stats(wcount int, uid int, topic bool, user User) error {
|
||||||
var mod int
|
var mod int
|
||||||
base_score := 1
|
baseScore := 1
|
||||||
if topic {
|
if topic {
|
||||||
_, err := increment_user_topics_stmt.Exec(1, uid)
|
_, err := increment_user_topics_stmt.Exec(1, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
base_score = 2
|
baseScore = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
settings := settingBox.Load().(SettingBox)
|
settings := settingBox.Load().(SettingBox)
|
||||||
@ -440,25 +451,25 @@ func increase_post_user_stats(wcount int, uid int, topic bool, user User) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, err := increment_user_score_stmt.Exec(base_score + mod, uid)
|
_, err := increment_user_score_stmt.Exec(baseScore+mod, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
//log.Print(user.Score + base_score + mod)
|
//log.Print(user.Score + base_score + mod)
|
||||||
//log.Print(getLevel(user.Score + base_score + mod))
|
//log.Print(getLevel(user.Score + base_score + mod))
|
||||||
_, err = update_user_level_stmt.Exec(getLevel(user.Score + base_score + mod), uid)
|
_, err = update_user_level_stmt.Exec(getLevel(user.Score+baseScore+mod), uid)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func decrease_post_user_stats(wcount int, uid int, topic bool, user User) error {
|
func decrease_post_user_stats(wcount int, uid int, topic bool, user User) error {
|
||||||
var mod int
|
var mod int
|
||||||
base_score := -1
|
baseScore := -1
|
||||||
if topic {
|
if topic {
|
||||||
_, err := increment_user_topics_stmt.Exec(-1, uid)
|
_, err := increment_user_topics_stmt.Exec(-1, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
base_score = -2
|
baseScore = -2
|
||||||
}
|
}
|
||||||
|
|
||||||
settings := settingBox.Load().(SettingBox)
|
settings := settingBox.Load().(SettingBox)
|
||||||
@ -480,16 +491,16 @@ func decrease_post_user_stats(wcount int, uid int, topic bool, user User) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, err := increment_user_score_stmt.Exec(base_score - mod, uid)
|
_, err := increment_user_score_stmt.Exec(baseScore-mod, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = update_user_level_stmt.Exec(getLevel(user.Score - base_score - mod), uid)
|
_, err = update_user_level_stmt.Exec(getLevel(user.Score-baseScore-mod), uid)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func init_user_perms(user *User) {
|
func initUserPerms(user *User) {
|
||||||
if user.Is_Super_Admin {
|
if user.IsSuperAdmin {
|
||||||
user.Perms = AllPerms
|
user.Perms = AllPerms
|
||||||
user.PluginPerms = AllPluginPerms
|
user.PluginPerms = AllPluginPerms
|
||||||
} else {
|
} else {
|
||||||
@ -501,16 +512,16 @@ func init_user_perms(user *User) {
|
|||||||
user.Group = user.TempGroup
|
user.Group = user.TempGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Is_Admin = user.Is_Super_Admin || groups[user.Group].Is_Admin
|
user.IsAdmin = user.IsSuperAdmin || groups[user.Group].IsAdmin
|
||||||
user.Is_Super_Mod = user.Is_Admin || groups[user.Group].Is_Mod
|
user.IsSuperMod = user.IsAdmin || groups[user.Group].IsMod
|
||||||
user.Is_Mod = user.Is_Super_Mod
|
user.IsMod = user.IsSuperMod
|
||||||
user.Is_Banned = groups[user.Group].Is_Banned
|
user.IsBanned = groups[user.Group].IsBanned
|
||||||
if user.Is_Banned && user.Is_Super_Mod {
|
if user.IsBanned && user.IsSuperMod {
|
||||||
user.Is_Banned = false
|
user.IsBanned = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func build_profile_url(slug string, uid int) string {
|
func buildProfileURL(slug string, uid int) string {
|
||||||
if slug == "" {
|
if slug == "" {
|
||||||
return "/user/" + strconv.Itoa(uid)
|
return "/user/" + strconv.Itoa(uid)
|
||||||
}
|
}
|
||||||
|
150
user_store.go
150
user_store.go
@ -1,12 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"sync"
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
"strconv"
|
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"./query_gen/lib"
|
"./query_gen/lib"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
// TO-DO: Add the watchdog goroutine
|
// TO-DO: Add the watchdog goroutine
|
||||||
var users UserStore
|
var users UserStore
|
||||||
var err_account_exists = errors.New("This username is already in use.")
|
var errAccountExists = errors.New("this username is already in use")
|
||||||
|
|
||||||
type UserStore interface {
|
type UserStore interface {
|
||||||
Load(id int) error
|
Load(id int) error
|
||||||
@ -106,7 +106,7 @@ func (sus *MemoryUserStore) CascadeGet(id int) (*User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
user = &User{ID: id, Loggedin: true}
|
user = &User{ID: id, Loggedin: true}
|
||||||
err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP, &user.TempGroup)
|
err := sus.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 != "" {
|
if user.Avatar != "" {
|
||||||
if user.Avatar[0] == '.' {
|
if user.Avatar[0] == '.' {
|
||||||
@ -115,9 +115,9 @@ func (sus *MemoryUserStore) CascadeGet(id int) (*User, error) {
|
|||||||
} else {
|
} else {
|
||||||
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
||||||
}
|
}
|
||||||
user.Link = build_profile_url(name_to_slug(user.Name),id)
|
user.Link = buildProfileURL(nameToSlug(user.Name), id)
|
||||||
user.Tag = groups[user.Group].Tag
|
user.Tag = groups[user.Group].Tag
|
||||||
init_user_perms(user)
|
initUserPerms(user)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
sus.Set(user)
|
sus.Set(user)
|
||||||
}
|
}
|
||||||
@ -138,22 +138,22 @@ func (sus *MemoryUserStore) bulkGet(ids []int) (list []*User) {
|
|||||||
// TO-DO: Optimise the query to avoid preparing it on the spot? Maybe, use knowledge of the most common IN() parameter counts?
|
// TO-DO: Optimise the query to avoid preparing it on the spot? Maybe, use knowledge of the most common IN() parameter counts?
|
||||||
// TO-DO: ID of 0 should always error?
|
// TO-DO: ID of 0 should always error?
|
||||||
func (sus *MemoryUserStore) BulkCascadeGetMap(ids []int) (list map[int]*User, err error) {
|
func (sus *MemoryUserStore) BulkCascadeGetMap(ids []int) (list map[int]*User, err error) {
|
||||||
var id_count int = len(ids)
|
var idCount int = len(ids)
|
||||||
list = make(map[int]*User)
|
list = make(map[int]*User)
|
||||||
if id_count == 0 {
|
if idCount == 0 {
|
||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var still_here []int
|
var stillHere []int
|
||||||
slice_list := sus.bulkGet(ids)
|
sliceList := sus.bulkGet(ids)
|
||||||
for i, slice_item := range slice_list {
|
for i, sliceItem := range sliceList {
|
||||||
if slice_item != nil {
|
if sliceItem != nil {
|
||||||
list[slice_item.ID] = slice_item
|
list[sliceItem.ID] = sliceItem
|
||||||
} else {
|
} else {
|
||||||
still_here = append(still_here,ids[i])
|
stillHere = append(stillHere, ids[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ids = still_here
|
ids = stillHere
|
||||||
|
|
||||||
// If every user is in the cache, then return immediately
|
// If every user is in the cache, then return immediately
|
||||||
if len(ids) == 0 {
|
if len(ids) == 0 {
|
||||||
@ -180,7 +180,7 @@ func (sus *MemoryUserStore) BulkCascadeGetMap(ids []int) (list map[int]*User, er
|
|||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
user := &User{Loggedin: true}
|
user := &User{Loggedin: true}
|
||||||
err := rows.Scan(&user.ID, &user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP, &user.TempGroup)
|
err := rows.Scan(&user.ID, &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 err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -193,40 +193,40 @@ func (sus *MemoryUserStore) BulkCascadeGetMap(ids []int) (list map[int]*User, er
|
|||||||
} else {
|
} else {
|
||||||
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
||||||
}
|
}
|
||||||
user.Link = build_profile_url(name_to_slug(user.Name),user.ID)
|
user.Link = buildProfileURL(nameToSlug(user.Name), user.ID)
|
||||||
user.Tag = groups[user.Group].Tag
|
user.Tag = groups[user.Group].Tag
|
||||||
init_user_perms(user)
|
initUserPerms(user)
|
||||||
|
|
||||||
// Add it to the cache...
|
// Add it to the cache...
|
||||||
sus.Set(user)
|
_ = sus.Set(user)
|
||||||
|
|
||||||
// Add it to the list to be returned
|
// Add it to the list to be returned
|
||||||
list[user.ID] = user
|
list[user.ID] = user
|
||||||
}
|
}
|
||||||
|
|
||||||
// Did we miss any users?
|
// Did we miss any users?
|
||||||
if id_count > len(list) {
|
if idCount > len(list) {
|
||||||
var sid_list string
|
var sidList string
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
_, ok := list[id]
|
_, ok := list[id]
|
||||||
if !ok {
|
if !ok {
|
||||||
sid_list += strconv.Itoa(id) + ","
|
sidList += strconv.Itoa(id) + ","
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We probably don't need this, but it might be useful in case of bugs in BulkCascadeGetMap
|
// We probably don't need this, but it might be useful in case of bugs in BulkCascadeGetMap
|
||||||
if sid_list == "" {
|
if sidList == "" {
|
||||||
if dev.DebugMode {
|
if dev.DebugMode {
|
||||||
log.Print("This data is sampled later in the BulkCascadeGetMap function, so it might miss the cached IDs")
|
log.Print("This data is sampled later in the BulkCascadeGetMap function, so it might miss the cached IDs")
|
||||||
log.Print("id_count",id_count)
|
log.Print("idCount", idCount)
|
||||||
log.Print("ids", ids)
|
log.Print("ids", ids)
|
||||||
log.Print("list", list)
|
log.Print("list", list)
|
||||||
}
|
}
|
||||||
return list, errors.New("We weren't able to find a user, but we don't know which one")
|
return list, errors.New("We weren't able to find a user, but we don't know which one")
|
||||||
}
|
}
|
||||||
sid_list = sid_list[0:len(sid_list) - 1]
|
sidList = sidList[0 : len(sidList)-1]
|
||||||
|
|
||||||
return list, errors.New("Unable to find the users with the following IDs: " + sid_list)
|
return list, errors.New("Unable to find the users with the following IDs: " + sidList)
|
||||||
}
|
}
|
||||||
|
|
||||||
return list, nil
|
return list, nil
|
||||||
@ -234,7 +234,7 @@ func (sus *MemoryUserStore) BulkCascadeGetMap(ids []int) (list map[int]*User, er
|
|||||||
|
|
||||||
func (sus *MemoryUserStore) BypassGet(id int) (*User, error) {
|
func (sus *MemoryUserStore) BypassGet(id int) (*User, error) {
|
||||||
user := &User{ID: id, Loggedin: true}
|
user := &User{ID: id, Loggedin: true}
|
||||||
err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP, &user.TempGroup)
|
err := sus.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 != "" {
|
if user.Avatar != "" {
|
||||||
if user.Avatar[0] == '.' {
|
if user.Avatar[0] == '.' {
|
||||||
@ -243,15 +243,15 @@ func (sus *MemoryUserStore) BypassGet(id int) (*User, error) {
|
|||||||
} else {
|
} else {
|
||||||
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
||||||
}
|
}
|
||||||
user.Link = build_profile_url(name_to_slug(user.Name),id)
|
user.Link = buildProfileURL(nameToSlug(user.Name), id)
|
||||||
user.Tag = groups[user.Group].Tag
|
user.Tag = groups[user.Group].Tag
|
||||||
init_user_perms(user)
|
initUserPerms(user)
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sus *MemoryUserStore) Load(id int) error {
|
func (sus *MemoryUserStore) Load(id int) error {
|
||||||
user := &User{ID: id, Loggedin: true}
|
user := &User{ID: id, Loggedin: true}
|
||||||
err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP, &user.TempGroup)
|
err := sus.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 err != nil {
|
if err != nil {
|
||||||
sus.Remove(id)
|
sus.Remove(id)
|
||||||
return err
|
return err
|
||||||
@ -264,10 +264,10 @@ func (sus *MemoryUserStore) Load(id int) error {
|
|||||||
} else {
|
} else {
|
||||||
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
||||||
}
|
}
|
||||||
user.Link = build_profile_url(name_to_slug(user.Name),id)
|
user.Link = buildProfileURL(nameToSlug(user.Name), id)
|
||||||
user.Tag = groups[user.Group].Tag
|
user.Tag = groups[user.Group].Tag
|
||||||
init_user_perms(user)
|
initUserPerms(user)
|
||||||
sus.Set(user)
|
_ = sus.Set(user)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +326,7 @@ func (sus *MemoryUserStore) CreateUser(username string, password string, email s
|
|||||||
// Is this username already taken..?
|
// Is this username already taken..?
|
||||||
err := sus.username_exists.QueryRow(username).Scan(&username)
|
err := sus.username_exists.QueryRow(username).Scan(&username)
|
||||||
if err != ErrNoRows {
|
if err != ErrNoRows {
|
||||||
return 0, err_account_exists
|
return 0, errAccountExists
|
||||||
}
|
}
|
||||||
|
|
||||||
salt, err := GenerateSafeString(saltLength)
|
salt, err := GenerateSafeString(saltLength)
|
||||||
@ -334,18 +334,18 @@ func (sus *MemoryUserStore) CreateUser(username string, password string, email s
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
hashed_password, err := bcrypt.GenerateFromPassword([]byte(password + salt), bcrypt.DefaultCost)
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password+salt), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := sus.register.Exec(username,email,string(hashed_password),salt,group,active)
|
res, err := sus.register.Exec(username, email, string(hashedPassword), salt, group, active)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
lastId, err := res.LastInsertId()
|
lastID, err := res.LastInsertId()
|
||||||
return int(lastId), err
|
return int(lastID), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sus *MemoryUserStore) GetLength() int {
|
func (sus *MemoryUserStore) GetLength() int {
|
||||||
@ -373,44 +373,44 @@ func (sus *MemoryUserStore) GetGlobalCount() int {
|
|||||||
type SqlUserStore struct {
|
type SqlUserStore struct {
|
||||||
get *sql.Stmt
|
get *sql.Stmt
|
||||||
register *sql.Stmt
|
register *sql.Stmt
|
||||||
username_exists *sql.Stmt
|
usernameExists *sql.Stmt
|
||||||
user_count *sql.Stmt
|
userCount *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSqlUserStore() *SqlUserStore {
|
func NewSqlUserStore() *SqlUserStore {
|
||||||
get_stmt, err := qgen.Builder.SimpleSelect("users","name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip, temp_group","uid = ?","","")
|
getStmt, err := qgen.Builder.SimpleSelect("users", "name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip, temp_group", "uid = ?", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add an admin version of register_stmt with more flexibility?
|
// Add an admin version of register_stmt with more flexibility?
|
||||||
// create_account_stmt, err = db.Prepare("INSERT INTO
|
// create_account_stmt, err = db.Prepare("INSERT INTO
|
||||||
register_stmt, err := qgen.Builder.SimpleInsert("users","name, email, password, salt, group, is_super_admin, session, active, message","?,?,?,?,?,0,'',?,''")
|
registerStmt, err := qgen.Builder.SimpleInsert("users", "name, email, password, salt, group, is_super_admin, session, active, message", "?,?,?,?,?,0,'',?,''")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
username_exists_stmt, err := qgen.Builder.SimpleSelect("users","name","name = ?","","")
|
usernameExistsStmt, err := qgen.Builder.SimpleSelect("users", "name", "name = ?", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
user_count_stmt, err := qgen.Builder.SimpleCount("users","","")
|
userCountStmt, err := qgen.Builder.SimpleCount("users", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SqlUserStore{
|
return &SqlUserStore{
|
||||||
get: get_stmt,
|
get: getStmt,
|
||||||
register: register_stmt,
|
register: registerStmt,
|
||||||
username_exists: username_exists_stmt,
|
usernameExists: usernameExistsStmt,
|
||||||
user_count: user_count_stmt,
|
userCount: userCountStmt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sus *SqlUserStore) Get(id int) (*User, error) {
|
func (sus *SqlUserStore) Get(id int) (*User, error) {
|
||||||
user := User{ID: id, Loggedin: true}
|
user := User{ID: id, Loggedin: true}
|
||||||
err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP, &user.TempGroup)
|
err := sus.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 != "" {
|
if user.Avatar != "" {
|
||||||
if user.Avatar[0] == '.' {
|
if user.Avatar[0] == '.' {
|
||||||
@ -419,15 +419,15 @@ func (sus *SqlUserStore) Get(id int) (*User, error) {
|
|||||||
} else {
|
} else {
|
||||||
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
||||||
}
|
}
|
||||||
user.Link = build_profile_url(name_to_slug(user.Name),id)
|
user.Link = buildProfileURL(nameToSlug(user.Name), id)
|
||||||
user.Tag = groups[user.Group].Tag
|
user.Tag = groups[user.Group].Tag
|
||||||
init_user_perms(&user)
|
initUserPerms(&user)
|
||||||
return &user, err
|
return &user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sus *SqlUserStore) GetUnsafe(id int) (*User, error) {
|
func (sus *SqlUserStore) GetUnsafe(id int) (*User, error) {
|
||||||
user := User{ID: id, Loggedin: true}
|
user := User{ID: id, Loggedin: true}
|
||||||
err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP, &user.TempGroup)
|
err := sus.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 != "" {
|
if user.Avatar != "" {
|
||||||
if user.Avatar[0] == '.' {
|
if user.Avatar[0] == '.' {
|
||||||
@ -436,15 +436,15 @@ func (sus *SqlUserStore) GetUnsafe(id int) (*User, error) {
|
|||||||
} else {
|
} else {
|
||||||
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
||||||
}
|
}
|
||||||
user.Link = build_profile_url(name_to_slug(user.Name),id)
|
user.Link = buildProfileURL(nameToSlug(user.Name), id)
|
||||||
user.Tag = groups[user.Group].Tag
|
user.Tag = groups[user.Group].Tag
|
||||||
init_user_perms(&user)
|
initUserPerms(&user)
|
||||||
return &user, err
|
return &user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sus *SqlUserStore) CascadeGet(id int) (*User, error) {
|
func (sus *SqlUserStore) CascadeGet(id int) (*User, error) {
|
||||||
user := User{ID: id, Loggedin: true}
|
user := User{ID: id, Loggedin: true}
|
||||||
err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP, &user.TempGroup)
|
err := sus.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 != "" {
|
if user.Avatar != "" {
|
||||||
if user.Avatar[0] == '.' {
|
if user.Avatar[0] == '.' {
|
||||||
@ -453,9 +453,9 @@ func (sus *SqlUserStore) CascadeGet(id int) (*User, error) {
|
|||||||
} else {
|
} else {
|
||||||
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
||||||
}
|
}
|
||||||
user.Link = build_profile_url(name_to_slug(user.Name),id)
|
user.Link = buildProfileURL(nameToSlug(user.Name), id)
|
||||||
user.Tag = groups[user.Group].Tag
|
user.Tag = groups[user.Group].Tag
|
||||||
init_user_perms(&user)
|
initUserPerms(&user)
|
||||||
return &user, err
|
return &user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,7 +482,7 @@ func (sus *SqlUserStore) BulkCascadeGetMap(ids []int) (list map[int]*User, err e
|
|||||||
list = make(map[int]*User)
|
list = make(map[int]*User)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
user := &User{Loggedin: true}
|
user := &User{Loggedin: true}
|
||||||
err := rows.Scan(&user.ID, &user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP, &user.TempGroup)
|
err := rows.Scan(&user.ID, &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 err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -495,9 +495,9 @@ func (sus *SqlUserStore) BulkCascadeGetMap(ids []int) (list map[int]*User, err e
|
|||||||
} else {
|
} else {
|
||||||
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
||||||
}
|
}
|
||||||
user.Link = build_profile_url(name_to_slug(user.Name),user.ID)
|
user.Link = buildProfileURL(nameToSlug(user.Name), user.ID)
|
||||||
user.Tag = groups[user.Group].Tag
|
user.Tag = groups[user.Group].Tag
|
||||||
init_user_perms(user)
|
initUserPerms(user)
|
||||||
|
|
||||||
// Add it to the list to be returned
|
// Add it to the list to be returned
|
||||||
list[user.ID] = user
|
list[user.ID] = user
|
||||||
@ -508,7 +508,7 @@ func (sus *SqlUserStore) BulkCascadeGetMap(ids []int) (list map[int]*User, err e
|
|||||||
|
|
||||||
func (sus *SqlUserStore) BypassGet(id int) (*User, error) {
|
func (sus *SqlUserStore) BypassGet(id int) (*User, error) {
|
||||||
user := User{ID: id, Loggedin: true}
|
user := User{ID: id, Loggedin: true}
|
||||||
err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP, &user.TempGroup)
|
err := sus.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 != "" {
|
if user.Avatar != "" {
|
||||||
if user.Avatar[0] == '.' {
|
if user.Avatar[0] == '.' {
|
||||||
@ -517,23 +517,23 @@ func (sus *SqlUserStore) BypassGet(id int) (*User, error) {
|
|||||||
} else {
|
} else {
|
||||||
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
user.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(user.ID), 1)
|
||||||
}
|
}
|
||||||
user.Link = build_profile_url(name_to_slug(user.Name),id)
|
user.Link = buildProfileURL(nameToSlug(user.Name), id)
|
||||||
user.Tag = groups[user.Group].Tag
|
user.Tag = groups[user.Group].Tag
|
||||||
init_user_perms(&user)
|
initUserPerms(&user)
|
||||||
return &user, err
|
return &user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sus *SqlUserStore) Load(id int) error {
|
func (sus *SqlUserStore) Load(id int) error {
|
||||||
user := &User{ID: id}
|
user := &User{ID: id}
|
||||||
// Simplify this into a quick check to see whether the user exists. Add an Exists method to facilitate this?
|
// Simplify this into a quick check to see whether the user exists. Add an Exists method to facilitate this?
|
||||||
return sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP, &user.TempGroup)
|
return sus.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)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sus *SqlUserStore) CreateUser(username string, password string, email string, group int, active int) (int, error) {
|
func (sus *SqlUserStore) CreateUser(username string, password string, email string, group int, active int) (int, error) {
|
||||||
// Is this username already taken..?
|
// Is this username already taken..?
|
||||||
err := sus.username_exists.QueryRow(username).Scan(&username)
|
err := sus.usernameExists.QueryRow(username).Scan(&username)
|
||||||
if err != ErrNoRows {
|
if err != ErrNoRows {
|
||||||
return 0, err_account_exists
|
return 0, errAccountExists
|
||||||
}
|
}
|
||||||
|
|
||||||
salt, err := GenerateSafeString(saltLength)
|
salt, err := GenerateSafeString(saltLength)
|
||||||
@ -541,18 +541,18 @@ func (sus *SqlUserStore) CreateUser(username string, password string, email stri
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
hashed_password, err := bcrypt.GenerateFromPassword([]byte(password + salt), bcrypt.DefaultCost)
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password+salt), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := sus.register.Exec(username,email,string(hashed_password),salt,group,active)
|
res, err := sus.register.Exec(username, email, string(hashedPassword), salt, group, active)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
lastId, err := res.LastInsertId()
|
lastID, err := res.LastInsertId()
|
||||||
return int(lastId), err
|
return int(lastID), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Placeholder methods, as we're not don't need to do any cache management with this implementation ofr the UserStore
|
// Placeholder methods, as we're not don't need to do any cache management with this implementation ofr the UserStore
|
||||||
@ -578,7 +578,7 @@ func (sus *SqlUserStore) GetCapacity() int {
|
|||||||
// Return the total number of users registered on the forums
|
// Return the total number of users registered on the forums
|
||||||
func (sus *SqlUserStore) GetLength() int {
|
func (sus *SqlUserStore) GetLength() int {
|
||||||
var ucount int
|
var ucount int
|
||||||
err := sus.user_count.QueryRow().Scan(&ucount)
|
err := sus.userCount.QueryRow().Scan(&ucount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError(err)
|
LogError(err)
|
||||||
}
|
}
|
||||||
@ -586,7 +586,7 @@ func (sus *SqlUserStore) GetLength() int {
|
|||||||
}
|
}
|
||||||
func (sus *SqlUserStore) GetGlobalCount() int {
|
func (sus *SqlUserStore) GetGlobalCount() int {
|
||||||
var ucount int
|
var ucount int
|
||||||
err := sus.user_count.QueryRow().Scan(&ucount)
|
err := sus.userCount.QueryRow().Scan(&ucount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError(err)
|
LogError(err)
|
||||||
}
|
}
|
||||||
|
173
utils.go
173
utils.go
@ -1,21 +1,21 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
"os"
|
|
||||||
"math"
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
"strconv"
|
|
||||||
"encoding/base64"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Version struct
|
// Version stores a Gosora version
|
||||||
{
|
type Version struct {
|
||||||
Major int
|
Major int
|
||||||
Minor int
|
Minor int
|
||||||
Patch int
|
Patch int
|
||||||
@ -34,7 +34,7 @@ func (version *Version) String() (out string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a cryptographically secure set of random bytes..
|
// GenerateSafeString is for generating a cryptographically secure set of random bytes..
|
||||||
func GenerateSafeString(length int) (string, error) {
|
func GenerateSafeString(length int) (string, error) {
|
||||||
rb := make([]byte, length)
|
rb := make([]byte, length)
|
||||||
_, err := rand.Read(rb)
|
_, err := rand.Read(rb)
|
||||||
@ -44,7 +44,7 @@ func GenerateSafeString(length int) (string, error) {
|
|||||||
return base64.URLEncoding.EncodeToString(rb), nil
|
return base64.URLEncoding.EncodeToString(rb), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func relative_time(in string) (string, error) {
|
func relativeTime(in string) (string, error) {
|
||||||
if in == "" {
|
if in == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
@ -64,38 +64,60 @@ func relative_time(in string) (string, error) {
|
|||||||
case months > 11:
|
case months > 11:
|
||||||
//return t.Format("Mon Jan 2 2006"), err
|
//return t.Format("Mon Jan 2 2006"), err
|
||||||
return t.Format("Jan 2 2006"), err
|
return t.Format("Jan 2 2006"), err
|
||||||
case months > 1: return fmt.Sprintf("%d months ago", months), err
|
case months > 1:
|
||||||
case months == 1: return "a month ago", err
|
return fmt.Sprintf("%d months ago", months), err
|
||||||
case weeks > 1: return fmt.Sprintf("%d weeks ago", weeks), err
|
case months == 1:
|
||||||
case int(hours / 24) == 7: return "a week ago", err
|
return "a month ago", err
|
||||||
case int(hours / 24) == 1: return "1 day ago", err
|
case weeks > 1:
|
||||||
case int(hours / 24) > 1: return fmt.Sprintf("%d days ago", int(hours / 24)), err
|
return fmt.Sprintf("%d weeks ago", weeks), err
|
||||||
case seconds <= 1: return "a moment ago", err
|
case int(hours/24) == 7:
|
||||||
case seconds < 60: return fmt.Sprintf("%d seconds ago", int(seconds)), err
|
return "a week ago", err
|
||||||
case seconds < 120: return "a minute ago", err
|
case int(hours/24) == 1:
|
||||||
case seconds < 3600: return fmt.Sprintf("%d minutes ago", int(seconds / 60)), err
|
return "1 day ago", err
|
||||||
case seconds < 7200: return "an hour ago", err
|
case int(hours/24) > 1:
|
||||||
default: return fmt.Sprintf("%d hours ago", int(seconds / 60 / 60)), err
|
return fmt.Sprintf("%d days ago", int(hours/24)), err
|
||||||
|
case seconds <= 1:
|
||||||
|
return "a moment ago", err
|
||||||
|
case seconds < 60:
|
||||||
|
return fmt.Sprintf("%d seconds ago", int(seconds)), err
|
||||||
|
case seconds < 120:
|
||||||
|
return "a minute ago", err
|
||||||
|
case seconds < 3600:
|
||||||
|
return fmt.Sprintf("%d minutes ago", int(seconds/60)), err
|
||||||
|
case seconds < 7200:
|
||||||
|
return "an hour ago", err
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("%d hours ago", int(seconds/60/60)), err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func convert_byte_unit(bytes float64) (float64,string) {
|
func convertByteUnit(bytes float64) (float64, string) {
|
||||||
switch {
|
switch {
|
||||||
case bytes >= float64(terabyte): return bytes / float64(terabyte), "TB"
|
case bytes >= float64(terabyte):
|
||||||
case bytes >= float64(gigabyte): return bytes / float64(gigabyte), "GB"
|
return bytes / float64(terabyte), "TB"
|
||||||
case bytes >= float64(megabyte): return bytes / float64(megabyte), "MB"
|
case bytes >= float64(gigabyte):
|
||||||
case bytes >= float64(kilobyte): return bytes / float64(kilobyte), "KB"
|
return bytes / float64(gigabyte), "GB"
|
||||||
default: return bytes, " bytes"
|
case bytes >= float64(megabyte):
|
||||||
|
return bytes / float64(megabyte), "MB"
|
||||||
|
case bytes >= float64(kilobyte):
|
||||||
|
return bytes / float64(kilobyte), "KB"
|
||||||
|
default:
|
||||||
|
return bytes, " bytes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func convert_byte_in_unit(bytes float64,unit string) (count float64) {
|
func convertByteInUnit(bytes float64, unit string) (count float64) {
|
||||||
switch(unit) {
|
switch unit {
|
||||||
case "TB": count = bytes / float64(terabyte)
|
case "TB":
|
||||||
case "GB": count = bytes / float64(gigabyte)
|
count = bytes / float64(terabyte)
|
||||||
case "MB": count = bytes / float64(megabyte)
|
case "GB":
|
||||||
case "KB": count = bytes / float64(kilobyte)
|
count = bytes / float64(gigabyte)
|
||||||
default: count = 0.1
|
case "MB":
|
||||||
|
count = bytes / float64(megabyte)
|
||||||
|
case "KB":
|
||||||
|
count = bytes / float64(kilobyte)
|
||||||
|
default:
|
||||||
|
count = 0.1
|
||||||
}
|
}
|
||||||
|
|
||||||
if count < 0.1 {
|
if count < 0.1 {
|
||||||
@ -104,27 +126,37 @@ func convert_byte_in_unit(bytes float64,unit string) (count float64) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func convert_unit(num int) (int,string) {
|
func convertUnit(num int) (int, string) {
|
||||||
switch {
|
switch {
|
||||||
case num >= 1000000000000: return 0, "∞"
|
case num >= 1000000000000:
|
||||||
case num >= 1000000000: return num / 1000000000, "B"
|
return 0, "∞"
|
||||||
case num >= 1000000: return num / 1000000, "M"
|
case num >= 1000000000:
|
||||||
case num >= 1000: return num / 1000, "K"
|
return num / 1000000000, "B"
|
||||||
default: return num, ""
|
case num >= 1000000:
|
||||||
|
return num / 1000000, "M"
|
||||||
|
case num >= 1000:
|
||||||
|
return num / 1000, "K"
|
||||||
|
default:
|
||||||
|
return num, ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func convert_friendly_unit(num int) (int,string) {
|
func convertFriendlyUnit(num int) (int, string) {
|
||||||
switch {
|
switch {
|
||||||
case num >= 1000000000000: return 0, " zillion"
|
case num >= 1000000000000:
|
||||||
case num >= 1000000000: return num / 1000000000, " billion"
|
return 0, " zillion"
|
||||||
case num >= 1000000: return num / 1000000, " million"
|
case num >= 1000000000:
|
||||||
case num >= 1000: return num / 1000, " thousand"
|
return num / 1000000000, " billion"
|
||||||
default: return num, ""
|
case num >= 1000000:
|
||||||
|
return num / 1000000, " million"
|
||||||
|
case num >= 1000:
|
||||||
|
return num / 1000, " thousand"
|
||||||
|
default:
|
||||||
|
return num, ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func name_to_slug(name string) (slug string) {
|
func nameToSlug(name string) (slug string) {
|
||||||
name = strings.TrimSpace(name)
|
name = strings.TrimSpace(name)
|
||||||
name = strings.Replace(name, " ", " ", -1)
|
name = strings.Replace(name, " ", " ", -1)
|
||||||
|
|
||||||
@ -193,12 +225,12 @@ func SendEmail(email string, subject string, msg string) (res bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func weak_password(password string) error {
|
func weakPassword(password string) error {
|
||||||
if len(password) < 8 {
|
if len(password) < 8 {
|
||||||
return errors.New("Your password needs to be at-least eight characters long.")
|
return errors.New("your password needs to be at-least eight characters long")
|
||||||
}
|
}
|
||||||
var charMap map[rune]int = make(map[rune]int)
|
var charMap map[rune]int = make(map[rune]int)
|
||||||
var numbers, /*letters, */symbols, upper, lower int
|
var numbers /*letters, */, symbols, upper, lower int
|
||||||
for _, char := range password {
|
for _, char := range password {
|
||||||
charItem, ok := charMap[char]
|
charItem, ok := charMap[char]
|
||||||
if ok {
|
if ok {
|
||||||
@ -222,35 +254,38 @@ func weak_password(password string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TO-DO: Disable the linter on these and fix up the grammar
|
||||||
if numbers == 0 {
|
if numbers == 0 {
|
||||||
return errors.New("You don't have any numbers in your password.")
|
return errors.New("you don't have any numbers in your password")
|
||||||
}
|
}
|
||||||
/*if letters == 0 {
|
/*if letters == 0 {
|
||||||
return errors.New("You don't have any letters in your password.")
|
return errors.New("You don't have any letters in your password.")
|
||||||
}*/
|
}*/
|
||||||
if upper == 0 {
|
if upper == 0 {
|
||||||
return errors.New("You don't have any uppercase characters in your password.")
|
return errors.New("you don't have any uppercase characters in your password")
|
||||||
}
|
}
|
||||||
if lower == 0 {
|
if lower == 0 {
|
||||||
return errors.New("You don't have any lowercase characters in your password.")
|
return errors.New("you don't have any lowercase characters in your password")
|
||||||
}
|
}
|
||||||
if (len(password) / 2) > len(charMap) {
|
if (len(password) / 2) > len(charMap) {
|
||||||
return errors.New("You don't have enough unique characters in your password.")
|
return errors.New("you don't have enough unique characters in your password")
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(strings.ToLower(password), "test") || /*strings.Contains(strings.ToLower(password),"123456") || */ strings.Contains(strings.ToLower(password), "123") || strings.Contains(strings.ToLower(password), "password") || strings.Contains(strings.ToLower(password), "qwerty") {
|
if strings.Contains(strings.ToLower(password), "test") || /*strings.Contains(strings.ToLower(password),"123456") || */ strings.Contains(strings.ToLower(password), "123") || strings.Contains(strings.ToLower(password), "password") || strings.Contains(strings.ToLower(password), "qwerty") {
|
||||||
return errors.New("You may not have 'test', '123', 'password' or 'qwerty' in your password.")
|
return errors.New("you may not have 'test', '123', 'password' or 'qwerty' in your password")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func create_file(name string) error {
|
func createFile(name string) error {
|
||||||
f, err := os.Create(name)
|
f, err := os.Create(name)
|
||||||
f.Close()
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
func write_file(name string, content string) (err error) {
|
func writeFile(name string, content string) (err error) {
|
||||||
f, err := os.Create(name)
|
f, err := os.Create(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -259,12 +294,14 @@ func write_file(name string, content string) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
f.Sync()
|
err = f.Sync()
|
||||||
f.Close()
|
if err != nil {
|
||||||
return
|
return err
|
||||||
|
}
|
||||||
|
return f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func word_count(input string) (count int) {
|
func wordCount(input string) (count int) {
|
||||||
input = strings.TrimSpace(input)
|
input = strings.TrimSpace(input)
|
||||||
if input == "" {
|
if input == "" {
|
||||||
return 0
|
return 0
|
||||||
@ -343,14 +380,14 @@ func getLevels(maxLevel int) []float64 {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func fill_group_id_gap(biggerID int, smallerID int) {
|
func fillGroupIDGap(biggerID int, smallerID int) {
|
||||||
dummy := Group{ID: 0, Name: ""}
|
dummy := Group{ID: 0, Name: ""}
|
||||||
for i := smallerID; i > biggerID; i++ {
|
for i := smallerID; i > biggerID; i++ {
|
||||||
groups = append(groups, dummy)
|
groups = append(groups, dummy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func build_slug(slug string, id int) string {
|
func buildSlug(slug string, id int) string {
|
||||||
if slug == "" {
|
if slug == "" {
|
||||||
return strconv.Itoa(id)
|
return strconv.Itoa(id)
|
||||||
}
|
}
|
||||||
|
203
websockets.go
203
websockets.go
@ -3,63 +3,61 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"bytes"
|
|
||||||
"strconv"
|
|
||||||
"errors"
|
|
||||||
"runtime"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
"github.com/Azareal/gopsutil/cpu"
|
"github.com/Azareal/gopsutil/cpu"
|
||||||
"github.com/Azareal/gopsutil/mem"
|
"github.com/Azareal/gopsutil/mem"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WS_User struct
|
type WS_User struct {
|
||||||
{
|
|
||||||
conn *websocket.Conn
|
conn *websocket.Conn
|
||||||
User *User
|
User *User
|
||||||
}
|
}
|
||||||
|
|
||||||
type WS_Hub struct
|
type WS_Hub struct {
|
||||||
{
|
onlineUsers map[int]*WS_User
|
||||||
online_users map[int]*WS_User
|
onlineGuests map[*WS_User]bool
|
||||||
online_guests map[*WS_User]bool
|
|
||||||
guests sync.RWMutex
|
guests sync.RWMutex
|
||||||
users sync.RWMutex
|
users sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
var ws_hub WS_Hub
|
var wsHub WS_Hub
|
||||||
var ws_upgrader = websocket.Upgrader{ReadBufferSize:1024,WriteBufferSize:1024}
|
var wsUpgrader = websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024}
|
||||||
var ws_nouser error = errors.New("This user isn't connected via WebSockets")
|
var errWsNouser = errors.New("This user isn't connected via WebSockets")
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
enable_websockets = true
|
enableWebsockets = true
|
||||||
admin_stats_watchers = make(map[*WS_User]bool)
|
adminStatsWatchers = make(map[*WS_User]bool)
|
||||||
ws_hub = WS_Hub{
|
wsHub = WS_Hub{
|
||||||
online_users: make(map[int]*WS_User),
|
onlineUsers: make(map[int]*WS_User),
|
||||||
online_guests: make(map[*WS_User]bool),
|
onlineGuests: make(map[*WS_User]bool),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WS_Hub) guest_count() int {
|
func (hub *WS_Hub) guestCount() int {
|
||||||
defer hub.guests.RUnlock()
|
defer hub.guests.RUnlock()
|
||||||
hub.guests.RLock()
|
hub.guests.RLock()
|
||||||
return len(hub.online_guests)
|
return len(hub.onlineGuests)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WS_Hub) user_count() int {
|
func (hub *WS_Hub) userCount() int {
|
||||||
defer hub.users.RUnlock()
|
defer hub.users.RUnlock()
|
||||||
hub.users.RLock()
|
hub.users.RLock()
|
||||||
return len(hub.online_users)
|
return len(hub.onlineUsers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WS_Hub) broadcast_message(msg string) error {
|
func (hub *WS_Hub) broadcastMessage(msg string) error {
|
||||||
hub.users.RLock()
|
hub.users.RLock()
|
||||||
for _, ws_user := range hub.online_users {
|
for _, wsUser := range hub.onlineUsers {
|
||||||
w, err := ws_user.conn.NextWriter(websocket.TextMessage)
|
w, err := wsUser.conn.NextWriter(websocket.TextMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -69,15 +67,15 @@ func (hub *WS_Hub) broadcast_message(msg string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *WS_Hub) push_message(targetUser int, msg string) error {
|
func (hub *WS_Hub) pushMessage(targetUser int, msg string) error {
|
||||||
hub.users.RLock()
|
hub.users.RLock()
|
||||||
ws_user, ok := hub.online_users[targetUser]
|
wsUser, ok := hub.onlineUsers[targetUser]
|
||||||
hub.users.RUnlock()
|
hub.users.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
return ws_nouser
|
return errWsNouser
|
||||||
}
|
}
|
||||||
|
|
||||||
w, err := ws_user.conn.NextWriter(websocket.TextMessage)
|
w, err := wsUser.conn.NextWriter(websocket.TextMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -87,23 +85,23 @@ func (hub *WS_Hub) push_message(targetUser int, msg string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func(hub *WS_Hub) push_alert(targetUser int, asid int, event string, elementType string, actor_id int, targetUser_id int, elementID int) error {
|
func (hub *WS_Hub) pushAlert(targetUser int, asid int, event string, elementType string, actorID int, targetUser_id int, elementID int) error {
|
||||||
//log.Print("In push_alert")
|
//log.Print("In push_alert")
|
||||||
hub.users.RLock()
|
hub.users.RLock()
|
||||||
ws_user, ok := hub.online_users[targetUser]
|
wsUser, ok := hub.onlineUsers[targetUser]
|
||||||
hub.users.RUnlock()
|
hub.users.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
return ws_nouser
|
return errWsNouser
|
||||||
}
|
}
|
||||||
|
|
||||||
//log.Print("Building alert")
|
//log.Print("Building alert")
|
||||||
alert, err := build_alert(asid, event, elementType, actor_id, targetUser_id, elementID, *ws_user.User)
|
alert, err := buildAlert(asid, event, elementType, actorID, targetUser_id, elementID, *wsUser.User)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
//log.Print("Getting WS Writer")
|
//log.Print("Getting WS Writer")
|
||||||
w, err := ws_user.conn.NextWriter(websocket.TextMessage)
|
w, err := wsUser.conn.NextWriter(websocket.TextMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -113,33 +111,33 @@ func(hub *WS_Hub) push_alert(targetUser int, asid int, event string, elementType
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func(hub *WS_Hub) push_alerts(users []int, asid int, event string, elementType string, actor_id int, targetUser_id int, elementID int) error {
|
func (hub *WS_Hub) pushAlerts(users []int, asid int, event string, elementType string, actorID int, targetUserID int, elementID int) error {
|
||||||
//log.Print("In push_alerts")
|
//log.Print("In pushAlerts")
|
||||||
var ws_users []*WS_User
|
var wsUsers []*WS_User
|
||||||
hub.users.RLock()
|
hub.users.RLock()
|
||||||
// We don't want to keep a lock on this for too long, so we'll accept some nil pointers
|
// We don't want to keep a lock on this for too long, so we'll accept some nil pointers
|
||||||
for _, uid := range users {
|
for _, uid := range users {
|
||||||
ws_users = append(ws_users, hub.online_users[uid])
|
wsUsers = append(wsUsers, hub.onlineUsers[uid])
|
||||||
}
|
}
|
||||||
hub.users.RUnlock()
|
hub.users.RUnlock()
|
||||||
if len(ws_users) == 0 {
|
if len(wsUsers) == 0 {
|
||||||
return ws_nouser
|
return errWsNouser
|
||||||
}
|
}
|
||||||
|
|
||||||
var errs []error
|
var errs []error
|
||||||
for _, ws_user := range ws_users {
|
for _, wsUser := range wsUsers {
|
||||||
if ws_user == nil {
|
if wsUser == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
//log.Print("Building alert")
|
//log.Print("Building alert")
|
||||||
alert, err := build_alert(asid, event, elementType, actor_id, targetUser_id, elementID, *ws_user.User)
|
alert, err := buildAlert(asid, event, elementType, actorID, targetUserID, elementID, *wsUser.User)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//log.Print("Getting WS Writer")
|
//log.Print("Getting WS Writer")
|
||||||
w, err := ws_user.conn.NextWriter(websocket.TextMessage)
|
w, err := wsUser.conn.NextWriter(websocket.TextMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
@ -158,7 +156,7 @@ func(hub *WS_Hub) push_alerts(users []int, asid int, event string, elementType s
|
|||||||
}
|
}
|
||||||
|
|
||||||
func route_websockets(w http.ResponseWriter, r *http.Request, user User) {
|
func route_websockets(w http.ResponseWriter, r *http.Request, user User) {
|
||||||
conn, err := ws_upgrader.Upgrade(w,r,nil)
|
conn, err := wsUpgrader.Upgrade(w, r, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -167,31 +165,31 @@ func route_websockets(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ws_user := &WS_User{conn,userptr}
|
wsUser := &WS_User{conn, userptr}
|
||||||
if user.ID == 0 {
|
if user.ID == 0 {
|
||||||
ws_hub.guests.Lock()
|
wsHub.guests.Lock()
|
||||||
ws_hub.online_guests[ws_user] = true
|
wsHub.onlineGuests[wsUser] = true
|
||||||
ws_hub.guests.Unlock()
|
wsHub.guests.Unlock()
|
||||||
} else {
|
} else {
|
||||||
ws_hub.users.Lock()
|
wsHub.users.Lock()
|
||||||
ws_hub.online_users[user.ID] = ws_user
|
wsHub.onlineUsers[user.ID] = wsUser
|
||||||
ws_hub.users.Unlock()
|
wsHub.users.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
//conn.SetReadLimit(/* put the max request size from earlier here? */)
|
//conn.SetReadLimit(/* put the max request size from earlier here? */)
|
||||||
//conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
//conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
||||||
var current_page []byte
|
var currentPage []byte
|
||||||
for {
|
for {
|
||||||
_, message, err := conn.ReadMessage()
|
_, message, err := conn.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if user.ID == 0 {
|
if user.ID == 0 {
|
||||||
ws_hub.guests.Lock()
|
wsHub.guests.Lock()
|
||||||
delete(ws_hub.online_guests,ws_user)
|
delete(wsHub.onlineGuests, wsUser)
|
||||||
ws_hub.guests.Unlock()
|
wsHub.guests.Unlock()
|
||||||
} else {
|
} else {
|
||||||
ws_hub.users.Lock()
|
wsHub.users.Lock()
|
||||||
delete(ws_hub.online_users,user.ID)
|
delete(wsHub.onlineUsers, user.ID)
|
||||||
ws_hub.users.Unlock()
|
wsHub.users.Unlock()
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -208,12 +206,12 @@ func route_websockets(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !bytes.Equal(msgblocks[1],current_page) {
|
if !bytes.Equal(msgblocks[1], currentPage) {
|
||||||
ws_leave_page(ws_user, current_page)
|
wsLeavePage(wsUser, currentPage)
|
||||||
current_page = msgblocks[1]
|
currentPage = msgblocks[1]
|
||||||
//log.Print("Current Page:",current_page)
|
//log.Print("Current Page:",currentPage)
|
||||||
//log.Print("Current Page:",string(current_page))
|
//log.Print("Current Page:",string(currentPage))
|
||||||
ws_page_responses(ws_user, current_page)
|
wsPageResponses(wsUser, currentPage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*if bytes.Equal(message,[]byte(`start-view`)) {
|
/*if bytes.Equal(message,[]byte(`start-view`)) {
|
||||||
@ -226,19 +224,19 @@ func route_websockets(w http.ResponseWriter, r *http.Request, user User) {
|
|||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func ws_page_responses(ws_user *WS_User, page []byte) {
|
func wsPageResponses(wsUser *WS_User, page []byte) {
|
||||||
switch(string(page)) {
|
switch string(page) {
|
||||||
case "/panel/":
|
case "/panel/":
|
||||||
//log.Print("/panel/ WS Route")
|
//log.Print("/panel/ WS Route")
|
||||||
/*w, err := ws_user.conn.NextWriter(websocket.TextMessage)
|
/*w, err := wsUser.conn.NextWriter(websocket.TextMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//log.Print(err.Error())
|
//log.Print(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print(ws_hub.online_users)
|
log.Print(wsHub.online_users)
|
||||||
uonline := ws_hub.user_count()
|
uonline := wsHub.userCount()
|
||||||
gonline := ws_hub.guest_count()
|
gonline := wsHub.guestCount()
|
||||||
totonline := uonline + gonline
|
totonline := uonline + gonline
|
||||||
|
|
||||||
w.Write([]byte("set #dash-totonline " + strconv.Itoa(totonline) + " online\r"))
|
w.Write([]byte("set #dash-totonline " + strconv.Itoa(totonline) + " online\r"))
|
||||||
@ -247,28 +245,29 @@ func ws_page_responses(ws_user *WS_User, page []byte) {
|
|||||||
w.Close()*/
|
w.Close()*/
|
||||||
|
|
||||||
// Listen for changes and inform the admins...
|
// Listen for changes and inform the admins...
|
||||||
admin_stats_mutex.Lock()
|
adminStatsMutex.Lock()
|
||||||
watchers := len(admin_stats_watchers)
|
watchers := len(adminStatsWatchers)
|
||||||
admin_stats_watchers[ws_user] = true
|
adminStatsWatchers[wsUser] = true
|
||||||
if watchers == 0 {
|
if watchers == 0 {
|
||||||
go admin_stats_ticker()
|
go adminStatsTicker()
|
||||||
}
|
}
|
||||||
admin_stats_mutex.Unlock()
|
adminStatsMutex.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ws_leave_page(ws_user *WS_User, page []byte) {
|
func wsLeavePage(wsUser *WS_User, page []byte) {
|
||||||
switch(string(page)) {
|
switch string(page) {
|
||||||
case "/panel/":
|
case "/panel/":
|
||||||
admin_stats_mutex.Lock()
|
adminStatsMutex.Lock()
|
||||||
delete(admin_stats_watchers,ws_user)
|
delete(adminStatsWatchers, wsUser)
|
||||||
admin_stats_mutex.Unlock()
|
adminStatsMutex.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var admin_stats_watchers map[*WS_User]bool
|
var adminStatsWatchers map[*WS_User]bool
|
||||||
var admin_stats_mutex sync.RWMutex
|
var adminStatsMutex sync.RWMutex
|
||||||
func admin_stats_ticker() {
|
|
||||||
|
func adminStatsTicker() {
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
var last_uonline int = -1
|
var last_uonline int = -1
|
||||||
@ -288,17 +287,17 @@ func admin_stats_ticker() {
|
|||||||
|
|
||||||
AdminStatLoop:
|
AdminStatLoop:
|
||||||
for {
|
for {
|
||||||
admin_stats_mutex.RLock()
|
adminStatsMutex.RLock()
|
||||||
watch_count := len(admin_stats_watchers)
|
watch_count := len(adminStatsWatchers)
|
||||||
admin_stats_mutex.RUnlock()
|
adminStatsMutex.RUnlock()
|
||||||
if watch_count == 0 {
|
if watch_count == 0 {
|
||||||
break AdminStatLoop
|
break AdminStatLoop
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_perc, cpuerr = cpu.Percent(time.Duration(time.Second), true)
|
cpu_perc, cpuerr = cpu.Percent(time.Duration(time.Second), true)
|
||||||
memres, ramerr = mem.VirtualMemory()
|
memres, ramerr = mem.VirtualMemory()
|
||||||
uonline := ws_hub.user_count()
|
uonline := wsHub.userCount()
|
||||||
gonline := ws_hub.guest_count()
|
gonline := wsHub.guestCount()
|
||||||
totonline := uonline + gonline
|
totonline := uonline + gonline
|
||||||
|
|
||||||
// It's far more likely that the CPU Usage will change than the other stats, so we'll optimise them seperately...
|
// It's far more likely that the CPU Usage will change than the other stats, so we'll optimise them seperately...
|
||||||
@ -334,9 +333,9 @@ AdminStatLoop:
|
|||||||
onlineUsersColour = "stat_red"
|
onlineUsersColour = "stat_red"
|
||||||
}
|
}
|
||||||
|
|
||||||
totonline, totunit = convert_friendly_unit(totonline)
|
totonline, totunit = convertFriendlyUnit(totonline)
|
||||||
uonline, uunit = convert_friendly_unit(uonline)
|
uonline, uunit = convertFriendlyUnit(uonline)
|
||||||
gonline, gunit = convert_friendly_unit(gonline)
|
gonline, gunit = convertFriendlyUnit(gonline)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cpuerr != nil {
|
if cpuerr != nil {
|
||||||
@ -357,8 +356,8 @@ AdminStatLoop:
|
|||||||
if ramerr != nil {
|
if ramerr != nil {
|
||||||
ramstr = "Unknown"
|
ramstr = "Unknown"
|
||||||
} else {
|
} else {
|
||||||
total_count, total_unit := convert_byte_unit(float64(memres.Total))
|
total_count, total_unit := convertByteUnit(float64(memres.Total))
|
||||||
used_count := convert_byte_in_unit(float64(memres.Total - memres.Available),total_unit)
|
used_count := convertByteInUnit(float64(memres.Total-memres.Available), total_unit)
|
||||||
|
|
||||||
// Round totals with .9s up, it's how most people see it anyway. Floats are notoriously imprecise, so do it off 0.85
|
// Round totals with .9s up, it's how most people see it anyway. Floats are notoriously imprecise, so do it off 0.85
|
||||||
var totstr string
|
var totstr string
|
||||||
@ -385,17 +384,17 @@ AdminStatLoop:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
admin_stats_mutex.RLock()
|
adminStatsMutex.RLock()
|
||||||
watchers := admin_stats_watchers
|
watchers := adminStatsWatchers
|
||||||
admin_stats_mutex.RUnlock()
|
adminStatsMutex.RUnlock()
|
||||||
|
|
||||||
for watcher, _ := range watchers {
|
for watcher, _ := range watchers {
|
||||||
w, err := watcher.conn.NextWriter(websocket.TextMessage)
|
w, err := watcher.conn.NextWriter(websocket.TextMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//log.Print(err.Error())
|
//log.Print(err.Error())
|
||||||
admin_stats_mutex.Lock()
|
adminStatsMutex.Lock()
|
||||||
delete(admin_stats_watchers,watcher)
|
delete(adminStatsWatchers, watcher)
|
||||||
admin_stats_mutex.Unlock()
|
adminStatsMutex.Unlock()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
26
widgets.go
26
widgets.go
@ -5,46 +5,42 @@ import "log"
|
|||||||
import "bytes"
|
import "bytes"
|
||||||
import "sync"
|
import "sync"
|
||||||
import "encoding/json"
|
import "encoding/json"
|
||||||
|
|
||||||
//import "html/template"
|
//import "html/template"
|
||||||
|
|
||||||
var docks WidgetDocks
|
var docks WidgetDocks
|
||||||
var widget_update_mutex sync.RWMutex
|
var widgetUpdateMutex sync.RWMutex
|
||||||
|
|
||||||
type WidgetDocks struct
|
type WidgetDocks struct {
|
||||||
{
|
|
||||||
LeftSidebar []Widget
|
LeftSidebar []Widget
|
||||||
RightSidebar []Widget
|
RightSidebar []Widget
|
||||||
//PanelLeft []Menus
|
//PanelLeft []Menus
|
||||||
}
|
}
|
||||||
|
|
||||||
type Widget struct
|
type Widget struct {
|
||||||
{
|
|
||||||
Enabled bool
|
Enabled bool
|
||||||
Location string // Coming Soon: overview, topics, topic / topic_view, forums, forum, global
|
Location string // Coming Soon: overview, topics, topic / topic_view, forums, forum, global
|
||||||
Position int
|
Position int
|
||||||
Body string
|
Body string
|
||||||
}
|
}
|
||||||
|
|
||||||
type WidgetMenu struct
|
type WidgetMenu struct {
|
||||||
{
|
|
||||||
Name string
|
Name string
|
||||||
MenuList []WidgetMenuItem
|
MenuList []WidgetMenuItem
|
||||||
}
|
}
|
||||||
|
|
||||||
type WidgetMenuItem struct
|
type WidgetMenuItem struct {
|
||||||
{
|
|
||||||
Text string
|
Text string
|
||||||
Location string
|
Location string
|
||||||
Compact bool
|
Compact bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type NameTextPair struct
|
type NameTextPair struct {
|
||||||
{
|
|
||||||
Name string
|
Name string
|
||||||
Text string
|
Text string
|
||||||
}
|
}
|
||||||
|
|
||||||
func init_widgets() error {
|
func initWidgets() error {
|
||||||
rows, err := get_widgets_stmt.Query()
|
rows, err := get_widgets_stmt.Query()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -65,7 +61,7 @@ func init_widgets() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sbytes = []byte(data)
|
sbytes = []byte(data)
|
||||||
switch(wtype) {
|
switch wtype {
|
||||||
case "simple":
|
case "simple":
|
||||||
var tmp NameTextPair
|
var tmp NameTextPair
|
||||||
err = json.Unmarshal(sbytes, &tmp)
|
err = json.Unmarshal(sbytes, &tmp)
|
||||||
@ -94,10 +90,10 @@ func init_widgets() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
widget_update_mutex.Lock()
|
widgetUpdateMutex.Lock()
|
||||||
docks.LeftSidebar = leftWidgets
|
docks.LeftSidebar = leftWidgets
|
||||||
docks.RightSidebar = rightWidgets
|
docks.RightSidebar = rightWidgets
|
||||||
widget_update_mutex.Unlock()
|
widgetUpdateMutex.Unlock()
|
||||||
|
|
||||||
if dev.SuperDebug {
|
if dev.SuperDebug {
|
||||||
log.Print("docks.LeftSidebar", docks.LeftSidebar)
|
log.Print("docks.LeftSidebar", docks.LeftSidebar)
|
||||||
|
Loading…
Reference in New Issue
Block a user