Added the Social Groups plugin. This is still under construction.
Made a few improvements to the ForumStore, including bringing it's API closer in line with the other datastores, adding stubs for future subforum functionality, and improving efficiency in a few places. The auth interface now handles all the authentication stuff. Renamed the debug config variable to debug_mode. Added the PluginPerms API. Internal Errors will now dump the stack trace in the console. Added support for installable plugins. Refactored the routing logic so that the router now handles the common PreRoute logic(exc. /static/) Added the CreateTable method to the query generator. It might need some tweaking to better support other database systems. Added the same CreateTable method to the query builder. Began work on PostgreSQL support. Added the string-string hook type Added the pre_render hook type. Added the ParentID and ParentType fields to forums. Added the get_forum_url_prefix function. Added a more generic build_slug function. Added the get_topic_url_prefix function. Added the override_perms and override_forum_perms functions for bulk setting and unsetting permissions. Added more ExtData fields in a few structs and removed them on the Perms struct as the PluginPerms API supersedes them there. Plugins can now see the router instance. The plugin initialisation handlers can now throw errors. Plugins are now initialised after all the forum's subsystems are. Refactored the unit test logic. For instance, we now use the proper .Log method rather than fmt.Println in many cases. Sorry, we'll have to break Github's generated file detection, as the build instructions aren't working, unless I put them at the top, and they're far, far more important than getting Github to recognise the generated code as generated code. Fixed an issue with mysql.go's _init_database() overwriting the dbpassword variable. Not a huge issue, but it is a "gotcha" for those not expecting a ':' at the start. Fixed an issue with forum creation where the forum permissions didn't get cached. Fixed a bug in plugin_bbcode where negative numbers in rand would crash Gosora. Made the outputs of plugin_markdown and plugin_bbcode more compliant with the tests. Revamped the phrase system to make it easier for us to add language pack related features in the future. Added the WidgetMenu widget type. Revamped the theme again. I'm experimenting to see which approach I like most. - Excuse the little W3C rage. Some things about CSS drive me crazy :p Tests: Added 22 bbcode_full_parse tests. Added 19 bbcode_regex_parse tests. Added 27 markdown_parse tests. Added four UserStore tests. More to come when the test database functionality is added. Added 18 name_to_slug tests. Hooks: Added the pre_render hook. Added the pre_render_forum_list hook. Added the pre_render_view_forum hook. Added the pre_render_topic_list hook. Added the pre_render_view_topic hook. Added the pre_render_profile hook. Added the pre_render_custom_page hook. Added the pre_render_overview hook. Added the pre_render_create_topic hook. Added the pre_render_account_own_edit_critical hook. Added the pre_render_account_own_edit_avatar hook. Added the pre_render_account_own_edit_username hook. Added the pre_render_account_own_edit_email hook. Added the pre_render_login hook. Added the pre_render_register hook. Added the pre_render_ban hook. Added the pre_render_panel_dashboard hook. Added the pre_render_panel_forums hook. Added the pre_render_panel_delete_forum hook. Added the pre_render_panel_edit_forum hook. Added the pre_render_panel_settings hook. Added the pre_render_panel_setting hook. Added the pre_render_panel_plugins hook. Added the pre_render_panel_users hook. Added the pre_render_panel_edit_user hook. Added the pre_render_panel_groups hook. Added the pre_render_panel_edit_group hook. Added the pre_render_panel_edit_group_perms hook. Added the pre_render_panel_themes hook. Added the pre_render_panel_mod_log hook. Added the pre_render_error hook. Added the pre_render_security_error hook. Added the create_group_preappend hook. Added the intercept_build_widgets hook. Added the simple_forum_check_pre_perms hook. Added the forum_check_pre_perms hook.
49
auth.go
|
@ -15,11 +15,13 @@ var ErrMismatchedHashAndPassword = bcrypt.ErrMismatchedHashAndPassword
|
|||
|
||||
type Auth interface
|
||||
{
|
||||
Authenticate(username string, password string) (int,error)
|
||||
Authenticate(username string, password string) (uid int, err error)
|
||||
Logout(w http.ResponseWriter, uid int)
|
||||
ForceLogout(uid int) error
|
||||
SetCookies(w http.ResponseWriter, uid int, session string)
|
||||
CreateSession(uid int) (string, error)
|
||||
GetCookies(r *http.Request) (uid int, session string, err error)
|
||||
SessionCheck(w http.ResponseWriter, r *http.Request) (user *User, halt bool)
|
||||
CreateSession(uid int) (session string, err error)
|
||||
}
|
||||
|
||||
type DefaultAuth struct
|
||||
|
@ -100,8 +102,47 @@ func (auth *DefaultAuth) SetCookies(w http.ResponseWriter, uid int, session stri
|
|||
http.SetCookie(w,&cookie)
|
||||
}
|
||||
|
||||
func(auth *DefaultAuth) CreateSession(uid int) (string, error) {
|
||||
session, err := GenerateSafeString(sessionLength)
|
||||
func (auth *DefaultAuth) GetCookies(r *http.Request) (uid int, session string, err error) {
|
||||
// Are there any session cookies..?
|
||||
cookie, err := r.Cookie("uid")
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
uid, err = strconv.Atoi(cookie.Value)
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
cookie, err = r.Cookie("session")
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
return uid, cookie.Value, err
|
||||
}
|
||||
|
||||
func (auth *DefaultAuth) SessionCheck(w http.ResponseWriter, r *http.Request) (user *User, halt bool) {
|
||||
uid, session, err := auth.GetCookies(r)
|
||||
if err != nil {
|
||||
return &guest_user, false
|
||||
}
|
||||
|
||||
// Is this session valid..?
|
||||
user, err = users.CascadeGet(uid)
|
||||
if err == ErrNoRows {
|
||||
return &guest_user, false
|
||||
} else if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return &guest_user, true
|
||||
}
|
||||
|
||||
if user.Session == "" || session != user.Session {
|
||||
return &guest_user, false
|
||||
}
|
||||
|
||||
return user, false
|
||||
}
|
||||
|
||||
func(auth *DefaultAuth) CreateSession(uid int) (session string, err error) {
|
||||
session, err = GenerateSafeString(sessionLength)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
1
cache.go
|
@ -5,6 +5,7 @@ const CACHE_STATIC int = 0
|
|||
const CACHE_DYNAMIC int = 1
|
||||
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
|
||||
var ErrStoreCapacityOverflow = errors.New("This datastore has already reached it's max capacity")
|
||||
|
||||
type DataStore interface {
|
||||
|
|
|
@ -45,6 +45,6 @@ var noavatar = "https://api.adorable.io/avatars/285/{id}@" + site_url + ".png"
|
|||
var items_per_page = 25
|
||||
|
||||
// Developer flags
|
||||
var debug = false
|
||||
var debug_mode = false
|
||||
var super_debug = false
|
||||
var profiling = false
|
||||
|
|
16
database.go
|
@ -7,7 +7,6 @@ import "database/sql"
|
|||
|
||||
var db *sql.DB
|
||||
var db_version string
|
||||
var db_collation string = "utf8mb4_general_ci"
|
||||
|
||||
var ErrNoRows = sql.ErrNoRows
|
||||
|
||||
|
@ -30,7 +29,7 @@ func init_database() (err error) {
|
|||
i := 1
|
||||
for ;rows.Next();i++ {
|
||||
group := Group{ID: 0,}
|
||||
err := rows.Scan(&group.ID, &group.Name, &group.PermissionsText, &group.Is_Mod, &group.Is_Admin, &group.Is_Banned, &group.Tag)
|
||||
err := rows.Scan(&group.ID, &group.Name, &group.PermissionsText, &group.PluginPermsText, &group.Is_Mod, &group.Is_Admin, &group.Is_Banned, &group.Tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -45,12 +44,21 @@ func init_database() (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print(group.Name + ": ")
|
||||
fmt.Printf("%+v\n", group.Perms)
|
||||
}
|
||||
|
||||
group.Perms.ExtData = make(map[string]bool)
|
||||
err = json.Unmarshal(group.PluginPermsText, &group.PluginPerms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if debug_mode {
|
||||
log.Print(group.Name + ": ")
|
||||
fmt.Printf("%+v\n", group.PluginPerms)
|
||||
}
|
||||
|
||||
//group.Perms.ExtData = make(map[string]bool)
|
||||
groups = append(groups, group)
|
||||
}
|
||||
err = rows.Err()
|
||||
|
|
81
errors.go
|
@ -1,14 +1,16 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
import "log"
|
||||
import "bytes"
|
||||
import "net/http"
|
||||
import "runtime/debug"
|
||||
|
||||
var error_internal []byte
|
||||
var error_notfound []byte
|
||||
func init_errors() error {
|
||||
var b bytes.Buffer
|
||||
user := User{0,"guest","Guest","",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",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"}
|
||||
pi := Page{"Internal Server Error",user,hvars,tList,"A problem has occurred in the system."}
|
||||
err := templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
if err != nil {
|
||||
|
@ -27,12 +29,16 @@ func init_errors() error {
|
|||
}
|
||||
|
||||
func LogError(err error) {
|
||||
log.Fatal(err)
|
||||
log.Print(err)
|
||||
debug.PrintStack()
|
||||
log.Fatal("")
|
||||
}
|
||||
|
||||
func InternalError(err error, w http.ResponseWriter, r *http.Request) {
|
||||
w.Write(error_internal)
|
||||
log.Fatal(err)
|
||||
log.Print(err)
|
||||
debug.PrintStack()
|
||||
log.Fatal("")
|
||||
}
|
||||
|
||||
func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, is_js string) {
|
||||
|
@ -42,7 +48,9 @@ func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, is_js s
|
|||
} else {
|
||||
w.Write([]byte(`{"errmsg":"A problem has occured in the system."}`))
|
||||
}
|
||||
log.Fatal(err)
|
||||
log.Print(err)
|
||||
debug.PrintStack()
|
||||
log.Fatal("")
|
||||
}
|
||||
|
||||
func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -55,6 +63,11 @@ func PreError(errmsg string, w http.ResponseWriter, r *http.Request) {
|
|||
w.WriteHeader(500)
|
||||
user := User{ID:0,Group:6,Perms:GuestPerms,}
|
||||
pi := Page{"Error",user,hvars,tList,errmsg}
|
||||
if pre_render_hooks["pre_render_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html",pi)
|
||||
fmt.Fprintln(w,b.String())
|
||||
|
@ -63,6 +76,11 @@ func PreError(errmsg string, w http.ResponseWriter, r *http.Request) {
|
|||
func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(500)
|
||||
pi := Page{"Local Error",user,hvars,tList,errmsg}
|
||||
if pre_render_hooks["pre_render_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html",pi)
|
||||
fmt.Fprintln(w,b.String())
|
||||
|
@ -71,6 +89,11 @@ func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User
|
|||
func LoginRequired(w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(401)
|
||||
pi := Page{"Local Error",user,hvars,tList,"You need to login to do that."}
|
||||
if pre_render_hooks["pre_render_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html",pi)
|
||||
fmt.Fprintln(w,b.String())
|
||||
|
@ -81,6 +104,11 @@ func PreErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, is_js st
|
|||
if is_js == "0" {
|
||||
user := User{ID:0,Group:6,Perms:GuestPerms,}
|
||||
pi := Page{"Local Error",user,hvars,tList,errmsg}
|
||||
if pre_render_hooks["pre_render_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
fmt.Fprintln(w,b.String())
|
||||
|
@ -93,6 +121,11 @@ func LocalErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, user U
|
|||
w.WriteHeader(500)
|
||||
if is_js == "0" {
|
||||
pi := Page{"Local Error",user,hvars,tList,errmsg}
|
||||
if pre_render_hooks["pre_render_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
fmt.Fprintln(w,b.String())
|
||||
|
@ -109,6 +142,11 @@ func LocalErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) {
|
|||
func NoPermissions(w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(403)
|
||||
pi := Page{"Local Error",user,hvars,tList,"You don't have permission to do that."}
|
||||
if pre_render_hooks["pre_render_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
errpage := b.String()
|
||||
|
@ -119,6 +157,11 @@ func NoPermissionsJSQ(w http.ResponseWriter, r *http.Request, user User, is_js s
|
|||
w.WriteHeader(403)
|
||||
if is_js == "0" {
|
||||
pi := Page{"Local Error",user,hvars,tList,"You don't have permission to do that."}
|
||||
if pre_render_hooks["pre_render_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
fmt.Fprintln(w,b.String())
|
||||
|
@ -130,6 +173,11 @@ func NoPermissionsJSQ(w http.ResponseWriter, r *http.Request, user User, is_js s
|
|||
func Banned(w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(403)
|
||||
pi := Page{"Banned",user,hvars,tList,"You have been banned from this site."}
|
||||
if pre_render_hooks["pre_render_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
fmt.Fprintln(w,b.String())
|
||||
|
@ -139,6 +187,11 @@ func BannedJSQ(w http.ResponseWriter, r *http.Request, user User, is_js string)
|
|||
w.WriteHeader(403)
|
||||
if is_js == "0" {
|
||||
pi := Page{"Banned",user,hvars,tList,"You have been banned from this site."}
|
||||
if pre_render_hooks["pre_render_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
fmt.Fprintln(w,b.String())
|
||||
|
@ -151,6 +204,11 @@ func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, is_js s
|
|||
w.WriteHeader(401)
|
||||
if is_js == "0" {
|
||||
pi := Page{"Local Error",user,hvars,tList,"You need to login to do that."}
|
||||
if pre_render_hooks["pre_render_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
fmt.Fprintln(w,b.String())
|
||||
|
@ -162,6 +220,11 @@ func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, is_js s
|
|||
func SecurityError(w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(403)
|
||||
pi := Page{"Security Error",user,hvars,tList,"There was a security issue with your request."}
|
||||
if pre_render_hooks["pre_render_security_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_security_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
fmt.Fprintln(w,b.String())
|
||||
|
@ -175,6 +238,11 @@ func NotFound(w http.ResponseWriter, r *http.Request) {
|
|||
func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) {
|
||||
w.WriteHeader(errcode)
|
||||
pi := Page{errtitle,user,hvars,tList,errmsg}
|
||||
if pre_render_hooks["pre_render_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
fmt.Fprintln(w,b.String())
|
||||
|
@ -184,6 +252,11 @@ func CustomErrorJSQ(errmsg string, errcode int, errtitle string, w http.Response
|
|||
w.WriteHeader(errcode)
|
||||
if is_js == "0" {
|
||||
pi := Page{errtitle,user,hvars,tList,errmsg}
|
||||
if pre_render_hooks["pre_render_error"] != nil {
|
||||
if run_pre_render_hook("pre_render_error", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
fmt.Fprintln(w,b.String())
|
||||
|
|
208
extend.go
|
@ -1,39 +1,72 @@
|
|||
/* Copyright Azareal 2016 - 2017 */
|
||||
/* Copyright Azareal 2016 - 2018 */
|
||||
package main
|
||||
import "log"
|
||||
import "net/http"
|
||||
|
||||
var plugins map[string]*Plugin = make(map[string]*Plugin)
|
||||
var hooks map[string][]func(interface{})interface{} = make(map[string][]func(interface{})interface{})
|
||||
var vhooks map[string]func(...interface{})interface{} = make(map[string]func(...interface{})interface{})
|
||||
|
||||
func LoadPlugins() error {
|
||||
rows, err := get_plugins_stmt.Query()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
// 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{}{
|
||||
"forums_frow_assign": nil,
|
||||
"topic_create_frow_assign": nil,
|
||||
"rrow_assign": nil, // TO-DO: Rename this hook to topic_rrow_assign
|
||||
}
|
||||
|
||||
var uname string
|
||||
var active bool
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&uname, &active)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Hooks with a variable number of arguments
|
||||
var vhooks map[string]func(...interface{})interface{} = map[string]func(...interface{})interface{}{
|
||||
"simple_forum_check_pre_perms": nil,
|
||||
"forum_check_pre_perms": nil,
|
||||
"intercept_build_widgets": nil,
|
||||
"forum_trow_assign": nil,
|
||||
"topics_trow_assign": nil,
|
||||
"create_group_preappend": nil, // What is this? Investigate!
|
||||
"topic_create_pre_loop": nil,
|
||||
}
|
||||
|
||||
// Was the plugin deleted at some point?
|
||||
plugin, ok := plugins[uname]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
plugin.Active = active
|
||||
plugins[uname] = plugin
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
// 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{
|
||||
"preparse_preassign": nil,
|
||||
"parse_assign": nil,
|
||||
}
|
||||
|
||||
// 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{
|
||||
"pre_render": nil,
|
||||
|
||||
"pre_render_forum_list": nil,
|
||||
"pre_render_view_forum": nil,
|
||||
"pre_render_topic_list": nil,
|
||||
"pre_render_view_topic": nil,
|
||||
"pre_render_profile": nil,
|
||||
"pre_render_custom_page": nil,
|
||||
"pre_render_overview": nil,
|
||||
"pre_render_create_topic": nil,
|
||||
|
||||
"pre_render_account_own_edit_critical": nil,
|
||||
"pre_render_account_own_edit_avatar": nil,
|
||||
"pre_render_account_own_edit_username": nil,
|
||||
"pre_render_account_own_edit_email": nil,
|
||||
"pre_render_login": nil,
|
||||
"pre_render_register": nil,
|
||||
"pre_render_ban": nil,
|
||||
|
||||
"pre_render_panel_dashboard": nil,
|
||||
"pre_render_panel_forums": nil,
|
||||
"pre_render_panel_delete_forum": nil,
|
||||
"pre_render_panel_edit_forum": nil,
|
||||
"pre_render_panel_settings": nil,
|
||||
"pre_render_panel_setting": nil,
|
||||
"pre_render_panel_plugins": nil,
|
||||
"pre_render_panel_users": nil,
|
||||
"pre_render_panel_edit_user": nil,
|
||||
"pre_render_panel_groups": nil,
|
||||
"pre_render_panel_edit_group": nil,
|
||||
"pre_render_panel_edit_group_perms": nil,
|
||||
"pre_render_panel_themes": nil,
|
||||
"pre_render_panel_mod_log": nil,
|
||||
|
||||
"pre_render_error": nil, // Note: This hook isn't run for a few errors whose templates are computed at startup and reused, such as InternalError. This hook is also not available in JS mode.
|
||||
"pre_render_security_error": nil,
|
||||
}
|
||||
|
||||
type Plugin struct
|
||||
|
@ -46,14 +79,51 @@ type Plugin struct
|
|||
Active bool
|
||||
Tag string
|
||||
Type string
|
||||
Init func()
|
||||
Installable bool
|
||||
Installed bool
|
||||
|
||||
Init func()error
|
||||
Activate func()error
|
||||
Deactivate func()
|
||||
Install func()error
|
||||
Uninstall func()error
|
||||
|
||||
Hooks map[string]int
|
||||
}
|
||||
|
||||
func NewPlugin(uname string, name string, author string, url string, settings string, tag string, ptype string, init func(), activate func()error, deactivate func()) *Plugin {
|
||||
func LoadPlugins() error {
|
||||
rows, err := get_plugins_stmt.Query()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var uname string
|
||||
var active bool
|
||||
var installed bool
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&uname, &active, &installed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Was the plugin deleted at some point?
|
||||
plugin, ok := plugins[uname]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
plugin.Active = active
|
||||
plugin.Installed = installed
|
||||
plugins[uname] = plugin
|
||||
}
|
||||
err = 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 {
|
||||
return &Plugin{
|
||||
UName: uname,
|
||||
Name: name,
|
||||
|
@ -62,14 +132,18 @@ func NewPlugin(uname string, name string, author string, url string, settings st
|
|||
Settings: settings,
|
||||
Tag: tag,
|
||||
Type: ptype,
|
||||
Installable: (install != nil),
|
||||
Init: init,
|
||||
Activate: activate,
|
||||
Deactivate: deactivate,
|
||||
Install: install,
|
||||
//Uninstall: uninstall,
|
||||
|
||||
/*
|
||||
The Active field should never be altered by a plugin. It's used internally by the software to determine whether an admin has enabled a plugin or not and whether to run it. This will be overwritten by the user's preference.
|
||||
*/
|
||||
Active: false,
|
||||
Installed: false,
|
||||
Hooks: make(map[string]int),
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +159,24 @@ func (plugin *Plugin) AddHook(name string, handler interface{}) {
|
|||
hooks[name] = append(hooks[name], h)
|
||||
}
|
||||
plugin.Hooks[name] = len(hooks[name])
|
||||
case func(string)string:
|
||||
if len(sshooks[name]) == 0 {
|
||||
var hookSlice []func(string)string
|
||||
hookSlice = append(hookSlice, h)
|
||||
sshooks[name] = hookSlice
|
||||
} else {
|
||||
sshooks[name] = append(sshooks[name], h)
|
||||
}
|
||||
plugin.Hooks[name] = len(sshooks[name])
|
||||
case func(http.ResponseWriter, *http.Request, *User, interface{})bool:
|
||||
if len(pre_render_hooks[name]) == 0 {
|
||||
var hookSlice []func(http.ResponseWriter, *http.Request, *User, interface{})bool
|
||||
hookSlice = append(hookSlice, h)
|
||||
pre_render_hooks[name] = hookSlice
|
||||
} else {
|
||||
pre_render_hooks[name] = append(pre_render_hooks[name], h)
|
||||
}
|
||||
plugin.Hooks[name] = len(pre_render_hooks[name])
|
||||
case func(...interface{}) interface{}:
|
||||
vhooks[name] = h
|
||||
plugin.Hooks[name] = 0
|
||||
|
@ -104,6 +196,24 @@ func (plugin *Plugin) RemoveHook(name string, handler interface{}) {
|
|||
hook = append(hook[:key], hook[key + 1:]...)
|
||||
}
|
||||
hooks[name] = hook
|
||||
case func(string)string:
|
||||
key := plugin.Hooks[name]
|
||||
hook := sshooks[name]
|
||||
if len(hook) == 1 {
|
||||
hook = []func(string)string{}
|
||||
} else {
|
||||
hook = append(hook[:key], hook[key + 1:]...)
|
||||
}
|
||||
sshooks[name] = hook
|
||||
case func(http.ResponseWriter, *http.Request, *User, interface{})bool:
|
||||
key := plugin.Hooks[name]
|
||||
hook := pre_render_hooks[name]
|
||||
if len(hook) == 1 {
|
||||
hook = []func(http.ResponseWriter, *http.Request, *User, interface{})bool{}
|
||||
} else {
|
||||
hook = append(hook[:key], hook[key + 1:]...)
|
||||
}
|
||||
pre_render_hooks[name] = hook
|
||||
case func(...interface{}) interface{}:
|
||||
delete(vhooks, name)
|
||||
default:
|
||||
|
@ -119,7 +229,10 @@ func init_plugins() {
|
|||
if body.Active {
|
||||
log.Print("Initialised plugin " + name)
|
||||
if plugins[name].Init != nil {
|
||||
plugins[name].Init()
|
||||
err := plugins[name].Init()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
} else {
|
||||
log.Print("Plugin " + name + " doesn't have an initialiser.")
|
||||
}
|
||||
|
@ -135,6 +248,12 @@ func run_hook(name string, data interface{}) interface{} {
|
|||
return data
|
||||
}
|
||||
|
||||
func run_hook_noreturn(name string, data interface{}) {
|
||||
for _, hook := range hooks[name] {
|
||||
_ = hook(data)
|
||||
}
|
||||
}
|
||||
|
||||
func run_vhook(name string, data ...interface{}) interface{} {
|
||||
return vhooks[name](data...)
|
||||
}
|
||||
|
@ -142,3 +261,28 @@ func run_vhook(name string, data ...interface{}) interface{} {
|
|||
func run_vhook_noreturn(name string, data ...interface{}) {
|
||||
_ = vhooks[name](data...)
|
||||
}
|
||||
|
||||
// Trying to get a teeny bit of type-safety where-ever possible, especially for such a critical set of hooks
|
||||
func run_sshook(name string, data string) string {
|
||||
for _, hook := range sshooks[name] {
|
||||
data = hook(data)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func run_pre_render_hook(name string, w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) {
|
||||
// This hook runs on ALL pre_render hooks
|
||||
for _, hook := range pre_render_hooks["pre_render"] {
|
||||
if hook(w,r,user,data) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// The actual pre_render hook
|
||||
for _, hook := range pre_render_hooks[name] {
|
||||
if hook(w,r,user,data) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
4
files.go
|
@ -49,7 +49,7 @@ func init_static_files() {
|
|||
|
||||
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)}
|
||||
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Added the '" + path + "' static file.")
|
||||
}
|
||||
return nil
|
||||
|
@ -79,7 +79,7 @@ func add_static_file(path string, prefix string) error {
|
|||
|
||||
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)}
|
||||
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Added the '" + path + "' static file")
|
||||
}
|
||||
return nil
|
||||
|
|
8
forum.go
|
@ -18,11 +18,13 @@ type ForumAdmin struct
|
|||
type Forum struct
|
||||
{
|
||||
ID int
|
||||
Slug string
|
||||
Link string
|
||||
Name string
|
||||
Desc string
|
||||
Active bool
|
||||
Preset string
|
||||
ParentID int
|
||||
ParentType string
|
||||
TopicCount int
|
||||
LastTopicSlug string
|
||||
LastTopic string
|
||||
|
@ -46,3 +48,7 @@ func build_forum_url(slug string, fid int) string {
|
|||
}
|
||||
return "/forum/" + slug + "." + strconv.Itoa(fid)
|
||||
}
|
||||
|
||||
func get_forum_url_prefix() string {
|
||||
return "/forum/"
|
||||
}
|
||||
|
|
112
forum_store.go
|
@ -2,8 +2,9 @@
|
|||
package main
|
||||
|
||||
import "log"
|
||||
import "sync"
|
||||
import "errors"
|
||||
import "sync"
|
||||
//import "sync/atomic"
|
||||
import "database/sql"
|
||||
import "./query_gen/lib"
|
||||
|
||||
|
@ -22,6 +23,8 @@ type ForumStore interface
|
|||
CascadeGet(id int) (*Forum, error)
|
||||
CascadeGetCopy(id int) (Forum, error)
|
||||
BypassGet(id int) (*Forum, error)
|
||||
Load(id int) error
|
||||
Set(forum *Forum) error
|
||||
//Update(Forum) error
|
||||
//CascadeUpdate(Forum) error
|
||||
Delete(id int) error
|
||||
|
@ -30,14 +33,17 @@ type ForumStore interface
|
|||
DecrementTopicCount(id int) error
|
||||
UpdateLastTopic(topic_name string, tid int, username string, uid int, time string, fid int) error
|
||||
Exists(id int) bool
|
||||
GetAll() ([]Forum,error)
|
||||
GetAll() ([]*Forum,error)
|
||||
GetAllIDs() ([]int,error)
|
||||
//GetChildren(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)
|
||||
//QuickCreate(string, string, bool, string) (*Forum, error)
|
||||
}
|
||||
|
||||
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
|
||||
forumCapCount int
|
||||
|
||||
get *sql.Stmt
|
||||
|
@ -45,11 +51,11 @@ type StaticForumStore struct
|
|||
}
|
||||
|
||||
func NewStaticForumStore() *StaticForumStore {
|
||||
get_stmt, err := qgen.Builder.SimpleSelect("forums","name, desc, active, preset, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","fid = ?","","")
|
||||
get_stmt, err := qgen.Builder.SimpleSelect("forums","name, desc, active, preset, parentID, parentType, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","fid = ?","","")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
get_all_stmt, err := qgen.Builder.SimpleSelect("forums","fid, name, desc, active, preset, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","","fid ASC","")
|
||||
get_all_stmt, err := qgen.Builder.SimpleSelect("forums","fid, name, desc, active, preset, parentID, parentType, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","","fid ASC","")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -60,11 +66,9 @@ func NewStaticForumStore() *StaticForumStore {
|
|||
}
|
||||
|
||||
func (sfs *StaticForumStore) LoadForums() error {
|
||||
//if debug {
|
||||
log.Print("Adding the uncategorised forum")
|
||||
//}
|
||||
var forums []Forum = []Forum{
|
||||
Forum{0,"uncategorised","Uncategorised","",uncategorised_forum_visible,"all",0,"","",0,"",0,""},
|
||||
var forums []*Forum = []*Forum{
|
||||
&Forum{0,"uncategorised","Uncategorised","",uncategorised_forum_visible,"all",0,"",0,"","",0,"",0,""},
|
||||
}
|
||||
|
||||
rows, err := get_forums_stmt.Query()
|
||||
|
@ -76,7 +80,7 @@ func (sfs *StaticForumStore) LoadForums() error {
|
|||
var i int = 1
|
||||
for ;rows.Next();i++ {
|
||||
forum := Forum{ID:0,Active:true,Preset:"all"}
|
||||
err = rows.Scan(&forum.ID, &forum.Name, &forum.Desc, &forum.Active, &forum.Preset, &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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -88,16 +92,16 @@ func (sfs *StaticForumStore) LoadForums() error {
|
|||
}
|
||||
|
||||
if forum.Name == "" {
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Adding a placeholder forum")
|
||||
}
|
||||
} else {
|
||||
log.Print("Adding the " + forum.Name + " forum")
|
||||
}
|
||||
|
||||
forum.Slug = name_to_slug(forum.Name)
|
||||
forum.LastTopicSlug = name_to_slug(forum.LastTopic)
|
||||
forums = append(forums,forum)
|
||||
forum.Link = build_forum_url(name_to_slug(forum.Name),forum.ID)
|
||||
forum.LastTopicSlug = build_slug(name_to_slug(forum.LastTopic),forum.LastTopicID)
|
||||
forums = append(forums,&forum)
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
|
@ -113,28 +117,28 @@ func (sfs *StaticForumStore) DirtyGet(id int) *Forum {
|
|||
if !((id <= sfs.forumCapCount) && (id >= 0) && sfs.forums[id].Name!="") {
|
||||
return &Forum{ID:-1,Name:""}
|
||||
}
|
||||
return &sfs.forums[id]
|
||||
return sfs.forums[id]
|
||||
}
|
||||
|
||||
func (sfs *StaticForumStore) Get(id int) (*Forum, error) {
|
||||
if !((id <= sfs.forumCapCount) && (id >= 0) && sfs.forums[id].Name!="") {
|
||||
return nil, err_noforum
|
||||
}
|
||||
return &sfs.forums[id], nil
|
||||
return sfs.forums[id], nil
|
||||
}
|
||||
|
||||
func (sfs *StaticForumStore) CascadeGet(id int) (*Forum, error) {
|
||||
if !((id <= sfs.forumCapCount) && (id >= 0) && sfs.forums[id].Name != "") {
|
||||
return nil, err_noforum
|
||||
}
|
||||
return &sfs.forums[id], nil
|
||||
return sfs.forums[id], nil
|
||||
}
|
||||
|
||||
func (sfs *StaticForumStore) CascadeGetCopy(id int) (forum Forum, err error) {
|
||||
if !((id <= sfs.forumCapCount) && (id >= 0) && sfs.forums[id].Name != "") {
|
||||
return forum, err_noforum
|
||||
}
|
||||
return sfs.forums[id], nil
|
||||
return *sfs.forums[id], nil
|
||||
}
|
||||
|
||||
func (sfs *StaticForumStore) BypassGet(id int) (*Forum, error) {
|
||||
|
@ -146,14 +150,55 @@ func (sfs *StaticForumStore) BypassGet(id int) (*Forum, error) {
|
|||
return &forum, nil
|
||||
}
|
||||
|
||||
func (sfs *StaticForumStore) Exists(id int) bool {
|
||||
return (id <= sfs.forumCapCount) && (id >= 0) && sfs.forums[id].Name != ""
|
||||
func (sfs *StaticForumStore) Load(id int) error {
|
||||
var forum 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sfs.Set(&forum)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sfs *StaticForumStore) GetAll() ([]Forum,error) {
|
||||
// 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 {
|
||||
forum_update_mutex.Lock()
|
||||
if !sfs.Exists(forum.ID) {
|
||||
forum_update_mutex.Unlock()
|
||||
return ErrNoRows
|
||||
}
|
||||
sfs.forums[forum.ID] = forum
|
||||
forum_update_mutex.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sfs *StaticForumStore) GetAll() ([]*Forum,error) {
|
||||
return sfs.forums, nil
|
||||
}
|
||||
|
||||
// TO-DO: Implement sub-forums.
|
||||
/*func (sfs *StaticForumStore) GetChildren(parentID int, parentType string) ([]*Forum,error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (sfs *StaticForumStore) GetFirstChild(parentID int, parentType string) (*Forum,error) {
|
||||
return nil, nil
|
||||
}*/
|
||||
|
||||
// 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.
|
||||
func (sfs *StaticForumStore) GetAllIDs() ([]int,error) {
|
||||
var max int = sfs.forumCapCount
|
||||
var ids []int = make([]int,max)
|
||||
for i := 0; i < max; i++ {
|
||||
ids[i] = i
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func (sfs *StaticForumStore) Exists(id int) bool {
|
||||
return (id <= sfs.forumCapCount) && (id >= 0) && sfs.forums[id].Name != ""
|
||||
}
|
||||
|
||||
func (sfs *StaticForumStore) Delete(id int) error {
|
||||
forum_update_mutex.Lock()
|
||||
if !sfs.Exists(id) {
|
||||
|
@ -240,10 +285,14 @@ func (sfs *StaticForumStore) CreateForum(forum_name string, forum_desc string, a
|
|||
if err != nil {
|
||||
return fid, err
|
||||
}
|
||||
sfs.forums[fid].Name = forum_name
|
||||
sfs.forums[fid].Desc = forum_desc
|
||||
sfs.forums[fid].Active = active
|
||||
sfs.forums[fid].Preset = preset
|
||||
forum, err := sfs.Get(fid)
|
||||
if err != nil {
|
||||
return 0, ErrCacheDesync
|
||||
}
|
||||
forum.Name = forum_name
|
||||
forum.Desc = forum_desc
|
||||
forum.Active = active
|
||||
forum.Preset = preset
|
||||
forum_update_mutex.Unlock()
|
||||
return fid, nil
|
||||
}
|
||||
|
@ -260,8 +309,11 @@ func (sfs *StaticForumStore) CreateForum(forum_name string, forum_desc string, a
|
|||
}
|
||||
fid = int(fid64)
|
||||
|
||||
sfs.forums = append(sfs.forums, Forum{fid,name_to_slug(forum_name),forum_name,forum_desc,active,preset,0,"","",0,"",0,""})
|
||||
sfs.forums = append(sfs.forums, &Forum{fid,name_to_slug(forum_name),forum_name,forum_desc,active,preset,0,"",0,"","",0,"",0,""})
|
||||
sfs.forumCapCount++
|
||||
|
||||
// TO-DO: Add a GroupStore. How would it interact with the ForumStore?
|
||||
permmap_to_query(preset_to_permmap(preset),fid)
|
||||
forum_create_mutex.Unlock()
|
||||
return fid, nil
|
||||
}
|
||||
|
@ -269,6 +321,10 @@ func (sfs *StaticForumStore) CreateForum(forum_name string, forum_desc string, a
|
|||
func (sfs *StaticForumStore) fill_forum_id_gap(biggerID int, smallerID int) {
|
||||
dummy := Forum{ID:0,Name:"",Active:false,Preset:"all"}
|
||||
for i := smallerID; i > biggerID; i++ {
|
||||
sfs.forums = append(sfs.forums, dummy)
|
||||
sfs.forums = append(sfs.forums, &dummy)
|
||||
}
|
||||
}
|
||||
|
||||
// TO-DO: Work on MapForumStore
|
||||
|
||||
// TO-DO: Work on SqlForumStore
|
||||
|
|
17
gen_mysql.go
|
@ -94,6 +94,7 @@ var delete_forum_stmt *sql.Stmt
|
|||
var update_forum_stmt *sql.Stmt
|
||||
var update_setting_stmt *sql.Stmt
|
||||
var update_plugin_stmt *sql.Stmt
|
||||
var update_plugin_install_stmt *sql.Stmt
|
||||
var update_theme_stmt *sql.Stmt
|
||||
var update_user_stmt *sql.Stmt
|
||||
var update_group_perms_stmt *sql.Stmt
|
||||
|
@ -112,7 +113,7 @@ var add_forum_perms_to_forum_members_stmt *sql.Stmt
|
|||
var notify_watchers_stmt *sql.Stmt
|
||||
|
||||
func gen_mysql() (err error) {
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Building the generated statements")
|
||||
}
|
||||
|
||||
|
@ -165,13 +166,13 @@ func gen_mysql() (err error) {
|
|||
}
|
||||
|
||||
log.Print("Preparing get_groups statement.")
|
||||
get_groups_stmt, err = db.Prepare("SELECT `gid`,`name`,`permissions`,`is_mod`,`is_admin`,`is_banned`,`tag` FROM `users_groups`")
|
||||
get_groups_stmt, err = db.Prepare("SELECT `gid`,`name`,`permissions`,`plugin_perms`,`is_mod`,`is_admin`,`is_banned`,`tag` FROM `users_groups`")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing get_forums statement.")
|
||||
get_forums_stmt, err = db.Prepare("SELECT `fid`,`name`,`desc`,`active`,`preset`,`topicCount`,`lastTopic`,`lastTopicID`,`lastReplyer`,`lastReplyerID`,`lastTopicTime` FROM `forums` ORDER BY fid ASC")
|
||||
get_forums_stmt, err = db.Prepare("SELECT `fid`,`name`,`desc`,`active`,`preset`,`parentID`,`parentType`,`topicCount`,`lastTopic`,`lastTopicID`,`lastReplyer`,`lastReplyerID`,`lastTopicTime` FROM `forums` ORDER BY fid ASC")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -183,7 +184,7 @@ func gen_mysql() (err error) {
|
|||
}
|
||||
|
||||
log.Print("Preparing get_plugins statement.")
|
||||
get_plugins_stmt, err = db.Prepare("SELECT `uname`,`active` FROM `plugins`")
|
||||
get_plugins_stmt, err = db.Prepare("SELECT `uname`,`active`,`installed` FROM `plugins`")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -435,7 +436,7 @@ func gen_mysql() (err error) {
|
|||
}
|
||||
|
||||
log.Print("Preparing add_plugin statement.")
|
||||
add_plugin_stmt, err = db.Prepare("INSERT INTO `plugins`(`uname`,`active`) VALUES (?,?)")
|
||||
add_plugin_stmt, err = db.Prepare("INSERT INTO `plugins`(`uname`,`active`,`installed`) VALUES (?,?,?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -644,6 +645,12 @@ func gen_mysql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing update_plugin_install statement.")
|
||||
update_plugin_install_stmt, err = db.Prepare("UPDATE `plugins` SET `installed` = ? WHERE `uname` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing update_theme statement.")
|
||||
update_theme_stmt, err = db.Prepare("UPDATE `themes` SET `default` = ? WHERE `uname` = ?")
|
||||
if err != nil {
|
||||
|
|
122
gen_router.go
|
@ -3,32 +3,48 @@
|
|||
package main
|
||||
|
||||
//import "fmt"
|
||||
import "sync"
|
||||
import "strings"
|
||||
import "sync"
|
||||
import "errors"
|
||||
import "net/http"
|
||||
|
||||
var ErrNoRoute = errors.New("That route doesn't exist.")
|
||||
|
||||
type GenRouter struct {
|
||||
UploadHandler func(http.ResponseWriter, *http.Request)
|
||||
sync.RWMutex // Temporary Fallback
|
||||
old_routes map[string]func(http.ResponseWriter, *http.Request) // Temporary Fallback
|
||||
extra_routes map[string]func(http.ResponseWriter, *http.Request, User)
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func NewGenRouter(uploads http.Handler) *GenRouter {
|
||||
return &GenRouter{
|
||||
UploadHandler: http.StripPrefix("/uploads/",uploads).ServeHTTP,
|
||||
old_routes: make(map[string]func(http.ResponseWriter, *http.Request)),
|
||||
extra_routes: make(map[string]func(http.ResponseWriter, *http.Request, User)),
|
||||
}
|
||||
}
|
||||
|
||||
func (router *GenRouter) Handle(_ string, _ http.Handler) {
|
||||
}
|
||||
|
||||
func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request)) {
|
||||
func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, User)) {
|
||||
router.Lock()
|
||||
router.old_routes[pattern] = handle
|
||||
router.extra_routes[pattern] = handle
|
||||
router.Unlock()
|
||||
}
|
||||
|
||||
func (router *GenRouter) RemoveFunc(pattern string) error {
|
||||
router.Lock()
|
||||
_, ok := router.extra_routes[pattern]
|
||||
if !ok {
|
||||
router.Unlock()
|
||||
return ErrNoRoute
|
||||
}
|
||||
delete(router.extra_routes,pattern)
|
||||
router.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
//if req.URL.Path == "/" {
|
||||
// default_route(w,req)
|
||||
|
@ -49,117 +65,129 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
//fmt.Println("prefix:",prefix)
|
||||
//fmt.Println("req.URL.Path:",req.URL.Path)
|
||||
//fmt.Println("extra_data:",extra_data)
|
||||
switch(prefix) {
|
||||
case "/api":
|
||||
route_api(w,req)
|
||||
return
|
||||
case "/static":
|
||||
|
||||
if prefix == "/static" {
|
||||
req.URL.Path += extra_data
|
||||
route_static(w,req)
|
||||
return
|
||||
}
|
||||
|
||||
// Deal with the session stuff, etc.
|
||||
user, ok := PreRoute(w,req)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
switch(prefix) {
|
||||
case "/api":
|
||||
route_api(w,req,user)
|
||||
return
|
||||
case "/overview":
|
||||
route_overview(w,req)
|
||||
route_overview(w,req,user)
|
||||
return
|
||||
case "/forums":
|
||||
route_forums(w,req)
|
||||
route_forums(w,req,user)
|
||||
return
|
||||
case "/forum":
|
||||
route_forum(w,req,extra_data)
|
||||
route_forum(w,req,user,extra_data)
|
||||
return
|
||||
case "/report":
|
||||
switch(req.URL.Path) {
|
||||
case "/report/submit/":
|
||||
route_report_submit(w,req,extra_data)
|
||||
route_report_submit(w,req,user,extra_data)
|
||||
return
|
||||
}
|
||||
case "/topics":
|
||||
switch(req.URL.Path) {
|
||||
case "/topics/create/":
|
||||
route_topic_create(w,req,extra_data)
|
||||
route_topic_create(w,req,user,extra_data)
|
||||
return
|
||||
default:
|
||||
route_topics(w,req)
|
||||
route_topics(w,req,user)
|
||||
return
|
||||
}
|
||||
case "/panel":
|
||||
switch(req.URL.Path) {
|
||||
case "/panel/forums/":
|
||||
route_panel_forums(w,req)
|
||||
route_panel_forums(w,req,user)
|
||||
return
|
||||
case "/panel/forums/create/":
|
||||
route_panel_forums_create_submit(w,req)
|
||||
route_panel_forums_create_submit(w,req,user)
|
||||
return
|
||||
case "/panel/forums/delete/":
|
||||
route_panel_forums_delete(w,req,extra_data)
|
||||
route_panel_forums_delete(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/forums/delete/submit/":
|
||||
route_panel_forums_delete_submit(w,req,extra_data)
|
||||
route_panel_forums_delete_submit(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/forums/edit/":
|
||||
route_panel_forums_edit(w,req,extra_data)
|
||||
route_panel_forums_edit(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/forums/edit/submit/":
|
||||
route_panel_forums_edit_submit(w,req,extra_data)
|
||||
route_panel_forums_edit_submit(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/forums/edit/perms/submit/":
|
||||
route_panel_forums_edit_perms_submit(w,req,extra_data)
|
||||
route_panel_forums_edit_perms_submit(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/settings/":
|
||||
route_panel_settings(w,req)
|
||||
route_panel_settings(w,req,user)
|
||||
return
|
||||
case "/panel/settings/edit/":
|
||||
route_panel_setting(w,req,extra_data)
|
||||
route_panel_setting(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/settings/edit/submit/":
|
||||
route_panel_setting_edit(w,req,extra_data)
|
||||
route_panel_setting_edit(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/themes/":
|
||||
route_panel_themes(w,req)
|
||||
route_panel_themes(w,req,user)
|
||||
return
|
||||
case "/panel/themes/default/":
|
||||
route_panel_themes_default(w,req,extra_data)
|
||||
route_panel_themes_default(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/plugins/":
|
||||
route_panel_plugins(w,req)
|
||||
route_panel_plugins(w,req,user)
|
||||
return
|
||||
case "/panel/plugins/activate/":
|
||||
route_panel_plugins_activate(w,req,extra_data)
|
||||
route_panel_plugins_activate(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/plugins/deactivate/":
|
||||
route_panel_plugins_deactivate(w,req,extra_data)
|
||||
route_panel_plugins_deactivate(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/plugins/install/":
|
||||
route_panel_plugins_install(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/users/":
|
||||
route_panel_users(w,req)
|
||||
route_panel_users(w,req,user)
|
||||
return
|
||||
case "/panel/users/edit/":
|
||||
route_panel_users_edit(w,req,extra_data)
|
||||
route_panel_users_edit(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/users/edit/submit/":
|
||||
route_panel_users_edit_submit(w,req,extra_data)
|
||||
route_panel_users_edit_submit(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/groups/":
|
||||
route_panel_groups(w,req)
|
||||
route_panel_groups(w,req,user)
|
||||
return
|
||||
case "/panel/groups/edit/":
|
||||
route_panel_groups_edit(w,req,extra_data)
|
||||
route_panel_groups_edit(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/groups/edit/perms/":
|
||||
route_panel_groups_edit_perms(w,req,extra_data)
|
||||
route_panel_groups_edit_perms(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/groups/edit/submit/":
|
||||
route_panel_groups_edit_submit(w,req,extra_data)
|
||||
route_panel_groups_edit_submit(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/groups/edit/perms/submit/":
|
||||
route_panel_groups_edit_perms_submit(w,req,extra_data)
|
||||
route_panel_groups_edit_perms_submit(w,req,user,extra_data)
|
||||
return
|
||||
case "/panel/groups/create/":
|
||||
route_panel_groups_create_submit(w,req)
|
||||
route_panel_groups_create_submit(w,req,user)
|
||||
return
|
||||
case "/panel/logs/mod/":
|
||||
route_panel_logs_mod(w,req)
|
||||
route_panel_logs_mod(w,req,user)
|
||||
return
|
||||
default:
|
||||
route_panel(w,req)
|
||||
route_panel(w,req,user)
|
||||
return
|
||||
}
|
||||
case "/uploads":
|
||||
|
@ -171,19 +199,19 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
router.UploadHandler(w,req)
|
||||
return
|
||||
case "":
|
||||
default_route(w,req)
|
||||
default_route(w,req,user)
|
||||
return
|
||||
//default: NotFound(w,req)
|
||||
}
|
||||
|
||||
// A fallback for the routes which haven't been converted to the new router yet
|
||||
// A fallback for the routes which haven't been converted to the new router yet or plugins
|
||||
router.RLock()
|
||||
handle, ok := router.old_routes[req.URL.Path]
|
||||
handle, ok := router.extra_routes[req.URL.Path]
|
||||
router.RUnlock()
|
||||
|
||||
if ok {
|
||||
req.URL.Path += extra_data
|
||||
handle(w,req)
|
||||
handle(w,req,user)
|
||||
return
|
||||
}
|
||||
NotFound(w,req)
|
||||
|
|
133
general_test.go
|
@ -2,7 +2,6 @@ package main
|
|||
|
||||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
"log"
|
||||
"bytes"
|
||||
"strings"
|
||||
|
@ -12,6 +11,7 @@ import (
|
|||
"time"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"database/sql"
|
||||
"runtime/pprof"
|
||||
|
@ -21,11 +21,12 @@ import (
|
|||
//"github.com/husobee/vestigo"
|
||||
)
|
||||
|
||||
var db_test, db_prod *sql.DB
|
||||
var gloinited bool = false
|
||||
var db_test *sql.DB
|
||||
var db_prod *sql.DB
|
||||
var gloinited bool
|
||||
|
||||
func gloinit() {
|
||||
debug = false
|
||||
debug_mode = false
|
||||
//nogrouplog = true
|
||||
|
||||
// init_database is a little noisy for a benchmark
|
||||
|
@ -64,8 +65,6 @@ func gloinit() {
|
|||
|
||||
init_static_files()
|
||||
external_sites["YT"] = "https://www.youtube.com/"
|
||||
hooks["trow_assign"] = nil
|
||||
hooks["rrow_assign"] = nil
|
||||
//log.SetOutput(os.Stdout)
|
||||
gloinited = true
|
||||
}
|
||||
|
@ -77,26 +76,34 @@ func init() {
|
|||
func BenchmarkTopicTemplateSerial(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0,"127.0.0.1"}
|
||||
admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","","",-1,58,"127.0.0.1"}
|
||||
noticeList := []string{"test"}
|
||||
user := User{0,"bob","Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0,"127.0.0.1"}
|
||||
admin := User{1,"admin-alice","Admin Alice","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",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",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}
|
||||
|
||||
var replyList []Reply
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry","Jerry",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry2","Jerry2",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry3","Jerry3",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry4","Jerry4",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry5","Jerry5",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry6","Jerry6",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry7","Jerry7",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry8","Jerry8",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry9","Jerry9",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"jerry10","Jerry10",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
|
||||
tpage := TopicPage{"Topic Blah",user,noticeList,replyList,topic,1,1,false}
|
||||
tpage2 := TopicPage{"Topic Blah",admin,noticeList,replyList,topic,1,1,false}
|
||||
headerVars := HeaderVars{
|
||||
NoticeList:[]string{"test"},
|
||||
Stylesheets:[]string{"panel"},
|
||||
Scripts:[]string{"whatever"},
|
||||
Widgets:PageWidgets{
|
||||
LeftSidebar: template.HTML("lalala"),
|
||||
},
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -157,25 +164,33 @@ func BenchmarkTopicTemplateSerial(b *testing.B) {
|
|||
func BenchmarkTopicsTemplateSerial(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0,"127.0.0.1"}
|
||||
admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","","",-1,58,"127.0.0.1"}
|
||||
noticeList := []string{"test"}
|
||||
user := User{0,"bob","Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0,"127.0.0.1"}
|
||||
admin := User{1,"admin-alice","Admin Alice","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","","",-1,58,"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,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,UserSlug:"admin-alice",CreatedByName:"Admin Alice",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,UserSlug:"admin-alice",CreatedByName:"Admin Alice",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,UserSlug:"admin-alice",CreatedByName:"Admin Alice",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,UserSlug:"admin-alice",CreatedByName:"Admin Alice",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,UserSlug:"admin-alice",CreatedByName:"Admin Alice",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,UserSlug:"admin-alice",CreatedByName:"Admin Alice",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,UserSlug:"admin-alice",CreatedByName:"Admin Alice",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,UserSlug:"admin-alice",CreatedByName:"Admin Alice",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,UserSlug:"admin-alice",CreatedByName:"Admin Alice",Css: no_css_tmpl,Tag: "Admin", Level: 58, 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,UserSlug:"admin-alice",CreatedByName:"Admin Alice",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"})
|
||||
|
||||
headerVars := HeaderVars{
|
||||
NoticeList:[]string{"test"},
|
||||
Stylesheets:[]string{"panel"},
|
||||
Scripts:[]string{"whatever"},
|
||||
Widgets:PageWidgets{
|
||||
LeftSidebar: template.HTML("lalala"),
|
||||
},
|
||||
}
|
||||
|
||||
w := ioutil.Discard
|
||||
tpage := TopicsPage{"Topic Blah",user,noticeList,topicList,nil}
|
||||
tpage2 := TopicsPage{"Topic Blah",admin,noticeList,topicList,nil}
|
||||
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++ {
|
||||
|
@ -1206,7 +1221,7 @@ func TestLevels(t *testing.T) {
|
|||
levels := getLevels(40)
|
||||
for level, score := range levels {
|
||||
sscore := strconv.FormatFloat(score, 'f', -1, 64)
|
||||
log.Print("Level: " + strconv.Itoa(level) + " Score: " + sscore)
|
||||
t.Log("Level: " + strconv.Itoa(level) + " Score: " + sscore)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1224,10 +1239,8 @@ func TestStaticRoute(t *testing.T) {
|
|||
|
||||
static_handler.ServeHTTP(static_w,static_req)
|
||||
if static_w.Code != 200 {
|
||||
fmt.Println(static_w.Body)
|
||||
panic("HTTP Error!")
|
||||
t.Fatal(static_w.Body)
|
||||
}
|
||||
fmt.Println("No problems found in the static route!")
|
||||
}
|
||||
|
||||
/*func TestTopicAdminRoute(t *testing.T) {
|
||||
|
@ -1294,10 +1307,10 @@ func TestForumsAdminRoute(t *testing.T) {
|
|||
|
||||
admin, err := users.CascadeGet(1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !admin.Is_Admin {
|
||||
panic("UID1 is not an admin")
|
||||
t.Fatal("UID1 is not an admin")
|
||||
}
|
||||
admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year}
|
||||
admin_session_cookie := http.Cookie{Name:"session",Value: admin.Session,Path:"/",MaxAge: year}
|
||||
|
@ -1311,10 +1324,8 @@ func TestForumsAdminRoute(t *testing.T) {
|
|||
|
||||
forums_handler.ServeHTTP(forums_w,forums_req_admin)
|
||||
if forums_w.Code != 200 {
|
||||
fmt.Println(forums_w.Body)
|
||||
panic("HTTP Error!")
|
||||
t.Fatal(forums_w.Body)
|
||||
}
|
||||
fmt.Println("No problems found in the forums-admin route!")
|
||||
}
|
||||
|
||||
func TestForumsGuestRoute(t *testing.T) {
|
||||
|
@ -1331,10 +1342,8 @@ func TestForumsGuestRoute(t *testing.T) {
|
|||
|
||||
forums_handler.ServeHTTP(forums_w,forums_req)
|
||||
if forums_w.Code != 200 {
|
||||
fmt.Println(forums_w.Body)
|
||||
panic("HTTP Error!")
|
||||
t.Fatal(forums_w.Body)
|
||||
}
|
||||
fmt.Println("No problems found in the forums-guest route!")
|
||||
}
|
||||
|
||||
/*func TestForumAdminRoute(t *testing.T) {
|
||||
|
@ -1419,35 +1428,29 @@ func TestForumsGuestRoute(t *testing.T) {
|
|||
db = db_prod
|
||||
}*/
|
||||
|
||||
/*func TestRoute(t *testing.T) {
|
||||
|
||||
}*/
|
||||
|
||||
func TestSplittyThing(t *testing.T) {
|
||||
fmt.Println("Splitty thing test")
|
||||
var extra_data string
|
||||
var path string = "/pages/hohoho"
|
||||
fmt.Println("Raw Path:",path)
|
||||
t.Log("Raw Path:",path)
|
||||
if path[len(path) - 1] != '/' {
|
||||
extra_data = path[strings.LastIndexByte(path,'/') + 1:]
|
||||
path = path[:strings.LastIndexByte(path,'/') + 1]
|
||||
}
|
||||
fmt.Println("Path:", path)
|
||||
fmt.Println("Extra Data:", extra_data)
|
||||
fmt.Println("Path Bytes:", []byte(path))
|
||||
fmt.Println("Extra Data Bytes:", []byte(extra_data))
|
||||
t.Log("Path:", path)
|
||||
t.Log("Extra Data:", extra_data)
|
||||
t.Log("Path Bytes:", []byte(path))
|
||||
t.Log("Extra Data Bytes:", []byte(extra_data))
|
||||
|
||||
|
||||
fmt.Println("Splitty thing test")
|
||||
t.Log("Splitty thing test")
|
||||
path = "/topics/"
|
||||
extra_data = ""
|
||||
fmt.Println("Raw Path:",path)
|
||||
t.Log("Raw Path:",path)
|
||||
if path[len(path) - 1] != '/' {
|
||||
extra_data = path[strings.LastIndexByte(path,'/') + 1:]
|
||||
path = path[:strings.LastIndexByte(path,'/') + 1]
|
||||
}
|
||||
fmt.Println("Path:", path)
|
||||
fmt.Println("Extra Data:", extra_data)
|
||||
fmt.Println("Path Bytes:", []byte(path))
|
||||
fmt.Println("Extra Data Bytes:", []byte(extra_data))
|
||||
t.Log("Path:", path)
|
||||
t.Log("Extra Data:", extra_data)
|
||||
t.Log("Path Bytes:", []byte(path))
|
||||
t.Log("Extra Data Bytes:", []byte(extra_data))
|
||||
}
|
||||
|
|
15
group.go
|
@ -25,6 +25,8 @@ type Group struct
|
|||
Tag string
|
||||
Perms Perms
|
||||
PermissionsText []byte
|
||||
PluginPerms map[string]bool // Custom permissions defined by plugins. What if two plugins declare the same permission, but they handle them in incompatible ways? Very unlikely, we probably don't need to worry about this, the plugin authors should be aware of each other to some extent
|
||||
PluginPermsText []byte
|
||||
Forums []ForumPerms
|
||||
CanSee []int // The IDs of the forums this group can see
|
||||
}
|
||||
|
@ -69,10 +71,17 @@ func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_
|
|||
return 0, err
|
||||
}
|
||||
gid = int(gid64)
|
||||
perms := BlankPerms
|
||||
|
||||
var perms Perms = BlankPerms
|
||||
var blankForums []ForumPerms
|
||||
var blankIntList []int
|
||||
groups = append(groups, Group{gid,group_name,is_mod,is_admin,is_banned,tag,perms,[]byte(permstr),blankForums,blankIntList})
|
||||
var plugin_perms map[string]bool = make(map[string]bool)
|
||||
var plugin_perms_bytes []byte = []byte("{}")
|
||||
if vhooks["create_group_preappend"] != nil {
|
||||
run_vhook("create_group_preappend", &plugin_perms, &plugin_perms_bytes)
|
||||
}
|
||||
|
||||
groups = append(groups, Group{gid,group_name,is_mod,is_admin,is_banned,tag,perms,[]byte(permstr),plugin_perms,plugin_perms_bytes,blankForums,blankIntList})
|
||||
group_create_mutex.Unlock()
|
||||
|
||||
// Generate the forum permissions based on the presets...
|
||||
|
@ -117,5 +126,5 @@ func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_
|
|||
}
|
||||
|
||||
func group_exists(gid int) bool {
|
||||
return (gid <= groupCapCount) && (gid > 0) && groups[gid].Name!=""
|
||||
return (gid <= groupCapCount) && (gid > 0) && groups[gid].Name != ""
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 482 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 406 KiB |
Before Width: | Height: | Size: 239 KiB After Width: | Height: | Size: 269 KiB |
|
@ -1,5 +1,7 @@
|
|||
echo "Installing the MySQL Driver"
|
||||
go get -u github.com/go-sql-driver/mysql
|
||||
echo "Installing the PostgreSQL Driver"
|
||||
go get -u github.com/lib/pq
|
||||
echo "Installing bcrypt"
|
||||
go get -u golang.org/x/crypto/bcrypt
|
||||
echo "Installing gopsutil"
|
||||
|
|
|
@ -5,6 +5,11 @@ if %errorlevel% neq 0 (
|
|||
pause
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
go get -u github.com/lib/pq
|
||||
if %errorlevel% neq 0 (
|
||||
pause
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
go get -u golang.org/x/crypto/bcrypt
|
||||
if %errorlevel% neq 0 (
|
||||
pause
|
||||
|
|
|
@ -180,7 +180,7 @@ var noavatar = "https://api.adorable.io/avatars/285/{id}@" + site_url + ".png"
|
|||
var items_per_page = 25
|
||||
|
||||
// Developer flag
|
||||
var debug = true
|
||||
var debug_mode = true
|
||||
var super_debug = false
|
||||
var profiling = false
|
||||
`)
|
||||
|
|
22
main.go
|
@ -25,6 +25,7 @@ const saltLength int = 32
|
|||
const sessionLength int = 80
|
||||
var enable_websockets bool = false // Don't change this, the value is overwritten by an initialiser
|
||||
|
||||
var router *GenRouter
|
||||
var startTime time.Time
|
||||
var timeLocation *time.Location
|
||||
var templates = template.New("")
|
||||
|
@ -46,7 +47,7 @@ var template_create_topic_handle func(CreateTopicPage,io.Writer) = nil
|
|||
|
||||
func compile_templates() error {
|
||||
var c CTemplateSet
|
||||
user := User{62,"fake-user","Fake User","compiler@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0,"0.0.0.0.0"}
|
||||
user := User{62,"fake-user","Fake User","compiler@localhost",0,false,false,false,false,false,false,GuestPerms,make(map[string]bool),"",false,"","","","","",0,0,"0.0.0.0.0"}
|
||||
headerVars := HeaderVars{
|
||||
NoticeList:[]string{"test"},
|
||||
Stylesheets:[]string{"panel"},
|
||||
|
@ -79,7 +80,7 @@ func compile_templates() error {
|
|||
|
||||
for _, forum := range forums {
|
||||
if forum.Active {
|
||||
forumList = append(forumList,forum)
|
||||
forumList = append(forumList,*forum)
|
||||
}
|
||||
}
|
||||
varList = make(map[string]VarItem)
|
||||
|
@ -87,13 +88,13 @@ func compile_templates() error {
|
|||
forums_tmpl := c.compile_template("forums.html","templates/","ForumsPage",forums_page,varList)
|
||||
|
||||
var topicsList []TopicsRow
|
||||
topicsList = append(topicsList,TopicsRow{1,"topic-title","Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"classname","admin-alice","Admin Alice","","",0,"","","","",58,"General"})
|
||||
topicsList = append(topicsList,TopicsRow{1,"topic-title","Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"classname","admin-alice","Admin Alice","","",0,"","","","",58,"General","/forum/general.2"})
|
||||
topics_page := TopicsPage{"Topic List",user,headerVars,topicsList,extData}
|
||||
topics_tmpl := c.compile_template("topics.html","templates/","TopicsPage",topics_page,varList)
|
||||
|
||||
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",default_group,"","",0,"","","","",58,false})
|
||||
forum_item := Forum{1,"general","General Forum","Where the general stuff happens",true,"all",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,topicList,forum_item,1,1,extData}
|
||||
forum_tmpl := c.compile_template("forum.html","templates/","ForumPage",forum_page,varList)
|
||||
|
||||
|
@ -117,7 +118,7 @@ func write_template(name string, content string) {
|
|||
}
|
||||
|
||||
func init_templates() {
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Initialising the template system")
|
||||
}
|
||||
compile_templates()
|
||||
|
@ -133,7 +134,7 @@ func init_templates() {
|
|||
fmap["divide"] = filler_func
|
||||
|
||||
// The interpreted templates...
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Loading the template files...")
|
||||
}
|
||||
templates.Funcs(fmap)
|
||||
|
@ -177,9 +178,6 @@ func main(){
|
|||
|
||||
init_static_files()
|
||||
external_sites["YT"] = "https://www.youtube.com/"
|
||||
hooks["trow_assign"] = nil
|
||||
hooks["rrow_assign"] = nil
|
||||
init_plugins()
|
||||
|
||||
log.Print("Initialising the widgets")
|
||||
err = init_widgets()
|
||||
|
@ -191,7 +189,7 @@ func main(){
|
|||
auth = NewDefaultAuth()
|
||||
|
||||
log.Print("Initialising the router")
|
||||
router := NewGenRouter(http.FileServer(http.Dir("./uploads")))
|
||||
router = NewGenRouter(http.FileServer(http.Dir("./uploads")))
|
||||
///router.HandleFunc("/static/", route_static)
|
||||
///router.HandleFunc("/overview/", route_overview)
|
||||
///router.HandleFunc("/topics/create/", route_topic_create)
|
||||
|
@ -276,6 +274,10 @@ func main(){
|
|||
//router.HandleFunc("/exit/", route_exit)
|
||||
///router.HandleFunc("/", default_route)
|
||||
router.HandleFunc("/ws/", route_websockets)
|
||||
|
||||
log.Print("Initialising the plugins")
|
||||
init_plugins()
|
||||
|
||||
defer db.Close()
|
||||
|
||||
//if profiling {
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
// TO-DO: Generate a test database to work with rather than a live one
|
||||
func TestUserStore(t *testing.T) {
|
||||
if !gloinited {
|
||||
gloinit()
|
||||
}
|
||||
if !plugins_inited {
|
||||
init_plugins()
|
||||
}
|
||||
|
||||
var user *User
|
||||
var err error
|
||||
|
||||
user, err = users.CascadeGet(-1)
|
||||
if err == nil {
|
||||
t.Error("UID #-1 shouldn't exist")
|
||||
} else if err != ErrNoRows {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user, err = users.CascadeGet(0)
|
||||
if err == nil {
|
||||
t.Error("UID #0 shouldn't exist")
|
||||
} else if err != ErrNoRows {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user, err = users.CascadeGet(1)
|
||||
if err == ErrNoRows {
|
||||
t.Error("Couldn't find UID #1")
|
||||
} else if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if user.ID != 1 {
|
||||
t.Error("user.ID doesn't not match the requested UID")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlugs(t *testing.T) {
|
||||
var res string
|
||||
var msgList []ME_Pair
|
||||
|
||||
msgList = addMEPair(msgList,"Unknown","unknown")
|
||||
msgList = addMEPair(msgList,"Unknown2","unknown2")
|
||||
msgList = addMEPair(msgList,"Unknown ","unknown")
|
||||
msgList = addMEPair(msgList,"Unknown 2","unknown-2")
|
||||
msgList = addMEPair(msgList,"Unknown 2","unknown-2")
|
||||
msgList = addMEPair(msgList,"Admin Alice","admin-alice")
|
||||
msgList = addMEPair(msgList,"Admin_Alice","adminalice")
|
||||
msgList = addMEPair(msgList,"Admin_Alice-","adminalice")
|
||||
msgList = addMEPair(msgList,"-Admin_Alice-","adminalice")
|
||||
msgList = addMEPair(msgList,"-Admin@Alice-","adminalice")
|
||||
msgList = addMEPair(msgList,"-Admin😀Alice-","adminalice")
|
||||
msgList = addMEPair(msgList,"u","u")
|
||||
msgList = addMEPair(msgList,"","untitled")
|
||||
msgList = addMEPair(msgList," ","untitled")
|
||||
msgList = addMEPair(msgList,"-","untitled")
|
||||
msgList = addMEPair(msgList,"--","untitled")
|
||||
msgList = addMEPair(msgList,"é","é")
|
||||
msgList = addMEPair(msgList,"-é-","é")
|
||||
|
||||
for _, item := range msgList {
|
||||
t.Log("Testing string '"+item.Msg+"'")
|
||||
res = name_to_slug(item.Msg)
|
||||
if res != item.Expects {
|
||||
t.Error("Bad output:","'"+res+"'")
|
||||
t.Error("Expected:",item.Expects)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import (
|
|||
"html"
|
||||
)
|
||||
|
||||
func route_edit_topic(w http.ResponseWriter, r *http.Request) {
|
||||
func route_edit_topic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
PreError("Bad Form",w,r)
|
||||
|
@ -36,7 +36,7 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
user, ok := SimpleForumSessionCheck(w,r,old_topic.ParentID)
|
||||
ok := SimpleForumSessionCheck(w,r,&user,old_topic.ParentID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func route_delete_topic(w http.ResponseWriter, r *http.Request) {
|
||||
func route_delete_topic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
tid, err := strconv.Atoi(r.URL.Path[len("/topic/delete/submit/"):])
|
||||
if err != nil {
|
||||
PreError("The provided TopicID is not a valid number.",w,r)
|
||||
|
@ -125,7 +125,7 @@ func route_delete_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
user, ok := SimpleForumSessionCheck(w,r,topic.ParentID)
|
||||
ok := SimpleForumSessionCheck(w,r,&user,topic.ParentID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ func route_delete_topic(w http.ResponseWriter, r *http.Request) {
|
|||
topics.Remove(tid)
|
||||
}
|
||||
|
||||
func route_stick_topic(w http.ResponseWriter, r *http.Request) {
|
||||
func route_stick_topic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
tid, err := strconv.Atoi(r.URL.Path[len("/topic/stick/submit/"):])
|
||||
if err != nil {
|
||||
PreError("The provided TopicID is not a valid number.",w,r)
|
||||
|
@ -192,7 +192,7 @@ func route_stick_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
user, ok := SimpleForumSessionCheck(w,r,topic.ParentID)
|
||||
ok := SimpleForumSessionCheck(w,r,&user,topic.ParentID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ func route_stick_topic(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_unstick_topic(w http.ResponseWriter, r *http.Request) {
|
||||
func route_unstick_topic(w http.ResponseWriter, r *http.Request, user User) {
|
||||
tid, err := strconv.Atoi(r.URL.Path[len("/topic/unstick/submit/"):])
|
||||
if err != nil {
|
||||
PreError("The provided TopicID is not a valid number.",w,r)
|
||||
|
@ -247,7 +247,7 @@ func route_unstick_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
user, ok := SimpleForumSessionCheck(w,r,topic.ParentID)
|
||||
ok := SimpleForumSessionCheck(w,r,&user,topic.ParentID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -286,7 +286,7 @@ func route_unstick_topic(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_reply_edit_submit(w http.ResponseWriter, r *http.Request) {
|
||||
func route_reply_edit_submit(w http.ResponseWriter, r *http.Request, user User) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
PreError("Bad Form",w,r)
|
||||
|
@ -328,7 +328,7 @@ func route_reply_edit_submit(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
user, ok := SimpleForumSessionCheck(w,r,fid)
|
||||
ok := SimpleForumSessionCheck(w,r,&user,fid)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -344,7 +344,7 @@ func route_reply_edit_submit(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func route_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
|
||||
func route_reply_delete_submit(w http.ResponseWriter, r *http.Request, user User) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
PreError("Bad Form",w,r)
|
||||
|
@ -380,7 +380,7 @@ func route_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
user, ok := SimpleForumSessionCheck(w,r,fid)
|
||||
ok := SimpleForumSessionCheck(w,r,&user,fid)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -430,12 +430,7 @@ func route_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := SimpleSessionCheck(w,r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request, user User) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
LocalError("Bad Form",w,r,user)
|
||||
|
@ -479,12 +474,7 @@ func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func route_profile_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := SimpleSessionCheck(w,r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
func route_profile_reply_delete_submit(w http.ResponseWriter, r *http.Request, user User) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
LocalError("Bad Form",w,r,user)
|
||||
|
@ -530,8 +520,8 @@ func route_profile_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func route_ban(w http.ResponseWriter, r *http.Request) {
|
||||
user, headerVars, ok := SessionCheck(w,r)
|
||||
func route_ban(w http.ResponseWriter, r *http.Request, user User) {
|
||||
headerVars, ok := SessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -560,14 +550,15 @@ func route_ban(w http.ResponseWriter, r *http.Request) {
|
|||
yousure := AreYouSure{"/users/ban/submit/" + strconv.Itoa(uid),confirm_msg}
|
||||
|
||||
pi := Page{"Ban User",user,headerVars,tList,yousure}
|
||||
if pre_render_hooks["pre_render_ban"] != nil {
|
||||
if run_pre_render_hook("pre_render_ban", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
templates.ExecuteTemplate(w,"areyousure.html",pi)
|
||||
}
|
||||
|
||||
func route_ban_submit(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := SimpleSessionCheck(w,r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
func route_ban_submit(w http.ResponseWriter, r *http.Request, user User) {
|
||||
if !user.Perms.BanUsers {
|
||||
NoPermissions(w,r,user)
|
||||
return
|
||||
|
@ -637,11 +628,7 @@ func route_ban_submit(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w,r,"/user/" + strconv.Itoa(uid),http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_unban(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := SimpleSessionCheck(w,r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
func route_unban(w http.ResponseWriter, r *http.Request, user User) {
|
||||
if !user.Perms.BanUsers {
|
||||
NoPermissions(w,r,user)
|
||||
return
|
||||
|
@ -701,11 +688,7 @@ func route_unban(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w,r,"/user/" + strconv.Itoa(uid),http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_activate(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := SimpleSessionCheck(w,r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
func route_activate(w http.ResponseWriter, r *http.Request, user User) {
|
||||
if !user.Perms.ActivateUsers {
|
||||
NoPermissions(w,r,user)
|
||||
return
|
||||
|
|
9
mysql.go
|
@ -1,5 +1,6 @@
|
|||
/* Copyright Azareal 2016 - 2017 */
|
||||
// +build !pgsql !sqlite !mssql
|
||||
|
||||
/* Copyright Azareal 2016 - 2018 */
|
||||
package main
|
||||
|
||||
import "log"
|
||||
|
@ -7,6 +8,7 @@ import "database/sql"
|
|||
import _ "github.com/go-sql-driver/mysql"
|
||||
import "./query_gen/lib"
|
||||
|
||||
var db_collation string = "utf8mb4_general_ci"
|
||||
var get_activity_feed_by_watcher_stmt *sql.Stmt
|
||||
var get_activity_count_by_watcher_stmt *sql.Stmt
|
||||
var todays_post_count_stmt *sql.Stmt
|
||||
|
@ -15,12 +17,13 @@ var todays_report_count_stmt *sql.Stmt
|
|||
var todays_newuser_count_stmt *sql.Stmt
|
||||
|
||||
func _init_database() (err error) {
|
||||
var _dbpassword string
|
||||
if(dbpassword != ""){
|
||||
dbpassword = ":" + dbpassword
|
||||
_dbpassword = ":" + dbpassword
|
||||
}
|
||||
|
||||
// Open the database connection
|
||||
db, err = sql.Open("mysql",dbuser + dbpassword + "@tcp(" + dbhost + ":" + dbport + ")/" + dbname + "?collation=" + db_collation)
|
||||
db, err = sql.Open("mysql",dbuser + _dbpassword + "@tcp(" + dbhost + ":" + dbport + ")/" + dbname + "?collation=" + db_collation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
16
mysql.sql
|
@ -29,6 +29,7 @@ CREATE TABLE `users_groups`(
|
|||
`gid` int not null AUTO_INCREMENT,
|
||||
`name` varchar(100) not null,
|
||||
`permissions` text not null,
|
||||
`plugin_perms` text not null,
|
||||
`is_mod` tinyint DEFAULT 0 not null,
|
||||
`is_admin` tinyint DEFAULT 0 not null,
|
||||
`is_banned` tinyint DEFAULT 0 not null,
|
||||
|
@ -50,6 +51,8 @@ CREATE TABLE `forums`(
|
|||
`active` tinyint DEFAULT 1 not null,
|
||||
`topicCount` int DEFAULT 0 not null,
|
||||
`preset` varchar(100) DEFAULT '' not null,
|
||||
`parentID` int DEFAULT 0 not null, /* TO-DO: Add support for subforums */
|
||||
`parentType` varchar(50) DEFAULT '' not null,
|
||||
`lastTopic` varchar(100) DEFAULT '' not null,
|
||||
`lastTopicID` int DEFAULT 0 not null,
|
||||
`lastReplyer` varchar(100) DEFAULT '' not null,
|
||||
|
@ -165,6 +168,7 @@ CREATE TABLE `settings`(
|
|||
CREATE TABLE `plugins`(
|
||||
`uname` varchar(200) not null,
|
||||
`active` tinyint DEFAULT 0 not null,
|
||||
`installed` tinyint DEFAULT 0 not null,
|
||||
unique(`uname`)
|
||||
);
|
||||
|
||||
|
@ -251,12 +255,12 @@ PinTopic
|
|||
CloseTopic
|
||||
*/
|
||||
|
||||
INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,1,"Admin");
|
||||
INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`tag`) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,"Mod");
|
||||
INSERT INTO users_groups(`name`,`permissions`) VALUES ('Member','{"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}');
|
||||
INSERT INTO users_groups(`name`,`permissions`,`is_banned`) VALUES ('Banned','{"ViewTopic":true}',1);
|
||||
INSERT INTO users_groups(`name`,`permissions`) VALUES ('Awaiting Activation','{"ViewTopic":true}');
|
||||
INSERT INTO users_groups(`name`,`permissions`,`tag`) VALUES ('Not Loggedin','{"ViewTopic":true}','Guest');
|
||||
INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}','{}',1,1,"Admin");
|
||||
INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`,`is_mod`,`tag`) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}','{}',1,"Mod");
|
||||
INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`) VALUES ('Member','{"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}');
|
||||
INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`,`is_banned`) VALUES ('Banned','{"ViewTopic":true}','{}',1);
|
||||
INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`) VALUES ('Awaiting Activation','{"ViewTopic":true}','{}');
|
||||
INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`,`tag`) VALUES ('Not Loggedin','{"ViewTopic":true}','{}','Guest');
|
||||
|
||||
INSERT INTO forums(`name`,`active`) VALUES ('Reports',0);
|
||||
INSERT INTO forums(`name`,`lastTopicTime`) VALUES ('General',NOW());
|
||||
|
|
|
@ -36,5 +36,5 @@ func(hub *WS_Hub) push_alerts(_ []int, _ string, _ string, _ int, _ int, _ int)
|
|||
return ws_nouser
|
||||
}
|
||||
|
||||
func route_websockets(_ http.ResponseWriter, _ *http.Request) {
|
||||
func route_websockets(_ http.ResponseWriter, _ *http.Request, _ User) {
|
||||
}
|
||||
|
|
30
pages.go
|
@ -14,6 +14,7 @@ type HeaderVars struct
|
|||
Scripts []string
|
||||
Stylesheets []string
|
||||
Widgets PageWidgets
|
||||
ExtData ExtData
|
||||
}
|
||||
|
||||
type PageWidgets struct
|
||||
|
@ -22,6 +23,11 @@ type PageWidgets struct
|
|||
RightSidebar template.HTML
|
||||
}
|
||||
|
||||
/*type UnsafeExtData struct
|
||||
{
|
||||
items map[string]interface{} // Key: pluginname
|
||||
}*/
|
||||
|
||||
type ExtData struct
|
||||
{
|
||||
items map[string]interface{} // Key: pluginname
|
||||
|
@ -365,9 +371,8 @@ func shortcode_to_unicode(msg string) string {
|
|||
}
|
||||
|
||||
func preparse_message(msg string) string {
|
||||
if hooks["preparse_preassign"] != nil {
|
||||
out := run_hook("preparse_preassign", msg)
|
||||
msg = out.(string)
|
||||
if sshooks["preparse_preassign"] != nil {
|
||||
msg = run_sshook("preparse_preassign", msg)
|
||||
}
|
||||
return shortcode_to_unicode(msg)
|
||||
}
|
||||
|
@ -516,9 +521,9 @@ func parse_message(msg string/*, user User*/) string {
|
|||
//fmt.Println(string(msgbytes))
|
||||
//fmt.Println(msgbytes)
|
||||
//fmt.Println(msgbytes[lastItem - 1])
|
||||
//fmt.Println(lastItem - 1)
|
||||
//fmt.Println(msgbytes[lastItem])
|
||||
//fmt.Println(lastItem)
|
||||
//fmt.Println("lastItem - 1",lastItem - 1)
|
||||
//fmt.Println("msgbytes[lastItem]",msgbytes[lastItem])
|
||||
//fmt.Println("lastItem",lastItem)
|
||||
} else if msgbytes[i]=='h' || msgbytes[i]=='f' || msgbytes[i]=='g' {
|
||||
//fmt.Println("IN hfg")
|
||||
if msgbytes[i + 1]=='t' && msgbytes[i + 2]=='t' && msgbytes[i + 3]=='p' {
|
||||
|
@ -556,8 +561,7 @@ func parse_message(msg string/*, user User*/) string {
|
|||
}
|
||||
|
||||
if lastItem != i && len(outbytes) != 0 {
|
||||
//fmt.Println("lastItem:")
|
||||
//fmt.Println(msgbytes[lastItem])
|
||||
//fmt.Println("lastItem:",msgbytes[lastItem])
|
||||
//fmt.Println("lastItem index:")
|
||||
//fmt.Println(lastItem)
|
||||
//fmt.Println("i:")
|
||||
|
@ -576,9 +580,8 @@ func parse_message(msg string/*, user User*/) string {
|
|||
//fmt.Println(`"`+msg+`"`)
|
||||
|
||||
msg = strings.Replace(msg,"\n","<br>",-1)
|
||||
if hooks["parse_assign"] != nil {
|
||||
out := run_hook("parse_assign", msg)
|
||||
msg = out.(string)
|
||||
if sshooks["parse_assign"] != nil {
|
||||
msg = run_sshook("parse_assign", msg)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
@ -589,9 +592,8 @@ func regex_parse_message(msg string) string {
|
|||
msg = strings.Replace(msg,":P","😛",-1)
|
||||
msg = url_reg.ReplaceAllString(msg,"<a href=\"$2$3//$4\" rel=\"nofollow\">$2$3//$4</a>")
|
||||
msg = strings.Replace(msg,"\n","<br>",-1)
|
||||
if hooks["parse_assign"] != nil {
|
||||
out := run_hook("parse_assign", msg)
|
||||
msg = out.(string)
|
||||
if sshooks["parse_assign"] != nil {
|
||||
msg = run_sshook("parse_assign", msg)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
|
291
panel_routes.go
|
@ -17,8 +17,8 @@ import (
|
|||
"github.com/shirou/gopsutil/mem"
|
||||
)
|
||||
|
||||
func route_panel(w http.ResponseWriter, r *http.Request){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel(w http.ResponseWriter, r *http.Request, user User){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -184,11 +184,16 @@ func route_panel(w http.ResponseWriter, r *http.Request){
|
|||
gridElements = append(gridElements, GridElement{"dash-postsperuser","5 posts / user / week",14,"grid_stat stat_disabled","","","Coming Soon!"/*"The average number of posts made by each active user over the past week"*/})
|
||||
|
||||
pi := PanelDashboardPage{"Control Panel Dashboard",user,headerVars,gridElements,extData}
|
||||
if pre_render_hooks["pre_render_panel_dashboard"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_dashboard", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
templates.ExecuteTemplate(w,"panel-dashboard.html",pi)
|
||||
}
|
||||
|
||||
func route_panel_forums(w http.ResponseWriter, r *http.Request){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_forums(w http.ResponseWriter, r *http.Request, user User){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -205,7 +210,7 @@ func route_panel_forums(w http.ResponseWriter, r *http.Request){
|
|||
}
|
||||
|
||||
for _, forum := range forums {
|
||||
if forum.Name != "" {
|
||||
if forum.Name != "" && forum.ParentID == 0 {
|
||||
fadmin := ForumAdmin{forum.ID,forum.Name,forum.Desc,forum.Active,forum.Preset,forum.TopicCount,preset_to_lang(forum.Preset)}
|
||||
if fadmin.Preset == "" {
|
||||
fadmin.Preset = "custom"
|
||||
|
@ -214,14 +219,19 @@ func route_panel_forums(w http.ResponseWriter, r *http.Request){
|
|||
}
|
||||
}
|
||||
pi := Page{"Forum Manager",user,headerVars,forumList,nil}
|
||||
if pre_render_hooks["pre_render_panel_forums"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_forums", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = templates.ExecuteTemplate(w,"panel-forums.html",pi)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
}
|
||||
}
|
||||
|
||||
func route_panel_forums_create_submit(w http.ResponseWriter, r *http.Request){
|
||||
user, ok := SimplePanelSessionCheck(w,r)
|
||||
func route_panel_forums_create_submit(w http.ResponseWriter, r *http.Request, user User){
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -246,18 +256,17 @@ func route_panel_forums_create_submit(w http.ResponseWriter, r *http.Request){
|
|||
factive := r.PostFormValue("forum-name")
|
||||
active := (factive == "on" || factive == "1" )
|
||||
|
||||
fid, err := fstore.CreateForum(fname,fdesc,active,fpreset)
|
||||
_, err = fstore.CreateForum(fname,fdesc,active,fpreset)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
permmap_to_query(preset_to_permmap(fpreset),fid)
|
||||
http.Redirect(w,r,"/panel/forums/",http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_panel_forums_delete(w http.ResponseWriter, r *http.Request, sfid string){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_forums_delete(w http.ResponseWriter, r *http.Request, user User, sfid string){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -289,11 +298,16 @@ func route_panel_forums_delete(w http.ResponseWriter, r *http.Request, sfid stri
|
|||
yousure := AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid),confirm_msg}
|
||||
|
||||
pi := Page{"Delete Forum",user,headerVars,tList,yousure}
|
||||
if pre_render_hooks["pre_render_panel_delete_forum"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_delete_forum", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
templates.ExecuteTemplate(w,"areyousure.html",pi)
|
||||
}
|
||||
|
||||
func route_panel_forums_delete_submit(w http.ResponseWriter, r *http.Request, sfid string) {
|
||||
user, ok := SimplePanelSessionCheck(w,r)
|
||||
func route_panel_forums_delete_submit(w http.ResponseWriter, r *http.Request, user User, sfid string) {
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -324,8 +338,8 @@ func route_panel_forums_delete_submit(w http.ResponseWriter, r *http.Request, sf
|
|||
http.Redirect(w,r,"/panel/forums/",http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_panel_forums_edit(w http.ResponseWriter, r *http.Request, sfid string) {
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_forums_edit(w http.ResponseWriter, r *http.Request, user User, sfid string) {
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -363,14 +377,19 @@ func route_panel_forums_edit(w http.ResponseWriter, r *http.Request, sfid string
|
|||
}
|
||||
|
||||
pi := EditForumPage{"Forum Editor",user,headerVars,forum.ID,forum.Name,forum.Desc,forum.Active,forum.Preset,gplist,extData}
|
||||
if pre_render_hooks["pre_render_panel_edit_forum"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_edit_forum", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = templates.ExecuteTemplate(w,"panel-forum-edit.html",pi)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
}
|
||||
}
|
||||
|
||||
func route_panel_forums_edit_submit(w http.ResponseWriter, r *http.Request, sfid string) {
|
||||
user, ok := SimplePanelSessionCheck(w,r)
|
||||
func route_panel_forums_edit_submit(w http.ResponseWriter, r *http.Request, user User, sfid string) {
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -455,8 +474,8 @@ func route_panel_forums_edit_submit(w http.ResponseWriter, r *http.Request, sfid
|
|||
}
|
||||
}
|
||||
|
||||
func route_panel_forums_edit_perms_submit(w http.ResponseWriter, r *http.Request, sfid string){
|
||||
user, ok := SimplePanelSessionCheck(w,r)
|
||||
func route_panel_forums_edit_perms_submit(w http.ResponseWriter, r *http.Request, user User, sfid string){
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -537,8 +556,8 @@ func route_panel_forums_edit_perms_submit(w http.ResponseWriter, r *http.Request
|
|||
}
|
||||
}
|
||||
|
||||
func route_panel_settings(w http.ResponseWriter, r *http.Request){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_settings(w http.ResponseWriter, r *http.Request, user User){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -588,11 +607,16 @@ func route_panel_settings(w http.ResponseWriter, r *http.Request){
|
|||
}
|
||||
|
||||
pi := Page{"Setting Manager",user,headerVars,tList,settingList}
|
||||
if pre_render_hooks["pre_render_panel_settings"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_settings", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
templates.ExecuteTemplate(w,"panel-settings.html",pi)
|
||||
}
|
||||
|
||||
func route_panel_setting(w http.ResponseWriter, r *http.Request, sname string){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_setting(w http.ResponseWriter, r *http.Request, user User, sname string){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -636,11 +660,16 @@ func route_panel_setting(w http.ResponseWriter, r *http.Request, sname string){
|
|||
}
|
||||
|
||||
pi := Page{"Edit Setting",user,headerVars,itemList,setting}
|
||||
if pre_render_hooks["pre_render_panel_setting"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_setting", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
templates.ExecuteTemplate(w,"panel-setting.html",pi)
|
||||
}
|
||||
|
||||
func route_panel_setting_edit(w http.ResponseWriter, r *http.Request, sname string) {
|
||||
user, ok := SimplePanelSessionCheck(w,r)
|
||||
func route_panel_setting_edit(w http.ResponseWriter, r *http.Request, user User, sname string) {
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -693,8 +722,8 @@ func route_panel_setting_edit(w http.ResponseWriter, r *http.Request, sname stri
|
|||
http.Redirect(w,r,"/panel/settings/",http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_panel_plugins(w http.ResponseWriter, r *http.Request){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_plugins(w http.ResponseWriter, r *http.Request, user User){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -705,15 +734,22 @@ func route_panel_plugins(w http.ResponseWriter, r *http.Request){
|
|||
|
||||
var pluginList []interface{}
|
||||
for _, plugin := range plugins {
|
||||
//fmt.Println("plugin.Name",plugin.Name)
|
||||
//fmt.Println("plugin.Installed",plugin.Installed)
|
||||
pluginList = append(pluginList,plugin)
|
||||
}
|
||||
|
||||
pi := Page{"Plugin Manager",user,headerVars,pluginList,nil}
|
||||
if pre_render_hooks["pre_render_panel_plugins"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_plugins", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
templates.ExecuteTemplate(w,"panel-plugins.html",pi)
|
||||
}
|
||||
|
||||
func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request, uname string){
|
||||
user, ok := SimplePanelSessionCheck(w,r)
|
||||
func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request, user User, uname string){
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -726,18 +762,25 @@ func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request, uname
|
|||
return
|
||||
}
|
||||
|
||||
//fmt.Println("uname","'"+uname+"'")
|
||||
plugin, ok := plugins[uname]
|
||||
if !ok {
|
||||
LocalError("The plugin isn't registered in the system",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
if plugin.Installable && !plugin.Installed {
|
||||
LocalError("You can't activate this plugin without installing it first",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
var active bool
|
||||
err := is_plugin_active_stmt.QueryRow(uname).Scan(&active)
|
||||
if err != nil && err != ErrNoRows {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
var has_plugin bool = (err == nil)
|
||||
|
||||
if plugins[uname].Activate != nil {
|
||||
err = plugins[uname].Activate()
|
||||
|
@ -747,19 +790,22 @@ func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request, uname
|
|||
}
|
||||
}
|
||||
|
||||
has_plugin := err != ErrNoRows
|
||||
//fmt.Println("err",err)
|
||||
//fmt.Println("active",active)
|
||||
if has_plugin {
|
||||
if active {
|
||||
LocalError("The plugin is already active",w,r,user)
|
||||
return
|
||||
}
|
||||
//fmt.Println("update_plugin")
|
||||
_, err = update_plugin_stmt.Exec(1,uname)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
_, err := add_plugin_stmt.Exec(uname,1)
|
||||
//fmt.Println("add_plugin")
|
||||
_, err := add_plugin_stmt.Exec(uname,1,0)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
|
@ -769,12 +815,17 @@ func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request, uname
|
|||
log.Print("Activating plugin '" + plugin.Name + "'")
|
||||
plugin.Active = true
|
||||
plugins[uname] = plugin
|
||||
plugins[uname].Init()
|
||||
err = plugins[uname].Init()
|
||||
if err != nil {
|
||||
LocalError(err.Error(),w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w,r,"/panel/plugins/",http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_panel_plugins_deactivate(w http.ResponseWriter, r *http.Request, uname string){
|
||||
user, ok := SimplePanelSessionCheck(w,r)
|
||||
func route_panel_plugins_deactivate(w http.ResponseWriter, r *http.Request, user User, uname string){
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -821,8 +872,95 @@ func route_panel_plugins_deactivate(w http.ResponseWriter, r *http.Request, unam
|
|||
http.Redirect(w,r,"/panel/plugins/",http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_panel_users(w http.ResponseWriter, r *http.Request){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_plugins_install(w http.ResponseWriter, r *http.Request, user User, uname string){
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if !user.Perms.ManagePlugins {
|
||||
NoPermissions(w,r,user)
|
||||
return
|
||||
}
|
||||
if r.FormValue("session") != user.Session {
|
||||
SecurityError(w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
plugin, ok := plugins[uname]
|
||||
if !ok {
|
||||
LocalError("The plugin isn't registered in the system",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
if !plugin.Installable {
|
||||
LocalError("This plugin is not installable",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
if plugin.Installed {
|
||||
LocalError("This plugin has already been installed",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
var active bool
|
||||
err := is_plugin_active_stmt.QueryRow(uname).Scan(&active)
|
||||
if err != nil && err != ErrNoRows {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
var has_plugin bool = (err == nil)
|
||||
|
||||
if plugins[uname].Install != nil {
|
||||
err = plugins[uname].Install()
|
||||
if err != nil {
|
||||
LocalError(err.Error(),w,r,user)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if plugins[uname].Activate != nil {
|
||||
err = plugins[uname].Activate()
|
||||
if err != nil {
|
||||
LocalError(err.Error(),w,r,user)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if has_plugin {
|
||||
_, err = update_plugin_install_stmt.Exec(1,uname)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
_, err = update_plugin_stmt.Exec(1,uname)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
_, err := add_plugin_stmt.Exec(uname,1,1)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Print("Installing plugin '" + plugin.Name + "'")
|
||||
plugin.Active = true
|
||||
plugin.Installed = true
|
||||
plugins[uname] = plugin
|
||||
err = plugins[uname].Init()
|
||||
if err != nil {
|
||||
LocalError(err.Error(),w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w,r,"/panel/plugins/",http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_panel_users(w http.ResponseWriter, r *http.Request, user User){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -866,14 +1004,19 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){
|
|||
}
|
||||
|
||||
pi := Page{"User Manager",user,headerVars,userList,nil}
|
||||
if pre_render_hooks["pre_render_panel_users"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_users", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = templates.ExecuteTemplate(w,"panel-users.html",pi)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
}
|
||||
}
|
||||
|
||||
func route_panel_users_edit(w http.ResponseWriter, r *http.Request,suid string){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_users_edit(w http.ResponseWriter, r *http.Request, user User, suid string){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -915,14 +1058,19 @@ func route_panel_users_edit(w http.ResponseWriter, r *http.Request,suid string){
|
|||
}
|
||||
|
||||
pi := Page{"User Editor",user,headerVars,groupList,targetUser}
|
||||
if pre_render_hooks["pre_render_panel_edit_user"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_edit_user", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = templates.ExecuteTemplate(w,"panel-user-edit.html",pi)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
}
|
||||
}
|
||||
|
||||
func route_panel_users_edit_submit(w http.ResponseWriter, r *http.Request, suid string){
|
||||
user, ok := SimplePanelSessionCheck(w,r)
|
||||
func route_panel_users_edit_submit(w http.ResponseWriter, r *http.Request, user User, suid string){
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -1016,8 +1164,8 @@ func route_panel_users_edit_submit(w http.ResponseWriter, r *http.Request, suid
|
|||
http.Redirect(w,r,"/panel/users/edit/" + strconv.Itoa(targetUser.ID),http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_panel_groups(w http.ResponseWriter, r *http.Request){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_groups(w http.ResponseWriter, r *http.Request, user User){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -1052,11 +1200,16 @@ func route_panel_groups(w http.ResponseWriter, r *http.Request){
|
|||
//fmt.Printf("%+v\n", groupList)
|
||||
|
||||
pi := Page{"Group Manager",user,headerVars,groupList,nil}
|
||||
if pre_render_hooks["pre_render_panel_groups"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_groups", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
templates.ExecuteTemplate(w,"panel-groups.html",pi)
|
||||
}
|
||||
|
||||
func route_panel_groups_edit(w http.ResponseWriter, r *http.Request, sgid string){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_groups_edit(w http.ResponseWriter, r *http.Request, user User, sgid string){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -1103,14 +1256,19 @@ func route_panel_groups_edit(w http.ResponseWriter, r *http.Request, sgid string
|
|||
disable_rank := !user.Perms.EditGroupGlobalPerms || (group.ID == 6)
|
||||
|
||||
pi := EditGroupPage{"Group Editor",user,headerVars,group.ID,group.Name,group.Tag,rank,disable_rank,extData}
|
||||
if pre_render_hooks["pre_render_panel_edit_group"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_edit_group", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = templates.ExecuteTemplate(w,"panel-group-edit.html",pi)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
}
|
||||
}
|
||||
|
||||
func route_panel_groups_edit_perms(w http.ResponseWriter, r *http.Request, sgid string){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_groups_edit_perms(w http.ResponseWriter, r *http.Request, user User, sgid string){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -1176,14 +1334,19 @@ func route_panel_groups_edit_perms(w http.ResponseWriter, r *http.Request, sgid
|
|||
globalPerms = append(globalPerms, NameLangToggle{"ViewIPs",GetGlobalPermPhrase("ViewIPs"),group.Perms.ViewIPs})
|
||||
|
||||
pi := EditGroupPermsPage{"Group Editor",user,headerVars,group.ID,group.Name,localPerms,globalPerms,extData}
|
||||
if pre_render_hooks["pre_render_panel_edit_group_perms"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_edit_group_perms", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = templates.ExecuteTemplate(w,"panel-group-edit-perms.html",pi)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
}
|
||||
}
|
||||
|
||||
func route_panel_groups_edit_submit(w http.ResponseWriter, r *http.Request, sgid string){
|
||||
user, ok := SimplePanelSessionCheck(w,r)
|
||||
func route_panel_groups_edit_submit(w http.ResponseWriter, r *http.Request, user User, sgid string){
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -1314,8 +1477,8 @@ func route_panel_groups_edit_submit(w http.ResponseWriter, r *http.Request, sgid
|
|||
http.Redirect(w,r,"/panel/groups/edit/" + strconv.Itoa(gid),http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_panel_groups_edit_perms_submit(w http.ResponseWriter, r *http.Request, sgid string){
|
||||
user, ok := SimplePanelSessionCheck(w,r)
|
||||
func route_panel_groups_edit_perms_submit(w http.ResponseWriter, r *http.Request, user User, sgid string){
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -1335,7 +1498,7 @@ func route_panel_groups_edit_perms_submit(w http.ResponseWriter, r *http.Request
|
|||
}
|
||||
|
||||
if !group_exists(gid) {
|
||||
//fmt.Println("aaaaa monsters")
|
||||
//fmt.Println("aaaaa monsters o.o")
|
||||
NotFound(w,r)
|
||||
return
|
||||
}
|
||||
|
@ -1390,8 +1553,8 @@ func route_panel_groups_edit_perms_submit(w http.ResponseWriter, r *http.Request
|
|||
http.Redirect(w,r,"/panel/groups/edit/perms/" + strconv.Itoa(gid),http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_panel_groups_create_submit(w http.ResponseWriter, r *http.Request){
|
||||
user, ok := SimplePanelSessionCheck(w,r)
|
||||
func route_panel_groups_create_submit(w http.ResponseWriter, r *http.Request, user User){
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -1441,8 +1604,8 @@ func route_panel_groups_create_submit(w http.ResponseWriter, r *http.Request){
|
|||
http.Redirect(w,r,"/panel/groups/edit/" + strconv.Itoa(gid),http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_panel_themes(w http.ResponseWriter, r *http.Request){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_themes(w http.ResponseWriter, r *http.Request, user User){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -1465,14 +1628,19 @@ func route_panel_themes(w http.ResponseWriter, r *http.Request){
|
|||
}
|
||||
|
||||
pi := ThemesPage{"Theme Manager",user,headerVars,pThemeList,vThemeList,extData}
|
||||
if pre_render_hooks["pre_render_panel_themes"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_themes", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
err := templates.ExecuteTemplate(w,"panel-themes.html",pi)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
}
|
||||
|
||||
func route_panel_themes_default(w http.ResponseWriter, r *http.Request, uname string){
|
||||
user, ok := SimplePanelSessionCheck(w,r)
|
||||
func route_panel_themes_default(w http.ResponseWriter, r *http.Request, user User, uname string){
|
||||
ok := SimplePanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -1549,8 +1717,8 @@ func route_panel_themes_default(w http.ResponseWriter, r *http.Request, uname st
|
|||
http.Redirect(w,r,"/panel/themes/",http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func route_panel_logs_mod(w http.ResponseWriter, r *http.Request){
|
||||
user, headerVars, ok := PanelSessionCheck(w,r)
|
||||
func route_panel_logs_mod(w http.ResponseWriter, r *http.Request, user User){
|
||||
headerVars, ok := PanelSessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -1642,6 +1810,11 @@ func route_panel_logs_mod(w http.ResponseWriter, r *http.Request){
|
|||
}
|
||||
|
||||
pi := LogsPage{"Moderation Logs",user,headerVars,logs,extData}
|
||||
if pre_render_hooks["pre_render_panel_mod_log"] != nil {
|
||||
if run_pre_render_hook("pre_render_panel_mod_log", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = templates.ExecuteTemplate(w,"panel-modlogs.html",pi)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
|
|
@ -15,6 +15,7 @@ var ReadReplyForumPerms ForumPerms
|
|||
var ReadWriteForumPerms ForumPerms
|
||||
var AllPerms Perms
|
||||
var AllForumPerms ForumPerms
|
||||
var AllPluginPerms map[string]bool = make(map[string]bool)
|
||||
|
||||
var LocalPermList []string = []string{
|
||||
"ViewTopic",
|
||||
|
@ -90,7 +91,7 @@ type Perms struct
|
|||
CloseTopic bool
|
||||
//CloseOwnTopic bool
|
||||
|
||||
ExtData map[string]bool
|
||||
//ExtData map[string]bool
|
||||
}
|
||||
|
||||
/* Inherit from group permissions for ones we don't have */
|
||||
|
@ -116,7 +117,7 @@ type ForumPerms struct
|
|||
|
||||
func init() {
|
||||
BlankPerms = Perms{
|
||||
ExtData: make(map[string]bool),
|
||||
//ExtData: make(map[string]bool),
|
||||
}
|
||||
|
||||
BlankForumPerms = ForumPerms{
|
||||
|
@ -125,7 +126,7 @@ func init() {
|
|||
|
||||
GuestPerms = Perms{
|
||||
ViewTopic: true,
|
||||
ExtData: make(map[string]bool),
|
||||
//ExtData: make(map[string]bool),
|
||||
}
|
||||
|
||||
AllPerms = Perms{
|
||||
|
@ -160,7 +161,7 @@ func init() {
|
|||
PinTopic: true,
|
||||
CloseTopic: true,
|
||||
|
||||
ExtData: make(map[string]bool),
|
||||
//ExtData: make(map[string]bool),
|
||||
}
|
||||
|
||||
AllForumPerms = ForumPerms{
|
||||
|
@ -204,7 +205,7 @@ func init() {
|
|||
|
||||
guest_user.Perms = GuestPerms
|
||||
|
||||
if debug {
|
||||
if debug_mode {
|
||||
fmt.Printf("Guest Perms: ")
|
||||
fmt.Printf("%+v\n", GuestPerms)
|
||||
fmt.Printf("All Perms: ")
|
||||
|
@ -303,7 +304,7 @@ func permmap_to_query(permmap map[string]ForumPerms, fid int) error {
|
|||
}
|
||||
|
||||
func rebuild_forum_permissions(fid int) error {
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Loading the forum permissions")
|
||||
}
|
||||
forums, err := fstore.GetAll()
|
||||
|
@ -317,7 +318,7 @@ func rebuild_forum_permissions(fid int) error {
|
|||
}
|
||||
defer rows.Close()
|
||||
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Updating the forum permissions")
|
||||
}
|
||||
for rows.Next() {
|
||||
|
@ -341,7 +342,7 @@ func rebuild_forum_permissions(fid int) error {
|
|||
forum_perms[gid][fid] = pperms
|
||||
}
|
||||
for gid, _ := range groups {
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Updating the forum permissions for Group #" + strconv.Itoa(gid))
|
||||
}
|
||||
var blank_list []ForumPerms
|
||||
|
@ -389,7 +390,7 @@ func build_forum_permissions() error {
|
|||
}
|
||||
defer rows.Close()
|
||||
|
||||
if debug {
|
||||
if debug_mode {
|
||||
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
|
||||
|
@ -415,7 +416,7 @@ func build_forum_permissions() error {
|
|||
forum_perms[gid][fid] = pperms
|
||||
}
|
||||
for gid, _ := range groups {
|
||||
if debug {
|
||||
if debug_mode {
|
||||
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
|
||||
|
@ -533,7 +534,9 @@ func rebuild_group_permissions(gid int) error {
|
|||
return err
|
||||
}
|
||||
|
||||
tmp_perms := Perms{ExtData: make(map[string]bool)}
|
||||
tmp_perms := Perms{
|
||||
//ExtData: make(map[string]bool),
|
||||
}
|
||||
err = json.Unmarshal(permstr, &tmp_perms)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -542,3 +545,33 @@ func rebuild_group_permissions(gid int) error {
|
|||
groups[gid].Perms = tmp_perms
|
||||
return nil
|
||||
}
|
||||
|
||||
func override_perms(perms *Perms, status bool) {
|
||||
if status {
|
||||
*perms = AllPerms
|
||||
} else {
|
||||
*perms = BlankPerms
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
perms.ViewTopic = status
|
||||
perms.LikeItem = status
|
||||
perms.CreateTopic = status
|
||||
perms.EditTopic = status
|
||||
perms.DeleteTopic = status
|
||||
perms.CreateReply = status
|
||||
perms.EditReply = status
|
||||
perms.DeleteReply = status
|
||||
perms.PinTopic = status
|
||||
perms.CloseTopic = status
|
||||
}
|
||||
|
||||
func register_plugin_perm(name string) {
|
||||
AllPluginPerms[name] = true
|
||||
}
|
||||
|
||||
func deregister_plugin_perm(name string) {
|
||||
delete(AllPluginPerms,name)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
// +build pgsql
|
||||
|
||||
/* Copyright Azareal 2016 - 2018 */
|
||||
/* Super experimental and incomplete. DON'T USE IT YET! */
|
||||
package main
|
||||
|
||||
import "strings"
|
||||
import "database/sql"
|
||||
import _ "github.com/lib/pq"
|
||||
import "./query_gen/lib"
|
||||
|
||||
// TO-DO: Add support for SSL for all database drivers, not just pgsql
|
||||
var db_sslmode = "disable" // verify-full
|
||||
var get_activity_feed_by_watcher_stmt *sql.Stmt
|
||||
var get_activity_count_by_watcher_stmt *sql.Stmt
|
||||
var todays_post_count_stmt *sql.Stmt
|
||||
var todays_topic_count_stmt *sql.Stmt
|
||||
var todays_report_count_stmt *sql.Stmt
|
||||
var todays_newuser_count_stmt *sql.Stmt
|
||||
// Note to self: PostgreSQL listens on a different port than MySQL does
|
||||
|
||||
func _init_database() (err error) {
|
||||
// TO-DO: Investigate connect_timeout to see what it does exactly and whether it's relevant to us
|
||||
var _dbpassword string
|
||||
if(dbpassword != ""){
|
||||
_dbpassword = " password='" + _escape_bit(dbpassword) + "'"
|
||||
}
|
||||
db, err = sql.Open("postgres", "host='" + _escape_bit(dbhost) + "' port='" + _escape_bit(dbport) + "' user='" + _escape_bit(dbuser) + "' dbname='" + _escape_bit(dbname) + "'" + _dbpassword + " sslmode='" + db_sslmode + "'")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TO-DO: Get the version number
|
||||
|
||||
// Set the number of max open connections. How many do we need? Might need to do some tests.
|
||||
db.SetMaxOpenConns(64)
|
||||
|
||||
err = gen_pgsql()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ready the query builder
|
||||
qgen.Builder.SetConn(db)
|
||||
err = qgen.Builder.SetAdapter("pgsql")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TO-DO Handle the queries which the query generator can't handle yet
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func _escape_bit(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?
|
||||
return strings.Replace(bit,"'","\\'",-1)
|
||||
}
|
66
phrases.go
|
@ -5,8 +5,40 @@ import "sync"
|
|||
// I wish we had constant maps x.x
|
||||
var phrase_mutex sync.RWMutex
|
||||
var perm_phrase_mutex sync.RWMutex
|
||||
var phrases map[string]string
|
||||
var global_perm_phrases map[string]string = map[string]string{
|
||||
var change_langpack_mutex sync.Mutex
|
||||
var currentLanguage string = "english"
|
||||
var currentLangPack *LanguagePack
|
||||
|
||||
type LevelPhrases struct
|
||||
{
|
||||
Level string
|
||||
LevelMax string
|
||||
|
||||
// Override the phrase for individual levels, if the phrases exist
|
||||
Levels []string // index = level
|
||||
}
|
||||
|
||||
type LanguagePack struct
|
||||
{
|
||||
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.
|
||||
LevelPhrases LevelPhrases
|
||||
GlobalPermPhrases map[string]string
|
||||
LocalPermPhrases map[string]string
|
||||
}
|
||||
|
||||
// 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{
|
||||
"english": &LanguagePack{
|
||||
Name: "english",
|
||||
|
||||
// We'll be implementing the level phrases in the software proper very very soon!
|
||||
LevelPhrases: LevelPhrases{
|
||||
Level: "Level {0}",
|
||||
LevelMax: "", // Add a max level setting?
|
||||
},
|
||||
|
||||
GlobalPermPhrases: map[string]string{
|
||||
"BanUsers": "Can ban users",
|
||||
"ActivateUsers": "Can activate users",
|
||||
"EditUser": "Can edit users",
|
||||
|
@ -26,9 +58,9 @@ var global_perm_phrases map[string]string = map[string]string{
|
|||
"ManagePlugins": "Can manage plugins",
|
||||
"ViewAdminLogs": "Can view the administrator action logs",
|
||||
"ViewIPs": "Can view IP addresses",
|
||||
}
|
||||
},
|
||||
|
||||
var local_perm_phrases map[string]string = map[string]string{
|
||||
LocalPermPhrases: map[string]string{
|
||||
"ViewTopic": "Can view topics",
|
||||
"LikeItem": "Can like items",
|
||||
"CreateTopic": "Can create topics",
|
||||
|
@ -39,25 +71,31 @@ var local_perm_phrases map[string]string = map[string]string{
|
|||
"DeleteReply": "Can delete replies",
|
||||
"PinTopic": "Can pin topics",
|
||||
"CloseTopic": "Can lock topics",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
currentLangPack = 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
|
||||
func GetPhrase(name string) (string,bool) {
|
||||
phrase_mutex.RLock()
|
||||
defer perm_phrase_mutex.RUnlock()
|
||||
res, ok := phrases[name]
|
||||
res, ok := currentLangPack.Phrases[name]
|
||||
return res, ok
|
||||
}
|
||||
|
||||
func GetPhraseUnsafe(name string) (string,bool) {
|
||||
res, ok := phrases[name]
|
||||
res, ok := currentLangPack.Phrases[name]
|
||||
return res, ok
|
||||
}
|
||||
|
||||
func GetGlobalPermPhrase(name string) string {
|
||||
perm_phrase_mutex.RLock()
|
||||
defer perm_phrase_mutex.RUnlock()
|
||||
res, ok := global_perm_phrases[name]
|
||||
res, ok := currentLangPack.GlobalPermPhrases[name]
|
||||
if !ok {
|
||||
return "{name}"
|
||||
}
|
||||
|
@ -67,7 +105,7 @@ func GetGlobalPermPhrase(name string) string {
|
|||
func GetLocalPermPhrase(name string) string {
|
||||
perm_phrase_mutex.RLock()
|
||||
defer perm_phrase_mutex.RUnlock()
|
||||
res, ok := local_perm_phrases[name]
|
||||
res, ok := currentLangPack.LocalPermPhrases[name]
|
||||
if !ok {
|
||||
return "{name}"
|
||||
}
|
||||
|
@ -81,3 +119,15 @@ func AddPhrase() {
|
|||
func DeletePhrase() {
|
||||
|
||||
}
|
||||
|
||||
func ChangeLanguagePack(name string) (exists bool) {
|
||||
change_langpack_mutex.Lock()
|
||||
pack, ok := langpacks[name]
|
||||
if !ok {
|
||||
change_langpack_mutex.Unlock()
|
||||
return false
|
||||
}
|
||||
currentLangPack = pack
|
||||
change_langpack_mutex.Unlock()
|
||||
return true
|
||||
}
|
||||
|
|
139
plugin_bbcode.go
|
@ -1,4 +1,5 @@
|
|||
package main
|
||||
|
||||
//import "log"
|
||||
//import "fmt"
|
||||
import "bytes"
|
||||
|
@ -10,6 +11,7 @@ import "math/rand"
|
|||
|
||||
var random *rand.Rand
|
||||
var bbcode_invalid_number []byte
|
||||
var bbcode_no_negative []byte
|
||||
var bbcode_missing_tag []byte
|
||||
|
||||
var bbcode_bold *regexp.Regexp
|
||||
|
@ -19,16 +21,18 @@ var bbcode_strikethrough *regexp.Regexp
|
|||
var bbcode_url *regexp.Regexp
|
||||
var bbcode_url_label *regexp.Regexp
|
||||
var bbcode_quotes *regexp.Regexp
|
||||
var bbcode_code *regexp.Regexp
|
||||
|
||||
func init() {
|
||||
plugins["bbcode"] = NewPlugin("bbcode","BBCode","Azareal","http://github.com/Azareal","","","",init_bbcode,nil,deactivate_bbcode)
|
||||
plugins["bbcode"] = NewPlugin("bbcode","BBCode","Azareal","http://github.com/Azareal","","","",init_bbcode,nil,deactivate_bbcode,nil,nil)
|
||||
}
|
||||
|
||||
func init_bbcode() {
|
||||
func init_bbcode() error {
|
||||
//plugins["bbcode"].AddHook("parse_assign", bbcode_parse_without_code)
|
||||
plugins["bbcode"].AddHook("parse_assign", bbcode_full_parse)
|
||||
|
||||
bbcode_invalid_number = []byte("<span style='color: red;'>[Invalid Number]</span>")
|
||||
bbcode_no_negative = []byte("<span style='color: red;'>[No Negative Numbers]</span>")
|
||||
bbcode_missing_tag = []byte("<span style='color: red;'>[Missing Tag]</span>")
|
||||
|
||||
bbcode_bold = regexp.MustCompile(`(?s)\[b\](.*)\[/b\]`)
|
||||
|
@ -39,8 +43,10 @@ func init_bbcode() {
|
|||
bbcode_url = regexp.MustCompile(`\[url\]` + urlpattern + `\[/url\]`)
|
||||
bbcode_url_label = regexp.MustCompile(`(?s)\[url=` + urlpattern + `\](.*)\[/url\]`)
|
||||
bbcode_quotes = regexp.MustCompile(`\[quote\](.*)\[/quote\]`)
|
||||
bbcode_code = regexp.MustCompile(`\[code\](.*)\[/code\]`)
|
||||
|
||||
random = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
return nil
|
||||
}
|
||||
|
||||
func deactivate_bbcode() {
|
||||
|
@ -48,26 +54,22 @@ func deactivate_bbcode() {
|
|||
plugins["bbcode"].RemoveHook("parse_assign", bbcode_full_parse)
|
||||
}
|
||||
|
||||
func bbcode_regex_parse(data interface{}) interface{} {
|
||||
msg := data.(string)
|
||||
func bbcode_regex_parse(msg string) string {
|
||||
msg = bbcode_bold.ReplaceAllString(msg,"<b>$1</b>")
|
||||
msg = bbcode_italic.ReplaceAllString(msg,"<i>$1</i>")
|
||||
msg = bbcode_underline.ReplaceAllString(msg,"<u>$1</u>")
|
||||
msg = bbcode_strikethrough.ReplaceAllString(msg,"<s>$1</s>")
|
||||
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 = bbcode_quotes.ReplaceAllString(msg,"<span class=\"postQuote\">$1</span>")
|
||||
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 = bbcode_quotes.ReplaceAllString(msg,"<span class='postQuote'>$1</span>")
|
||||
//msg = bbcode_code.ReplaceAllString(msg,"<span class='codequotes'>$1</span>")
|
||||
return msg
|
||||
}
|
||||
|
||||
// Only does the simple BBCode like [u], [b], [i] and [s]
|
||||
func bbcode_simple_parse(data interface{}) interface{} {
|
||||
msg := data.(string)
|
||||
func bbcode_simple_parse(msg string) string {
|
||||
var has_u, has_b, has_i, has_s bool
|
||||
msgbytes := []byte(msg)
|
||||
has_u := false
|
||||
has_b := false
|
||||
has_i := false
|
||||
has_s := false
|
||||
for i := 0; (i + 2) < len(msgbytes); i++ {
|
||||
if msgbytes[i] == '[' && msgbytes[i + 2] == ']' {
|
||||
if msgbytes[i + 1] == 'b' && !has_b {
|
||||
|
@ -93,21 +95,32 @@ func bbcode_simple_parse(data interface{}) interface{} {
|
|||
|
||||
// There's an unclosed tag in there x.x
|
||||
if has_i || has_u || has_b || has_s {
|
||||
closer := []byte("</u></i></b></s>")
|
||||
msgbytes = append(msgbytes, closer...)
|
||||
close_under := []byte("</u>")
|
||||
close_italic := []byte("</i>")
|
||||
close_bold := []byte("</b>")
|
||||
close_strike := []byte("</s>")
|
||||
if has_i {
|
||||
msgbytes = append(msgbytes, close_italic...)
|
||||
}
|
||||
if has_u {
|
||||
msgbytes = append(msgbytes, close_under...)
|
||||
}
|
||||
if has_b {
|
||||
msgbytes = append(msgbytes, close_bold...)
|
||||
}
|
||||
if has_s {
|
||||
msgbytes = append(msgbytes, close_strike...)
|
||||
}
|
||||
}
|
||||
return string(msgbytes)
|
||||
}
|
||||
|
||||
// Here for benchmarking purposes. Might add a plugin setting for disabling [code] as it has it's paws everywhere
|
||||
func bbcode_parse_without_code(data interface{}) interface{} {
|
||||
msg := data.(string)
|
||||
func bbcode_parse_without_code(msg string) string {
|
||||
var has_u, has_b, has_i, has_s bool
|
||||
var complex_bbc bool
|
||||
msgbytes := []byte(msg)
|
||||
has_u := false
|
||||
has_b := false
|
||||
has_i := false
|
||||
has_s := false
|
||||
complex_bbc := false
|
||||
|
||||
for i := 0; (i + 3) < len(msgbytes); i++ {
|
||||
if msgbytes[i] == '[' {
|
||||
if msgbytes[i + 2] != ']' {
|
||||
|
@ -162,39 +175,46 @@ func bbcode_parse_without_code(data interface{}) interface{} {
|
|||
|
||||
// There's an unclosed tag in there x.x
|
||||
if has_i || has_u || has_b || has_s {
|
||||
closer := []byte("</u></i></b></s>")
|
||||
msgbytes = append(msgbytes, closer...)
|
||||
close_under := []byte("</u>")
|
||||
close_italic := []byte("</i>")
|
||||
close_bold := []byte("</b>")
|
||||
close_strike := []byte("</s>")
|
||||
if has_i {
|
||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_italic...)
|
||||
}
|
||||
if has_u {
|
||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_under...)
|
||||
}
|
||||
if has_b {
|
||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_bold...)
|
||||
}
|
||||
if has_s {
|
||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_strike...)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the new complex parser over once the rough edges have been smoothed over
|
||||
if complex_bbc {
|
||||
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 = bbcode_quotes.ReplaceAllString(msg,"<span class=\"postQuote\">$1</span>")
|
||||
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 = bbcode_quotes.ReplaceAllString(msg,"<span class='postQuote'>$1</span>")
|
||||
msg = bbcode_code.ReplaceAllString(msg,"<span class='codequotes'>$1</span>")
|
||||
}
|
||||
|
||||
return string(msgbytes)
|
||||
}
|
||||
|
||||
// Does every type of BBCode
|
||||
func bbcode_full_parse(data interface{}) interface{} {
|
||||
msg := data.(string)
|
||||
//fmt.Println("BBCode PrePre String:")
|
||||
//fmt.Println("`"+msg+"`")
|
||||
//fmt.Println("----")
|
||||
func bbcode_full_parse(msg string) string {
|
||||
var has_u, has_b, has_i, has_s, has_c bool
|
||||
var complex_bbc bool
|
||||
|
||||
msgbytes := []byte(msg)
|
||||
has_u := false
|
||||
has_b := false
|
||||
has_i := false
|
||||
has_s := false
|
||||
has_c := false
|
||||
complex_bbc := false
|
||||
msgbytes = append(msgbytes,space_gap...)
|
||||
|
||||
//fmt.Println("BBCode Simple Pre:")
|
||||
//fmt.Println("`"+string(msgbytes)+"`")
|
||||
//fmt.Println("----")
|
||||
|
||||
for i := 0; i < len(msgbytes); i++ {
|
||||
if msgbytes[i] == '[' {
|
||||
if msgbytes[i + 2] != ']' {
|
||||
|
@ -267,10 +287,25 @@ func bbcode_full_parse(data interface{}) interface{} {
|
|||
}
|
||||
}
|
||||
|
||||
// There's an unclosed tag in there x.x
|
||||
// There's an unclosed tag in there somewhere x.x
|
||||
if has_i || has_u || has_b || has_s {
|
||||
closer := []byte("</u></i></b></s>")
|
||||
msgbytes = append(msgbytes, closer...)
|
||||
close_under := []byte("</u>")
|
||||
close_italic := []byte("</i>")
|
||||
close_bold := []byte("</b>")
|
||||
close_strike := []byte("</s>")
|
||||
if has_i {
|
||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_italic...)
|
||||
}
|
||||
if has_u {
|
||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_under...)
|
||||
}
|
||||
if has_b {
|
||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_bold...)
|
||||
}
|
||||
if has_s {
|
||||
msgbytes = append(bytes.TrimSpace(msgbytes), close_strike...)
|
||||
}
|
||||
msgbytes = append(msgbytes,space_gap...)
|
||||
}
|
||||
|
||||
if complex_bbc {
|
||||
|
@ -290,7 +325,6 @@ func bbcode_full_parse(data interface{}) interface{} {
|
|||
outbytes = append(outbytes, msgbytes[lastTag:i]...)
|
||||
i = start
|
||||
i += partial_url_bytes_len(msgbytes[start:])
|
||||
|
||||
//fmt.Println("Partial Bytes:")
|
||||
//fmt.Println(string(msgbytes[start:]))
|
||||
//fmt.Println("-----")
|
||||
|
@ -334,6 +368,12 @@ func bbcode_full_parse(data interface{}) interface{} {
|
|||
goto MainLoop
|
||||
}
|
||||
|
||||
// TO-DO: Add support for negative numbers?
|
||||
if number < 0 {
|
||||
outbytes = append(outbytes, bbcode_no_negative...)
|
||||
goto MainLoop
|
||||
}
|
||||
|
||||
dat := []byte(strconv.FormatInt((random.Int63n(number)),10))
|
||||
outbytes = append(outbytes, dat...)
|
||||
//log.Print("Outputted the random number")
|
||||
|
@ -346,14 +386,12 @@ func bbcode_full_parse(data interface{}) interface{} {
|
|||
//fmt.Println(string(outbytes))
|
||||
if lastTag != i {
|
||||
outbytes = append(outbytes, msgbytes[lastTag:]...)
|
||||
//fmt.Println("Outbytes:")
|
||||
//fmt.Println(`"`+string(outbytes)+`"`)
|
||||
//fmt.Println("Outbytes:",`"`+string(outbytes)+`"`)
|
||||
//fmt.Println("----")
|
||||
}
|
||||
|
||||
if len(outbytes) != 0 {
|
||||
//fmt.Println("BBCode Post:")
|
||||
//fmt.Println(`"`+string(outbytes[0:len(outbytes) - 10])+`"`)
|
||||
//fmt.Println("BBCode Post:",`"`+string(outbytes[0:len(outbytes) - 10])+`"`)
|
||||
//fmt.Println("----")
|
||||
msg = string(outbytes[0:len(outbytes) - 10])
|
||||
} else {
|
||||
|
@ -361,10 +399,9 @@ func bbcode_full_parse(data interface{}) interface{} {
|
|||
}
|
||||
|
||||
//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 = bbcode_quotes.ReplaceAllString(msg,"<span class=\"postQuote\">$1</span>")
|
||||
// Convert [code] into class="codequotes"
|
||||
//fmt.Println("guuuaaaa")
|
||||
msg = bbcode_url_label.ReplaceAllString(msg,"<a href='$1$2//$3' rel='nofollow'>$4</i>")
|
||||
msg = bbcode_quotes.ReplaceAllString(msg,"<span class='postQuote'>$1</span>")
|
||||
msg = bbcode_code.ReplaceAllString(msg,"<span class='codequotes'>$1</span>")
|
||||
} else {
|
||||
msg = string(msgbytes[0:len(msgbytes) - 10])
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package main
|
||||
|
||||
func init() {
|
||||
plugins["helloworld"] = NewPlugin("helloworld","Hello World","Azareal","http://github.com/Azareal","","","",init_helloworld,nil,deactivate_helloworld)
|
||||
plugins["helloworld"] = NewPlugin("helloworld","Hello World","Azareal","http://github.com/Azareal","","","",init_helloworld,nil,deactivate_helloworld,nil,nil)
|
||||
}
|
||||
|
||||
// init_helloworld is separate from init() as we don't want the plugin to run if the plugin is disabled
|
||||
func init_helloworld() {
|
||||
func init_helloworld() error {
|
||||
plugins["helloworld"].AddHook("rrow_assign", helloworld_reply)
|
||||
// TO-DO: Add a route injection example here
|
||||
return nil
|
||||
}
|
||||
|
||||
func deactivate_helloworld() {
|
||||
|
@ -15,9 +15,9 @@ func deactivate_helloworld() {
|
|||
}
|
||||
|
||||
func helloworld_reply(data interface{}) interface{} {
|
||||
reply := data.(Reply)
|
||||
reply := data.(*Reply)
|
||||
reply.Content = "Hello World!"
|
||||
reply.ContentHtml = "Hello World!"
|
||||
reply.Tag = "Auto"
|
||||
return reply
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package main
|
|||
|
||||
//import "fmt"
|
||||
import "regexp"
|
||||
//import "strings"
|
||||
import "strings"
|
||||
|
||||
var markdown_max_depth int = 25 // How deep the parser will go when parsing Markdown strings
|
||||
var markdown_unclosed_element []byte
|
||||
|
@ -19,10 +19,10 @@ var markdown_strike *regexp.Regexp
|
|||
var markdown_underline *regexp.Regexp
|
||||
|
||||
func init() {
|
||||
plugins["markdown"] = NewPlugin("markdown","Markdown","Azareal","http://github.com/Azareal","","","",init_markdown,nil,deactivate_markdown)
|
||||
plugins["markdown"] = NewPlugin("markdown","Markdown","Azareal","http://github.com/Azareal","","","",init_markdown,nil,deactivate_markdown,nil,nil)
|
||||
}
|
||||
|
||||
func init_markdown() {
|
||||
func init_markdown() error {
|
||||
//plugins["markdown"].AddHook("parse_assign", markdown_regex_parse)
|
||||
plugins["markdown"].AddHook("parse_assign", markdown_parse)
|
||||
|
||||
|
@ -44,6 +44,7 @@ func init_markdown() {
|
|||
markdown_strike = regexp.MustCompile(`\~(.*)\~`)
|
||||
//markdown_underline = regexp.MustCompile(`\_\_(.*)\_\_`)
|
||||
markdown_underline = regexp.MustCompile(`\_(.*)\_`)
|
||||
return nil
|
||||
}
|
||||
|
||||
func deactivate_markdown() {
|
||||
|
@ -51,8 +52,7 @@ func deactivate_markdown() {
|
|||
plugins["markdown"].RemoveHook("parse_assign", markdown_parse)
|
||||
}
|
||||
|
||||
func markdown_regex_parse(data interface{}) interface{} {
|
||||
msg := data.(string)
|
||||
func markdown_regex_parse(msg string) string {
|
||||
msg = markdown_bold_italic.ReplaceAllString(msg,"<i><b>$1</b></i>")
|
||||
msg = markdown_bold.ReplaceAllString(msg,"<b>$1</b>")
|
||||
msg = markdown_italic.ReplaceAllString(msg,"<i>$1</i>")
|
||||
|
@ -64,8 +64,8 @@ func markdown_regex_parse(data interface{}) interface{} {
|
|||
|
||||
// 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.
|
||||
func markdown_parse(data interface{}) interface{} {
|
||||
return _markdown_parse(data.(string) + " ",0)
|
||||
func markdown_parse(msg string) string {
|
||||
return strings.TrimSpace(_markdown_parse(msg + " ",0))
|
||||
}
|
||||
|
||||
// Under Construction!
|
||||
|
@ -277,12 +277,12 @@ func _markdown_parse(msg string, n int) string {
|
|||
|
||||
outbytes = append(outbytes, msg[sIndex:lIndex]...)
|
||||
|
||||
if bold {
|
||||
outbytes = append(outbytes, markdown_bold_tag_close...)
|
||||
}
|
||||
if italic {
|
||||
outbytes = append(outbytes, markdown_italic_tag_close...)
|
||||
}
|
||||
if bold {
|
||||
outbytes = append(outbytes, markdown_bold_tag_close...)
|
||||
}
|
||||
|
||||
lastElement = index
|
||||
index--
|
||||
|
|
|
@ -21,13 +21,17 @@ func init() {
|
|||
The Activate field is for the handler which is called by the software when the admin hits the Activate button in the control panel. This is separate from the Init handler which is called upon the start of the server and upon activation. Use nil if you don't have a handler for this.
|
||||
|
||||
The Deactivate field is for the handler which is called by the software when the admin hits the Deactivate button in the control panel. You should clean-up any resources you have allocated, remove any hooks, close any statements, etc. within this handler.
|
||||
|
||||
The Installation field is for one-off installation logic such as creating tables. You will need to run the seperate uninstallation function for that.
|
||||
|
||||
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)
|
||||
plugins["skeleton"] = NewPlugin("skeleton","Skeleton","Azareal","","","","",init_skeleton, activate_skeleton, deactivate_skeleton,nil,nil)
|
||||
}
|
||||
|
||||
func init_skeleton() {}
|
||||
func init_skeleton() 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 deactivate_skeleton() {}
|
|
@ -0,0 +1,643 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
//"fmt"
|
||||
"bytes"
|
||||
"strings"
|
||||
"strconv"
|
||||
"errors"
|
||||
"context"
|
||||
"net/http"
|
||||
"html"
|
||||
"html/template"
|
||||
"database/sql"
|
||||
|
||||
"./query_gen/lib"
|
||||
)
|
||||
|
||||
var socialgroups_list_stmt *sql.Stmt
|
||||
var socialgroups_member_list_stmt *sql.Stmt
|
||||
var socialgroups_member_list_join_stmt *sql.Stmt
|
||||
var socialgroups_get_member_stmt *sql.Stmt
|
||||
var socialgroups_get_group_stmt *sql.Stmt
|
||||
var socialgroups_create_group_stmt *sql.Stmt
|
||||
var socialgroups_attach_forum_stmt *sql.Stmt
|
||||
var socialgroups_unattach_forum_stmt *sql.Stmt
|
||||
var socialgroups_add_member_stmt *sql.Stmt
|
||||
|
||||
// TO-DO: Add a better way of splitting up giant plugins like this
|
||||
type SocialGroup struct
|
||||
{
|
||||
ID int
|
||||
Link string
|
||||
Name string
|
||||
Desc string
|
||||
Active bool
|
||||
Privacy int /* 0: Public, 1: Protected, 2: Private */
|
||||
MemberCount int
|
||||
Owner int
|
||||
Backdrop string
|
||||
CreatedAt string
|
||||
LastUpdateTime string
|
||||
|
||||
MainForum *Forum
|
||||
Forums []*Forum
|
||||
ExtData ExtData
|
||||
}
|
||||
|
||||
type SocialGroupPage struct
|
||||
{
|
||||
Title string
|
||||
CurrentUser User
|
||||
Header HeaderVars
|
||||
ItemList []TopicUser
|
||||
Forum Forum
|
||||
SocialGroup SocialGroup
|
||||
Page int
|
||||
LastPage int
|
||||
ExtData ExtData
|
||||
}
|
||||
|
||||
type SocialGroupListPage struct
|
||||
{
|
||||
Title string
|
||||
CurrentUser User
|
||||
Header HeaderVars
|
||||
GroupList []SocialGroup
|
||||
ExtData ExtData
|
||||
}
|
||||
|
||||
type SocialGroupMemberListPage struct
|
||||
{
|
||||
Title string
|
||||
CurrentUser User
|
||||
Header HeaderVars
|
||||
ItemList []SocialGroupMember
|
||||
SocialGroup SocialGroup
|
||||
Page int
|
||||
LastPage int
|
||||
ExtData ExtData
|
||||
}
|
||||
|
||||
type SocialGroupMember struct
|
||||
{
|
||||
Link string
|
||||
Rank int /* 0: Member. 1: Mod. 2: Admin. */
|
||||
RankString string /* Member, Mod, Admin, Owner */
|
||||
PostCount int
|
||||
JoinedAt string
|
||||
Offline bool // TO-DO: Need to track the online states of members when WebSockets are enabled
|
||||
|
||||
User User
|
||||
}
|
||||
|
||||
func init() {
|
||||
plugins["socialgroups"] = NewPlugin("socialgroups","Social Groups","Azareal","http://github.com/Azareal","","","",init_socialgroups,nil,deactivate_socialgroups,install_socialgroups,nil)
|
||||
}
|
||||
|
||||
func init_socialgroups() (err error) {
|
||||
plugins["socialgroups"].AddHook("intercept_build_widgets", socialgroups_widgets)
|
||||
plugins["socialgroups"].AddHook("trow_assign", socialgroups_trow_assign)
|
||||
plugins["socialgroups"].AddHook("topic_create_pre_loop", socialgroups_topic_create_pre_loop)
|
||||
plugins["socialgroups"].AddHook("pre_render_view_forum", socialgroups_pre_render_view_forum)
|
||||
plugins["socialgroups"].AddHook("simple_forum_check_pre_perms", socialgroups_forum_check)
|
||||
plugins["socialgroups"].AddHook("forum_check_pre_perms", socialgroups_forum_check)
|
||||
// TO-DO: Auto-grant this perm to admins upon installation?
|
||||
register_plugin_perm("CreateSocialGroup")
|
||||
router.HandleFunc("/groups/", socialgroups_group_list)
|
||||
router.HandleFunc("/group/", socialgroups_view_group)
|
||||
router.HandleFunc("/group/create/", socialgroups_create_group)
|
||||
router.HandleFunc("/group/create/submit/", socialgroups_create_group_submit)
|
||||
router.HandleFunc("/group/members/", socialgroups_member_list)
|
||||
|
||||
socialgroups_list_stmt, err = qgen.Builder.SimpleSelect("socialgroups","sgid, name, desc, active, privacy, owner, memberCount, createdAt, lastUpdateTime","","","")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
socialgroups_get_group_stmt, err = qgen.Builder.SimpleSelect("socialgroups","name, desc, active, privacy, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime","sgid = ?","","")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
socialgroups_member_list_stmt, err = qgen.Builder.SimpleSelect("socialgroups_members","sgid, uid, rank, posts, joinedAt","","","")
|
||||
if err != nil {
|
||||
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","")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
socialgroups_get_member_stmt, err = qgen.Builder.SimpleSelect("socialgroups_members","rank, posts, joinedAt","sgid = ? AND uid = ?","","")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
socialgroups_create_group_stmt, err = qgen.Builder.SimpleInsert("socialgroups","name, desc, active, privacy, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime","?,?,?,?,?,1,?,'',NOW(),NOW()")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
socialgroups_attach_forum_stmt, err = qgen.Builder.SimpleUpdate("forums","parentID = ?, parentType = 'socialgroup'","fid = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
socialgroups_unattach_forum_stmt, err = qgen.Builder.SimpleUpdate("forums","parentID = 0, parentType = ''","fid = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
socialgroups_add_member_stmt, err = qgen.Builder.SimpleInsert("socialgroups_members","sgid, uid, rank, posts, joinedAt","?,?,?,0,NOW()")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deactivate_socialgroups() {
|
||||
plugins["socialgroups"].RemoveHook("intercept_build_widgets", socialgroups_widgets)
|
||||
plugins["socialgroups"].RemoveHook("trow_assign", socialgroups_trow_assign)
|
||||
plugins["socialgroups"].RemoveHook("topic_create_pre_loop", socialgroups_topic_create_pre_loop)
|
||||
plugins["socialgroups"].RemoveHook("pre_render_view_forum", socialgroups_pre_render_view_forum)
|
||||
plugins["socialgroups"].RemoveHook("simple_forum_check_pre_perms", socialgroups_forum_check)
|
||||
plugins["socialgroups"].RemoveHook("forum_check_pre_perms", socialgroups_forum_check)
|
||||
deregister_plugin_perm("CreateSocialGroup")
|
||||
_ = router.RemoveFunc("/groups/")
|
||||
_ = router.RemoveFunc("/group/")
|
||||
_ = router.RemoveFunc("/group/create/")
|
||||
_ = router.RemoveFunc("/group/create/submit/")
|
||||
_ = socialgroups_list_stmt.Close()
|
||||
_ = socialgroups_member_list_stmt.Close()
|
||||
_ = socialgroups_member_list_join_stmt.Close()
|
||||
_ = socialgroups_get_member_stmt.Close()
|
||||
_ = socialgroups_get_group_stmt.Close()
|
||||
_ = socialgroups_create_group_stmt.Close()
|
||||
_ = socialgroups_attach_forum_stmt.Close()
|
||||
_ = socialgroups_unattach_forum_stmt.Close()
|
||||
_ = socialgroups_add_member_stmt.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
|
||||
func install_socialgroups() error {
|
||||
sg_table_stmt, err := qgen.Builder.CreateTable("socialgroups","utf8mb4","utf8mb4_general_ci",
|
||||
[]qgen.DB_Table_Column{
|
||||
qgen.DB_Table_Column{"sgid","int",0,false,true,""},
|
||||
qgen.DB_Table_Column{"name","varchar",100,false,false,""},
|
||||
qgen.DB_Table_Column{"desc","varchar",200,false,false,""},
|
||||
qgen.DB_Table_Column{"active","tinyint",1,false,false,""},
|
||||
qgen.DB_Table_Column{"privacy","tinyint",1,false,false,""},
|
||||
qgen.DB_Table_Column{"owner","int",0,false,false,""},
|
||||
qgen.DB_Table_Column{"memberCount","int",0,false,false,""},
|
||||
qgen.DB_Table_Column{"mainForum","int",0,false,false,"0"}, // The board the user lands on when they click ona group, we'll make it possible for group admins to change what users land on
|
||||
//qgen.DB_Table_Column{"boards","varchar",200,false,false,""}, // Cap the max number of boards at 8 to avoid overflowing the confines of a 64-bit integer?
|
||||
qgen.DB_Table_Column{"backdrop","varchar",200,false,false,""}, // File extension for the uploaded file, or an external link
|
||||
qgen.DB_Table_Column{"createdAt","createdAt",0,false,false,""},
|
||||
qgen.DB_Table_Column{"lastUpdateTime","datetime",0,false,false,""},
|
||||
},
|
||||
[]qgen.DB_Table_Key{
|
||||
qgen.DB_Table_Key{"sgid","primary"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sg_table_stmt.Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sg_members_table_stmt, err := qgen.Builder.CreateTable("socialgroups_members","","",
|
||||
[]qgen.DB_Table_Column{
|
||||
qgen.DB_Table_Column{"sgid","int",0,false,false,""},
|
||||
qgen.DB_Table_Column{"uid","int",0,false,false,""},
|
||||
qgen.DB_Table_Column{"rank","int",0,false,false,"0"}, /* 0: Member. 1: Mod. 2: Admin. */
|
||||
qgen.DB_Table_Column{"posts","int",0,false,false,"0"}, /* Per-Group post count. Should we do some sort of score system? */
|
||||
qgen.DB_Table_Column{"joinedAt","datetime",0,false,false,""},
|
||||
},
|
||||
[]qgen.DB_Table_Key{},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sg_members_table_stmt.Exec()
|
||||
return err
|
||||
}
|
||||
|
||||
// TO-DO; Implement an uninstallation system into Gosora. And a better installation system.
|
||||
func uninstall_socialgroups() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TO-DO: Do this properly via the widget system
|
||||
func socialgroups_common_area_widgets(headerVars *HeaderVars) {
|
||||
// TO-DO: Hot Groups? Featured Groups? Official Groups?
|
||||
var b bytes.Buffer
|
||||
var menu WidgetMenu = WidgetMenu{"Social Groups",[]WidgetMenuItem{
|
||||
WidgetMenuItem{"Create Group","/group/create/",false},
|
||||
}}
|
||||
|
||||
err := templates.ExecuteTemplate(&b,"widget_menu.html",menu)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if themes[defaultTheme].Sidebars == "left" {
|
||||
headerVars.Widgets.LeftSidebar = template.HTML(string(b.Bytes()))
|
||||
} else if themes[defaultTheme].Sidebars == "right" || themes[defaultTheme].Sidebars == "both" {
|
||||
headerVars.Widgets.RightSidebar = template.HTML(string(b.Bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
// TO-DO: Do this properly via the widget system
|
||||
// TO-DO: Make a better more customisable group widget system
|
||||
func socialgroups_group_widgets(headerVars *HeaderVars, sgItem SocialGroup) (success bool) {
|
||||
return false // Disabled until the next commit
|
||||
|
||||
var b bytes.Buffer
|
||||
var menu WidgetMenu = WidgetMenu{"Group Options",[]WidgetMenuItem{
|
||||
WidgetMenuItem{"Join","/group/join/" + strconv.Itoa(sgItem.ID),false},
|
||||
WidgetMenuItem{"Members","/group/members/" + strconv.Itoa(sgItem.ID),false},
|
||||
}}
|
||||
|
||||
err := templates.ExecuteTemplate(&b,"widget_menu.html",menu)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
return false
|
||||
}
|
||||
|
||||
if themes[defaultTheme].Sidebars == "left" {
|
||||
headerVars.Widgets.LeftSidebar = template.HTML(string(b.Bytes()))
|
||||
} else if themes[defaultTheme].Sidebars == "right" || themes[defaultTheme].Sidebars == "both" {
|
||||
headerVars.Widgets.RightSidebar = template.HTML(string(b.Bytes()))
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
Custom Pages
|
||||
*/
|
||||
|
||||
func socialgroups_group_list(w http.ResponseWriter, r *http.Request, user User) {
|
||||
headerVars, ok := SessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
socialgroups_common_area_widgets(&headerVars)
|
||||
|
||||
rows, err := socialgroups_list_stmt.Query()
|
||||
if err != nil && err != ErrNoRows {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
var sgList []SocialGroup
|
||||
for rows.Next() {
|
||||
sgItem := SocialGroup{ID:0}
|
||||
err := rows.Scan(&sgItem.ID, &sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Owner, &sgItem.MemberCount, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
sgItem.Link = socialgroups_build_group_url(name_to_slug(sgItem.Name),sgItem.ID)
|
||||
sgList = append(sgList,sgItem)
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
pi := SocialGroupListPage{"Group List",user,headerVars,sgList,extData}
|
||||
err = templates.ExecuteTemplate(w,"socialgroups_group_list.html", pi)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
}
|
||||
}
|
||||
|
||||
func socialgroups_view_group(w http.ResponseWriter, r *http.Request, user User) {
|
||||
// SEO URLs...
|
||||
halves := strings.Split(r.URL.Path[len("/group/"):],".")
|
||||
if len(halves) < 2 {
|
||||
halves = append(halves,halves[0])
|
||||
}
|
||||
sgid, err := strconv.Atoi(halves[1])
|
||||
if err != nil {
|
||||
PreError("Not a valid group ID",w,r)
|
||||
return
|
||||
}
|
||||
|
||||
var sgItem SocialGroup = SocialGroup{ID:sgid}
|
||||
var mainForum int
|
||||
err = socialgroups_get_group_stmt.QueryRow(sgid).Scan(&sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Owner, &sgItem.MemberCount, &mainForum, &sgItem.Backdrop, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
|
||||
if err != nil {
|
||||
LocalError("Bad group",w,r,user)
|
||||
return
|
||||
}
|
||||
if !sgItem.Active {
|
||||
NotFound(w,r)
|
||||
}
|
||||
|
||||
// Re-route the request to route_forums
|
||||
var ctx context.Context = context.WithValue(r.Context(),"socialgroups_current_group",sgItem)
|
||||
route_forum(w,r.WithContext(ctx),user,strconv.Itoa(mainForum))
|
||||
}
|
||||
|
||||
func socialgroups_create_group(w http.ResponseWriter, r *http.Request, user User) {
|
||||
headerVars, ok := SessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// TO-DO: Add an approval queue mode for group creation
|
||||
if !user.Loggedin || !user.PluginPerms["CreateSocialGroup"] {
|
||||
NoPermissions(w,r,user)
|
||||
return
|
||||
}
|
||||
socialgroups_common_area_widgets(&headerVars)
|
||||
|
||||
pi := Page{"Create Group",user,headerVars,tList,nil}
|
||||
err := templates.ExecuteTemplate(w,"socialgroups_create_group.html", pi)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
}
|
||||
}
|
||||
|
||||
func socialgroups_create_group_submit(w http.ResponseWriter, r *http.Request, user User) {
|
||||
// TO-DO: Add an approval queue mode for group creation
|
||||
if !user.Loggedin || !user.PluginPerms["CreateSocialGroup"] {
|
||||
NoPermissions(w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
var group_active bool = true
|
||||
var group_name string = html.EscapeString(r.PostFormValue("group_name"))
|
||||
var group_desc string = html.EscapeString(r.PostFormValue("group_desc"))
|
||||
var gprivacy string = r.PostFormValue("group_privacy")
|
||||
|
||||
var group_privacy int
|
||||
switch(gprivacy) {
|
||||
case "0": group_privacy = 0 // Public
|
||||
case "1": group_privacy = 1 // Protected
|
||||
case "2": group_privacy = 2 // private
|
||||
default: group_privacy = 0
|
||||
}
|
||||
|
||||
// Create the backing forum
|
||||
fid, err := fstore.CreateForum(group_name,"",true,"")
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
res, err := socialgroups_create_group_stmt.Exec(group_name, group_desc, group_active, group_privacy, user.ID, fid)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
lastId, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
// Add the main backing forum to the forum list
|
||||
err = socialgroups_attach_forum(int(lastId),fid)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = socialgroups_add_member_stmt.Exec(lastId,user.ID,2)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w,r,socialgroups_build_group_url(name_to_slug(group_name),int(lastId)), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func socialgroups_member_list(w http.ResponseWriter, r *http.Request, user User) {
|
||||
headerVars, ok := SessionCheck(w,r,&user)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// SEO URLs...
|
||||
halves := strings.Split(r.URL.Path[len("/group/members/"):],".")
|
||||
if len(halves) < 2 {
|
||||
halves = append(halves,halves[0])
|
||||
}
|
||||
sgid, err := strconv.Atoi(halves[1])
|
||||
if err != nil {
|
||||
PreError("Not a valid group ID",w,r)
|
||||
return
|
||||
}
|
||||
|
||||
var sgItem SocialGroup = SocialGroup{ID:sgid}
|
||||
var mainForum int // Unused
|
||||
err = socialgroups_get_group_stmt.QueryRow(sgid).Scan(&sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Owner, &sgItem.MemberCount, &mainForum, &sgItem.Backdrop, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
|
||||
if err != nil {
|
||||
LocalError("Bad group",w,r,user)
|
||||
return
|
||||
}
|
||||
sgItem.Link = socialgroups_build_group_url(name_to_slug(sgItem.Name),sgItem.ID)
|
||||
|
||||
socialgroups_group_widgets(&headerVars, sgItem)
|
||||
|
||||
rows, err := socialgroups_member_list_join_stmt.Query(sgid)
|
||||
if err != nil && err != ErrNoRows {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
var sgMembers []SocialGroupMember
|
||||
for rows.Next() {
|
||||
sgMember := SocialGroupMember{PostCount:0}
|
||||
err := rows.Scan(&sgMember.User.ID,&sgMember.Rank,&sgMember.PostCount,&sgMember.JoinedAt,&sgMember.User.Name, &sgMember.User.Avatar)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
sgMember.Link = build_profile_url(name_to_slug(sgMember.User.Name),sgMember.User.ID)
|
||||
if sgMember.User.Avatar != "" {
|
||||
if sgMember.User.Avatar[0] == '.' {
|
||||
sgMember.User.Avatar = "/uploads/avatar_" + strconv.Itoa(sgMember.User.ID) + sgMember.User.Avatar
|
||||
}
|
||||
} else {
|
||||
sgMember.User.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(sgMember.User.ID),1)
|
||||
}
|
||||
sgMember.JoinedAt, _ = relative_time(sgMember.JoinedAt)
|
||||
if sgItem.Owner == sgMember.User.ID {
|
||||
sgMember.RankString = "Owner"
|
||||
} else {
|
||||
switch(sgMember.Rank) {
|
||||
case 0: sgMember.RankString = "Member"
|
||||
case 1: sgMember.RankString = "Mod"
|
||||
case 2: sgMember.RankString = "Admin"
|
||||
}
|
||||
}
|
||||
sgMembers = append(sgMembers,sgMember)
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
pi := SocialGroupMemberListPage{"Group Member List",user,headerVars,sgMembers,sgItem,0,0,extData}
|
||||
// A plugin with plugins. Pluginception!
|
||||
if pre_render_hooks["pre_render_socialgroups_member_list"] != nil {
|
||||
if run_pre_render_hook("pre_render_socialgroups_member_list", w, r, &user, &pi) {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = templates.ExecuteTemplate(w,"socialgroups_member_list.html", pi)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
}
|
||||
}
|
||||
|
||||
func socialgroups_attach_forum(sgid int, fid int) error {
|
||||
_, err := socialgroups_attach_forum_stmt.Exec(sgid,fid)
|
||||
return err
|
||||
}
|
||||
|
||||
func socialgroups_unattach_forum(fid int) error {
|
||||
_, err := socialgroups_attach_forum_stmt.Exec(fid)
|
||||
return err
|
||||
}
|
||||
|
||||
func socialgroups_build_group_url(slug string, id int) string {
|
||||
if slug == "" {
|
||||
return "/group/" + slug + "." + strconv.Itoa(id)
|
||||
}
|
||||
return "/group/" + strconv.Itoa(id)
|
||||
}
|
||||
|
||||
/*
|
||||
Hooks
|
||||
*/
|
||||
|
||||
func socialgroups_pre_render_view_forum(w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) {
|
||||
pi := data.(*ForumPage)
|
||||
if pi.Header.ExtData.items != nil {
|
||||
if sgData, ok := pi.Header.ExtData.items["socialgroups_current_group"]; ok {
|
||||
sgItem := sgData.(SocialGroup)
|
||||
|
||||
sgpi := SocialGroupPage{pi.Title,pi.CurrentUser,pi.Header,pi.ItemList,pi.Forum,sgItem,pi.Page,pi.LastPage,pi.ExtData}
|
||||
err := templates.ExecuteTemplate(w,"socialgroups_view_group.html", sgpi)
|
||||
if err != nil {
|
||||
LogError(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func socialgroups_trow_assign(args ...interface{}) interface{} {
|
||||
var forum *Forum = args[1].(*Forum)
|
||||
if forum.ParentType == "socialgroup" {
|
||||
var topicItem *TopicsRow = args[0].(*TopicsRow)
|
||||
topicItem.ForumLink = "/group/" + strings.TrimPrefix(topicItem.ForumLink,get_forum_url_prefix())
|
||||
}
|
||||
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
|
||||
func socialgroups_topic_create_pre_loop(args ...interface{}) interface{} {
|
||||
var fid int = args[2].(int)
|
||||
if fstore.DirtyGet(fid).ParentType == "socialgroup" {
|
||||
var strictmode *bool = args[5].(*bool)
|
||||
*strictmode = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TO-DO: Permissions Override. It doesn't quite work yet.
|
||||
func socialgroups_forum_check(args ...interface{}) (skip interface{}) {
|
||||
var r = args[1].(*http.Request)
|
||||
var fid *int = args[3].(*int)
|
||||
if fstore.DirtyGet(*fid).ParentType == "socialgroup" {
|
||||
sgItem, ok := r.Context().Value("socialgroups_current_group").(SocialGroup)
|
||||
if !ok {
|
||||
LogError(errors.New("Unable to find a parent group in the context data"))
|
||||
return false
|
||||
}
|
||||
|
||||
//run_vhook("simple_forum_check_pre_perms", w, r, user, &fid, &success).(bool)
|
||||
var w = args[0].(http.ResponseWriter)
|
||||
var user *User = args[2].(*User)
|
||||
var success *bool = args[4].(*bool)
|
||||
var rank int
|
||||
var posts int
|
||||
var joinedAt string
|
||||
|
||||
// TO-DO: Group privacy settings. For now, groups are all globally visible
|
||||
|
||||
// Clear the default group permissions
|
||||
// TO-DO: Do this more efficiently, doing it quick and dirty for now to get this out quickly
|
||||
override_forum_perms(&user.Perms, false)
|
||||
user.Perms.ViewTopic = true
|
||||
|
||||
err := socialgroups_get_member_stmt.QueryRow(sgItem.ID,user.ID).Scan(&rank,&posts,&joinedAt)
|
||||
if err != nil && err != ErrNoRows {
|
||||
*success = false
|
||||
InternalError(err,w,r)
|
||||
return false
|
||||
} else if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// TO-DO: Implement bans properly by adding the Local Ban API in the next commit
|
||||
if rank < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Basic permissions for members, more complicated permissions coming in the next commit!
|
||||
if sgItem.Owner == user.ID {
|
||||
override_forum_perms(&user.Perms,true)
|
||||
} else if rank == 0 {
|
||||
user.Perms.LikeItem = true
|
||||
user.Perms.CreateTopic = true
|
||||
user.Perms.CreateReply = true
|
||||
} else {
|
||||
override_forum_perms(&user.Perms,true)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// TO-DO: Override redirects? I don't think this is needed quite yet
|
||||
|
||||
func socialgroups_widgets(args ...interface{}) interface{} {
|
||||
var zone string = args[0].(string)
|
||||
var headerVars *HeaderVars = args[2].(*HeaderVars)
|
||||
var request *http.Request = args[3].(*http.Request)
|
||||
|
||||
if zone != "view_forum" {
|
||||
return false
|
||||
}
|
||||
|
||||
var forum *Forum = args[1].(*Forum)
|
||||
if forum.ParentType == "socialgroup" {
|
||||
// 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)
|
||||
if !ok {
|
||||
LogError(errors.New("Unable to find a parent group in the context data"))
|
||||
return false
|
||||
}
|
||||
|
||||
if headerVars.ExtData.items == nil {
|
||||
headerVars.ExtData.items = make(map[string]interface{})
|
||||
}
|
||||
headerVars.ExtData.items["socialgroups_current_group"] = sgItem
|
||||
|
||||
return socialgroups_group_widgets(headerVars,sgItem)
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package main
|
||||
|
||||
import "strconv"
|
||||
import "testing"
|
||||
|
||||
// go test -v
|
||||
|
||||
type ME_Pair struct
|
||||
{
|
||||
Msg string
|
||||
Expects string
|
||||
}
|
||||
|
||||
func addMEPair(msgList []ME_Pair, msg string, expects string) []ME_Pair {
|
||||
return append(msgList,ME_Pair{msg,expects})
|
||||
}
|
||||
|
||||
func TestBBCodeRender(t *testing.T) {
|
||||
var res string
|
||||
var msgList []ME_Pair
|
||||
msgList = addMEPair(msgList,"hi","hi")
|
||||
msgList = addMEPair(msgList,"😀","😀")
|
||||
msgList = addMEPair(msgList,"[b]😀[/b]","<b>😀</b>")
|
||||
msgList = addMEPair(msgList,"[b]😀😀😀[/b]","<b>😀😀😀</b>")
|
||||
msgList = addMEPair(msgList,"[b]hi[/b]","<b>hi</b>")
|
||||
msgList = addMEPair(msgList,"[u]hi[/u]","<u>hi</u>")
|
||||
msgList = addMEPair(msgList,"[i]hi[/i]","<i>hi</i>")
|
||||
msgList = addMEPair(msgList,"[s]hi[/s]","<s>hi</s>")
|
||||
msgList = addMEPair(msgList,"[c]hi[/c]","[c]hi[/c]")
|
||||
msgList = addMEPair(msgList,"[b]hi[/i]","[b]hi[/i]")
|
||||
msgList = addMEPair(msgList,"[/b]hi[b]","[/b]hi[b]")
|
||||
msgList = addMEPair(msgList,"[/b]hi[/b]","[/b]hi[/b]")
|
||||
msgList = addMEPair(msgList,"[/b]hi","[/b]hi")
|
||||
msgList = addMEPair(msgList,"[code]hi[/code]","<span class='codequotes'>hi</span>")
|
||||
msgList = addMEPair(msgList,"[code][b]hi[/b][/code]","<span class='codequotes'>[b]hi[/b]</span>")
|
||||
msgList = addMEPair(msgList,"[quote]hi[/quote]","<span class='postQuote'>hi</span>")
|
||||
msgList = addMEPair(msgList,"[quote][b]hi[/b][/quote]","<span class='postQuote'><b>hi</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>")
|
||||
|
||||
t.Log("Testing bbcode_full_parse")
|
||||
for _, item := range msgList {
|
||||
t.Log("Testing string '"+item.Msg+"'")
|
||||
res = bbcode_full_parse(item.Msg).(string)
|
||||
if res != item.Expects {
|
||||
t.Error("Bad output:","'"+res+"'")
|
||||
t.Error("Expected:",item.Expects)
|
||||
}
|
||||
}
|
||||
|
||||
var msg, expects string
|
||||
var err error
|
||||
|
||||
msg = "[rand][/rand]"
|
||||
expects = "<span style='color: red;'>[Invalid Number]</span>[rand][/rand]"
|
||||
t.Log("Testing string '"+msg+"'")
|
||||
res = bbcode_full_parse(msg).(string)
|
||||
if res != expects {
|
||||
t.Error("Bad output:","'"+res+"'")
|
||||
t.Error("Expected:",expects)
|
||||
}
|
||||
|
||||
msg = "[rand]-1[/rand]"
|
||||
expects = "<span style='color: red;'>[No Negative Numbers]</span>[rand]-1[/rand]"
|
||||
t.Log("Testing string '"+msg+"'")
|
||||
res = bbcode_full_parse(msg).(string)
|
||||
if res != expects {
|
||||
t.Error("Bad output:","'"+res+"'")
|
||||
t.Error("Expected:",expects)
|
||||
}
|
||||
|
||||
var conv int
|
||||
msg = "[rand]1[/rand]"
|
||||
t.Log("Testing string '"+msg+"'")
|
||||
res = bbcode_full_parse(msg).(string)
|
||||
conv, err = strconv.Atoi(res)
|
||||
if err != nil && (conv > 1 || conv < 0) {
|
||||
t.Error("Bad output:","'"+res+"'")
|
||||
t.Error("Expected a number in the range 0-1")
|
||||
}
|
||||
|
||||
t.Log("Testing bbcode_regex_parse")
|
||||
for _, item := range msgList {
|
||||
t.Log("Testing string '"+item.Msg+"'")
|
||||
res = bbcode_regex_parse(item.Msg).(string)
|
||||
if res != item.Expects {
|
||||
t.Error("Bad output:","'"+res+"'")
|
||||
t.Error("Expected:",item.Expects)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarkdownRender(t *testing.T) {
|
||||
var res string
|
||||
var msgList []ME_Pair
|
||||
msgList = addMEPair(msgList,"hi","hi")
|
||||
msgList = addMEPair(msgList,"**hi**","<b>hi</b>")
|
||||
msgList = addMEPair(msgList,"_hi_","<u>hi</u>")
|
||||
msgList = addMEPair(msgList,"*hi*","<i>hi</i>")
|
||||
msgList = addMEPair(msgList,"~hi~","<s>hi</s>")
|
||||
msgList = addMEPair(msgList,"*hi**","<i>hi</i>*")
|
||||
msgList = addMEPair(msgList,"**hi***","<b>hi</b>*")
|
||||
msgList = addMEPair(msgList,"**hi*","*<i>hi</i>")
|
||||
msgList = addMEPair(msgList,"***hi***","*<b><i>hi</i></b>")
|
||||
msgList = addMEPair(msgList,"\\*hi\\*","*hi*")
|
||||
msgList = addMEPair(msgList,"*~hi~*","<i><s>hi</s></i>")
|
||||
msgList = addMEPair(msgList,"**","**")
|
||||
msgList = addMEPair(msgList,"***","***")
|
||||
msgList = addMEPair(msgList,"****","****")
|
||||
msgList = addMEPair(msgList,"*****","*****")
|
||||
msgList = addMEPair(msgList,"******","******")
|
||||
msgList = addMEPair(msgList,"*******","*******")
|
||||
msgList = addMEPair(msgList,"~~","~~")
|
||||
msgList = addMEPair(msgList,"~~~","~~~")
|
||||
msgList = addMEPair(msgList,"~~~~","~~~~")
|
||||
msgList = addMEPair(msgList,"~~~~~","~~~~~")
|
||||
msgList = addMEPair(msgList,"__","__")
|
||||
msgList = addMEPair(msgList,"___","___")
|
||||
msgList = addMEPair(msgList,"_ _","<u> </u>")
|
||||
msgList = addMEPair(msgList,"* *","<i> </i>")
|
||||
msgList = addMEPair(msgList,"** **","<b> </b>")
|
||||
msgList = addMEPair(msgList,"*** ***","<b><i> </i></b>")
|
||||
|
||||
for _, item := range msgList {
|
||||
t.Log("Testing string '"+item.Msg+"'")
|
||||
res = markdown_parse(item.Msg).(string)
|
||||
if res != item.Expects {
|
||||
t.Error("Bad output:","'"+res+"'")
|
||||
t.Error("Expected:",item.Expects)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,6 +56,14 @@ func (build *builder) SimpleInnerJoin(table1 string, table2 string, columns stri
|
|||
return build.conn.Prepare(res)
|
||||
}
|
||||
|
||||
func (build *builder) CreateTable(table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (stmt *sql.Stmt, err error) {
|
||||
res, err := build.adapter.CreateTable("_builder", table, charset, collation, columns, keys)
|
||||
if err != nil {
|
||||
return stmt, err
|
||||
}
|
||||
return build.conn.Prepare(res)
|
||||
}
|
||||
|
||||
func (build *builder) SimpleInsert(table string, columns string, fields string) (stmt *sql.Stmt, err error) {
|
||||
res, err := build.adapter.SimpleInsert("_builder", table, columns, fields)
|
||||
if err != nil {
|
||||
|
|
|
@ -3,6 +3,7 @@ package qgen
|
|||
|
||||
//import "fmt"
|
||||
import "strings"
|
||||
import "strconv"
|
||||
import "errors"
|
||||
|
||||
func init() {
|
||||
|
@ -30,6 +31,74 @@ func (adapter *Mysql_Adapter) GetStmts() map[string]string {
|
|||
return adapter.Buffer
|
||||
}
|
||||
|
||||
func (adapter *Mysql_Adapter) CreateTable(name string, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (string, error) {
|
||||
if name == "" {
|
||||
return "", errors.New("You need a name for this statement")
|
||||
}
|
||||
if table == "" {
|
||||
return "", errors.New("You need a name for this table")
|
||||
}
|
||||
if len(columns) == 0 {
|
||||
return "", errors.New("You can't have a table with no columns")
|
||||
}
|
||||
|
||||
var querystr string = "CREATE TABLE `" + table + "` ("
|
||||
for _, column := range columns {
|
||||
// Make it easier to support Cassandra in the future
|
||||
if column.Type == "createdAt" {
|
||||
column.Type = "datetime"
|
||||
}
|
||||
|
||||
var size string
|
||||
if column.Size > 0 {
|
||||
size = "(" + strconv.Itoa(column.Size) + ")"
|
||||
}
|
||||
|
||||
var end string
|
||||
if column.Default != "" {
|
||||
end = " DEFAULT "
|
||||
if adapter.stringy_type(column.Type) {
|
||||
end += "'" + column.Default + "'"
|
||||
} else {
|
||||
end += column.Default
|
||||
}
|
||||
}
|
||||
|
||||
if column.Null {
|
||||
end += " null"
|
||||
} else {
|
||||
end += " not null"
|
||||
}
|
||||
|
||||
if column.Auto_Increment {
|
||||
end += " AUTO_INCREMENT"
|
||||
}
|
||||
|
||||
querystr += "\n\t`"+column.Name+"` " + column.Type + size + end + ","
|
||||
}
|
||||
|
||||
if len(keys) > 0 {
|
||||
for _, key := range keys {
|
||||
querystr += "\n\t" + key.Type + " key("
|
||||
for _, column := range strings.Split(key.Columns,",") {
|
||||
querystr += "`" + column + "`,"
|
||||
}
|
||||
querystr = querystr[0:len(querystr) - 1] + "),"
|
||||
}
|
||||
}
|
||||
|
||||
querystr = querystr[0:len(querystr) - 1] + "\n)"
|
||||
if charset != "" {
|
||||
querystr += " CHARSET=" + charset
|
||||
}
|
||||
if collation != "" {
|
||||
querystr += " COLLATE " + collation
|
||||
}
|
||||
|
||||
adapter.push_statement(name,querystr + ";")
|
||||
return querystr + ";", nil
|
||||
}
|
||||
|
||||
func (adapter *Mysql_Adapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) {
|
||||
if name == "" {
|
||||
return "", errors.New("You need a name for this statement")
|
||||
|
@ -761,7 +830,7 @@ import "database/sql"
|
|||
|
||||
` + stmts + `
|
||||
func gen_mysql() (err error) {
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Building the generated statements")
|
||||
}
|
||||
` + body + `
|
||||
|
@ -771,8 +840,13 @@ func gen_mysql() (err error) {
|
|||
return write_file("./gen_mysql.go", out)
|
||||
}
|
||||
|
||||
// Internal method, not exposed in the interface
|
||||
func (adapter *Mysql_Adapter) push_statement(name string, querystr string ) {
|
||||
// Internal methods, not exposed in the interface
|
||||
func (adapter *Mysql_Adapter) push_statement(name string, querystr string) {
|
||||
adapter.Buffer[name] = querystr
|
||||
adapter.BufferOrder = append(adapter.BufferOrder,name)
|
||||
}
|
||||
|
||||
func (adapter *Mysql_Adapter) stringy_type(ctype string) bool {
|
||||
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"
|
||||
}
|
||||
|
|
|
@ -6,6 +6,22 @@ import "errors"
|
|||
var DB_Registry []DB_Adapter
|
||||
var No_Adapter = errors.New("This adapter doesn't exist")
|
||||
|
||||
type DB_Table_Column struct
|
||||
{
|
||||
Name string
|
||||
Type string
|
||||
Size int
|
||||
Null bool
|
||||
Auto_Increment bool
|
||||
Default string
|
||||
}
|
||||
|
||||
type DB_Table_Key struct
|
||||
{
|
||||
Columns string
|
||||
Type string
|
||||
}
|
||||
|
||||
type DB_Select struct
|
||||
{
|
||||
Table string
|
||||
|
@ -84,7 +100,8 @@ type DB_Limit struct {
|
|||
|
||||
type DB_Adapter interface {
|
||||
GetName() string
|
||||
SimpleInsert(string,string,string,string) (string, error)
|
||||
CreateTable(name string, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (string, error)
|
||||
SimpleInsert(name string, table string, columns string, fields string) (string, error)
|
||||
SimpleReplace(string,string,string,string) (string, error)
|
||||
SimpleUpdate(string,string,string,string) (string, error)
|
||||
SimpleDelete(string,string,string) (string, error)
|
||||
|
|
|
@ -93,13 +93,13 @@ func write_selects(adapter qgen.DB_Adapter) error {
|
|||
|
||||
adapter.SimpleSelect("get_full_settings","settings","name, content, type, constraints","","","")
|
||||
|
||||
adapter.SimpleSelect("get_groups","users_groups","gid, name, permissions, is_mod, is_admin, is_banned, tag","","","")
|
||||
adapter.SimpleSelect("get_groups","users_groups","gid, name, permissions, plugin_perms, is_mod, is_admin, is_banned, tag","","","")
|
||||
|
||||
adapter.SimpleSelect("get_forums","forums","fid, name, desc, active, preset, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","","fid ASC","")
|
||||
adapter.SimpleSelect("get_forums","forums","fid, name, desc, active, preset, parentID, parentType, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","","fid ASC","")
|
||||
|
||||
adapter.SimpleSelect("get_forums_permissions","forums_permissions","gid, fid, permissions","","gid ASC, fid ASC","")
|
||||
|
||||
adapter.SimpleSelect("get_plugins","plugins","uname, active","","","")
|
||||
adapter.SimpleSelect("get_plugins","plugins","uname, active, installed","","","")
|
||||
|
||||
adapter.SimpleSelect("get_themes","themes","uname, default","","","")
|
||||
|
||||
|
@ -107,6 +107,8 @@ func write_selects(adapter qgen.DB_Adapter) error {
|
|||
|
||||
adapter.SimpleSelect("is_plugin_active","plugins","active","uname = ?","","")
|
||||
|
||||
//adapter.SimpleSelect("is_plugin_installed","plugins","installed","uname = ?","","")
|
||||
|
||||
adapter.SimpleSelect("get_users","users","uid, name, group, active, is_super_admin, avatar","","","")
|
||||
|
||||
adapter.SimpleSelect("is_theme_default","themes","default","uname = ?","","")
|
||||
|
@ -195,7 +197,7 @@ func write_inserts(adapter qgen.DB_Adapter) error {
|
|||
|
||||
adapter.SimpleInsert("add_forum_perms_to_forum","forums_permissions","gid,fid,preset,permissions","?,?,?,?")
|
||||
|
||||
adapter.SimpleInsert("add_plugin","plugins","uname,active","?,?")
|
||||
adapter.SimpleInsert("add_plugin","plugins","uname, active, installed","?,?,?")
|
||||
|
||||
adapter.SimpleInsert("add_theme","themes","uname,default","?,?")
|
||||
|
||||
|
@ -275,6 +277,8 @@ func write_updates(adapter qgen.DB_Adapter) error {
|
|||
|
||||
adapter.SimpleUpdate("update_plugin","plugins","active = ?","uname = ?")
|
||||
|
||||
adapter.SimpleUpdate("update_plugin_install","plugins","installed = ?","uname = ?")
|
||||
|
||||
adapter.SimpleUpdate("update_theme","themes","default = ?","uname = ?")
|
||||
|
||||
adapter.SimpleUpdate("update_user","users","name = ?, email = ?, group = ?","uid = ?")
|
||||
|
|
2
reply.go
|
@ -2,6 +2,8 @@
|
|||
package main
|
||||
import "html/template"
|
||||
|
||||
// Should we add a reply store to centralise all the reply logic? Would this cover profile replies too or would that be seperate?
|
||||
|
||||
type Reply struct /* Should probably rename this to ReplyUser and rename ReplyShort to Reply */
|
||||
{
|
||||
ID int
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* Obsoleted by gen_router.go :( */
|
||||
package main
|
||||
|
||||
//import "fmt"
|
||||
|
@ -5,6 +6,7 @@ import "strings"
|
|||
import "sync"
|
||||
import "net/http"
|
||||
|
||||
// TO-DO: Support the new handler signatures created by our efforts to move the PreRoute middleware into the generated router
|
||||
type Router struct {
|
||||
sync.RWMutex
|
||||
routes map[string]func(http.ResponseWriter, *http.Request)
|
||||
|
|
|
@ -29,7 +29,7 @@ func main() {
|
|||
if route.Before != "" {
|
||||
out += "\n\t\t\t" + route.Before
|
||||
}
|
||||
out += "\n\t\t\t" + route.Name + "(w,req"
|
||||
out += "\n\t\t\t" + route.Name + "(w,req,user"
|
||||
for _, item := range route.Vars {
|
||||
out += "," + item
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ func main() {
|
|||
if route.Before != "" {
|
||||
out += "\n\t\t\t\t\t" + route.Before
|
||||
}
|
||||
out += "\n\t\t\t\t\t" + route.Name + "(w,req"
|
||||
out += "\n\t\t\t\t\t" + route.Name + "(w,req,user"
|
||||
for _, item := range route.Vars {
|
||||
out += "," + item
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ func main() {
|
|||
if default_route.Before != "" {
|
||||
out += "\n\t\t\t\t\t" + default_route.Before
|
||||
}
|
||||
out += "\n\t\t\t\t\t" + default_route.Name + "(w,req"
|
||||
out += "\n\t\t\t\t\t" + default_route.Name + "(w,req,user"
|
||||
for _, item := range default_route.Vars {
|
||||
out += ", " + item
|
||||
}
|
||||
|
@ -81,32 +81,48 @@ func main() {
|
|||
fdata += `package main
|
||||
|
||||
//import "fmt"
|
||||
import "sync"
|
||||
import "strings"
|
||||
import "sync"
|
||||
import "errors"
|
||||
import "net/http"
|
||||
|
||||
var ErrNoRoute = errors.New("That route doesn't exist.")
|
||||
|
||||
type GenRouter struct {
|
||||
UploadHandler func(http.ResponseWriter, *http.Request)
|
||||
sync.RWMutex // Temporary Fallback
|
||||
old_routes map[string]func(http.ResponseWriter, *http.Request) // Temporary Fallback
|
||||
extra_routes map[string]func(http.ResponseWriter, *http.Request, User)
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func NewGenRouter(uploads http.Handler) *GenRouter {
|
||||
return &GenRouter{
|
||||
UploadHandler: http.StripPrefix("/uploads/",uploads).ServeHTTP,
|
||||
old_routes: make(map[string]func(http.ResponseWriter, *http.Request)),
|
||||
extra_routes: make(map[string]func(http.ResponseWriter, *http.Request, User)),
|
||||
}
|
||||
}
|
||||
|
||||
func (router *GenRouter) Handle(_ string, _ http.Handler) {
|
||||
}
|
||||
|
||||
func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request)) {
|
||||
func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, User)) {
|
||||
router.Lock()
|
||||
router.old_routes[pattern] = handle
|
||||
router.extra_routes[pattern] = handle
|
||||
router.Unlock()
|
||||
}
|
||||
|
||||
func (router *GenRouter) RemoveFunc(pattern string) error {
|
||||
router.Lock()
|
||||
_, ok := router.extra_routes[pattern]
|
||||
if !ok {
|
||||
router.Unlock()
|
||||
return ErrNoRoute
|
||||
}
|
||||
delete(router.extra_routes,pattern)
|
||||
router.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
//if req.URL.Path == "/" {
|
||||
// default_route(w,req)
|
||||
|
@ -127,6 +143,19 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
//fmt.Println("prefix:",prefix)
|
||||
//fmt.Println("req.URL.Path:",req.URL.Path)
|
||||
//fmt.Println("extra_data:",extra_data)
|
||||
|
||||
if prefix == "/static" {
|
||||
req.URL.Path += extra_data
|
||||
route_static(w,req)
|
||||
return
|
||||
}
|
||||
|
||||
// Deal with the session stuff, etc.
|
||||
user, ok := PreRoute(w,req)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
switch(prefix) {` + out + `
|
||||
case "/uploads":
|
||||
if extra_data == "" {
|
||||
|
@ -137,19 +166,19 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
router.UploadHandler(w,req)
|
||||
return
|
||||
case "":
|
||||
default_route(w,req)
|
||||
default_route(w,req,user)
|
||||
return
|
||||
//default: NotFound(w,req)
|
||||
}
|
||||
|
||||
// A fallback for the routes which haven't been converted to the new router yet
|
||||
// A fallback for the routes which haven't been converted to the new router yet or plugins
|
||||
router.RLock()
|
||||
handle, ok := router.old_routes[req.URL.Path]
|
||||
handle, ok := router.extra_routes[req.URL.Path]
|
||||
router.RUnlock()
|
||||
|
||||
if ok {
|
||||
req.URL.Path += extra_data
|
||||
handle(w,req)
|
||||
handle(w,req,user)
|
||||
return
|
||||
}
|
||||
NotFound(w,req)
|
||||
|
|
|
@ -23,7 +23,7 @@ func addRouteGroup(path string, routes ...Route) {
|
|||
func routes() {
|
||||
//addRoute("default_route","","")
|
||||
addRoute("route_api","/api/","")
|
||||
addRoute("route_static","/static/","req.URL.Path += extra_data")
|
||||
///addRoute("route_static","/static/","req.URL.Path += extra_data")
|
||||
addRoute("route_overview","/overview/","")
|
||||
//addRoute("route_custom_page","/pages/",""/*,"&extra_data"*/)
|
||||
addRoute("route_forums","/forums/",""/*,"&forums"*/)
|
||||
|
@ -61,6 +61,7 @@ func routes() {
|
|||
Route{"route_panel_plugins","/panel/plugins/","",[]string{}},
|
||||
Route{"route_panel_plugins_activate","/panel/plugins/activate/","",[]string{"extra_data"}},
|
||||
Route{"route_panel_plugins_deactivate","/panel/plugins/deactivate/","",[]string{"extra_data"}},
|
||||
Route{"route_panel_plugins_install","/panel/plugins/install/","",[]string{"extra_data"}},
|
||||
|
||||
Route{"route_panel_users","/panel/users/","",[]string{}},
|
||||
Route{"route_panel_users_edit","/panel/users/edit/","",[]string{"extra_data"}},
|
||||
|
|
|
@ -2,6 +2,7 @@ package main
|
|||
import "strconv"
|
||||
import "strings"
|
||||
|
||||
// TO-DO: Move this into the phrase system
|
||||
var settingLabels map[string]string
|
||||
|
||||
type OptionLabel struct
|
||||
|
|
|
@ -83,65 +83,71 @@ w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Page + 1)))
|
|||
w.Write(forum_7)
|
||||
}
|
||||
w.Write(forum_8)
|
||||
w.Write([]byte(tmpl_forum_vars.Title))
|
||||
w.Write(forum_9)
|
||||
if tmpl_forum_vars.CurrentUser.ID != 0 {
|
||||
if !tmpl_forum_vars.CurrentUser.Perms.CreateTopic {
|
||||
w.Write(forum_9)
|
||||
}
|
||||
w.Write(forum_10)
|
||||
} else {
|
||||
w.Write([]byte(tmpl_forum_vars.Title))
|
||||
w.Write(forum_11)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
||||
if tmpl_forum_vars.CurrentUser.ID != 0 {
|
||||
if tmpl_forum_vars.CurrentUser.Perms.CreateTopic {
|
||||
w.Write(forum_12)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w.Write(forum_13)
|
||||
}
|
||||
w.Write(forum_14)
|
||||
}
|
||||
w.Write(forum_15)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
||||
w.Write(forum_16)
|
||||
if len(tmpl_forum_vars.ItemList) != 0 {
|
||||
for _, item := range tmpl_forum_vars.ItemList {
|
||||
w.Write(forum_14)
|
||||
if item.Avatar != "" {
|
||||
w.Write(forum_15)
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write(forum_16)
|
||||
}
|
||||
if item.Sticky {
|
||||
w.Write(forum_17)
|
||||
} else {
|
||||
if item.Is_Closed {
|
||||
if item.Sticky {
|
||||
w.Write(forum_18)
|
||||
}
|
||||
}
|
||||
w.Write(forum_19)
|
||||
w.Write([]byte(strconv.Itoa(item.PostCount)))
|
||||
w.Write(forum_20)
|
||||
w.Write([]byte(item.LastReplyAt))
|
||||
w.Write(forum_21)
|
||||
w.Write([]byte(item.Slug))
|
||||
w.Write(forum_22)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(forum_23)
|
||||
w.Write([]byte(item.Title))
|
||||
w.Write(forum_24)
|
||||
w.Write([]byte(item.UserSlug))
|
||||
w.Write(forum_25)
|
||||
w.Write([]byte(strconv.Itoa(item.CreatedBy)))
|
||||
w.Write(forum_26)
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write(forum_27)
|
||||
if item.Is_Closed {
|
||||
w.Write(forum_28)
|
||||
}
|
||||
w.Write(forum_29)
|
||||
}
|
||||
} else {
|
||||
if item.Is_Closed {
|
||||
w.Write(forum_19)
|
||||
}
|
||||
}
|
||||
w.Write(forum_20)
|
||||
if item.Avatar != "" {
|
||||
w.Write(forum_21)
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write(forum_22)
|
||||
}
|
||||
w.Write(forum_23)
|
||||
w.Write([]byte(strconv.Itoa(item.PostCount)))
|
||||
w.Write(forum_24)
|
||||
w.Write([]byte(item.LastReplyAt))
|
||||
w.Write(forum_25)
|
||||
w.Write([]byte(item.Slug))
|
||||
w.Write(forum_26)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(forum_27)
|
||||
w.Write([]byte(item.Title))
|
||||
w.Write(forum_28)
|
||||
w.Write([]byte(item.UserSlug))
|
||||
w.Write(forum_29)
|
||||
w.Write([]byte(strconv.Itoa(item.CreatedBy)))
|
||||
w.Write(forum_30)
|
||||
if tmpl_forum_vars.CurrentUser.Perms.CreateTopic {
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write(forum_31)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
||||
if item.Is_Closed {
|
||||
w.Write(forum_32)
|
||||
}
|
||||
w.Write(forum_33)
|
||||
}
|
||||
} else {
|
||||
w.Write(forum_34)
|
||||
if tmpl_forum_vars.CurrentUser.Perms.CreateTopic {
|
||||
w.Write(forum_35)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
||||
w.Write(forum_36)
|
||||
}
|
||||
w.Write(forum_37)
|
||||
}
|
||||
w.Write(forum_38)
|
||||
w.Write(footer_0)
|
||||
if tmpl_forum_vars.Header.Widgets.RightSidebar != "" {
|
||||
w.Write(footer_1)
|
||||
|
|
|
@ -74,51 +74,43 @@ w.Write(forums_2)
|
|||
w.Write(forums_3)
|
||||
if item.Desc != "" {
|
||||
w.Write(forums_4)
|
||||
w.Write([]byte(item.Slug))
|
||||
w.Write([]byte(item.Link))
|
||||
w.Write(forums_5)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write([]byte(item.Name))
|
||||
w.Write(forums_6)
|
||||
w.Write([]byte(item.Name))
|
||||
w.Write(forums_7)
|
||||
w.Write([]byte(item.Desc))
|
||||
w.Write(forums_7)
|
||||
} else {
|
||||
if item.LastTopicTime != "" {
|
||||
w.Write(forums_8)
|
||||
} else {
|
||||
if item.LastTopicTime != "" {
|
||||
w.Write([]byte(item.Link))
|
||||
w.Write(forums_9)
|
||||
w.Write([]byte(item.Slug))
|
||||
w.Write([]byte(item.Name))
|
||||
w.Write(forums_10)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
} else {
|
||||
w.Write(forums_11)
|
||||
w.Write([]byte(item.Name))
|
||||
w.Write([]byte(item.Link))
|
||||
w.Write(forums_12)
|
||||
} else {
|
||||
w.Write(forums_13)
|
||||
w.Write([]byte(item.Slug))
|
||||
w.Write(forums_14)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(forums_15)
|
||||
w.Write([]byte(item.Name))
|
||||
w.Write(forums_16)
|
||||
w.Write(forums_13)
|
||||
}
|
||||
}
|
||||
w.Write(forums_17)
|
||||
w.Write(forums_14)
|
||||
w.Write([]byte(item.LastTopicSlug))
|
||||
w.Write(forums_18)
|
||||
w.Write([]byte(strconv.Itoa(item.LastTopicID)))
|
||||
w.Write(forums_19)
|
||||
w.Write(forums_15)
|
||||
w.Write([]byte(item.LastTopic))
|
||||
w.Write(forums_20)
|
||||
w.Write(forums_16)
|
||||
if item.LastTopicTime != "" {
|
||||
w.Write(forums_21)
|
||||
w.Write(forums_17)
|
||||
w.Write([]byte(item.LastTopicTime))
|
||||
w.Write(forums_22)
|
||||
w.Write(forums_18)
|
||||
}
|
||||
w.Write(forums_23)
|
||||
w.Write(forums_19)
|
||||
}
|
||||
} else {
|
||||
w.Write(forums_24)
|
||||
w.Write(forums_20)
|
||||
}
|
||||
w.Write(forums_25)
|
||||
w.Write(forums_21)
|
||||
w.Write(footer_0)
|
||||
if tmpl_forums_vars.Header.Widgets.RightSidebar != "" {
|
||||
w.Write(footer_1)
|
||||
|
|
177
template_list.go
|
@ -84,10 +84,10 @@ var topic_7 []byte = []byte(`">></a>
|
|||
</div>`)
|
||||
var topic_8 []byte = []byte(`
|
||||
|
||||
<div class="rowblock topic_block">
|
||||
<div class="rowblock rowhead topic_block">
|
||||
<form action='/topic/edit/submit/`)
|
||||
var topic_9 []byte = []byte(`' method="post">
|
||||
<div class="rowitem rowhead topic_item"`)
|
||||
<div class="rowitem topic_item"`)
|
||||
var topic_10 []byte = []byte(` style="background-color:#FFFFEA;"`)
|
||||
var topic_11 []byte = []byte(` style="background-color:#eaeaea;"`)
|
||||
var topic_12 []byte = []byte(`>
|
||||
|
@ -249,10 +249,10 @@ var topic_alt_6 []byte = []byte(`?page=`)
|
|||
var topic_alt_7 []byte = []byte(`">></a></div>`)
|
||||
var topic_alt_8 []byte = []byte(`
|
||||
|
||||
<div class="rowblock topic_block">
|
||||
<div class="rowblock rowhead topic_block">
|
||||
<form action='/topic/edit/submit/`)
|
||||
var topic_alt_9 []byte = []byte(`' method="post">
|
||||
<div class="rowitem topic_item rowhead`)
|
||||
<div class="rowitem topic_item`)
|
||||
var topic_alt_10 []byte = []byte(` topic_sticky_head`)
|
||||
var topic_alt_11 []byte = []byte(` topic_closed_head`)
|
||||
var topic_alt_12 []byte = []byte(`">
|
||||
|
@ -441,8 +441,8 @@ var profile_16 []byte = []byte(`&type=user" class="profile_menu_item report_item
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="colblock_right" style="width: calc(95% - 210px);">
|
||||
<div class="rowitem rowhead"><a>Comments</a></div>
|
||||
<div class="colblock_right rowhead" style="width: calc(95% - 210px);">
|
||||
<div class="rowitem"><a>Comments</a></div>
|
||||
</div>
|
||||
<div id="profile_comments" class="colblock_right" style="overflow: hidden;border-top: none;width:calc(95% - 210px);">`)
|
||||
var profile_17 []byte = []byte(`
|
||||
|
@ -499,7 +499,7 @@ var profile_39 []byte = []byte(`
|
|||
`)
|
||||
var forums_0 []byte = []byte(`
|
||||
<div class="rowblock opthead">
|
||||
<div class="rowitem rowhead"><a>Forums</a></div>
|
||||
<div class="rowitem"><a>Forums</a></div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
`)
|
||||
|
@ -508,85 +508,82 @@ var forums_2 []byte = []byte(`datarow`)
|
|||
var forums_3 []byte = []byte(`">
|
||||
`)
|
||||
var forums_4 []byte = []byte(`<span style="float: left;">
|
||||
<a href="/forum/`)
|
||||
var forums_5 []byte = []byte(`.`)
|
||||
var forums_6 []byte = []byte(`" style="">`)
|
||||
var forums_7 []byte = []byte(`</a>
|
||||
<a href="`)
|
||||
var forums_5 []byte = []byte(`" style="">`)
|
||||
var forums_6 []byte = []byte(`</a>
|
||||
<br /><span class="rowsmall">`)
|
||||
var forums_8 []byte = []byte(`</span>
|
||||
var forums_7 []byte = []byte(`</span>
|
||||
</span>`)
|
||||
var forums_9 []byte = []byte(`<span style="float: left;padding-top: 8px;font-size: 18px;">
|
||||
<a href="/forum/`)
|
||||
var forums_10 []byte = []byte(`.`)
|
||||
var forums_11 []byte = []byte(`">`)
|
||||
var forums_12 []byte = []byte(`</a>
|
||||
var forums_8 []byte = []byte(`<span style="float: left;padding-top: 8px;font-size: 18px;">
|
||||
<a href="`)
|
||||
var forums_9 []byte = []byte(`">`)
|
||||
var forums_10 []byte = []byte(`</a>
|
||||
</span>`)
|
||||
var forums_13 []byte = []byte(`<span style="float: left;">
|
||||
<a href="/forum/`)
|
||||
var forums_14 []byte = []byte(`.`)
|
||||
var forums_15 []byte = []byte(`">`)
|
||||
var forums_16 []byte = []byte(`</a>
|
||||
var forums_11 []byte = []byte(`<span style="float: left;">
|
||||
<a href="`)
|
||||
var forums_12 []byte = []byte(`">`)
|
||||
var forums_13 []byte = []byte(`</a>
|
||||
</span>`)
|
||||
var forums_17 []byte = []byte(`
|
||||
var forums_14 []byte = []byte(`
|
||||
|
||||
<span style="float: right;">
|
||||
<a href="/topic/`)
|
||||
var forums_18 []byte = []byte(`.`)
|
||||
var forums_19 []byte = []byte(`" style="float: right;font-size: 14px;">`)
|
||||
var forums_20 []byte = []byte(`</a>
|
||||
var forums_15 []byte = []byte(`" style="float: right;font-size: 14px;">`)
|
||||
var forums_16 []byte = []byte(`</a>
|
||||
`)
|
||||
var forums_21 []byte = []byte(`<br /><span class="rowsmall">`)
|
||||
var forums_22 []byte = []byte(`</span>`)
|
||||
var forums_23 []byte = []byte(`
|
||||
var forums_17 []byte = []byte(`<br /><span class="rowsmall">`)
|
||||
var forums_18 []byte = []byte(`</span>`)
|
||||
var forums_19 []byte = []byte(`
|
||||
</span>
|
||||
<div style="clear: both;"></div>
|
||||
</div>
|
||||
`)
|
||||
var forums_24 []byte = []byte(`<div class="rowitem passive">You don't have access to any forums.</div>`)
|
||||
var forums_25 []byte = []byte(`
|
||||
var forums_20 []byte = []byte(`<div class="rowitem passive">You don't have access to any forums.</div>`)
|
||||
var forums_21 []byte = []byte(`
|
||||
</div>
|
||||
`)
|
||||
var topics_0 []byte = []byte(`
|
||||
<div class="rowblock">
|
||||
<div class="rowitem rowhead"><a>Topic List</a></div>
|
||||
<div class="rowblock rowhead">
|
||||
<div class="rowitem"><a>Topic List</a></div>
|
||||
</div>
|
||||
<div id="topic_list" class="rowblock topic_list">
|
||||
`)
|
||||
var topics_1 []byte = []byte(`<div class="rowitem passive datarow" style="`)
|
||||
var topics_2 []byte = []byte(`background-image: url(`)
|
||||
var topics_3 []byte = []byte(`);background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;`)
|
||||
var topics_4 []byte = []byte(`background-color: #FFFFCC;`)
|
||||
var topics_5 []byte = []byte(`background-color: #eaeaea;`)
|
||||
var topics_6 []byte = []byte(`">
|
||||
var topics_1 []byte = []byte(`<div class="rowitem passive datarow `)
|
||||
var topics_2 []byte = []byte(`topic_sticky`)
|
||||
var topics_3 []byte = []byte(`topic_closed`)
|
||||
var topics_4 []byte = []byte(`" style="`)
|
||||
var topics_5 []byte = []byte(`background-image: url(`)
|
||||
var topics_6 []byte = []byte(`);background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;`)
|
||||
var topics_7 []byte = []byte(`">
|
||||
<span class="rowsmall" style="float: right;">
|
||||
<span class="replyCount">`)
|
||||
var topics_7 []byte = []byte(` replies</span><br />
|
||||
var topics_8 []byte = []byte(` replies</span><br />
|
||||
<span class="lastReplyAt">`)
|
||||
var topics_8 []byte = []byte(`</span>
|
||||
var topics_9 []byte = []byte(`</span>
|
||||
</span>
|
||||
<span>
|
||||
<a class="rowtopic" href="/topic/`)
|
||||
var topics_9 []byte = []byte(`.`)
|
||||
var topics_10 []byte = []byte(`">`)
|
||||
var topics_11 []byte = []byte(`</a> `)
|
||||
var topics_12 []byte = []byte(`<a class="rowsmall" href="/forum/`)
|
||||
var topics_13 []byte = []byte(`">`)
|
||||
var topics_14 []byte = []byte(`</a>`)
|
||||
var topics_15 []byte = []byte(`
|
||||
var topics_10 []byte = []byte(`.`)
|
||||
var topics_11 []byte = []byte(`">`)
|
||||
var topics_12 []byte = []byte(`</a> `)
|
||||
var topics_13 []byte = []byte(`<a class="rowsmall" href="`)
|
||||
var topics_14 []byte = []byte(`">`)
|
||||
var topics_15 []byte = []byte(`</a>`)
|
||||
var topics_16 []byte = []byte(`
|
||||
<br /><a class="rowsmall" href="/user/`)
|
||||
var topics_16 []byte = []byte(`.`)
|
||||
var topics_17 []byte = []byte(`">Starter: `)
|
||||
var topics_18 []byte = []byte(`</a>
|
||||
var topics_17 []byte = []byte(`.`)
|
||||
var topics_18 []byte = []byte(`">Starter: `)
|
||||
var topics_19 []byte = []byte(`</a>
|
||||
`)
|
||||
var topics_19 []byte = []byte(`<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎`)
|
||||
var topics_20 []byte = []byte(`</span>
|
||||
var topics_20 []byte = []byte(`<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎`)
|
||||
var topics_21 []byte = []byte(`</span>
|
||||
</span>
|
||||
</div>
|
||||
`)
|
||||
var topics_21 []byte = []byte(`<div class="rowitem passive">There aren't any topics yet.`)
|
||||
var topics_22 []byte = []byte(` <a href="/topics/create/">Start one?</a>`)
|
||||
var topics_23 []byte = []byte(`</div>`)
|
||||
var topics_24 []byte = []byte(`
|
||||
var topics_22 []byte = []byte(`<div class="rowitem passive">There aren't any topics yet.`)
|
||||
var topics_23 []byte = []byte(` <a href="/topics/create/">Start one?</a>`)
|
||||
var topics_24 []byte = []byte(`</div>`)
|
||||
var topics_25 []byte = []byte(`
|
||||
</div>
|
||||
`)
|
||||
var forum_0 []byte = []byte(`<div id="prevFloat" class="prev_button"><a class="prev_link" href="/forum/`)
|
||||
|
@ -600,48 +597,58 @@ var forum_6 []byte = []byte(`?page=`)
|
|||
var forum_7 []byte = []byte(`">></a></div>`)
|
||||
var forum_8 []byte = []byte(`
|
||||
|
||||
<div class="rowblock">
|
||||
<div class="rowitem rowhead"><a>`)
|
||||
var forum_9 []byte = []byte(`</a>
|
||||
<div class="rowblock rowhead">
|
||||
<div class="rowitem `)
|
||||
var forum_9 []byte = []byte(`has_opt`)
|
||||
var forum_10 []byte = []byte(`"><a>`)
|
||||
var forum_11 []byte = []byte(`</a>
|
||||
</div>
|
||||
`)
|
||||
var forum_10 []byte = []byte(`<span class='username head_tag_upshift' title='No Permissions'>🔒︎</span>`)
|
||||
var forum_11 []byte = []byte(`<a href="/topics/create/`)
|
||||
var forum_12 []byte = []byte(`" class='username head_tag_upshift'>New Topic</a>`)
|
||||
var forum_13 []byte = []byte(`</div>
|
||||
var forum_12 []byte = []byte(`
|
||||
<div class="opt create_topic_opt" title="Create Topic">🖊︎</div>
|
||||
`)
|
||||
var forum_13 []byte = []byte(`<div class="opt locked_opt" title="You don't have the permissions needed to create a topic">🔒︎</div>`)
|
||||
var forum_14 []byte = []byte(`
|
||||
<div style="clear: both;"></div>
|
||||
`)
|
||||
var forum_15 []byte = []byte(`
|
||||
<!--href="/topics/create/`)
|
||||
var forum_16 []byte = []byte(`"-->
|
||||
</div>
|
||||
<div id="forum_topic_list" class="rowblock topic_list">
|
||||
`)
|
||||
var forum_14 []byte = []byte(`<div class="rowitem passive datarow" style="`)
|
||||
var forum_15 []byte = []byte(`background-image: url(`)
|
||||
var forum_16 []byte = []byte(`);background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;`)
|
||||
var forum_17 []byte = []byte(`background-color: #FFFFCC;`)
|
||||
var forum_18 []byte = []byte(`background-color: #eaeaea;`)
|
||||
var forum_19 []byte = []byte(`">
|
||||
var forum_17 []byte = []byte(`<div class="rowitem passive datarow `)
|
||||
var forum_18 []byte = []byte(`topic_sticky`)
|
||||
var forum_19 []byte = []byte(`topic_closed`)
|
||||
var forum_20 []byte = []byte(`" style="`)
|
||||
var forum_21 []byte = []byte(`background-image: url(`)
|
||||
var forum_22 []byte = []byte(`);background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;`)
|
||||
var forum_23 []byte = []byte(`">
|
||||
<span class="rowsmall" style="float: right;">
|
||||
<span class="replyCount">`)
|
||||
var forum_20 []byte = []byte(` replies</span><br />
|
||||
var forum_24 []byte = []byte(` replies</span><br />
|
||||
<span class="lastReplyAt">`)
|
||||
var forum_21 []byte = []byte(`</span>
|
||||
var forum_25 []byte = []byte(`</span>
|
||||
</span>
|
||||
<span>
|
||||
<a class="rowtopic" href="/topic/`)
|
||||
var forum_22 []byte = []byte(`.`)
|
||||
var forum_23 []byte = []byte(`">`)
|
||||
var forum_24 []byte = []byte(`</a>
|
||||
var forum_26 []byte = []byte(`.`)
|
||||
var forum_27 []byte = []byte(`">`)
|
||||
var forum_28 []byte = []byte(`</a>
|
||||
<br /><a class="rowsmall" href="/user/`)
|
||||
var forum_25 []byte = []byte(`.`)
|
||||
var forum_26 []byte = []byte(`">Starter: `)
|
||||
var forum_27 []byte = []byte(`</a>
|
||||
var forum_29 []byte = []byte(`.`)
|
||||
var forum_30 []byte = []byte(`">Starter: `)
|
||||
var forum_31 []byte = []byte(`</a>
|
||||
`)
|
||||
var forum_28 []byte = []byte(`<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎`)
|
||||
var forum_29 []byte = []byte(`</span>
|
||||
var forum_32 []byte = []byte(`<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎`)
|
||||
var forum_33 []byte = []byte(`</span>
|
||||
</span>
|
||||
</div>
|
||||
`)
|
||||
var forum_30 []byte = []byte(`<div class="rowitem passive">There aren't any topics in this forum yet.`)
|
||||
var forum_31 []byte = []byte(` <a href="/topics/create/`)
|
||||
var forum_32 []byte = []byte(`">Start one?</a>`)
|
||||
var forum_33 []byte = []byte(`</div>`)
|
||||
var forum_34 []byte = []byte(`
|
||||
var forum_34 []byte = []byte(`<div class="rowitem passive">There aren't any topics in this forum yet.`)
|
||||
var forum_35 []byte = []byte(` <a href="/topics/create/`)
|
||||
var forum_36 []byte = []byte(`">Start one?</a>`)
|
||||
var forum_37 []byte = []byte(`</div>`)
|
||||
var forum_38 []byte = []byte(`
|
||||
</div>
|
||||
`)
|
||||
|
|
|
@ -68,56 +68,57 @@ w.Write(topics_0)
|
|||
if len(tmpl_topics_vars.ItemList) != 0 {
|
||||
for _, item := range tmpl_topics_vars.ItemList {
|
||||
w.Write(topics_1)
|
||||
if item.Avatar != "" {
|
||||
if item.Sticky {
|
||||
w.Write(topics_2)
|
||||
w.Write([]byte(item.Avatar))
|
||||
} else {
|
||||
if item.Is_Closed {
|
||||
w.Write(topics_3)
|
||||
}
|
||||
if item.Sticky {
|
||||
}
|
||||
w.Write(topics_4)
|
||||
} else {
|
||||
if item.Is_Closed {
|
||||
if item.Avatar != "" {
|
||||
w.Write(topics_5)
|
||||
}
|
||||
}
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write(topics_6)
|
||||
w.Write([]byte(strconv.Itoa(item.PostCount)))
|
||||
}
|
||||
w.Write(topics_7)
|
||||
w.Write([]byte(item.LastReplyAt))
|
||||
w.Write([]byte(strconv.Itoa(item.PostCount)))
|
||||
w.Write(topics_8)
|
||||
w.Write([]byte(item.Slug))
|
||||
w.Write([]byte(item.LastReplyAt))
|
||||
w.Write(topics_9)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write([]byte(item.Slug))
|
||||
w.Write(topics_10)
|
||||
w.Write([]byte(item.Title))
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topics_11)
|
||||
if item.ForumName != "" {
|
||||
w.Write([]byte(item.Title))
|
||||
w.Write(topics_12)
|
||||
w.Write([]byte(strconv.Itoa(item.ParentID)))
|
||||
if item.ForumName != "" {
|
||||
w.Write(topics_13)
|
||||
w.Write([]byte(item.ForumName))
|
||||
w.Write([]byte(item.ForumLink))
|
||||
w.Write(topics_14)
|
||||
}
|
||||
w.Write([]byte(item.ForumName))
|
||||
w.Write(topics_15)
|
||||
w.Write([]byte(item.UserSlug))
|
||||
w.Write(topics_16)
|
||||
w.Write([]byte(strconv.Itoa(item.CreatedBy)))
|
||||
w.Write(topics_17)
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write(topics_18)
|
||||
if item.Is_Closed {
|
||||
w.Write(topics_19)
|
||||
}
|
||||
w.Write(topics_16)
|
||||
w.Write([]byte(item.UserSlug))
|
||||
w.Write(topics_17)
|
||||
w.Write([]byte(strconv.Itoa(item.CreatedBy)))
|
||||
w.Write(topics_18)
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write(topics_19)
|
||||
if item.Is_Closed {
|
||||
w.Write(topics_20)
|
||||
}
|
||||
} else {
|
||||
w.Write(topics_21)
|
||||
if tmpl_topics_vars.CurrentUser.Perms.CreateTopic {
|
||||
w.Write(topics_22)
|
||||
}
|
||||
} else {
|
||||
w.Write(topics_22)
|
||||
if tmpl_topics_vars.CurrentUser.Perms.CreateTopic {
|
||||
w.Write(topics_23)
|
||||
}
|
||||
w.Write(topics_24)
|
||||
}
|
||||
w.Write(topics_25)
|
||||
w.Write(footer_0)
|
||||
if tmpl_topics_vars.Header.Widgets.RightSidebar != "" {
|
||||
w.Write(footer_1)
|
||||
|
|
|
@ -168,7 +168,7 @@ w.Write([]byte(`," + ",-1)
|
|||
//whitespace_writes := regexp.MustCompile(`(?s)w.Write\(\[\]byte\(`+spstr+`\)\)`)
|
||||
//fout = whitespace_writes.ReplaceAllString(fout,"")
|
||||
|
||||
if debug {
|
||||
if debug_mode {
|
||||
for index, count := range c.stats {
|
||||
fmt.Println(index + ": " + strconv.Itoa(count))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="colstack_left">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>My Account</a></div>
|
||||
<div class="colstack_item colstack_head rowhead">
|
||||
<div class="rowitem"><a>My Account</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
<div class="rowitem passive"><a href="/user/edit/avatar/">Change Avatar</a></div>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{{template "header.html" . }}
|
||||
{{template "account-menu.html" . }}
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Edit Avatar</a></div>
|
||||
<div class="colstack_item colstack_head rowhead">
|
||||
<div class="rowitem"><a>Edit Avatar</a></div>
|
||||
</div>
|
||||
{{if .CurrentUser.Avatar}}
|
||||
<div class="colstack_item">
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{{template "header.html" . }}
|
||||
{{template "account-menu.html" . }}
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Emails</a></div>
|
||||
<div class="colstack_item colstack_head rowhead">
|
||||
<div class="rowitem"><a>Emails</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
{{range .ItemList}}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{{template "header.html" . }}
|
||||
{{template "account-menu.html" . }}
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Edit Username</a></div>
|
||||
<div class="colstack_item colstack_head rowhead">
|
||||
<div class="rowitem"><a>Edit Username</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
<form action="/user/edit/username/submit/" method="post">
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{{template "header.html" . }}
|
||||
{{template "account-menu.html" . }}
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Edit Password</a></div>
|
||||
<div class="colstack_item colstack_head rowhead">
|
||||
<div class="rowitem"><a>Edit Password</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
<form action="/user/edit/critical/submit/" method="post">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="rowblock">
|
||||
<div class="rowitem rowhead"><a>Are you sure?</a></div>
|
||||
<div class="rowblock rowhead">
|
||||
<div class="rowitem"><a>Are you sure?</a></div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
<div class="rowitem passive">{{.Something.Message}}<br /><br />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="rowblock">
|
||||
<div class="rowitem rowhead"><a>Create Topic</a></div>
|
||||
<div class="rowblock rowhead">
|
||||
<div class="rowitem"><a>Create Topic</a></div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
<form action="/topic/create/submit/" method="post">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="rowblock">
|
||||
<div class="rowitem rowhead"><a>An error has occured</a></div>
|
||||
<div class="rowblock rowhead">
|
||||
<div class="rowitem"><a>An error has occured</a></div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
<div class="rowitem passive">{{.Something}}</div>
|
||||
|
|
|
@ -4,12 +4,19 @@
|
|||
{{if ne .LastPage .Page}}<link rel="prerender" href="/forum/{{.Forum.ID}}?page={{add .Page 1}}" />
|
||||
<div id="nextFloat" class="next_button"><a class="next_link" href="/forum/{{.Forum.ID}}?page={{add .Page 1}}">></a></div>{{end}}
|
||||
|
||||
<div class="rowblock">
|
||||
<div class="rowitem rowhead"><a>{{.Title}}</a>
|
||||
{{if ne .CurrentUser.ID 0}}{{if not .CurrentUser.Perms.CreateTopic}}<span class='username head_tag_upshift' title='No Permissions'>🔒︎</span>{{else}}<a href="/topics/create/{{.Forum.ID}}" class='username head_tag_upshift'>New Topic</a>{{end}}{{end}}</div>
|
||||
<div class="rowblock rowhead">
|
||||
<div class="rowitem {{if ne .CurrentUser.ID 0}}has_opt{{end}}"><a>{{.Title}}</a>
|
||||
</div>
|
||||
{{if ne .CurrentUser.ID 0}}
|
||||
{{if .CurrentUser.Perms.CreateTopic}}
|
||||
<div class="opt create_topic_opt" title="Create Topic">🖊︎</div>
|
||||
{{else}}<div class="opt locked_opt" title="You don't have the permissions needed to create a topic">🔒︎</div>{{end}}
|
||||
<div style="clear: both;"></div>
|
||||
{{end}}
|
||||
<!--href="/topics/create/{{.Forum.ID}}"-->
|
||||
</div>
|
||||
<div id="forum_topic_list" class="rowblock topic_list">
|
||||
{{range .ItemList}}<div class="rowitem passive datarow" style="{{if .Avatar}}background-image: url({{.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 passive datarow {{if .Sticky}}topic_sticky{{else if .Is_Closed}}topic_closed{{end}}" style="{{if .Avatar}}background-image: url({{.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}">
|
||||
<span class="rowsmall" style="float: right;">
|
||||
<span class="replyCount">{{.PostCount}} replies</span><br />
|
||||
<span class="lastReplyAt">{{.LastReplyAt}}</span>
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="rowblock opthead">
|
||||
<div class="rowitem rowhead"><a>Forums</a></div>
|
||||
<div class="rowitem"><a>Forums</a></div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
{{range .ItemList}}<div class="rowitem {{if (.Desc) or (.LastTopicTime)}}datarow{{end}}">
|
||||
{{if .Desc}}<span style="float: left;">
|
||||
<a href="/forum/{{.Slug}}.{{.ID}}" style="">{{.Name}}</a>
|
||||
<a href="{{.Link}}" style="">{{.Name}}</a>
|
||||
<br /><span class="rowsmall">{{.Desc}}</span>
|
||||
</span>{{else if .LastTopicTime}}<span style="float: left;padding-top: 8px;font-size: 18px;">
|
||||
<a href="/forum/{{.Slug}}.{{.ID}}">{{.Name}}</a>
|
||||
<a href="{{.Link}}">{{.Name}}</a>
|
||||
</span>{{else}}<span style="float: left;">
|
||||
<a href="/forum/{{.Slug}}.{{.ID}}">{{.Name}}</a>
|
||||
<a href="{{.Link}}">{{.Name}}</a>
|
||||
</span>{{end}}
|
||||
|
||||
<span style="float: right;">
|
||||
<a href="/topic/{{.LastTopicSlug}}.{{.LastTopicID}}" style="float: right;font-size: 14px;">{{.LastTopic}}</a>
|
||||
<a href="/topic/{{.LastTopicSlug}}" style="float: right;font-size: 14px;">{{.LastTopic}}</a>
|
||||
{{if .LastTopicTime}}<br /><span class="rowsmall">{{.LastTopicTime}}</span>{{end}}
|
||||
</span>
|
||||
<div style="clear: both;"></div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="rowblock">
|
||||
<div class="rowitem rowhead"><a>Login</a></div>
|
||||
<div class="rowblock rowhead">
|
||||
<div class="rowitem"><a>Login</a></div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
<form action="/accounts/login/submit/" method="post">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="colstack_left">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a href="/panel/logs/mod/">Logs</a></div>
|
||||
<div class="rowitem"><a href="/panel/logs/mod/">Logs</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
<div class="rowitem passive"><a href="/panel/logs/mod/">Moderation Logs</a></div>
|
||||
|
@ -12,7 +12,7 @@
|
|||
</div>
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Administration Logs</a></div>
|
||||
<div class="rowitem"><a>Administration Logs</a></div>
|
||||
</div>
|
||||
<div id="panel_adminlogs" class="colstack_item">
|
||||
{{range .Logs}}
|
||||
|
|
|
@ -7,7 +7,7 @@ var form_vars = {'perm_preset': ['can_moderate','can_post','read_only','no_acces
|
|||
</div>
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>{{.Name}} Forum</a></div>
|
||||
<div class="rowitem"><a>{{.Name}} Forum</a></div>
|
||||
</div>
|
||||
<div id="panel_forum" class="colstack_item">
|
||||
<form action="/panel/forums/edit/submit/{{.ID}}?session={{.CurrentUser.Session}}" method="post">
|
||||
|
@ -46,7 +46,7 @@ var form_vars = {'perm_preset': ['can_moderate','can_post','read_only','no_acces
|
|||
</form>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Forum Permissions</a></div>
|
||||
<div class="rowitem"><a>Forum Permissions</a></div>
|
||||
</div>
|
||||
<div id="forum_quick_perms" class="colstack_item">
|
||||
{{range .Groups}}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Forums</a></div>
|
||||
<div class="rowitem"><a>Forums</a></div>
|
||||
</div>
|
||||
<div id="panel_forums" class="colstack_item">
|
||||
{{range .ItemList}}
|
||||
|
@ -33,7 +33,7 @@
|
|||
</div>
|
||||
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Add Forum</a></div>
|
||||
<div class="rowitem"><a>Add Forum</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
<form action="/panel/forums/create/?session={{.CurrentUser.Session}}" method="post">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="colstack_left">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a href="/panel/groups/edit/{{.ID}}">Group Editor</a></div>
|
||||
<div class="rowitem"><a href="/panel/groups/edit/{{.ID}}">Group Editor</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
<div class="rowitem passive"><a href="/panel/groups/edit/{{.ID}}">General</a></div>
|
||||
|
@ -12,7 +12,7 @@
|
|||
</div>
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>{{.Name}} Group</a></div>
|
||||
<div class="rowitem"><a>{{.Name}} Group</a></div>
|
||||
</div>
|
||||
<form action="/panel/groups/edit/perms/submit/{{.ID}}?session={{.CurrentUser.Session}}" method="post">
|
||||
<div id="panel_group" class="colstack_item">
|
||||
|
@ -36,7 +36,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Extended Permissions</a></div>
|
||||
<div class="rowitem"><a>Extended Permissions</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
{{if .CurrentUser.Perms.EditGroupGlobalPerms}}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="colstack_left">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a href="/panel/groups/edit/{{.ID}}">Group Editor</a></div>
|
||||
<div class="rowitem"><a href="/panel/groups/edit/{{.ID}}">Group Editor</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
<div class="rowitem passive"><a href="/panel/groups/edit/{{.ID}}">General</a></div>
|
||||
|
@ -12,7 +12,7 @@
|
|||
</div>
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>{{.Name}} Group</a></div>
|
||||
<div class="rowitem"><a>{{.Name}} Group</a></div>
|
||||
</div>
|
||||
<div id="panel_group" class="colstack_item">
|
||||
<form action="/panel/groups/edit/submit/{{.ID}}?session={{.CurrentUser.Session}}" method="post">
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Groups</a></div>
|
||||
<div class="rowitem"><a>Groups</a></div>
|
||||
</div>
|
||||
<div id="panel_groups" class="colstack_item">
|
||||
{{range .ItemList}}
|
||||
|
@ -19,7 +19,7 @@
|
|||
{{end}}
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Create Group</a></div>
|
||||
<div class="rowitem"><a>Create Group</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
<form action="/panel/groups/create/?session={{.CurrentUser.Session}}" method="post">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a href="/panel/">Control Panel</a></div>
|
||||
<div class="rowitem"><a href="/panel/">Control Panel</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
<div class="rowitem passive"><a href="/panel/users/">Users</a></div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="colstack_left">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a href="/panel/logs/mod/">Logs</a></div>
|
||||
<div class="rowitem"><a href="/panel/logs/mod/">Logs</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
<div class="rowitem passive"><a href="/panel/logs/mod/">Moderation Logs</a></div>
|
||||
|
@ -12,7 +12,7 @@
|
|||
</div>
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Moderation Logs</a></div>
|
||||
<div class="rowitem"><a>Moderation Logs</a></div>
|
||||
</div>
|
||||
<div id="panel_modlogs" class="colstack_item">
|
||||
{{range .Logs}}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{{template "panel-menu.html" . }}
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Plugins</a></div>
|
||||
<div class="rowitem"><a>Plugins</a></div>
|
||||
</div>
|
||||
<div id="panel_plugins" class="colstack_item">
|
||||
{{range .ItemList}}
|
||||
|
@ -12,6 +12,9 @@
|
|||
<span style="float: right;">
|
||||
{{if .Settings}}<a href="/panel/settings/" class="panel_tag">Settings</a>{{end}}
|
||||
{{if .Active}}<a href="/panel/plugins/deactivate/{{.UName}}?session={{$.CurrentUser.Session}}" class="panel_tag">Deactivate</a>
|
||||
{{else if .Installable}}
|
||||
{{/** TO-DO: Write a custom template interpreter to fix this nonsense **/}}
|
||||
{{if .Installed}}<a href="/panel/plugins/activate/{{.UName}}?session={{$.CurrentUser.Session}}" class="panel_tag">Activate</a>{{else}}<a href="/panel/plugins/install/{{.UName}}?session={{$.CurrentUser.Session}}" class="panel_tag">Install</a>{{end}}
|
||||
{{else}}<a href="/panel/plugins/activate/{{.UName}}?session={{$.CurrentUser.Session}}" class="panel_tag">Activate</a>{{end}}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{{template "panel-menu.html" . }}
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Edit Setting</a></div>
|
||||
<div class="rowitem"><a>Edit Setting</a></div>
|
||||
</div>
|
||||
<div id="panel_setting" class="colstack_item">
|
||||
<form action="/panel/settings/edit/submit/{{.Something.Name}}?session={{.CurrentUser.Session}}" method="post">
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{{template "panel-menu.html" . }}
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Settings</a></div>
|
||||
<div class="rowitem"><a>Settings</a></div>
|
||||
</div>
|
||||
<div id="panel_settings" class="colstack_item">
|
||||
{{range $key, $value := .Something}}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="colstack_left">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a href="/panel/themes/">Theme Manager</a></div>
|
||||
<div class="rowitem"><a href="/panel/themes/">Theme Manager</a></div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
<div class="rowitem passive"><a href="#">Widgets</a></div>
|
||||
|
@ -20,7 +20,7 @@
|
|||
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Primary Themes</a></div>
|
||||
<div class="rowitem"><a>Primary Themes</a></div>
|
||||
</div>
|
||||
<div id="panel_primary_themes" class="colstack_item panel_themes">
|
||||
{{range .PrimaryThemes}}
|
||||
|
@ -38,7 +38,7 @@
|
|||
{{end}}
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Variant Themes</a></div>
|
||||
<div class="rowitem"><a>Variant Themes</a></div>
|
||||
</div>
|
||||
<div id="panel_variant_themes" class="colstack_item panel_themes">
|
||||
{{range .VariantThemes}}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{{template "panel-menu.html" . }}
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>User Editor</a></div>
|
||||
<div class="rowitem"><a>User Editor</a></div>
|
||||
</div>
|
||||
<div id="panel_user" class="colstack_item">
|
||||
<form action="/panel/users/edit/submit/{{.Something.ID}}?session={{.CurrentUser.Session}}" method="post">
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<div class="colstack_right">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem rowhead"><a>Users</a></div>
|
||||
<div class="rowitem"><a>Users</a></div>
|
||||
</div>
|
||||
<div id="panel_users" class="colstack_item">
|
||||
{{range .ItemList}}
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="colblock_right" style="width: calc(95% - 210px);">
|
||||
<div class="rowitem rowhead"><a>Comments</a></div>
|
||||
<div class="colblock_right rowhead" style="width: calc(95% - 210px);">
|
||||
<div class="rowitem"><a>Comments</a></div>
|
||||
</div>
|
||||
<div id="profile_comments" class="colblock_right" style="overflow: hidden;border-top: none;width:calc(95% - 210px);">{{range .ItemList}}
|
||||
<div class="rowitem passive deletable_block editable_parent simple" style="{{if .Avatar}}background-image: url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px {{if le .ContentLines 5}}-1{{end}}0px;background-repeat: no-repeat, repeat-y;background-size: 128px;padding-left: 136px;{{.Css}}{{end}}">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="rowblock">
|
||||
<div class="rowitem rowhead"><a>Create Account</a></div>
|
||||
<div class="rowblock rowhead">
|
||||
<div class="rowitem"><a>Create Account</a></div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
<form action="/accounts/create/submit/" method="post">
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="rowblock rowhead">
|
||||
<div class="rowitem"><a>Create Group</a></div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
<form action="/group/create/submit/" method="post">
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>Group Name</a></div>
|
||||
<div class="formitem"><input name="group_name" type="text" placeholder="Group Name" /></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>Description</a></div>
|
||||
<div class="formitem"><input name="group_desc" type="text" placeholder="Description" /></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>Visibility</a></div>
|
||||
<div class="formitem">
|
||||
<select name="group_privacy">
|
||||
<option val="0">Public</option>
|
||||
<option val="1">Protected</option>
|
||||
<option val="2">Private</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem"><button name="group_button" class="formbutton">Create Group</button></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{template "footer.html" . }}
|
|
@ -0,0 +1,48 @@
|
|||
<style>
|
||||
.miniMenu {
|
||||
min-height: 41px;
|
||||
border-top: 1px solid rgba(255,255,255,0.5);
|
||||
background-color: rgba(255,255,255,0.5);
|
||||
position: relative;
|
||||
top: 0px;
|
||||
z-index: 0;
|
||||
padding-top: 3px;
|
||||
}
|
||||
.menuItem:first-child {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.menuItem {
|
||||
float: left;
|
||||
min-height: 38px;
|
||||
padding: 10px;
|
||||
border-right: 1px solid rgba(204,204,204,0.9);
|
||||
background-color: rgba(255,255,255,0.9);
|
||||
margin-right: 5px;
|
||||
max-height: 30px;
|
||||
box-shadow: 0 7px 15px rgba(0,0,0,0.1);
|
||||
border-top: white;
|
||||
border-left: white;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
.menuItem:hover {
|
||||
top: 4px;
|
||||
}
|
||||
.menuItem a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
.rightMenu {
|
||||
float: right;
|
||||
border-right: none;
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
.sgBackdrop {
|
||||
background-image: url('/uploads/socialgroup_1.jpg');
|
||||
min-height: 150px;
|
||||
width: 100%;
|
||||
border: 1px solid #ccc;
|
||||
padding-top: calc(150px - 38px);
|
||||
border-bottom: none;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,19 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="rowblock opthead">
|
||||
<div class="rowitem"><a>Group List</a></div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
{{range .GroupList}}<div class="rowitem datarow">
|
||||
<span style="float: left;">
|
||||
<a href="{{.Link}}" style="">{{.Name}}</a>
|
||||
<br /><span class="rowsmall">{{.Desc}}</span>
|
||||
</span>
|
||||
<span style="float: right;">
|
||||
<span style="float: right;font-size: 14px;">{{.MemberCount}} members</span>
|
||||
<br /><span class="rowsmall">{{.LastUpdateTime}}</span>
|
||||
</span>
|
||||
<div style="clear: both;"></div>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive">There aren't any visible groups.</div>{{end}}
|
||||
</div>
|
||||
{{template "footer.html" . }}
|
|
@ -0,0 +1,34 @@
|
|||
{{template "header.html" . }}
|
||||
{{/** TO-DO: Move this into a CSS file **/}}
|
||||
{{template "socialgroups_css.html" . }}
|
||||
|
||||
{{/** TO-DO: Port the page template functions to the template interpreter **/}}
|
||||
{{if gt .Page 1}}<div id="prevFloat" class="prev_button"><a class="prev_link" href="/group/members/{{.SocialGroup.ID}}?page={{subtract .Page 1}}"><</a></div>{{end}}
|
||||
{{if ne .LastPage .Page}}<link rel="prerender" href="/group/members/{{.SocialGroup.ID}}?page={{add .Page 1}}" />
|
||||
<div id="nextFloat" class="next_button"><a class="next_link" href="/group/members/{{.SocialGroup.ID}}?page={{add .Page 1}}">></a></div>{{end}}
|
||||
|
||||
<div class="sgBackdrop">
|
||||
<div class="miniMenu">
|
||||
<div class="menuItem"><a href="#">Test Group</a></div>
|
||||
<div class="menuItem"><a href="#">About</a></div>
|
||||
<div class="menuItem"><a href="#">Members</a></div>
|
||||
<div class="menuItem rightMenu"><a href="#">Edit</a></div>
|
||||
<div class="menuItem rightMenu"><a href="/group/join/{{.SocialGroup.ID}}">Join</a></div>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
</div>
|
||||
<div id="socialgroups_member_list" class="rowblock member_list" style="position: relative;z-index: 50;">
|
||||
{{range .ItemList}}<div class="rowitem passive datarow" style="{{if .User.Avatar}}background-image: url({{.User.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 78px;{{end}}{{if .Offline}}background-color: #eaeaea;{{else if gt .Rank 0}}background-color: #e6f3ff;{{end}}">
|
||||
<span style="float: right;">
|
||||
<span class="rank" style="font-size: 15px;">{{.RankString}}</span><br />
|
||||
<span class="joinedAt rowsmall">{{.JoinedAt}}</span>
|
||||
</span>
|
||||
<span>
|
||||
<a class="rowtopic" href="{{.Link}}">{{.User.Name}}</a>
|
||||
{{/** Use this for badges instead of rank? Both? Group Titles? **/}}
|
||||
<br /><span class="rowsmall postCount">{{.PostCount}} posts</span>
|
||||
</span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{template "footer.html" . }}
|
|
@ -0,0 +1,34 @@
|
|||
{{template "header.html" . }}
|
||||
{{/** TO-DO: Move this into a CSS file **/}}
|
||||
{{template "socialgroups_css.html" . }}
|
||||
|
||||
{{/** TO-DO: Port the page template functions to the template interpreter **/}}
|
||||
{{if gt .Page 1}}<div id="prevFloat" class="prev_button"><a class="prev_link" href="/group/{{.SocialGroup.ID}}?page={{subtract .Page 1}}"><</a></div>{{end}}
|
||||
{{if ne .LastPage .Page}}<link rel="prerender" href="/group/{{.SocialGroup.ID}}?page={{add .Page 1}}" />
|
||||
<div id="nextFloat" class="next_button"><a class="next_link" href="/group/{{.SocialGroup.ID}}?page={{add .Page 1}}">></a></div>{{end}}
|
||||
|
||||
<div class="sgBackdrop">
|
||||
<div class="miniMenu">
|
||||
<div class="menuItem"><a href="#">Test Group</a></div>
|
||||
<div class="menuItem"><a href="#">About</a></div>
|
||||
<div class="menuItem"><a href="#">Members</a></div>
|
||||
<div class="menuItem rightMenu"><a href="#">Edit</a></div>
|
||||
<div class="menuItem rightMenu"><a href="/group/join/{{.SocialGroup.ID}}">Join</a></div>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
</div>
|
||||
<div id="forum_topic_list" class="rowblock topic_list" style="position: relative;z-index: 50;">
|
||||
{{range .ItemList}}<div class="rowitem passive datarow" style="{{if .Avatar}}background-image: url({{.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}}">
|
||||
<span class="rowsmall" style="float: right;">
|
||||
<span class="replyCount">{{.PostCount}} replies</span><br />
|
||||
<span class="lastReplyAt">{{.LastReplyAt}}</span>
|
||||
</span>
|
||||
<span>
|
||||
<a class="rowtopic" href="/topic/{{.Slug}}.{{.ID}}">{{.Title}}</a>
|
||||
<br /><a class="rowsmall" href="/user/{{.UserSlug}}.{{.CreatedBy}}">Starter: {{.CreatedByName}}</a>
|
||||
{{if .Is_Closed}}<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎{{end}}</span>
|
||||
</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive">There aren't any topics in here yet.{{if .CurrentUser.Perms.CreateTopic}} <a href="/topics/create/{{.Forum.ID}}">Start one?</a>{{end}}</div>{{end}}
|
||||
</div>
|
||||
{{template "footer.html" . }}
|
|
@ -7,9 +7,9 @@
|
|||
<a class="next_link" href="/topic/{{.Topic.ID}}?page={{add .Page 1}}">></a>
|
||||
</div>{{end}}
|
||||
|
||||
<div class="rowblock topic_block">
|
||||
<div class="rowblock rowhead topic_block">
|
||||
<form action='/topic/edit/submit/{{.Topic.ID}}' method="post">
|
||||
<div class="rowitem rowhead topic_item"{{if .Topic.Sticky}} style="background-color:#FFFFEA;"{{else if .Topic.Is_Closed}} style="background-color:#eaeaea;"{{end}}>
|
||||
<div class="rowitem topic_item"{{if .Topic.Sticky}} style="background-color:#FFFFEA;"{{else if .Topic.Is_Closed}} style="background-color:#eaeaea;"{{end}}>
|
||||
<a class='topic_name hide_on_edit'>{{.Topic.Title}}</a>
|
||||
{{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 .CurrentUser.Perms.EditTopic}}
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
{{if ne .LastPage .Page}}<link rel="prerender" href="/topic/{{.Topic.ID}}?page={{add .Page 1}}" />
|
||||
<div id="nextFloat" class="next_button"><a class="next_link" href="/topic/{{.Topic.ID}}?page={{add .Page 1}}">></a></div>{{end}}
|
||||
|
||||
<div class="rowblock topic_block">
|
||||
<div class="rowblock rowhead topic_block">
|
||||
<form action='/topic/edit/submit/{{.Topic.ID}}' method="post">
|
||||
<div class="rowitem topic_item rowhead{{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.Is_Closed}} topic_closed_head{{end}}">
|
||||
<a class='topic_name hide_on_edit'>{{.Topic.Title}}</a>
|
||||
{{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 .CurrentUser.Perms.EditTopic}}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="rowblock">
|
||||
<div class="rowitem rowhead"><a>Topic List</a></div>
|
||||
<div class="rowblock rowhead">
|
||||
<div class="rowitem"><a>Topic List</a></div>
|
||||
</div>
|
||||
<div id="topic_list" class="rowblock topic_list">
|
||||
{{range .ItemList}}<div class="rowitem passive datarow" style="{{if .Avatar}}background-image: url({{.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 passive datarow {{if .Sticky}}topic_sticky{{else if .Is_Closed}}topic_closed{{end}}" style="{{if .Avatar}}background-image: url({{.Avatar}});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}">
|
||||
<span class="rowsmall" style="float: right;">
|
||||
<span class="replyCount">{{.PostCount}} replies</span><br />
|
||||
<span class="lastReplyAt">{{.LastReplyAt}}</span>
|
||||
</span>
|
||||
<span>
|
||||
<a class="rowtopic" href="/topic/{{.Slug}}.{{.ID}}">{{.Title}}</a> {{if .ForumName}}<a class="rowsmall" href="/forum/{{.ParentID}}">{{.ForumName}}</a>{{end}}
|
||||
<a class="rowtopic" href="/topic/{{.Slug}}.{{.ID}}">{{.Title}}</a> {{if .ForumName}}<a class="rowsmall" href="{{.ForumLink}}">{{.ForumName}}</a>{{end}}
|
||||
<br /><a class="rowsmall" href="/user/{{.UserSlug}}.{{.CreatedBy}}">Starter: {{.CreatedByName}}</a>
|
||||
{{if .Is_Closed}}<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎{{end}}</span>
|
||||
</span>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<div class="rowblock rowhead">
|
||||
<div class="rowitem">{{.Name}}</div>
|
||||
</div>
|
||||
<div class="rowblock">{{range .MenuList}}
|
||||
<div class="rowitem {{if .Compact}}datarow{{end}}"><a href="{{.Location}}">{{.Text}}</a></div>
|
||||
{{end}}</div>
|
|
@ -1,5 +1,5 @@
|
|||
<div class="rowblock">
|
||||
<div class="rowitem rowhead">{{.Name}}</div>
|
||||
<div class="rowblock rowhead">
|
||||
<div class="rowitem">{{.Name}}</div>
|
||||
</div>
|
||||
<div class="rowblock">
|
||||
<div class="rowitem">{{.Text}}</div>
|
||||
|
|
|
@ -140,7 +140,7 @@ func init_themes() {
|
|||
theme.Active = false // Set this to false, just in case someone explicitly overrode this value in the JSON file
|
||||
|
||||
if theme.FullImage != "" {
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Adding theme image")
|
||||
}
|
||||
err = add_static_file("./themes/" + themeName + "/" + theme.FullImage, "./themes/" + themeName)
|
||||
|
@ -155,7 +155,7 @@ func init_themes() {
|
|||
|
||||
func add_theme_static_files(theme Theme) {
|
||||
err := filepath.Walk("./themes/" + theme.Name + "/public", func(path string, f os.FileInfo, err error) error {
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Attempting to add static file '" + path + "' for default theme '" + theme.Name + "'")
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -190,7 +190,7 @@ func add_theme_static_files(theme Theme) {
|
|||
gzip_data := compress_bytes_gzip(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)}
|
||||
|
||||
if debug {
|
||||
if debug_mode {
|
||||
log.Print("Added the '" + path + "' static file for default theme " + theme.Name + ".")
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -151,12 +151,13 @@ li:hover {
|
|||
|
||||
hr { color: silver; border: 1px solid silver; }
|
||||
|
||||
.rowhead {
|
||||
/* I HATE CSS for being so incompetently designed that I have to declare this for THREE different elements rather than just having a statement go back up the tree. What on earth is the W3C doing?! */
|
||||
.rowhead .rowitem, .colstack_head .rowitem, .opthead .rowitem {
|
||||
border-top: none;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
}
|
||||
.rowhead:hover {
|
||||
.rowhead .rowitem:hover, .colstack_head .rowItem:hover, .opthead .rowitem:hover {
|
||||
color: rgba(200,200,200,1);
|
||||
transition: color 1s;
|
||||
-moz-transition: color 1s;
|
||||
|
@ -192,7 +193,7 @@ hr { color: silver; border: 1px solid silver; }
|
|||
font-size:12px;
|
||||
}
|
||||
|
||||
.rowhead, .colhead {
|
||||
.rowhead .rowitem, .colhead, .opthead .rowitem, .colstack_head .rowitem {
|
||||
background: #ce2424;
|
||||
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#f97779), to(#ce2424));
|
||||
background: -moz-linear-gradient(#f97779, #ce2424);
|
||||
|
@ -213,13 +214,45 @@ hr { color: silver; border: 1px solid silver; }
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.rowhead a { color: white; display: block; padding-top: 5px; }
|
||||
.rowhead span { display: block; padding-top: 5px; }
|
||||
.colhead a { color: white; display: block; padding-top: 5px; }
|
||||
.colhead span { display: block; padding-top: 5px; }
|
||||
.show_on_edit { display: none; }
|
||||
.rowhead .topic_status_e { display: none !important; }
|
||||
.topic_button { float: right; position: relative; top: -22px; margin-right: 2px; border-style: solid !important; }
|
||||
.rowhead a, .opthead a, .colstack_head a {
|
||||
color: white;
|
||||
display: block;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.rowhead span, .opthead span, .colstack_head span {
|
||||
display: block;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.colhead a {
|
||||
color: white;
|
||||
display: block;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.colhead span {
|
||||
display: block;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.show_on_edit {
|
||||
display: none;
|
||||
}
|
||||
.rowhead .topic_status_e, .opthead .topic_status_e, .colstack_head .topic_status_e {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.topic_sticky {
|
||||
background-color: rgb(255,255,234);
|
||||
}
|
||||
.topic_closed {
|
||||
background-color: rgb(248,248,248);
|
||||
}
|
||||
|
||||
.topic_button {
|
||||
float: right;
|
||||
position: relative;
|
||||
top: -22px;
|
||||
margin-right: 2px;
|
||||
border-style: solid !important;
|
||||
}
|
||||
|
||||
.colblock_left {
|
||||
padding: 0px;
|
||||
|
@ -736,8 +769,15 @@ blockquote p {
|
|||
background-image: -webkit-linear-gradient(bottom, #4c4c4c, #2e2e2e);
|
||||
}
|
||||
|
||||
.rowblock { border-left: none; border-right: none; border-bottom: none; }
|
||||
.rowitem, .rowhead, .tbody { border-left: none; border-right: none; }
|
||||
.rowblock {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
.rowitem, .tbody {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width: 620px) {
|
||||
|
|
|
@ -139,12 +139,13 @@ li:hover {
|
|||
|
||||
hr { color: silver; border: 1px solid silver; }
|
||||
|
||||
.rowhead {
|
||||
/* I HATE CSS for being so incompetently designed that I have to declare this for THREE different elements rather than just having a statement go back up the tree. What on earth is the W3C doing?! */
|
||||
.rowhead .rowitem, .opthead .rowitem, .colstack_head .rowitem {
|
||||
border-top: none;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
}
|
||||
.rowhead:hover {
|
||||
.rowhead .rowitem:hover, .opthead .rowitem:hover, .colstack_head .rowitem:hover {
|
||||
color: rgba(200,200,200,1);
|
||||
transition: color 1s;
|
||||
-moz-transition: color 1s;
|
||||
|
@ -179,7 +180,7 @@ hr { color: silver; border: 1px solid silver; }
|
|||
font-size:12px;
|
||||
}
|
||||
|
||||
.rowhead, .colhead {
|
||||
.rowhead .rowitem, .opthead .rowitem, .colstack_head .rowitem, .colhead {
|
||||
background: #ce2424;
|
||||
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#f97779), to(#ce2424));
|
||||
background: -moz-linear-gradient(#f97779, #ce2424);
|
||||
|
@ -200,13 +201,36 @@ hr { color: silver; border: 1px solid silver; }
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.rowhead a { color: white; display: block; padding-top: 5px; }
|
||||
.rowhead span { display: block; padding-top: 5px; }
|
||||
.rowhead a, .opthead a, .colstack_head a {
|
||||
color: white;
|
||||
display: block;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.rowhead span, .opthead span, .colstack_head span {
|
||||
display: block;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.colhead a { color: white; display: block; padding-top: 5px; }
|
||||
.colhead span { display: block; padding-top: 5px; }
|
||||
.show_on_edit { display: none; }
|
||||
.rowhead .topic_status_e { display: none !important; }
|
||||
.topic_button { float: right; position: relative; top: -22px; margin-right: 2px; border-style: solid !important; }
|
||||
.rowhead .topic_status_e, .opthead .topic_status_e, .colstack_head .topic_status_e {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.topic_sticky {
|
||||
background-color: rgb(255,255,234);
|
||||
}
|
||||
.topic_closed {
|
||||
background-color: rgb(248,248,248);
|
||||
}
|
||||
|
||||
.topic_button {
|
||||
float: right;
|
||||
position: relative;
|
||||
top: -22px;
|
||||
margin-right: 2px;
|
||||
border-style: solid !important;
|
||||
}
|
||||
|
||||
.colblock_left {
|
||||
padding: 0px;
|
||||
|
@ -748,10 +772,19 @@ blockquote p {
|
|||
background-image: -webkit-linear-gradient(bottom, #4c4c4c, #2e2e2e);
|
||||
}
|
||||
|
||||
.rowblock { border-left: none; border-right: none; border-bottom: none; }
|
||||
.rowitem { border-left: none; border-right: none; }
|
||||
.rowhead { border-left: none; border-right: none; }
|
||||
.tbody { border-left: none; border-right: none; }
|
||||
.rowblock {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
.rowitem {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
.tbody {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
.forumLastposter { width: 35%; }
|
||||
.forumLastposter .title { width: 90px; }
|
||||
.cell_author img { display: none; }
|
||||
|
|
|
@ -301,6 +301,14 @@ button {
|
|||
}
|
||||
|
||||
/* Topics */
|
||||
|
||||
.topic_sticky {
|
||||
background-color: rgb(255,255,234);
|
||||
}
|
||||
.topic_closed {
|
||||
background-color: rgb(248,248,248);
|
||||
}
|
||||
|
||||
.topic_status {
|
||||
text-transform: none;
|
||||
margin-left: 8px;
|
||||
|
@ -314,7 +322,9 @@ button {
|
|||
}
|
||||
.topic_status:empty { display: none; }
|
||||
|
||||
.rowhead { background: linear-gradient(to bottom, white, hsl(0, 0%, 93%)); }
|
||||
.rowhead .rowitem, .opthead .rowitem, .colstack_head .rowitem {
|
||||
background: linear-gradient(to bottom, white, hsl(0, 0%, 93%));
|
||||
}
|
||||
.topic_sticky_head {
|
||||
background-color: #FFFFEA;
|
||||
background: linear-gradient(to bottom, hsl(60, 70%, 96%), hsl(60, 70%, 89%)), url('/static/fabric-base-simple-alpha.png');
|
||||
|
|
|
@ -299,6 +299,14 @@ button {
|
|||
}
|
||||
|
||||
/* Topics */
|
||||
|
||||
.topic_sticky {
|
||||
background-color: rgb(255,255,234);
|
||||
}
|
||||
.topic_closed {
|
||||
background-color: rgb(248,248,248);
|
||||
}
|
||||
|
||||
.topic_status {
|
||||
text-transform: none;
|
||||
margin-left: 8px;
|
||||
|
|
|
@ -18,7 +18,7 @@ ul {
|
|||
height: 36px;
|
||||
list-style-type: none;
|
||||
border: 1px solid #ccc;
|
||||
background-color: white;
|
||||
background-color: rgb(248,248,248);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
li {
|
||||
|
@ -26,6 +26,8 @@ li {
|
|||
padding-left: 10px;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
background: white;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
li:hover { background: rgb(250,250,250); }
|
||||
li a {
|
||||
|
@ -101,7 +103,7 @@ li a {
|
|||
padding: 8px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-top: 15px;
|
||||
padding-top: 17px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.alertItem.withAvatar {
|
||||
|
@ -220,6 +222,13 @@ li a {
|
|||
.stat_red { background-color: #ffb2b2; border-color: #ffb2b2; }
|
||||
.stat_disabled { background-color: lightgray; border-color: lightgray; }
|
||||
|
||||
.rowhead {
|
||||
border-bottom: none;
|
||||
}
|
||||
.rowhead .rowitem, .colstack_head .rowitem {
|
||||
background-color: rgb(252,252,252);
|
||||
}
|
||||
|
||||
.rowitem {
|
||||
width: 100%;
|
||||
/*padding-left: 8px;
|
||||
|
@ -242,6 +251,27 @@ li a {
|
|||
.top_post { margin-bottom: 12px; }
|
||||
.opthead { display: none; }
|
||||
|
||||
.rowitem.has_opt {
|
||||
float: left;
|
||||
width: calc(100% - 50px);
|
||||
border-right: 1px solid #ccc;
|
||||
border-bottom: none;
|
||||
}
|
||||
.opt {
|
||||
float: left;
|
||||
font-size: 32px;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
.create_topic_opt {
|
||||
color: rgb(120,120,120);
|
||||
}
|
||||
.locked_opt {
|
||||
color: rgb(80,80,80);
|
||||
}
|
||||
|
||||
.datarow {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
|
@ -302,6 +332,14 @@ button {
|
|||
}
|
||||
|
||||
/* Topics */
|
||||
|
||||
.topic_sticky {
|
||||
background-color: rgb(255,255,234);
|
||||
}
|
||||
.topic_closed {
|
||||
background-color: rgb(248,248,248);
|
||||
}
|
||||
|
||||
.topic_status {
|
||||
text-transform: none;
|
||||
margin-left: 8px;
|
||||
|
|
7
topic.go
|
@ -71,7 +71,7 @@ type TopicsRow struct
|
|||
LastReplyAt string
|
||||
//LastReplyBy int
|
||||
ParentID int
|
||||
Status string // Deprecated. Marked for removal.
|
||||
Status string // Deprecated. Marked for removal. -Is there anything we could use it for?
|
||||
IpAddress string
|
||||
PostCount int
|
||||
LikeCount int
|
||||
|
@ -89,6 +89,7 @@ type TopicsRow struct
|
|||
Level int
|
||||
|
||||
ForumName string //TopicsRow
|
||||
ForumLink string
|
||||
}
|
||||
|
||||
func get_topicuser(tid int) (TopicUser,error) {
|
||||
|
@ -170,3 +171,7 @@ func build_topic_url(slug string, tid int) string {
|
|||
}
|
||||
return "/topic/" + slug + "." + strconv.Itoa(tid)
|
||||
}
|
||||
|
||||
func get_topic_url_prefix() string {
|
||||
return "/topic/"
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import "sync"
|
|||
import "database/sql"
|
||||
import "./query_gen/lib"
|
||||
|
||||
// TO-DO: Add the watchdog goroutine
|
||||
var topics TopicStore
|
||||
|
||||
type TopicStore interface {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
echo "Updating the MySQL Driver"
|
||||
go get -u github.com/go-sql-driver/mysql
|
||||
echo "Updating the PostgreSQL Driver"
|
||||
go get -u github.com/lib/pq
|
||||
echo "Updating bcrypt"
|
||||
go get -u golang.org/x/crypto/bcrypt
|
||||
echo "Updating gopsutil"
|
||||
|
|
|
@ -5,6 +5,12 @@ if %errorlevel% neq 0 (
|
|||
pause
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
echo Updating the PostgreSQL Driver
|
||||
go get -u github.com/lib/pq
|
||||
if %errorlevel% neq 0 (
|
||||
pause
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Updating bcrypt
|
||||
go get -u golang.org/x/crypto/bcrypt
|
||||
|
|
112
user.go
|
@ -12,9 +12,13 @@ import (
|
|||
)
|
||||
|
||||
var guest_user User = User{ID:0,Group:6,Perms:GuestPerms}
|
||||
var SimpleSessionCheck func(http.ResponseWriter, *http.Request) (User,bool) = _simple_session_check
|
||||
var PanelSessionCheck func(http.ResponseWriter, *http.Request) (User,HeaderVars,bool) = _panel_session_check
|
||||
var SimplePanelSessionCheck func(http.ResponseWriter, *http.Request) (User,bool) = _simple_panel_session_check
|
||||
var PreRoute func(http.ResponseWriter, *http.Request) (User,bool) = _pre_route
|
||||
var PanelSessionCheck func(http.ResponseWriter, *http.Request, *User) (HeaderVars,bool) = _panel_session_check
|
||||
var SimplePanelSessionCheck func(http.ResponseWriter, *http.Request, *User) 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 ForumSessionCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars HeaderVars, success bool) = _forum_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
|
||||
|
||||
type User struct
|
||||
{
|
||||
|
@ -30,11 +34,12 @@ type User struct
|
|||
Is_Super_Admin bool
|
||||
Is_Banned bool
|
||||
Perms Perms
|
||||
PluginPerms map[string]bool
|
||||
Session string
|
||||
Loggedin bool
|
||||
Avatar string
|
||||
Message string
|
||||
URLPrefix string
|
||||
URLPrefix string // Move this to another table? Create a user lite?
|
||||
URLName string
|
||||
Tag string
|
||||
Level int
|
||||
|
@ -51,7 +56,7 @@ type Email struct
|
|||
Token string
|
||||
}
|
||||
|
||||
func CheckPassword(real_password string, password string, salt string) (err error) {
|
||||
func BcryptCheckPassword(real_password string, password string, salt string) (err error) {
|
||||
return bcrypt.CompareHashAndPassword([]byte(real_password), []byte(password + salt))
|
||||
}
|
||||
|
||||
|
@ -86,7 +91,14 @@ func SendValidationEmail(username string, email string, token string) bool {
|
|||
}
|
||||
|
||||
// TO-DO: Support for left sidebars and sidebars on both sides
|
||||
func BuildWidgets(zone string, data interface{}, headerVars *HeaderVars) {
|
||||
// http.Request is for context.Context middleware. Mostly for plugin_socialgroups right now
|
||||
func BuildWidgets(zone string, data interface{}, headerVars *HeaderVars, r *http.Request) {
|
||||
if vhooks["intercept_build_widgets"] != nil {
|
||||
if run_vhook("intercept_build_widgets", zone, data, headerVars, r).(bool) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//fmt.Println("themes[defaultTheme].Sidebars",themes[defaultTheme].Sidebars)
|
||||
if themes[defaultTheme].Sidebars == "right" {
|
||||
if len(docks.RightSidebar) != 0 {
|
||||
|
@ -103,11 +115,17 @@ func BuildWidgets(zone string, data interface{}, headerVars *HeaderVars) {
|
|||
}
|
||||
}
|
||||
|
||||
func SimpleForumSessionCheck(w http.ResponseWriter, r *http.Request, fid int) (user User, success bool) {
|
||||
user, success = SimpleSessionCheck(w,r)
|
||||
func _simple_forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fid int) (success bool) {
|
||||
if !fstore.Exists(fid) {
|
||||
PreError("The target forum doesn't exist.",w,r)
|
||||
return user, false
|
||||
return false
|
||||
}
|
||||
|
||||
// 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 run_vhook("simple_forum_check_pre_perms", w, r, user, &fid, &success).(bool) {
|
||||
return success
|
||||
}
|
||||
}
|
||||
|
||||
fperms := groups[user.Group].Forums[fid]
|
||||
|
@ -125,18 +143,24 @@ func SimpleForumSessionCheck(w http.ResponseWriter, r *http.Request, fid int) (u
|
|||
|
||||
if len(fperms.ExtData) != 0 {
|
||||
for name, perm := range fperms.ExtData {
|
||||
user.Perms.ExtData[name] = perm
|
||||
user.PluginPerms[name] = perm
|
||||
}
|
||||
}
|
||||
}
|
||||
return user, success
|
||||
return true
|
||||
}
|
||||
|
||||
func ForumSessionCheck(w http.ResponseWriter, r *http.Request, fid int) (user User, headerVars HeaderVars, success bool) {
|
||||
user, headerVars, success = SessionCheck(w,r)
|
||||
func _forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars HeaderVars, success bool) {
|
||||
headerVars, success = SessionCheck(w,r,user)
|
||||
if !fstore.Exists(fid) {
|
||||
NotFound(w,r)
|
||||
return user, headerVars, false
|
||||
return headerVars, false
|
||||
}
|
||||
|
||||
if vhooks["forum_check_pre_perms"] != nil {
|
||||
if run_vhook("forum_check_pre_perms", w, r, user, &fid, &success, &headerVars).(bool) {
|
||||
return headerVars, success
|
||||
}
|
||||
}
|
||||
|
||||
fperms := groups[user.Group].Forums[fid]
|
||||
|
@ -156,19 +180,18 @@ func ForumSessionCheck(w http.ResponseWriter, r *http.Request, fid int) (user Us
|
|||
|
||||
if len(fperms.ExtData) != 0 {
|
||||
for name, perm := range fperms.ExtData {
|
||||
user.Perms.ExtData[name] = perm
|
||||
user.PluginPerms[name] = perm
|
||||
}
|
||||
}
|
||||
}
|
||||
return user, headerVars, success
|
||||
return headerVars, success
|
||||
}
|
||||
|
||||
// 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, success bool) {
|
||||
user, success = SimpleSessionCheck(w,r)
|
||||
func _panel_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerVars HeaderVars, success bool) {
|
||||
if !user.Is_Super_Mod {
|
||||
NoPermissions(w,r,user)
|
||||
return user, headerVars, false
|
||||
NoPermissions(w,r,*user)
|
||||
return headerVars, false
|
||||
}
|
||||
|
||||
headerVars.Stylesheets = append(headerVars.Stylesheets,"panel.css")
|
||||
|
@ -189,19 +212,17 @@ func _panel_session_check(w http.ResponseWriter, r *http.Request) (user User, he
|
|||
}
|
||||
}
|
||||
|
||||
return user, headerVars, success
|
||||
return headerVars, true
|
||||
}
|
||||
func _simple_panel_session_check(w http.ResponseWriter, r *http.Request) (user User, success bool) {
|
||||
user, success = SimpleSessionCheck(w,r)
|
||||
func _simple_panel_session_check(w http.ResponseWriter, r *http.Request, user *User) (success bool) {
|
||||
if !user.Is_Super_Mod {
|
||||
NoPermissions(w,r,user)
|
||||
return user, false
|
||||
NoPermissions(w,r,*user)
|
||||
return false
|
||||
}
|
||||
return user, success
|
||||
return true
|
||||
}
|
||||
|
||||
func SessionCheck(w http.ResponseWriter, r *http.Request) (user User, headerVars HeaderVars, success bool) {
|
||||
user, success = SimpleSessionCheck(w,r)
|
||||
func _session_check(w http.ResponseWriter, r *http.Request, user *User) (headerVars HeaderVars, success bool) {
|
||||
if user.Is_Banned {
|
||||
headerVars.NoticeList = append(headerVars.NoticeList,"Your account has been suspended. Some of your permissions may have been revoked.")
|
||||
}
|
||||
|
@ -223,41 +244,24 @@ func SessionCheck(w http.ResponseWriter, r *http.Request) (user User, headerVars
|
|||
}
|
||||
}
|
||||
|
||||
return user, headerVars, success
|
||||
return headerVars, true
|
||||
}
|
||||
|
||||
func _simple_session_check(w http.ResponseWriter, r *http.Request) (User,bool) {
|
||||
// Are there any session cookies..?
|
||||
cookie, err := r.Cookie("uid")
|
||||
if err != nil {
|
||||
return guest_user, true
|
||||
func _pre_route(w http.ResponseWriter, r *http.Request) (User,bool) {
|
||||
user, halt := auth.SessionCheck(w,r)
|
||||
if halt {
|
||||
return *user, false
|
||||
}
|
||||
uid, err := strconv.Atoi(cookie.Value)
|
||||
if err != nil {
|
||||
return guest_user, true
|
||||
}
|
||||
cookie, err = r.Cookie("session")
|
||||
if err != nil {
|
||||
return guest_user, true
|
||||
}
|
||||
|
||||
// Is this session valid..?
|
||||
user, err := users.CascadeGet(uid)
|
||||
if err == ErrNoRows {
|
||||
return guest_user, true
|
||||
} else if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return guest_user, false
|
||||
}
|
||||
|
||||
if user.Session == "" || cookie.Value != user.Session {
|
||||
return guest_user, true
|
||||
if user == &guest_user {
|
||||
return *user, true
|
||||
}
|
||||
|
||||
if user.Is_Super_Admin {
|
||||
user.Perms = AllPerms
|
||||
user.PluginPerms = AllPluginPerms
|
||||
} else {
|
||||
user.Perms = groups[user.Group].Perms
|
||||
user.PluginPerms = groups[user.Group].PluginPerms
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
|
|