diff --git a/database.go b/database.go index 61617efc..ea501d9a 100644 --- a/database.go +++ b/database.go @@ -6,6 +6,7 @@ import "database/sql" var db *sql.DB var db_version string +var db_adapter string var ErrNoRows = sql.ErrNoRows diff --git a/errors.go b/errors.go index f2e5a335..b4b2e302 100644 --- a/errors.go +++ b/errors.go @@ -6,6 +6,9 @@ import "bytes" import "net/http" import "runtime/debug" +//var notfound_count_per_second int +//var noperms_count_per_second int + var error_internal []byte var error_notfound []byte func init_errors() error { diff --git a/forum_store.go b/forum_store.go index 7fcbe517..e192c96e 100644 --- a/forum_store.go +++ b/forum_store.go @@ -35,6 +35,8 @@ type ForumStore interface //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) + + GetGlobalCount() int } type StaticForumStore struct @@ -45,6 +47,7 @@ type StaticForumStore struct get *sql.Stmt get_all *sql.Stmt + forum_count *sql.Stmt } func NewStaticForumStore() *StaticForumStore { @@ -56,9 +59,14 @@ func NewStaticForumStore() *StaticForumStore { if err != nil { log.Fatal(err) } + forum_count_stmt, err := qgen.Builder.SimpleCount("forums","name != ''","") + if err != nil { + log.Fatal(err) + } return &StaticForumStore{ get: get_stmt, get_all: get_all_stmt, + forum_count: forum_count_stmt, } } @@ -322,6 +330,17 @@ func (sfs *StaticForumStore) fill_forum_id_gap(biggerID int, smallerID int) { } } +// Return the total number of forums +// TO-DO: Get the total count of forums in the forum store minus the blanked forums rather than doing a heavy query for this? +func (sfs *StaticForumStore) GetGlobalCount() int { + var fcount int + err := sfs.forum_count.QueryRow().Scan(&fcount) + if err != nil { + LogError(err) + } + return fcount +} + // TO-DO: Work on MapForumStore // TO-DO: Work on SqlForumStore diff --git a/gen_mysql.go b/gen_mysql.go index f15a9931..1dd57bcb 100644 --- a/gen_mysql.go +++ b/gen_mysql.go @@ -108,6 +108,7 @@ var delete_topic_stmt *sql.Stmt var delete_profile_reply_stmt *sql.Stmt var delete_forum_perms_by_forum_stmt *sql.Stmt var report_exists_stmt *sql.Stmt +var group_count_stmt *sql.Stmt var add_forum_perms_to_forum_admins_stmt *sql.Stmt var add_forum_perms_to_forum_staff_stmt *sql.Stmt var add_forum_perms_to_forum_members_stmt *sql.Stmt @@ -724,6 +725,12 @@ func _gen_mysql() (err error) { return err } + log.Print("Preparing group_count statement.") + group_count_stmt, err = db.Prepare("SELECT COUNT(*) AS `count` FROM `users_groups`") + if err != nil { + return err + } + log.Print("Preparing add_forum_perms_to_forum_admins statement.") add_forum_perms_to_forum_admins_stmt, err = db.Prepare("INSERT INTO `forums_permissions`(`gid`,`fid`,`preset`,`permissions`) SELECT `gid`, ? AS `fid`, ? AS `preset`, ? AS `permissions` FROM `users_groups` WHERE `is_admin` = 1") if err != nil { diff --git a/gen_router.go b/gen_router.go index b327c95c..a257cb4f 100644 --- a/gen_router.go +++ b/gen_router.go @@ -50,7 +50,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { // default_route(w,req) // return //} - if req.URL.Path[0] != '/' { + if len(req.URL.Path) == 0 || req.URL.Path[0] != '/' { w.WriteHeader(405) w.Write([]byte("")) return @@ -198,6 +198,9 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { case "/panel/logs/mod/": route_panel_logs_mod(w,req,user) return + case "/panel/debug/": + route_panel_debug(w,req,user) + return default: route_panel(w,req,user) return diff --git a/install/install.go b/install/install.go index a0ee4972..56dec0a8 100644 --- a/install/install.go +++ b/install/install.go @@ -145,6 +145,7 @@ site.Url = "` + site_url + `" site.Port = "` + server_port + `" site.EnableSsl = false site.EnableEmails = false +site.HasProxy = false // Cloudflare counts as this, if it's sitting in the middle config.SslPrivkey = "" config.SslFullchain = "" diff --git a/main.go b/main.go index 2491fd61..296efdd0 100644 --- a/main.go +++ b/main.go @@ -210,15 +210,59 @@ func init_templates() { } compile_templates() - // Filler functions for now... - filler_func := func(in interface{}, in2 interface{})interface{} { - return 1 - } + // TO-DO: Add support for 64-bit integers + // TO-DO: Add support for floats fmap := make(map[string]interface{}) - fmap["add"] = filler_func - fmap["subtract"] = filler_func - fmap["multiply"] = filler_func - fmap["divide"] = filler_func + fmap["add"] = func(left interface{}, right interface{})interface{} { + var left_int int + var right_int int + switch left := left.(type) { + case uint, uint8, uint16, int, int32: left_int = left.(int) + } + switch right := right.(type) { + case uint, uint8, uint16, int, int32: right_int = right.(int) + } + return left_int + right_int + } + + fmap["subtract"] = func(left interface{}, right interface{})interface{} { + var left_int int + var right_int int + switch left := left.(type) { + case uint, uint8, uint16, int, int32: left_int = left.(int) + } + switch right := right.(type) { + case uint, uint8, uint16, int, int32: right_int = right.(int) + } + return left_int - right_int + } + + fmap["multiply"] = func(left interface{}, right interface{})interface{} { + var left_int int + var right_int int + switch left := left.(type) { + case uint, uint8, uint16, int, int32: left_int = left.(int) + } + switch right := right.(type) { + case uint, uint8, uint16, int, int32: right_int = right.(int) + } + return left_int * right_int + } + + fmap["divide"] = func(left interface{}, right interface{})interface{} { + var left_int int + var right_int int + switch left := left.(type) { + case uint, uint8, uint16, int, int32: left_int = left.(int) + } + switch right := right.(type) { + case uint, uint8, uint16, int, int32: right_int = right.(int) + } + if left_int == 0 || right_int == 0 { + return 0 + } + return left_int / right_int + } // The interpreted templates... if dev.DebugMode { @@ -377,6 +421,7 @@ func main(){ ///router.HandleFunc("/panel/groups/edit/perms/submit/", route_panel_groups_edit_perms_submit) ///router.HandleFunc("/panel/groups/create/", route_panel_groups_create_submit) ///router.HandleFunc("/panel/logs/mod/", route_panel_logs_mod) + ///router.HandleFunc("/panel/debug/", route_panel_debug) ///router.HandleFunc("/api/", route_api) //router.HandleFunc("/exit/", route_exit) diff --git a/mysql.go b/mysql.go index ce502aa7..37efc475 100644 --- a/mysql.go +++ b/mysql.go @@ -4,6 +4,7 @@ package main import "log" +//import "time" import "database/sql" import _ "github.com/go-sql-driver/mysql" import "./query_gen/lib" @@ -16,6 +17,10 @@ var todays_topic_count_stmt *sql.Stmt var todays_report_count_stmt *sql.Stmt var todays_newuser_count_stmt *sql.Stmt +func init() { + db_adapter = "mysql" +} + func _init_database() (err error) { var _dbpassword string if(db_config.Password != ""){ @@ -39,6 +44,10 @@ func _init_database() (err error) { // Set the number of max open connections db.SetMaxOpenConns(64) + db.SetMaxIdleConns(32) + + // Only hold connections open for five seconds to avoid accumulating a large number of stale connections + //db.SetConnMaxLifetime(5 * time.Second) // Build the generated prepared statements, we are going to slowly move the queries over to the query generator rather than writing them all by hand, this'll make it easier for us to implement database adapters for other databases like PostgreSQL, MSSQL, SQlite, etc. err = _gen_mysql() diff --git a/pages.go b/pages.go index 4d06a2e9..ddc6dec9 100644 --- a/pages.go +++ b/pages.go @@ -106,6 +106,39 @@ type CreateTopicPage struct ExtData ExtData } +type PanelStats struct +{ + Users int + Groups int + Forums int + Settings int + Themes int + Reports int +} + +type PanelPage struct +{ + Title string + CurrentUser User + Header HeaderVars + Stats PanelStats + ItemList []interface{} + Something interface{} +} + +type PanelGroupPage struct +{ + Title string + CurrentUser User + Header HeaderVars + Stats PanelStats + ItemList []GroupAdmin + PageList []int + Page int + LastPage int + ExtData ExtData +} + type GridElement struct { ID string @@ -122,25 +155,28 @@ type PanelDashboardPage struct Title string CurrentUser User Header HeaderVars + Stats PanelStats GridItems []GridElement ExtData ExtData } -type ThemesPage struct +type PanelThemesPage struct { Title string CurrentUser User Header HeaderVars + Stats PanelStats PrimaryThemes []Theme VariantThemes []Theme ExtData ExtData } -type EditGroupPage struct +type PanelEditGroupPage struct { Title string CurrentUser User Header HeaderVars + Stats PanelStats ID int Name string Tag string @@ -155,11 +191,12 @@ type GroupForumPermPreset struct Preset string } -type EditForumPage struct +type PanelEditForumPage struct { Title string CurrentUser User Header HeaderVars + Stats PanelStats ID int Name string Desc string @@ -182,11 +219,12 @@ type NameLangToggle struct Toggle bool } -type EditGroupPermsPage struct +type PanelEditGroupPermsPage struct { Title string CurrentUser User Header HeaderVars + Stats PanelStats ID int Name string LocalPerms []NameLangToggle @@ -200,15 +238,28 @@ type Log struct { DoneAt string } -type LogsPage struct +type PanelLogsPage struct { Title string CurrentUser User Header HeaderVars + Stats PanelStats Logs []Log ExtData ExtData } +type PanelDebugPage struct +{ + Title string + CurrentUser User + Header HeaderVars + Stats PanelStats + Uptime string + OpenConns int + DBAdapter string + ExtData ExtData +} + type PageSimple struct { Title string @@ -747,3 +798,41 @@ func coerce_int_bytes(data []byte) (res int, length int) { } return conv, i } + +// TO-DO: Write tests for this +func paginate(count int, per_page int, maxPages int) []int { + if count < per_page { + return []int{1} + } + + var page int + var out []int + for current := 0; current < count; current += per_page { + page++ + out = append(out,page) + if len(out) >= maxPages { + break + } + } + return out +} + +// TO-DO: Write tests for this +func page_offset(count int, page int, perPage int) (int, int, int) { + var offset int + lastPage := int(count / perPage) + 1 + if page > 1 { + offset = (perPage * page) - perPage + } else if page == -1 { + page = lastPage + offset = (perPage * page) - perPage + } else { + page = 1 + } + + // We don't want the offset to overflow the slices, if everything's in memory + if offset >= (count - 1) { + offset = 0 + } + return offset, page, lastPage +} diff --git a/panel_routes.go b/panel_routes.go index 3dfd04f7..fd9a719a 100644 --- a/panel_routes.go +++ b/panel_routes.go @@ -15,7 +15,7 @@ import ( ) func route_panel(w http.ResponseWriter, r *http.Request, user User){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -168,7 +168,7 @@ func route_panel(w http.ResponseWriter, r *http.Request, user User){ gridElements = append(gridElements, GridElement{"dash-visitorsperweek","2 visitors / week",13,"grid_stat stat_disabled","","","Coming Soon!"/*"The number of unique visitors we've had over the last 7 days"*/}) 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} + pi := PanelDashboardPage{"Control Panel Dashboard",user,headerVars,stats,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 @@ -181,7 +181,7 @@ func route_panel(w http.ResponseWriter, r *http.Request, user User){ } func route_panel_forums(w http.ResponseWriter, r *http.Request, user User){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -206,7 +206,7 @@ func route_panel_forums(w http.ResponseWriter, r *http.Request, user User){ forumList = append(forumList,fadmin) } } - pi := Page{"Forum Manager",user,headerVars,forumList,nil} + pi := PanelPage{"Forum Manager",user,headerVars,stats,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 @@ -254,7 +254,7 @@ func route_panel_forums_create_submit(w http.ResponseWriter, r *http.Request, us } func route_panel_forums_delete(w http.ResponseWriter, r *http.Request, user User, sfid string){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -285,7 +285,7 @@ func route_panel_forums_delete(w http.ResponseWriter, r *http.Request, user User confirm_msg := "Are you sure you want to delete the '" + forum.Name + "' forum?" yousure := AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid),confirm_msg} - pi := Page{"Delete Forum",user,headerVars,tList,yousure} + pi := PanelPage{"Delete Forum",user,headerVars,stats,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 @@ -330,7 +330,7 @@ func route_panel_forums_delete_submit(w http.ResponseWriter, r *http.Request, us } func route_panel_forums_edit(w http.ResponseWriter, r *http.Request, user User, sfid string) { - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -367,7 +367,7 @@ func route_panel_forums_edit(w http.ResponseWriter, r *http.Request, user User, gplist = append(gplist,GroupForumPermPreset{group,forum_perms_to_group_forum_preset(group.Forums[fid])}) } - pi := EditForumPage{"Forum Editor",user,headerVars,forum.ID,forum.Name,forum.Desc,forum.Active,forum.Preset,gplist,extData} + pi := PanelEditForumPage{"Forum Editor",user,headerVars,stats,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 @@ -548,7 +548,7 @@ func route_panel_forums_edit_perms_submit(w http.ResponseWriter, r *http.Request } func route_panel_settings(w http.ResponseWriter, r *http.Request, user User){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -597,7 +597,7 @@ func route_panel_settings(w http.ResponseWriter, r *http.Request, user User){ return } - pi := Page{"Setting Manager",user,headerVars,tList,settingList} + pi := PanelPage{"Setting Manager",user,headerVars,stats,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 @@ -610,7 +610,7 @@ func route_panel_settings(w http.ResponseWriter, r *http.Request, user User){ } func route_panel_setting(w http.ResponseWriter, r *http.Request, user User, sname string){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -653,7 +653,7 @@ func route_panel_setting(w http.ResponseWriter, r *http.Request, user User, snam } } - pi := Page{"Edit Setting",user,headerVars,itemList,setting} + pi := PanelPage{"Edit Setting",user,headerVars,stats,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 @@ -720,7 +720,7 @@ func route_panel_setting_edit(w http.ResponseWriter, r *http.Request, user User, } func route_panel_plugins(w http.ResponseWriter, r *http.Request, user User){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -736,7 +736,7 @@ func route_panel_plugins(w http.ResponseWriter, r *http.Request, user User){ pluginList = append(pluginList,plugin) } - pi := Page{"Plugin Manager",user,headerVars,pluginList,nil} + pi := PanelPage{"Plugin Manager",user,headerVars,stats,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 @@ -926,7 +926,6 @@ func route_panel_plugins_install(w http.ResponseWriter, r *http.Request, user Us } } - if has_plugin { _, err = update_plugin_install_stmt.Exec(1,uname) if err != nil { @@ -960,7 +959,7 @@ func route_panel_plugins_install(w http.ResponseWriter, r *http.Request, user Us } func route_panel_users(w http.ResponseWriter, r *http.Request, user User){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -1004,7 +1003,7 @@ func route_panel_users(w http.ResponseWriter, r *http.Request, user User){ return } - pi := Page{"User Manager",user,headerVars,userList,nil} + pi := PanelPage{"User Manager",user,headerVars,stats,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 @@ -1017,7 +1016,7 @@ func route_panel_users(w http.ResponseWriter, r *http.Request, user User){ } func route_panel_users_edit(w http.ResponseWriter, r *http.Request, user User, suid string){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -1058,7 +1057,7 @@ func route_panel_users_edit(w http.ResponseWriter, r *http.Request, user User, s groupList = append(groupList,group) } - pi := Page{"User Editor",user,headerVars,groupList,targetUser} + pi := PanelPage{"User Editor",user,headerVars,stats,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 @@ -1166,13 +1165,25 @@ func route_panel_users_edit_submit(w http.ResponseWriter, r *http.Request, user } func route_panel_groups(w http.ResponseWriter, r *http.Request, user User){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } - var groupList []interface{} - for _, group := range groups[1:] { + page, _ := strconv.Atoi(r.FormValue("page")) + perPage := 9 + offset, page, lastPage := page_offset(stats.Groups, page, perPage) + + // Skip the System group + offset++ + + var count int + var groupList []GroupAdmin + for _, group := range groups[offset:] { + if count == perPage { + break + } + var rank string var rank_class string var can_edit bool @@ -1197,10 +1208,12 @@ func route_panel_groups(w http.ResponseWriter, r *http.Request, user User){ can_edit = user.Perms.EditGroup && (!group.Is_Admin || user.Perms.EditGroupAdmin) && (!group.Is_Mod || user.Perms.EditGroupSuperMod) groupList = append(groupList, GroupAdmin{group.ID,group.Name,rank,rank_class,can_edit,can_delete}) + count++ } //log.Printf("groupList: %+v\n", groupList) - pi := Page{"Group Manager",user,headerVars,groupList,nil} + pageList := paginate(stats.Groups, perPage, 5) + pi := PanelGroupPage{"Group Manager",user,headerVars,stats,groupList,pageList,page,lastPage,extData} if pre_render_hooks["pre_render_panel_groups"] != nil { if run_pre_render_hook("pre_render_panel_groups", w, r, &user, &pi) { return @@ -1214,7 +1227,7 @@ func route_panel_groups(w http.ResponseWriter, r *http.Request, user User){ } func route_panel_groups_edit(w http.ResponseWriter, r *http.Request, user User, sgid string){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -1260,7 +1273,7 @@ func route_panel_groups_edit(w http.ResponseWriter, r *http.Request, user User, disable_rank := !user.Perms.EditGroupGlobalPerms || (group.ID == 6) - pi := EditGroupPage{"Group Editor",user,headerVars,group.ID,group.Name,group.Tag,rank,disable_rank,extData} + pi := PanelEditGroupPage{"Group Editor",user,headerVars,stats,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 @@ -1273,7 +1286,7 @@ func route_panel_groups_edit(w http.ResponseWriter, r *http.Request, user User, } func route_panel_groups_edit_perms(w http.ResponseWriter, r *http.Request, user User, sgid string){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -1338,7 +1351,7 @@ func route_panel_groups_edit_perms(w http.ResponseWriter, r *http.Request, user globalPerms = append(globalPerms, NameLangToggle{"ViewAdminLogs",GetGlobalPermPhrase("ViewAdminLogs"),group.Perms.ViewAdminLogs}) globalPerms = append(globalPerms, NameLangToggle{"ViewIPs",GetGlobalPermPhrase("ViewIPs"),group.Perms.ViewIPs}) - pi := EditGroupPermsPage{"Group Editor",user,headerVars,group.ID,group.Name,localPerms,globalPerms,extData} + pi := PanelEditGroupPermsPage{"Group Editor",user,headerVars,stats,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 @@ -1609,7 +1622,7 @@ func route_panel_groups_create_submit(w http.ResponseWriter, r *http.Request, us } func route_panel_themes(w http.ResponseWriter, r *http.Request, user User){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -1631,7 +1644,7 @@ func route_panel_themes(w http.ResponseWriter, r *http.Request, user User){ } - pi := ThemesPage{"Theme Manager",user,headerVars,pThemeList,vThemeList,extData} + pi := PanelThemesPage{"Theme Manager",user,headerVars,stats,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 @@ -1722,7 +1735,7 @@ func route_panel_themes_default(w http.ResponseWriter, r *http.Request, user Use } func route_panel_logs_mod(w http.ResponseWriter, r *http.Request, user User){ - headerVars, ok := PanelSessionCheck(w,r,&user) + headerVars, stats, ok := PanelSessionCheck(w,r,&user) if !ok { return } @@ -1813,7 +1826,7 @@ func route_panel_logs_mod(w http.ResponseWriter, r *http.Request, user User){ return } - pi := LogsPage{"Moderation Logs",user,headerVars,logs,extData} + pi := PanelLogsPage{"Moderation Logs",user,headerVars,stats,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 @@ -1821,6 +1834,28 @@ func route_panel_logs_mod(w http.ResponseWriter, r *http.Request, user User){ } err = templates.ExecuteTemplate(w,"panel-modlogs.html",pi) if err != nil { - log.Print(err) + InternalError(err,w) + } +} + +func route_panel_debug(w http.ResponseWriter, r *http.Request, user User) { + headerVars, stats, ok := PanelSessionCheck(w,r,&user) + if !ok { + return + } + if !user.Is_Admin { + NoPermissions(w,r,user) + return + } + + uptime := "..." + db_stats := db.Stats() + open_conn_count := db_stats.OpenConnections + // Disk I/O? + + pi := PanelDebugPage{"Debug",user,headerVars,stats,uptime,open_conn_count,db_adapter,extData} + err := templates.ExecuteTemplate(w,"panel-debug.html",pi) + if err != nil { + InternalError(err,w) } } diff --git a/pgsql.go b/pgsql.go index 05300d9a..bb43de30 100644 --- a/pgsql.go +++ b/pgsql.go @@ -5,6 +5,7 @@ package main import "strings" +//import "time" import "database/sql" import _ "github.com/lib/pq" import "./query_gen/lib" @@ -18,6 +19,10 @@ var todays_topic_count_stmt *sql.Stmt var todays_report_count_stmt *sql.Stmt var todays_newuser_count_stmt *sql.Stmt +func init() { + db_adapter = "pgsql" +} + 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 @@ -40,6 +45,10 @@ func _init_database() (err error) { // Set the number of max open connections. How many do we need? Might need to do some tests. db.SetMaxOpenConns(64) + db.SetMaxIdleConns(32) + + // Only hold connections open for five seconds to avoid accumulating a large number of stale connections + //db.SetConnMaxLifetime(5 * time.Second) err = _gen_pgsql() if err != nil { diff --git a/public/global.js b/public/global.js index 524d6851..4d0f67f3 100644 --- a/public/global.js +++ b/public/global.js @@ -13,14 +13,16 @@ function post_link(event) function load_alerts(menu_alerts) { - menu_alerts.find(".alert_counter").text(""); + var alertListNode = menu_alerts.getElementsByClassName("alertList")[0]; + var alertCounterNode = menu_alerts.getElementsByClassName("alert_counter")[0]; + alertCounterNode.textContent = ""; $.ajax({ type: 'get', dataType: 'json', url:'/api/?action=get&module=alerts&format=json', success: function(data) { if("errmsg" in data) { - menu_alerts.find(".alertList").html("