From 5ba7aa74f796ffd24d8d30bb8fae7053c6ae7818 Mon Sep 17 00:00:00 2001 From: Azareal Date: Thu, 11 Jan 2018 08:03:17 +0000 Subject: [PATCH] Renamed the pre_render_panel_mod_log pre-render hook to pre_render_panel_modlogs. Added the half-second task type, you'll why later ;) Reduced the amount of code duplication in the panel routes (saved a hundred lines). Added the two day time range option for graphs. We now track the discord, lynx and blank user agents. Renamed some template files for consistency and to help stamp out some duplicate code. Began work on topic move. --- common/extend.go | 2 +- common/tasks.go | 6 + gen_mssql.go | 8 + gen_mysql.go | 7 + gen_router.go | 14 +- langs/english.json | 37 +-- main.go | 13 +- mod_routes.go | 42 +++ panel_routes.go | 289 ++++++------------ public/global.js | 8 + query_gen/main.go | 2 + router_gen/main.go | 11 +- template_list.go | 113 ++++--- template_topics.go | 148 ++++----- templates/forum.html | 1 + templates/panel-analytics-views.html | 1 + ....html => panel_analytics_agent_views.html} | 1 + ...gents.html => panel_analytics_agents.html} | 0 ....html => panel_analytics_route_views.html} | 1 + ...outes.html => panel_analytics_routes.html} | 0 ...{panel-backups.html => panel_backups.html} | 0 .../{panel-debug.html => panel_debug.html} | 0 .../{panel-forums.html => panel_forums.html} | 0 .../{panel-groups.html => panel_groups.html} | 0 ...{panel-modlogs.html => panel_modlogs.html} | 0 ...{panel-plugins.html => panel_plugins.html} | 0 ...{panel-setting.html => panel_setting.html} | 0 ...anel-settings.html => panel_settings.html} | 0 .../{panel-themes.html => panel_themes.html} | 0 .../{panel-users.html => panel_users.html} | 0 ...d-filters.html => panel_word_filters.html} | 0 templates/topics.html | 20 ++ themes/cosora/public/main.css | 23 +- themes/cosora/public/panel.css | 2 +- 34 files changed, 414 insertions(+), 335 deletions(-) rename templates/{panel-analytics-agent-views.html => panel_analytics_agent_views.html} (94%) rename templates/{panel-analytics-agents.html => panel_analytics_agents.html} (100%) rename templates/{panel-analytics-route-views.html => panel_analytics_route_views.html} (94%) rename templates/{panel-analytics-routes.html => panel_analytics_routes.html} (100%) rename templates/{panel-backups.html => panel_backups.html} (100%) rename templates/{panel-debug.html => panel_debug.html} (100%) rename templates/{panel-forums.html => panel_forums.html} (100%) rename templates/{panel-groups.html => panel_groups.html} (100%) rename templates/{panel-modlogs.html => panel_modlogs.html} (100%) rename templates/{panel-plugins.html => panel_plugins.html} (100%) rename templates/{panel-setting.html => panel_setting.html} (100%) rename templates/{panel-settings.html => panel_settings.html} (100%) rename templates/{panel-themes.html => panel_themes.html} (100%) rename templates/{panel-users.html => panel_users.html} (100%) rename templates/{panel-word-filters.html => panel_word_filters.html} (100%) diff --git a/common/extend.go b/common/extend.go index 2b9896ea..ae2f0428 100644 --- a/common/extend.go +++ b/common/extend.go @@ -112,7 +112,7 @@ var PreRenderHooks = map[string][]func(http.ResponseWriter, *http.Request, *User "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_panel_modlogs": 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, diff --git a/common/tasks.go b/common/tasks.go index aaf36dc3..c7c616b6 100644 --- a/common/tasks.go +++ b/common/tasks.go @@ -19,6 +19,7 @@ type TaskStmts struct { getSync *sql.Stmt } +var ScheduledHalfSecondTasks []func() error var ScheduledSecondTasks []func() error var ScheduledFifteenMinuteTasks []func() error var ShutdownTasks []func() error @@ -37,6 +38,11 @@ func init() { }) } +// AddScheduledHalfSecondTask is not concurrency safe +func AddScheduledHalfSecondTask(task func() error) { + ScheduledHalfSecondTasks = append(ScheduledHalfSecondTasks, task) +} + // AddScheduledSecondTask is not concurrency safe func AddScheduledSecondTask(task func() error) { ScheduledSecondTasks = append(ScheduledSecondTasks, task) diff --git a/gen_mssql.go b/gen_mssql.go index 9ab0b781..881f07f6 100644 --- a/gen_mssql.go +++ b/gen_mssql.go @@ -15,6 +15,7 @@ type Stmts struct { isThemeDefault *sql.Stmt getModlogs *sql.Stmt getModlogsOffset *sql.Stmt + getAdminlogsOffset *sql.Stmt getReplyTID *sql.Stmt getTopicFID *sql.Stmt getUserReplyUID *sql.Stmt @@ -122,6 +123,13 @@ func _gen_mssql() (err error) { return err } + log.Print("Preparing getAdminlogsOffset statement.") + stmts.getAdminlogsOffset, err = db.Prepare("SELECT [action],[elementID],[elementType],[ipaddress],[actorID],[doneAt] FROM [administration_logs] ORDER BY doneAt DESC OFFSET ?1 ROWS FETCH NEXT ?2 ROWS ONLY") + if err != nil { + log.Print("Bad Query: ","SELECT [action],[elementID],[elementType],[ipaddress],[actorID],[doneAt] FROM [administration_logs] ORDER BY doneAt DESC OFFSET ?1 ROWS FETCH NEXT ?2 ROWS ONLY") + return err + } + log.Print("Preparing getReplyTID statement.") stmts.getReplyTID, err = db.Prepare("SELECT [tid] FROM [replies] WHERE [rid] = ?1") if err != nil { diff --git a/gen_mysql.go b/gen_mysql.go index b771e4fc..caffba4d 100644 --- a/gen_mysql.go +++ b/gen_mysql.go @@ -17,6 +17,7 @@ type Stmts struct { isThemeDefault *sql.Stmt getModlogs *sql.Stmt getModlogsOffset *sql.Stmt + getAdminlogsOffset *sql.Stmt getReplyTID *sql.Stmt getTopicFID *sql.Stmt getUserReplyUID *sql.Stmt @@ -118,6 +119,12 @@ func _gen_mysql() (err error) { return err } + log.Print("Preparing getAdminlogsOffset statement.") + stmts.getAdminlogsOffset, err = db.Prepare("SELECT `action`,`elementID`,`elementType`,`ipaddress`,`actorID`,`doneAt` FROM `administration_logs` ORDER BY doneAt DESC LIMIT ?,?") + if err != nil { + return err + } + log.Print("Preparing getReplyTID statement.") stmts.getReplyTID, err = db.Prepare("SELECT `tid` FROM `replies` WHERE `rid` = ?") if err != nil { diff --git a/gen_router.go b/gen_router.go index d888058f..0477f5d3 100644 --- a/gen_router.go +++ b/gen_router.go @@ -233,6 +233,9 @@ var agentMapEnum = map[string]int{ "bing": 9, "baidu": 10, "duckduckgo": 11, + "discord": 12, + "lynx": 13, + "blank": 14, } var reverseAgentMapEnum = map[int]string{ 0: "unknown", @@ -247,6 +250,9 @@ var reverseAgentMapEnum = map[int]string{ 9: "bing", 10: "baidu", 11: "duckduckgo", + 12: "discord", + 13: "lynx", + 14: "blank", } // TODO: Stop spilling these into the package scope? @@ -344,7 +350,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Track the user agents. Unfortunately, everyone pretends to be Mozilla, so this'll be a little less efficient than I would like. // TODO: Add a setting to disable this? // TODO: Use a more efficient detector instead of smashing every possible combination in - ua := strings.TrimSuffix(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36") // Noise, no one's going to be running this and it complicates implementing an efficient UA parser, particularly the more efficient right-to-left one I have in mind + ua := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36")) // Noise, no one's going to be running this and it complicates implementing an efficient UA parser, particularly the more efficient right-to-left one I have in mind switch { case strings.Contains(ua,"Google"): common.AgentViewCounter.Bump(7) @@ -368,6 +374,12 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { common.AgentViewCounter.Bump(10) case strings.Contains(ua,"DuckDuckBot"): common.AgentViewCounter.Bump(11) + case strings.Contains(ua,"Discordbot"): + common.AgentViewCounter.Bump(12) + case strings.Contains(ua,"Lynx"): + common.AgentViewCounter.Bump(13) + case ua == "": + common.AgentViewCounter.Bump(14) default: common.AgentViewCounter.Bump(0) if common.Dev.DebugMode { diff --git a/langs/english.json b/langs/english.json index 676c94b6..18c0cf03 100644 --- a/langs/english.json +++ b/langs/english.json @@ -69,23 +69,24 @@ "register":"Registration", "ip-search":"IP Search", - "panel-dashboard":"Control Panel Dashboard", - "panel-forums":"Forum Manager", - "panel-delete-forum":"Delete Forum", - "panel-edit-forum":"Forum Editor", - "panel-analytics":"Analytics", - "panel-settings":"Setting Manager", - "panel-edit-setting":"Edit Setting", - "panel-word-filters":"Word Filter Manager", - "panel-edit-word-filter":"Edit Word Filter", - "panel-plugins":"Plugin Manager", - "panel-users":"User Manager", - "panel-edit-user":"User Editor", - "panel-groups":"Group Manager", - "panel-edit-group":"Group Editor", - "panel-themes":"Theme Manager", - "panel-backups":"Backups", - "panel-mod-logs":"Moderation Logs", - "panel-debug":"Debug" + "panel_dashboard":"Control Panel Dashboard", + "panel_forums":"Forum Manager", + "panel_delete_forum":"Delete Forum", + "panel_edit_forum":"Forum Editor", + "panel_analytics":"Analytics", + "panel_settings":"Setting Manager", + "panel_edit_setting":"Edit Setting", + "panel_word_filters":"Word Filter Manager", + "panel_edit_word_filter":"Edit Word Filter", + "panel_plugins":"Plugin Manager", + "panel_users":"User Manager", + "panel_edit_user":"User Editor", + "panel_groups":"Group Manager", + "panel_edit_group":"Group Editor", + "panel_themes":"Theme Manager", + "panel_backups":"Backups", + "panel_mod_logs":"Moderation Logs", + "panel_admin_logs":"Administration Logs", + "panel_debug":"Debug" } } \ No newline at end of file diff --git a/main.go b/main.go index ca50706d..1cccba3d 100644 --- a/main.go +++ b/main.go @@ -246,13 +246,18 @@ func main() { } } - // Run this goroutine once a second + // Run this goroutine once every half second + halfSecondTicker := time.NewTicker(time.Second / 2) secondTicker := time.NewTicker(1 * time.Second) fifteenMinuteTicker := time.NewTicker(15 * time.Minute) //hourTicker := time.NewTicker(1 * time.Hour) go func() { for { select { + case <-halfSecondTicker.C: + // TODO: Add a plugin hook here + runTasks(common.ScheduledHalfSecondTasks) + // TODO: Add a plugin hook here case <-secondTicker.C: // TODO: Add a plugin hook here runTasks(common.ScheduledSecondTasks) @@ -291,13 +296,14 @@ func main() { } }() + // TODO: Move these routes into the new routes list log.Print("Initialising the router") router = NewGenRouter(http.FileServer(http.Dir("./uploads"))) router.HandleFunc("/topic/create/submit/", routeTopicCreateSubmit) router.HandleFunc("/topic/", routeTopicID) router.HandleFunc("/reply/create/", routeCreateReply) - //router.HandleFunc("/reply/edit/", routeReplyEdit) - //router.HandleFunc("/reply/delete/", routeReplyDelete) + //router.HandleFunc("/reply/edit/", routeReplyEdit) // No js fallback + //router.HandleFunc("/reply/delete/", routeReplyDelete) // No js confirmation page? We could have a confirmation modal for the JS case router.HandleFunc("/reply/edit/submit/", routeReplyEditSubmit) router.HandleFunc("/reply/delete/submit/", routeReplyDeleteSubmit) router.HandleFunc("/reply/like/submit/", routeReplyLikeSubmit) @@ -307,6 +313,7 @@ func main() { router.HandleFunc("/topic/unstick/submit/", routeUnstickTopic) router.HandleFunc("/topic/lock/submit/", routeLockTopic) router.HandleFunc("/topic/unlock/submit/", routeUnlockTopic) + router.HandleFunc("/topic/move/submit/", routeMoveTopic) router.HandleFunc("/topic/like/submit/", routeLikeTopic) // Accounts diff --git a/mod_routes.go b/mod_routes.go index 2c223c59..e163099a 100644 --- a/mod_routes.go +++ b/mod_routes.go @@ -312,6 +312,48 @@ func routeUnlockTopic(w http.ResponseWriter, r *http.Request, user common.User) return nil } +func routeMoveTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + return common.NoPermissions(w, r, user) + + tid, err := strconv.Atoi(r.URL.Path[len("/topic/move/submit/"):]) + if err != nil { + return common.PreError("The provided TopicID is not a valid number.", w, r) + } + + topic, err := common.Topics.Get(tid) + if err == ErrNoRows { + return common.PreError("The topic you tried to move doesn't exist.", w, r) + } else if err != nil { + return common.InternalError(err, w, r) + } + + // TODO: Add hooks to make use of headerLite + _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + if ferr != nil { + return ferr + } + if !user.Perms.ViewTopic { // TODO: MoveTopic permission? + return common.NoPermissions(w, r, user) + } + + err = topic.Unlock() + if err != nil { + return common.InternalError(err, w, r) + } + + err = common.ModLogs.Create("move", tid, "topic", user.LastIP, user.ID) + if err != nil { + return common.InternalError(err, w, r) + } + err = topic.CreateActionReply("move", user.LastIP, user) + if err != nil { + return common.InternalError(err, w, r) + } + + http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) + return nil +} + // TODO: Disable stat updates in posts handled by plugin_guilds // TODO: Update the stats after edits so that we don't under or over decrement stats during deletes func routeReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { diff --git a/panel_routes.go b/panel_routes.go index 2607ab67..b02bab95 100644 --- a/panel_routes.go +++ b/panel_routes.go @@ -30,20 +30,18 @@ func panelSuccessRedirect(dest string, w http.ResponseWriter, r *http.Request, i } return nil } - -// TODO: Implement this properly -/*func panelRenderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, user common.User, pi interface{}) common.RouteError { +func panelRenderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, user common.User, pi interface{}) common.RouteError { if common.PreRenderHooks["pre_render_"+tmplName] != nil { - if common.RunPreRenderHook("pre_render_"+tmplName, w, r, &user, &pi) { + if common.RunPreRenderHook("pre_render_"+tmplName, w, r, &user, pi) { return nil } } - err = common.Templates.ExecuteTemplate(w, tmplName+".html", pi) + err := common.Templates.ExecuteTemplate(w, tmplName+".html", pi) if err != nil { return common.InternalError(err, w, r) } return nil -}*/ +} func routePanel(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) @@ -170,18 +168,8 @@ func routePanel(w http.ResponseWriter, r *http.Request, user common.User) common gridElements = append(gridElements, common.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 := common.PanelDashboardPage{common.GetTitlePhrase("panel-dashboard"), user, headerVars, stats, "dashboard", gridElements} - if common.PreRenderHooks["pre_render_panel_dashboard"] != nil { - if common.RunPreRenderHook("pre_render_panel_dashboard", w, r, &user, &pi) { - return nil - } - } - err = common.Templates.ExecuteTemplate(w, "panel_dashboard.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil - //return panelRenderTemplate("panel_dashboard",w,r,user,pi) + pi := common.PanelDashboardPage{common.GetTitlePhrase("panel_dashboard"), user, headerVars, stats, "dashboard", gridElements} + return panelRenderTemplate("panel_dashboard", w, r, user, &pi) } func routePanelForums(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { @@ -210,18 +198,8 @@ func routePanelForums(w http.ResponseWriter, r *http.Request, user common.User) forumList = append(forumList, fadmin) } } - pi := common.PanelPage{common.GetTitlePhrase("panel-forums"), user, headerVars, stats, "forums", forumList, nil} - if common.PreRenderHooks["pre_render_panel_forums"] != nil { - if common.RunPreRenderHook("pre_render_panel_forums", w, r, &user, &pi) { - return nil - } - } - err = common.Templates.ExecuteTemplate(w, "panel-forums.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - - return nil + pi := common.PanelPage{common.GetTitlePhrase("panel_forums"), user, headerVars, stats, "forums", forumList, nil} + return panelRenderTemplate("panel_forums", w, r, user, &pi) } func routePanelForumsCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { @@ -274,7 +252,7 @@ func routePanelForumsDelete(w http.ResponseWriter, r *http.Request, user common. confirmMsg := "Are you sure you want to delete the '" + forum.Name + "' forum?" yousure := common.AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid), confirmMsg} - pi := common.PanelPage{common.GetTitlePhrase("panel-delete-forum"), user, headerVars, stats, "forums", tList, yousure} + pi := common.PanelPage{common.GetTitlePhrase("panel_delete_forum"), user, headerVars, stats, "forums", tList, yousure} if common.PreRenderHooks["pre_render_panel_delete_forum"] != nil { if common.RunPreRenderHook("pre_render_panel_delete_forum", w, r, &user, &pi) { return nil @@ -351,7 +329,7 @@ func routePanelForumsEdit(w http.ResponseWriter, r *http.Request, user common.Us gplist = append(gplist, common.GroupForumPermPreset{group, common.ForumPermsToGroupForumPreset(group.Forums[fid])}) } - pi := common.PanelEditForumPage{common.GetTitlePhrase("panel-edit-forum"), user, headerVars, stats, "forums", forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, gplist} + pi := common.PanelEditForumPage{common.GetTitlePhrase("panel_edit_forum"), user, headerVars, stats, "forums", forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, gplist} if common.PreRenderHooks["pre_render_panel_edit_forum"] != nil { if common.RunPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) { return nil @@ -513,7 +491,7 @@ func routePanelForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, us addNameLangToggle("PinTopic", forumPerms.PinTopic) addNameLangToggle("CloseTopic", forumPerms.CloseTopic) - pi := common.PanelEditForumGroupPage{common.GetTitlePhrase("panel-edit-forum"), user, headerVars, stats, "forums", forum.ID, gid, forum.Name, forum.Desc, forum.Active, forum.Preset, formattedPermList} + pi := common.PanelEditForumGroupPage{common.GetTitlePhrase("panel_edit_forum"), user, headerVars, stats, "forums", forum.ID, gid, forum.Name, forum.Desc, forum.Active, forum.Preset, formattedPermList} if common.PreRenderHooks["pre_render_panel_edit_forum"] != nil { if common.RunPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) { return nil @@ -596,6 +574,12 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo var timeRange = "six-hours" switch r.FormValue("timeRange") { + case "two-days": // Two days is experimental + timeQuantity = 2 + timeUnit = "day" + timeSlices = 24 + sliceWidth = 60 * 60 * 2 + timeRange = "two-days" case "one-day": timeQuantity = 1 timeUnit = "day" @@ -668,7 +652,7 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo graph := common.PanelTimeGraph{Series: viewList, Labels: labelList} log.Printf("graph: %+v\n", graph) - pi := common.PanelAnalyticsPage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", graph, viewItems, timeRange} + pi := common.PanelAnalyticsPage{common.GetTitlePhrase("panel_analytics"), user, headerVars, stats, "analytics", graph, viewItems, timeRange} if common.PreRenderHooks["pre_render_panel_analytics"] != nil { if common.RunPreRenderHook("pre_render_panel_analytics", w, r, &user, &pi) { return nil @@ -696,6 +680,12 @@ func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user var timeRange = "six-hours" switch r.FormValue("timeRange") { + case "two-days": // Two days is experimental + timeQuantity = 2 + timeUnit = "day" + timeSlices = 24 + sliceWidth = 60 * 60 * 2 + timeRange = "two-days" case "one-day": timeQuantity = 1 timeUnit = "day" @@ -767,17 +757,8 @@ func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user graph := common.PanelTimeGraph{Series: viewList, Labels: labelList} log.Printf("graph: %+v\n", graph) - pi := common.PanelAnalyticsRoutePage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", html.EscapeString(route), graph, timeRange} - if common.PreRenderHooks["pre_render_panel_analytics_route_views"] != nil { - if common.RunPreRenderHook("pre_render_panel_analytics_route_views", w, r, &user, &pi) { - return nil - } - } - err = common.Templates.ExecuteTemplate(w, "panel-analytics-route-views.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelAnalyticsRoutePage{common.GetTitlePhrase("panel_analytics"), user, headerVars, stats, "analytics", html.EscapeString(route), graph, timeRange} + return panelRenderTemplate("panel_analytics_route_views", w, r, user, &pi) } func routePanelAnalyticsAgentViews(w http.ResponseWriter, r *http.Request, user common.User, agent string) common.RouteError { @@ -795,6 +776,12 @@ func routePanelAnalyticsAgentViews(w http.ResponseWriter, r *http.Request, user var timeRange = "six-hours" switch r.FormValue("timeRange") { + case "two-days": // Two days is experimental + timeQuantity = 2 + timeUnit = "day" + timeSlices = 24 + sliceWidth = 60 * 60 * 2 + timeRange = "two-days" case "one-day": timeQuantity = 1 timeUnit = "day" @@ -866,17 +853,8 @@ func routePanelAnalyticsAgentViews(w http.ResponseWriter, r *http.Request, user graph := common.PanelTimeGraph{Series: viewList, Labels: labelList} log.Printf("graph: %+v\n", graph) - pi := common.PanelAnalyticsAgentPage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", html.EscapeString(agent), graph, timeRange} - if common.PreRenderHooks["pre_render_panel_analytics_agent_views"] != nil { - if common.RunPreRenderHook("pre_render_panel_analytics_agent_views", w, r, &user, &pi) { - return nil - } - } - err = common.Templates.ExecuteTemplate(w, "panel-analytics-agent-views.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelAnalyticsAgentPage{common.GetTitlePhrase("panel_analytics"), user, headerVars, stats, "analytics", html.EscapeString(agent), graph, timeRange} + return panelRenderTemplate("panel_analytics_agent_views", w, r, user, &pi) } func routePanelAnalyticsRoutes(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { @@ -919,17 +897,8 @@ func routePanelAnalyticsRoutes(w http.ResponseWriter, r *http.Request, user comm }) } - pi := common.PanelAnalyticsRoutesPage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", routeItems} - if common.PreRenderHooks["pre_render_panel_analytics_routes"] != nil { - if common.RunPreRenderHook("pre_render_panel_analytics_routes", w, r, &user, &pi) { - return nil - } - } - err = common.Templates.ExecuteTemplate(w, "panel-analytics-routes.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelAnalyticsRoutesPage{common.GetTitlePhrase("panel_analytics"), user, headerVars, stats, "analytics", routeItems} + return panelRenderTemplate("panel_analytics_routes", w, r, user, &pi) } func routePanelAnalyticsAgents(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { @@ -972,17 +941,8 @@ func routePanelAnalyticsAgents(w http.ResponseWriter, r *http.Request, user comm }) } - pi := common.PanelAnalyticsAgentsPage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", agentItems} - if common.PreRenderHooks["pre_render_panel_analytics_agents"] != nil { - if common.RunPreRenderHook("pre_render_panel_analytics_agents", w, r, &user, &pi) { - return nil - } - } - err = common.Templates.ExecuteTemplate(w, "panel-analytics-agents.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelAnalyticsAgentsPage{common.GetTitlePhrase("panel_analytics"), user, headerVars, stats, "analytics", agentItems} + return panelRenderTemplate("panel_analytics_agents", w, r, user, &pi) } func routePanelSettings(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { @@ -1021,17 +981,8 @@ func routePanelSettings(w http.ResponseWriter, r *http.Request, user common.User settingList[setting.Name] = setting.Content } - pi := common.PanelPage{common.GetTitlePhrase("panel-settings"), user, headerVars, stats, "settings", tList, settingList} - if common.PreRenderHooks["pre_render_panel_settings"] != nil { - if common.RunPreRenderHook("pre_render_panel_settings", w, r, &user, &pi) { - return nil - } - } - err = common.Templates.ExecuteTemplate(w, "panel-settings.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelPage{common.GetTitlePhrase("panel_settings"), user, headerVars, stats, "settings", tList, settingList} + return panelRenderTemplate("panel_settings", w, r, user, &pi) } func routePanelSettingEdit(w http.ResponseWriter, r *http.Request, user common.User, sname string) common.RouteError { @@ -1067,17 +1018,8 @@ func routePanelSettingEdit(w http.ResponseWriter, r *http.Request, user common.U } } - pi := common.PanelPage{common.GetTitlePhrase("panel-edit-setting"), user, headerVars, stats, "settings", itemList, setting} - if common.PreRenderHooks["pre_render_panel_setting"] != nil { - if common.RunPreRenderHook("pre_render_panel_setting", w, r, &user, &pi) { - return nil - } - } - err = common.Templates.ExecuteTemplate(w, "panel-setting.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelPage{common.GetTitlePhrase("panel_edit_setting"), user, headerVars, stats, "settings", itemList, setting} + return panelRenderTemplate("panel_setting", w, r, user, &pi) } func routePanelSettingEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, sname string) common.RouteError { @@ -1112,17 +1054,8 @@ func routePanelWordFilters(w http.ResponseWriter, r *http.Request, user common.U } var filterList = common.WordFilterBox.Load().(common.WordFilterMap) - pi := common.PanelPage{common.GetTitlePhrase("panel-word-filters"), user, headerVars, stats, "word-filters", tList, filterList} - if common.PreRenderHooks["pre_render_panel_word_filters"] != nil { - if common.RunPreRenderHook("pre_render_panel_word_filters", w, r, &user, &pi) { - return nil - } - } - err := common.Templates.ExecuteTemplate(w, "panel-word-filters.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelPage{common.GetTitlePhrase("panel_word_filters"), user, headerVars, stats, "word-filters", tList, filterList} + return panelRenderTemplate("panel_word_filters", w, r, user, &pi) } func routePanelWordFiltersCreate(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { @@ -1156,6 +1089,7 @@ func routePanelWordFiltersCreate(w http.ResponseWriter, r *http.Request, user co return panelSuccessRedirect("/panel/settings/word-filters/", w, r, isJs) } +// TODO: Implement this as a non-JS fallback func routePanelWordFiltersEdit(w http.ResponseWriter, r *http.Request, user common.User, wfid string) common.RouteError { headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { @@ -1167,17 +1101,8 @@ func routePanelWordFiltersEdit(w http.ResponseWriter, r *http.Request, user comm _ = wfid - pi := common.PanelPage{common.GetTitlePhrase("panel-edit-word-filter"), user, headerVars, stats, "word-filters", tList, nil} - if common.PreRenderHooks["pre_render_panel_word_filters_edit"] != nil { - if common.RunPreRenderHook("pre_render_panel_word_filters_edit", w, r, &user, &pi) { - return nil - } - } - err := common.Templates.ExecuteTemplate(w, "panel-word-filters-edit.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelPage{common.GetTitlePhrase("panel_edit_word_filter"), user, headerVars, stats, "word-filters", tList, nil} + return panelRenderTemplate("panel_word_filters_edit", w, r, user, &pi) } func routePanelWordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, wfid string) common.RouteError { @@ -1260,17 +1185,8 @@ func routePanelPlugins(w http.ResponseWriter, r *http.Request, user common.User) pluginList = append(pluginList, plugin) } - pi := common.PanelPage{common.GetTitlePhrase("panel-plugins"), user, headerVars, stats, "plugins", pluginList, nil} - if common.PreRenderHooks["pre_render_panel_plugins"] != nil { - if common.RunPreRenderHook("pre_render_panel_plugins", w, r, &user, &pi) { - return nil - } - } - err := common.Templates.ExecuteTemplate(w, "panel-plugins.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelPage{common.GetTitlePhrase("panel_plugins"), user, headerVars, stats, "plugins", pluginList, nil} + return panelRenderTemplate("panel_plugins", w, r, user, &pi) } func routePanelPluginsActivate(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError { @@ -1481,17 +1397,8 @@ func routePanelUsers(w http.ResponseWriter, r *http.Request, user common.User) c } pageList := common.Paginate(stats.Users, perPage, 5) - pi := common.PanelUserPage{common.GetTitlePhrase("panel-users"), user, headerVars, stats, "users", userList, pageList, page, lastPage} - if common.PreRenderHooks["pre_render_panel_users"] != nil { - if common.RunPreRenderHook("pre_render_panel_users", w, r, &user, &pi) { - return nil - } - } - err = common.Templates.ExecuteTemplate(w, "panel-users.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelUserPage{common.GetTitlePhrase("panel_users"), user, headerVars, stats, "users", userList, pageList, page, lastPage} + return panelRenderTemplate("panel_users", w, r, user, &pi) } func routePanelUsersEdit(w http.ResponseWriter, r *http.Request, user common.User, suid string) common.RouteError { @@ -1536,7 +1443,7 @@ func routePanelUsersEdit(w http.ResponseWriter, r *http.Request, user common.Use groupList = append(groupList, group) } - pi := common.PanelPage{common.GetTitlePhrase("panel-edit-user"), user, headerVars, stats, "users", groupList, targetUser} + pi := common.PanelPage{common.GetTitlePhrase("panel_edit_user"), user, headerVars, stats, "users", groupList, targetUser} if common.PreRenderHooks["pre_render_panel_edit_user"] != nil { if common.RunPreRenderHook("pre_render_panel_edit_user", w, r, &user, &pi) { return nil @@ -1679,18 +1586,8 @@ func routePanelGroups(w http.ResponseWriter, r *http.Request, user common.User) //log.Printf("groupList: %+v\n", groupList) pageList := common.Paginate(stats.Groups, perPage, 5) - pi := common.PanelGroupPage{common.GetTitlePhrase("panel-groups"), user, headerVars, stats, "groups", groupList, pageList, page, lastPage} - if common.PreRenderHooks["pre_render_panel_groups"] != nil { - if common.RunPreRenderHook("pre_render_panel_groups", w, r, &user, &pi) { - return nil - } - } - - err := common.Templates.ExecuteTemplate(w, "panel-groups.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelGroupPage{common.GetTitlePhrase("panel_groups"), user, headerVars, stats, "groups", groupList, pageList, page, lastPage} + return panelRenderTemplate("panel_groups", w, r, user, &pi) } func routePanelGroupsEdit(w http.ResponseWriter, r *http.Request, user common.User, sgid string) common.RouteError { @@ -1738,7 +1635,7 @@ func routePanelGroupsEdit(w http.ResponseWriter, r *http.Request, user common.Us disableRank := !user.Perms.EditGroupGlobalPerms || (group.ID == 6) - pi := common.PanelEditGroupPage{common.GetTitlePhrase("panel-edit-group"), user, headerVars, stats, "groups", group.ID, group.Name, group.Tag, rank, disableRank} + pi := common.PanelEditGroupPage{common.GetTitlePhrase("panel_edit_group"), user, headerVars, stats, "groups", group.ID, group.Name, group.Tag, rank, disableRank} if common.PreRenderHooks["pre_render_panel_edit_group"] != nil { if common.RunPreRenderHook("pre_render_panel_edit_group", w, r, &user, &pi) { return nil @@ -1825,7 +1722,7 @@ func routePanelGroupsEditPerms(w http.ResponseWriter, r *http.Request, user comm addGlobalPerm("ViewIPs", group.Perms.ViewIPs) addGlobalPerm("UploadFiles", group.Perms.UploadFiles) - pi := common.PanelEditGroupPermsPage{common.GetTitlePhrase("panel-edit-group"), user, headerVars, stats, "groups", group.ID, group.Name, localPerms, globalPerms} + pi := common.PanelEditGroupPermsPage{common.GetTitlePhrase("panel_edit_group"), user, headerVars, stats, "groups", group.ID, group.Name, localPerms, globalPerms} if common.PreRenderHooks["pre_render_panel_edit_group_perms"] != nil { if common.RunPreRenderHook("pre_render_panel_edit_group_perms", w, r, &user, &pi) { return nil @@ -2055,17 +1952,8 @@ func routePanelThemes(w http.ResponseWriter, r *http.Request, user common.User) } - pi := common.PanelThemesPage{common.GetTitlePhrase("panel-themes"), user, headerVars, stats, "themes", pThemeList, vThemeList} - if common.PreRenderHooks["pre_render_panel_themes"] != nil { - if common.RunPreRenderHook("pre_render_panel_themes", w, r, &user, &pi) { - return nil - } - } - err := common.Templates.ExecuteTemplate(w, "panel-themes.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelThemesPage{common.GetTitlePhrase("panel_themes"), user, headerVars, stats, "themes", pThemeList, vThemeList} + return panelRenderTemplate("panel_themes", w, r, user, &pi) } func routePanelThemesSetDefault(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError { @@ -2172,12 +2060,8 @@ func routePanelBackups(w http.ResponseWriter, r *http.Request, user common.User, backupList = append(backupList, common.BackupItem{backupFile.Name(), backupFile.ModTime()}) } - pi := common.PanelBackupPage{common.GetTitlePhrase("panel-backups"), user, headerVars, stats, "backups", backupList} - err = common.Templates.ExecuteTemplate(w, "panel-backups.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelBackupPage{common.GetTitlePhrase("panel_backups"), user, headerVars, stats, "backups", backupList} + return panelRenderTemplate("panel_backups", w, r, user, &pi) } // TODO: Log errors when something really screwy is going on? @@ -2270,17 +2154,48 @@ func routePanelLogsMod(w http.ResponseWriter, r *http.Request, user common.User) } pageList := common.Paginate(logCount, perPage, 5) - pi := common.PanelLogsPage{common.GetTitlePhrase("panel-mod-logs"), user, headerVars, stats, "logs", logs, pageList, page, lastPage} - if common.PreRenderHooks["pre_render_panel_mod_log"] != nil { - if common.RunPreRenderHook("pre_render_panel_mod_log", w, r, &user, &pi) { - return nil - } + pi := common.PanelLogsPage{common.GetTitlePhrase("panel_mod_logs"), user, headerVars, stats, "logs", logs, pageList, page, lastPage} + return panelRenderTemplate("panel_modlogs", w, r, user, &pi) +} + +func routePanelLogsAdmin(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) + if ferr != nil { + return ferr } - err = common.Templates.ExecuteTemplate(w, "panel-modlogs.html", pi) + + logCount := common.ModLogs.GlobalCount() + page, _ := strconv.Atoi(r.FormValue("page")) + perPage := 10 + offset, page, lastPage := common.PageOffset(logCount, page, perPage) + + rows, err := stmts.getAdminlogsOffset.Query(offset, perPage) if err != nil { return common.InternalError(err, w, r) } - return nil + defer rows.Close() + + var logs []common.LogItem + var action, elementType, ipaddress, doneAt string + var elementID, actorID int + for rows.Next() { + err := rows.Scan(&action, &elementID, &elementType, &ipaddress, &actorID, &doneAt) + if err != nil { + return common.InternalError(err, w, r) + } + + actor := handleUnknownUser(common.Users.Get(actorID)) + action = modlogsElementType(action, elementType, elementID, actor) + logs = append(logs, common.LogItem{Action: template.HTML(action), IPAddress: ipaddress, DoneAt: doneAt}) + } + err = rows.Err() + if err != nil { + return common.InternalError(err, w, r) + } + + pageList := common.Paginate(logCount, perPage, 5) + pi := common.PanelLogsPage{common.GetTitlePhrase("panel_admin_logs"), user, headerVars, stats, "logs", logs, pageList, page, lastPage} + return panelRenderTemplate("panel_adminlogs", w, r, user, &pi) } func routePanelDebug(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { @@ -2294,10 +2209,6 @@ func routePanelDebug(w http.ResponseWriter, r *http.Request, user common.User) c openConnCount := dbStats.OpenConnections // Disk I/O? - pi := common.PanelDebugPage{common.GetTitlePhrase("panel-debug"), user, headerVars, stats, "debug", uptime, openConnCount, dbAdapter} - err := common.Templates.ExecuteTemplate(w, "panel-debug.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil + pi := common.PanelDebugPage{common.GetTitlePhrase("panel_debug"), user, headerVars, stats, "debug", uptime, openConnCount, dbAdapter} + return panelRenderTemplate("panel_debug", w, r, user, &pi) } diff --git a/public/global.js b/public/global.js index 7f757eb4..90f061ec 100644 --- a/public/global.js +++ b/public/global.js @@ -506,6 +506,14 @@ $(document).ready(function(){ let optionNode = selectNode.options[selectNode.selectedIndex]; let action = optionNode.getAttribute("val"); //console.log("action",action); + + // Handle these specially + switch(action) { + case "move": + console.log("move action"); + $("#mod_topic_mover").removeClass("auto_hide"); + return; + } let url = "/topic/"+action+"/submit/"; //console.log("JSON.stringify(selectedTopics) ", JSON.stringify(selectedTopics)); diff --git a/query_gen/main.go b/query_gen/main.go index 487ebdb2..01fe681c 100644 --- a/query_gen/main.go +++ b/query_gen/main.go @@ -230,6 +230,8 @@ func writeSelects(adapter qgen.Adapter) error { build.Select("getModlogsOffset").Table("moderation_logs").Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Orderby("doneAt DESC").Limit("?,?").Parse() + build.Select("getAdminlogsOffset").Table("administration_logs").Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Orderby("doneAt DESC").Limit("?,?").Parse() + build.Select("getReplyTID").Table("replies").Columns("tid").Where("rid = ?").Parse() build.Select("getTopicFID").Table("topics").Columns("parentID").Where("tid = ?").Parse() diff --git a/router_gen/main.go b/router_gen/main.go index 45f8d96e..85ac2a46 100644 --- a/router_gen/main.go +++ b/router_gen/main.go @@ -171,6 +171,9 @@ func main() { "bing", "baidu", "duckduckgo", + "discord", + "lynx", + "blank", } tmplVars.AllAgentMap = make(map[string]int) @@ -307,7 +310,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Track the user agents. Unfortunately, everyone pretends to be Mozilla, so this'll be a little less efficient than I would like. // TODO: Add a setting to disable this? // TODO: Use a more efficient detector instead of smashing every possible combination in - ua := strings.TrimSuffix(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36") // Noise, no one's going to be running this and it complicates implementing an efficient UA parser, particularly the more efficient right-to-left one I have in mind + ua := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36")) // Noise, no one's going to be running this and it complicates implementing an efficient UA parser, particularly the more efficient right-to-left one I have in mind switch { case strings.Contains(ua,"Google"): common.AgentViewCounter.Bump({{.AllAgentMap.googlebot}}) @@ -331,6 +334,12 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { common.AgentViewCounter.Bump({{.AllAgentMap.baidu}}) case strings.Contains(ua,"DuckDuckBot"): common.AgentViewCounter.Bump({{.AllAgentMap.duckduckgo}}) + case strings.Contains(ua,"Discordbot"): + common.AgentViewCounter.Bump({{.AllAgentMap.discord}}) + case strings.Contains(ua,"Lynx"): + common.AgentViewCounter.Bump({{.AllAgentMap.lynx}}) + case ua == "": + common.AgentViewCounter.Bump({{.AllAgentMap.blank}}) default: common.AgentViewCounter.Bump({{.AllAgentMap.unknown}}) if common.Dev.DebugMode { diff --git a/template_list.go b/template_list.go index c553f709..7618b42e 100644 --- a/template_list.go +++ b/template_list.go @@ -811,6 +811,7 @@ var topics_8 = []byte(` @@ -819,21 +820,40 @@ var topics_8 = []byte(` `) var topics_9 = []byte(` + diff --git a/templates/panel-analytics-views.html b/templates/panel-analytics-views.html index 5cbf9dcd..b433ab09 100644 --- a/templates/panel-analytics-views.html +++ b/templates/panel-analytics-views.html @@ -7,6 +7,7 @@
Views + diff --git a/templates/panel-analytics-agents.html b/templates/panel_analytics_agents.html similarity index 100% rename from templates/panel-analytics-agents.html rename to templates/panel_analytics_agents.html diff --git a/templates/panel-analytics-route-views.html b/templates/panel_analytics_route_views.html similarity index 94% rename from templates/panel-analytics-route-views.html rename to templates/panel_analytics_route_views.html index f9c09916..af8be889 100644 --- a/templates/panel-analytics-route-views.html +++ b/templates/panel_analytics_route_views.html @@ -7,6 +7,7 @@
{{.Route}} Views +
@@ -33,6 +35,24 @@
{{if .ForumList}} +{{/** TODO: Have a seperate forum list for moving topics? Maybe an AJAX forum search compatible with plugin_guilds? **/}} +{{/** TODO: Add ARIA attributes for this **/}} +