From c7aec90612dbe60b9179d711d41ac7a875866ead Mon Sep 17 00:00:00 2001 From: Azareal Date: Mon, 8 Jan 2018 08:53:51 +0000 Subject: [PATCH] You can now filter analytics graphs by a day, twelve hours and six hours. Added a X-XSS-Protection header. Fixed some Group Editor CSS for Cosora. --- CONTRIBUTING.md | 33 +++ common/pages.go | 8 + common/routes_common.go | 2 +- common/user.go | 21 +- gen_router.go | 282 +++++++++++---------- panel_routes.go | 116 ++++++++- public/global.js | 20 +- query_gen/tables.go | 1 + router_gen/routes.go | 3 +- templates/panel-analytics-route-views.html | 15 +- templates/panel-analytics-views.html | 27 +- templates/panel-forum-edit-perms.html | 31 +++ templates/panel-group-edit-perms.html | 16 +- themes/cosora/public/panel.css | 11 +- 14 files changed, 409 insertions(+), 177 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 templates/panel-forum-edit-perms.html diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..d847602e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,33 @@ +We're not accepting contributions right now, although you're welcome to poke me about things. I'd like to put a process together at some point. + +# Coding Standards + +All code must be unit tested where ever possible with the exception of JavaScript which is untestable with our current technologies, tread with caution there. + +# Golang + +Use the standard linter and listen to what it tells you to do. + +The route assignments in main.go are *legacy code*, add new routes to `router_gen/routes.go` instead. + +Try to use the single responsibility principle where ever possible, with the exception for if doing so will cause a large performance drop. In other words, don't give your interfaces / structs too many responsibilities, keep them simple. + +Avoid hand-rolling queries. Use the builders, a ready built statement or a datastore structure instead. Preferably a datastore. + +More coming up. + +# JavaScript + +Use semicolons at the end of statements. If you don't, you might wind up breaking a minifier or two. + +Always use strict mode. + +Don't worry about ES5, we're targetting modern browsers. If we decide to backport code to older browsers, then we'll transpile the files. + +Don't use await until Edge gets around to implementing it. + +To keep consistency with Go code, variables must be camelCase. + +# JSON + +To keep consistency with Go code, map keys must be camelCase. \ No newline at end of file diff --git a/common/pages.go b/common/pages.go index cb624a97..681ec2e4 100644 --- a/common/pages.go +++ b/common/pages.go @@ -154,6 +154,11 @@ type PanelTimeGraph struct { Labels []int64 // unixtimes for the bottom, gets converted into 1:00, 2:00, etc. with JS } +type PanelAnalyticsItem struct { + Time int64 + Count int64 +} + type PanelAnalyticsPage struct { Title string CurrentUser User @@ -161,6 +166,8 @@ type PanelAnalyticsPage struct { Stats PanelStats Zone string PrimaryGraph PanelTimeGraph + ViewItems []PanelAnalyticsItem + TimeRange string } type PanelAnalyticsRoutesItem struct { @@ -185,6 +192,7 @@ type PanelAnalyticsRoutePage struct { Zone string Route string PrimaryGraph PanelTimeGraph + TimeRange string } type PanelThemesPage struct { diff --git a/common/routes_common.go b/common/routes_common.go index 313266bf..3d127a0c 100644 --- a/common/routes_common.go +++ b/common/routes_common.go @@ -278,7 +278,7 @@ func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) { h := w.Header() h.Set("X-Frame-Options", "deny") - //h.Set("X-XSS-Protection", "1") + h.Set("X-XSS-Protection", "1; mode=block") // TODO: Remove when we add a CSP? CSP's are horrendously glitchy things, tread with caution before removing // TODO: Set the content policy header return *usercpy, true diff --git a/common/user.go b/common/user.go index d461f432..6c5e8096 100644 --- a/common/user.go +++ b/common/user.go @@ -45,16 +45,17 @@ type User struct { Perms Perms PluginPerms map[string]bool Session string - Loggedin bool - Avatar string - Message string - URLPrefix string // Move this to another table? Create a user lite? - URLName string - Tag string - Level int - Score int - LastIP string // ! This part of the UserCache data might fall out of date - TempGroup int + //AuthToken string + Loggedin bool + Avatar string + Message string + URLPrefix string // Move this to another table? Create a user lite? + URLName string + Tag string + Level int + Score int + LastIP string // ! This part of the UserCache data might fall out of date + TempGroup int } type UserStmts struct { diff --git a/gen_router.go b/gen_router.go index a2562d6c..e33b1e10 100644 --- a/gen_router.go +++ b/gen_router.go @@ -32,6 +32,7 @@ var RouteMap = map[string]interface{}{ "routePanelForumsEdit": routePanelForumsEdit, "routePanelForumsEditSubmit": routePanelForumsEditSubmit, "routePanelForumsEditPermsSubmit": routePanelForumsEditPermsSubmit, + "routePanelForumsEditPermsAdvance": routePanelForumsEditPermsAdvance, "routePanelSettings": routePanelSettings, "routePanelSettingEdit": routePanelSettingEdit, "routePanelSettingEditSubmit": routePanelSettingEditSubmit, @@ -98,51 +99,52 @@ var routeMapEnum = map[string]int{ "routePanelForumsEdit": 14, "routePanelForumsEditSubmit": 15, "routePanelForumsEditPermsSubmit": 16, - "routePanelSettings": 17, - "routePanelSettingEdit": 18, - "routePanelSettingEditSubmit": 19, - "routePanelWordFilters": 20, - "routePanelWordFiltersCreate": 21, - "routePanelWordFiltersEdit": 22, - "routePanelWordFiltersEditSubmit": 23, - "routePanelWordFiltersDeleteSubmit": 24, - "routePanelThemes": 25, - "routePanelThemesSetDefault": 26, - "routePanelPlugins": 27, - "routePanelPluginsActivate": 28, - "routePanelPluginsDeactivate": 29, - "routePanelPluginsInstall": 30, - "routePanelUsers": 31, - "routePanelUsersEdit": 32, - "routePanelUsersEditSubmit": 33, - "routePanelAnalyticsViews": 34, - "routePanelAnalyticsRoutes": 35, - "routePanelAnalyticsRouteViews": 36, - "routePanelGroups": 37, - "routePanelGroupsEdit": 38, - "routePanelGroupsEditPerms": 39, - "routePanelGroupsEditSubmit": 40, - "routePanelGroupsEditPermsSubmit": 41, - "routePanelGroupsCreateSubmit": 42, - "routePanelBackups": 43, - "routePanelLogsMod": 44, - "routePanelDebug": 45, - "routePanel": 46, - "routeAccountEditCritical": 47, - "routeAccountEditCriticalSubmit": 48, - "routeAccountEditAvatar": 49, - "routeAccountEditAvatarSubmit": 50, - "routeAccountEditUsername": 51, - "routeAccountEditUsernameSubmit": 52, - "routeAccountEditEmail": 53, - "routeAccountEditEmailTokenSubmit": 54, - "routeProfile": 55, - "routeBanSubmit": 56, - "routeUnban": 57, - "routeActivate": 58, - "routeIps": 59, - "routeDynamic": 60, - "routeUploads": 61, + "routePanelForumsEditPermsAdvance": 17, + "routePanelSettings": 18, + "routePanelSettingEdit": 19, + "routePanelSettingEditSubmit": 20, + "routePanelWordFilters": 21, + "routePanelWordFiltersCreate": 22, + "routePanelWordFiltersEdit": 23, + "routePanelWordFiltersEditSubmit": 24, + "routePanelWordFiltersDeleteSubmit": 25, + "routePanelThemes": 26, + "routePanelThemesSetDefault": 27, + "routePanelPlugins": 28, + "routePanelPluginsActivate": 29, + "routePanelPluginsDeactivate": 30, + "routePanelPluginsInstall": 31, + "routePanelUsers": 32, + "routePanelUsersEdit": 33, + "routePanelUsersEditSubmit": 34, + "routePanelAnalyticsViews": 35, + "routePanelAnalyticsRoutes": 36, + "routePanelAnalyticsRouteViews": 37, + "routePanelGroups": 38, + "routePanelGroupsEdit": 39, + "routePanelGroupsEditPerms": 40, + "routePanelGroupsEditSubmit": 41, + "routePanelGroupsEditPermsSubmit": 42, + "routePanelGroupsCreateSubmit": 43, + "routePanelBackups": 44, + "routePanelLogsMod": 45, + "routePanelDebug": 46, + "routePanel": 47, + "routeAccountEditCritical": 48, + "routeAccountEditCriticalSubmit": 49, + "routeAccountEditAvatar": 50, + "routeAccountEditAvatarSubmit": 51, + "routeAccountEditUsername": 52, + "routeAccountEditUsernameSubmit": 53, + "routeAccountEditEmail": 54, + "routeAccountEditEmailTokenSubmit": 55, + "routeProfile": 56, + "routeBanSubmit": 57, + "routeUnban": 58, + "routeActivate": 59, + "routeIps": 60, + "routeDynamic": 61, + "routeUploads": 62, } var reverseRouteMapEnum = map[int]string{ 0: "routeAPI", @@ -162,51 +164,52 @@ var reverseRouteMapEnum = map[int]string{ 14: "routePanelForumsEdit", 15: "routePanelForumsEditSubmit", 16: "routePanelForumsEditPermsSubmit", - 17: "routePanelSettings", - 18: "routePanelSettingEdit", - 19: "routePanelSettingEditSubmit", - 20: "routePanelWordFilters", - 21: "routePanelWordFiltersCreate", - 22: "routePanelWordFiltersEdit", - 23: "routePanelWordFiltersEditSubmit", - 24: "routePanelWordFiltersDeleteSubmit", - 25: "routePanelThemes", - 26: "routePanelThemesSetDefault", - 27: "routePanelPlugins", - 28: "routePanelPluginsActivate", - 29: "routePanelPluginsDeactivate", - 30: "routePanelPluginsInstall", - 31: "routePanelUsers", - 32: "routePanelUsersEdit", - 33: "routePanelUsersEditSubmit", - 34: "routePanelAnalyticsViews", - 35: "routePanelAnalyticsRoutes", - 36: "routePanelAnalyticsRouteViews", - 37: "routePanelGroups", - 38: "routePanelGroupsEdit", - 39: "routePanelGroupsEditPerms", - 40: "routePanelGroupsEditSubmit", - 41: "routePanelGroupsEditPermsSubmit", - 42: "routePanelGroupsCreateSubmit", - 43: "routePanelBackups", - 44: "routePanelLogsMod", - 45: "routePanelDebug", - 46: "routePanel", - 47: "routeAccountEditCritical", - 48: "routeAccountEditCriticalSubmit", - 49: "routeAccountEditAvatar", - 50: "routeAccountEditAvatarSubmit", - 51: "routeAccountEditUsername", - 52: "routeAccountEditUsernameSubmit", - 53: "routeAccountEditEmail", - 54: "routeAccountEditEmailTokenSubmit", - 55: "routeProfile", - 56: "routeBanSubmit", - 57: "routeUnban", - 58: "routeActivate", - 59: "routeIps", - 60: "routeDynamic", - 61: "routeUploads", + 17: "routePanelForumsEditPermsAdvance", + 18: "routePanelSettings", + 19: "routePanelSettingEdit", + 20: "routePanelSettingEditSubmit", + 21: "routePanelWordFilters", + 22: "routePanelWordFiltersCreate", + 23: "routePanelWordFiltersEdit", + 24: "routePanelWordFiltersEditSubmit", + 25: "routePanelWordFiltersDeleteSubmit", + 26: "routePanelThemes", + 27: "routePanelThemesSetDefault", + 28: "routePanelPlugins", + 29: "routePanelPluginsActivate", + 30: "routePanelPluginsDeactivate", + 31: "routePanelPluginsInstall", + 32: "routePanelUsers", + 33: "routePanelUsersEdit", + 34: "routePanelUsersEditSubmit", + 35: "routePanelAnalyticsViews", + 36: "routePanelAnalyticsRoutes", + 37: "routePanelAnalyticsRouteViews", + 38: "routePanelGroups", + 39: "routePanelGroupsEdit", + 40: "routePanelGroupsEditPerms", + 41: "routePanelGroupsEditSubmit", + 42: "routePanelGroupsEditPermsSubmit", + 43: "routePanelGroupsCreateSubmit", + 44: "routePanelBackups", + 45: "routePanelLogsMod", + 46: "routePanelDebug", + 47: "routePanel", + 48: "routeAccountEditCritical", + 49: "routeAccountEditCriticalSubmit", + 50: "routeAccountEditAvatar", + 51: "routeAccountEditAvatarSubmit", + 52: "routeAccountEditUsername", + 53: "routeAccountEditUsernameSubmit", + 54: "routeAccountEditEmail", + 55: "routeAccountEditEmailTokenSubmit", + 56: "routeProfile", + 57: "routeBanSubmit", + 58: "routeUnban", + 59: "routeActivate", + 60: "routeIps", + 61: "routeDynamic", + 62: "routeUploads", } // TODO: Stop spilling these into the package scope? @@ -469,11 +472,14 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { common.RouteViewCounter.Bump(16) err = routePanelForumsEditPermsSubmit(w,req,user,extraData) - case "/panel/settings/": + case "/panel/forums/edit/perms/": common.RouteViewCounter.Bump(17) + err = routePanelForumsEditPermsAdvance(w,req,user,extraData) + case "/panel/settings/": + common.RouteViewCounter.Bump(18) err = routePanelSettings(w,req,user) case "/panel/settings/edit/": - common.RouteViewCounter.Bump(18) + common.RouteViewCounter.Bump(19) err = routePanelSettingEdit(w,req,user,extraData) case "/panel/settings/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -482,10 +488,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(19) + common.RouteViewCounter.Bump(20) err = routePanelSettingEditSubmit(w,req,user,extraData) case "/panel/settings/word-filters/": - common.RouteViewCounter.Bump(20) + common.RouteViewCounter.Bump(21) err = routePanelWordFilters(w,req,user) case "/panel/settings/word-filters/create/": err = common.NoSessionMismatch(w,req,user) @@ -494,10 +500,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(21) + common.RouteViewCounter.Bump(22) err = routePanelWordFiltersCreate(w,req,user) case "/panel/settings/word-filters/edit/": - common.RouteViewCounter.Bump(22) + common.RouteViewCounter.Bump(23) err = routePanelWordFiltersEdit(w,req,user,extraData) case "/panel/settings/word-filters/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -506,7 +512,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(23) + common.RouteViewCounter.Bump(24) err = routePanelWordFiltersEditSubmit(w,req,user,extraData) case "/panel/settings/word-filters/delete/submit/": err = common.NoSessionMismatch(w,req,user) @@ -515,10 +521,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(24) + common.RouteViewCounter.Bump(25) err = routePanelWordFiltersDeleteSubmit(w,req,user,extraData) case "/panel/themes/": - common.RouteViewCounter.Bump(25) + common.RouteViewCounter.Bump(26) err = routePanelThemes(w,req,user) case "/panel/themes/default/": err = common.NoSessionMismatch(w,req,user) @@ -527,10 +533,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(26) + common.RouteViewCounter.Bump(27) err = routePanelThemesSetDefault(w,req,user,extraData) case "/panel/plugins/": - common.RouteViewCounter.Bump(27) + common.RouteViewCounter.Bump(28) err = routePanelPlugins(w,req,user) case "/panel/plugins/activate/": err = common.NoSessionMismatch(w,req,user) @@ -539,7 +545,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(28) + common.RouteViewCounter.Bump(29) err = routePanelPluginsActivate(w,req,user,extraData) case "/panel/plugins/deactivate/": err = common.NoSessionMismatch(w,req,user) @@ -548,7 +554,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(29) + common.RouteViewCounter.Bump(30) err = routePanelPluginsDeactivate(w,req,user,extraData) case "/panel/plugins/install/": err = common.NoSessionMismatch(w,req,user) @@ -557,13 +563,13 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(30) + common.RouteViewCounter.Bump(31) err = routePanelPluginsInstall(w,req,user,extraData) case "/panel/users/": - common.RouteViewCounter.Bump(31) + common.RouteViewCounter.Bump(32) err = routePanelUsers(w,req,user) case "/panel/users/edit/": - common.RouteViewCounter.Bump(32) + common.RouteViewCounter.Bump(33) err = routePanelUsersEdit(w,req,user,extraData) case "/panel/users/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -572,25 +578,31 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(33) + common.RouteViewCounter.Bump(34) err = routePanelUsersEditSubmit(w,req,user,extraData) case "/panel/analytics/views/": - common.RouteViewCounter.Bump(34) + err = common.ParseForm(w,req,user) + if err != nil { + router.handleError(err,w,req,user) + return + } + + common.RouteViewCounter.Bump(35) err = routePanelAnalyticsViews(w,req,user) case "/panel/analytics/routes/": - common.RouteViewCounter.Bump(35) + common.RouteViewCounter.Bump(36) err = routePanelAnalyticsRoutes(w,req,user) case "/panel/analytics/route/": - common.RouteViewCounter.Bump(36) + common.RouteViewCounter.Bump(37) err = routePanelAnalyticsRouteViews(w,req,user,extraData) case "/panel/groups/": - common.RouteViewCounter.Bump(37) + common.RouteViewCounter.Bump(38) err = routePanelGroups(w,req,user) case "/panel/groups/edit/": - common.RouteViewCounter.Bump(38) + common.RouteViewCounter.Bump(39) err = routePanelGroupsEdit(w,req,user,extraData) case "/panel/groups/edit/perms/": - common.RouteViewCounter.Bump(39) + common.RouteViewCounter.Bump(40) err = routePanelGroupsEditPerms(w,req,user,extraData) case "/panel/groups/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -599,7 +611,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(40) + common.RouteViewCounter.Bump(41) err = routePanelGroupsEditSubmit(w,req,user,extraData) case "/panel/groups/edit/perms/submit/": err = common.NoSessionMismatch(w,req,user) @@ -608,7 +620,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(41) + common.RouteViewCounter.Bump(42) err = routePanelGroupsEditPermsSubmit(w,req,user,extraData) case "/panel/groups/create/": err = common.NoSessionMismatch(w,req,user) @@ -617,7 +629,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(42) + common.RouteViewCounter.Bump(43) err = routePanelGroupsCreateSubmit(w,req,user) case "/panel/backups/": err = common.SuperAdminOnly(w,req,user) @@ -626,10 +638,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(43) + common.RouteViewCounter.Bump(44) err = routePanelBackups(w,req,user,extraData) case "/panel/logs/mod/": - common.RouteViewCounter.Bump(44) + common.RouteViewCounter.Bump(45) err = routePanelLogsMod(w,req,user) case "/panel/debug/": err = common.AdminOnly(w,req,user) @@ -638,10 +650,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(45) + common.RouteViewCounter.Bump(46) err = routePanelDebug(w,req,user) default: - common.RouteViewCounter.Bump(46) + common.RouteViewCounter.Bump(47) err = routePanel(w,req,user) } if err != nil { @@ -656,7 +668,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(47) + common.RouteViewCounter.Bump(48) err = routeAccountEditCritical(w,req,user) case "/user/edit/critical/submit/": err = common.NoSessionMismatch(w,req,user) @@ -671,7 +683,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(48) + common.RouteViewCounter.Bump(49) err = routeAccountEditCriticalSubmit(w,req,user) case "/user/edit/avatar/": err = common.MemberOnly(w,req,user) @@ -680,7 +692,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(49) + common.RouteViewCounter.Bump(50) err = routeAccountEditAvatar(w,req,user) case "/user/edit/avatar/submit/": err = common.MemberOnly(w,req,user) @@ -689,7 +701,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(50) + common.RouteViewCounter.Bump(51) err = routeAccountEditAvatarSubmit(w,req,user) case "/user/edit/username/": err = common.MemberOnly(w,req,user) @@ -698,7 +710,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(51) + common.RouteViewCounter.Bump(52) err = routeAccountEditUsername(w,req,user) case "/user/edit/username/submit/": err = common.NoSessionMismatch(w,req,user) @@ -713,7 +725,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(52) + common.RouteViewCounter.Bump(53) err = routeAccountEditUsernameSubmit(w,req,user) case "/user/edit/email/": err = common.MemberOnly(w,req,user) @@ -722,7 +734,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(53) + common.RouteViewCounter.Bump(54) err = routeAccountEditEmail(w,req,user) case "/user/edit/token/": err = common.NoSessionMismatch(w,req,user) @@ -737,11 +749,11 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(54) + common.RouteViewCounter.Bump(55) err = routeAccountEditEmailTokenSubmit(w,req,user,extraData) default: req.URL.Path += extraData - common.RouteViewCounter.Bump(55) + common.RouteViewCounter.Bump(56) err = routeProfile(w,req,user) } if err != nil { @@ -762,7 +774,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(56) + common.RouteViewCounter.Bump(57) err = routeBanSubmit(w,req,user,extraData) case "/users/unban/": err = common.NoSessionMismatch(w,req,user) @@ -777,7 +789,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(57) + common.RouteViewCounter.Bump(58) err = routeUnban(w,req,user,extraData) case "/users/activate/": err = common.NoSessionMismatch(w,req,user) @@ -792,7 +804,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(58) + common.RouteViewCounter.Bump(59) err = routeActivate(w,req,user,extraData) case "/users/ips/": err = common.MemberOnly(w,req,user) @@ -801,7 +813,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(59) + common.RouteViewCounter.Bump(60) err = routeIps(w,req,user) } if err != nil { @@ -818,7 +830,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { common.NotFound(w,req) return } - common.RouteViewCounter.Bump(61) + common.RouteViewCounter.Bump(62) req.URL.Path += extraData // TODO: Find a way to propagate errors up from this? router.UploadHandler(w,req) // TODO: Count these views @@ -862,7 +874,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { router.RUnlock() if ok { - common.RouteViewCounter.Bump(60) // TODO: Be more specific about *which* dynamic route it is + common.RouteViewCounter.Bump(61) // TODO: Be more specific about *which* dynamic route it is req.URL.Path += extraData err = handle(w,req,user) if err != nil { diff --git a/panel_routes.go b/panel_routes.go index c21aca44..dd6e413c 100644 --- a/panel_routes.go +++ b/panel_routes.go @@ -427,6 +427,58 @@ func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use return nil } +func routePanelForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) + if ferr != nil { + return ferr + } + if !user.Perms.ManageForums { + return common.NoPermissions(w, r, user) + } + + fid, err := strconv.Atoi(sfid) + if err != nil { + return common.LocalError("The provided Forum ID is not a valid number.", w, r, user) + } + + forum, err := common.Forums.Get(fid) + if err == ErrNoRows { + return common.LocalError("The forum you're trying to edit doesn't exist.", w, r, user) + } else if err != nil { + return common.InternalError(err, w, r) + } + + if forum.Preset == "" { + forum.Preset = "custom" + } + + glist, err := common.Groups.GetAll() + if err != nil { + return common.InternalError(err, w, r) + } + + var gplist []common.GroupForumPermPreset + for gid, group := range glist { + if gid == 0 { + continue + } + 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} + if common.PreRenderHooks["pre_render_panel_edit_forum"] != nil { + if common.RunPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) { + return nil + } + } + err = common.Templates.ExecuteTemplate(w, "panel-forum-edit-perms.html", pi) + if err != nil { + return common.InternalError(err, w, r) + } + + return nil +} + func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { @@ -435,13 +487,36 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo headerVars.Stylesheets = append(headerVars.Stylesheets, "chartist/chartist.min.css") headerVars.Scripts = append(headerVars.Scripts, "chartist/chartist.min.js") + var timeQuantity = 6 + var timeUnit = "hour" + var timeSlices = 12 + var sliceWidth = 60 * 30 + var timeRange = "six-hours" + + switch r.FormValue("timeRange") { + case "one-day": + timeQuantity = 1 + timeUnit = "day" + timeSlices = 24 + sliceWidth = 60 * 60 + timeRange = "one-day" + case "twelve-hours": + timeQuantity = 12 + timeSlices = 24 + timeRange = "twelve-hours" + case "six-hours", "": + timeRange = "six-hours" + default: + return common.LocalError("Unknown time range", w, r, user) + } + var revLabelList []int64 var labelList []int64 var viewMap = make(map[int64]int64) var currentTime = time.Now().Unix() - for i := 1; i <= 12; i++ { - var label = currentTime - int64(i*60*30) + for i := 1; i <= timeSlices; i++ { + var label = currentTime - int64(i*sliceWidth) revLabelList = append(revLabelList, label) viewMap[label] = 0 } @@ -453,7 +528,7 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo log.Print("in routePanelAnalyticsViews") acc := qgen.Builder.Accumulator() - rows, err := acc.Select("viewchunks").Columns("count, createdAt").Where("route = ''").DateCutoff("createdAt", 6, "hour").Query() + rows, err := acc.Select("viewchunks").Columns("count, createdAt").Where("route = ''").DateCutoff("createdAt", timeQuantity, timeUnit).Query() if err != nil && err != ErrNoRows { return common.InternalError(err, w, r) } @@ -483,13 +558,15 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo return common.InternalError(err, w, r) } + var viewItems []common.PanelAnalyticsItem for _, value := range revLabelList { viewList = append(viewList, viewMap[value]) + viewItems = append(viewItems, common.PanelAnalyticsItem{Time: value, Count: viewMap[value]}) } 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} + 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 @@ -563,13 +640,36 @@ func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user headerVars.Stylesheets = append(headerVars.Stylesheets, "chartist/chartist.min.css") headerVars.Scripts = append(headerVars.Scripts, "chartist/chartist.min.js") + var timeQuantity = 6 + var timeUnit = "hour" + var timeSlices = 12 + var sliceWidth = 60 * 30 + var timeRange = "six-hours" + + switch r.FormValue("timeRange") { + case "one-day": + timeQuantity = 1 + timeUnit = "day" + timeSlices = 24 + sliceWidth = 60 * 60 + timeRange = "one-day" + case "twelve-hours": + timeQuantity = 12 + timeSlices = 24 + timeRange = "twelve-hours" + case "six-hours", "": + timeRange = "six-hours" + default: + return common.LocalError("Unknown time range", w, r, user) + } + var revLabelList []int64 var labelList []int64 var viewMap = make(map[int64]int64) var currentTime = time.Now().Unix() - for i := 1; i <= 12; i++ { - var label = currentTime - int64(i*60*30) + for i := 1; i <= timeSlices; i++ { + var label = currentTime - int64(i*sliceWidth) revLabelList = append(revLabelList, label) viewMap[label] = 0 } @@ -581,7 +681,7 @@ func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user log.Print("in routePanelAnalyticsRouteViews") acc := qgen.Builder.Accumulator() - rows, err := acc.Select("viewchunks").Columns("count, createdAt").Where("route = ?").DateCutoff("createdAt", 6, "hour").Query(route) + rows, err := acc.Select("viewchunks").Columns("count, createdAt").Where("route = ?").DateCutoff("createdAt", timeQuantity, timeUnit).Query(route) if err != nil && err != ErrNoRows { return common.InternalError(err, w, r) } @@ -617,7 +717,7 @@ 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} + 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 diff --git a/public/global.js b/public/global.js index fe8c24ba..c08b9589 100644 --- a/public/global.js +++ b/public/global.js @@ -248,15 +248,13 @@ $(document).ready(function(){ $(this).closest('.deletable_block').remove(); }); - $(".edit_item").click(function(event) - { + $(".edit_item").click(function(event){ event.preventDefault(); let blockParent = $(this).closest('.editable_parent'); let block = blockParent.find('.editable_block').eq(0); block.html("
"); - $(".submit_edit").click(function(event) - { + $(".submit_edit").click(function(event){ event.preventDefault(); let blockParent = $(this).closest('.editable_parent'); let block = blockParent.find('.editable_block').eq(0); @@ -270,6 +268,12 @@ $(document).ready(function(){ }); }); + $("#forum_quick_perms").click(function(){ + $(".submit_edit").click(function(event){ + + }); + }); + $(".edit_field").click(function(event) { event.preventDefault(); @@ -536,8 +540,16 @@ $(document).ready(function(){ }); }); + // The time range selector for the time graphs in the Control Panel + $(".timeRangeSelector").change(function(){ + console.log("Changed the time range to " + this.options[this.selectedIndex].getAttribute("val")); + window.location = this.form.getAttribute("action")+"?timeRange=" + this.options[this.selectedIndex].getAttribute("val"); // Do a redirect as a form submission refuses to work properly + }); + this.onkeyup = function(event) { if(event.which == 37) this.querySelectorAll("#prevFloat a")[0].click(); if(event.which == 39) this.querySelectorAll("#nextFloat a")[0].click(); }; + + }); diff --git a/query_gen/tables.go b/query_gen/tables.go index 9f935ac3..8a10cda0 100644 --- a/query_gen/tables.go +++ b/query_gen/tables.go @@ -17,6 +17,7 @@ func createTables(adapter qgen.Adapter) error { qgen.DBTableColumn{"createdAt", "createdAt", 0, false, false, ""}, qgen.DBTableColumn{"lastActiveAt", "datetime", 0, false, false, ""}, qgen.DBTableColumn{"session", "varchar", 200, false, false, "''"}, + //qgen.DBTableColumn{"authToken", "varchar", 200, false, false, "''"}, qgen.DBTableColumn{"last_ip", "varchar", 200, false, false, "0.0.0.0.0"}, qgen.DBTableColumn{"email", "varchar", 200, false, false, "''"}, qgen.DBTableColumn{"avatar", "varchar", 100, false, false, "''"}, diff --git a/router_gen/routes.go b/router_gen/routes.go index 4b6b52e5..f48bc4d5 100644 --- a/router_gen/routes.go +++ b/router_gen/routes.go @@ -66,6 +66,7 @@ func buildPanelRoutes() { View("routePanelForumsEdit", "/panel/forums/edit/", "extraData"), Action("routePanelForumsEditSubmit", "/panel/forums/edit/submit/", "extraData"), Action("routePanelForumsEditPermsSubmit", "/panel/forums/edit/perms/submit/", "extraData"), + View("routePanelForumsEditPermsAdvance", "/panel/forums/edit/perms/", "extraData"), View("routePanelSettings", "/panel/settings/"), View("routePanelSettingEdit", "/panel/settings/edit/", "extraData"), @@ -89,7 +90,7 @@ func buildPanelRoutes() { View("routePanelUsersEdit", "/panel/users/edit/", "extraData"), Action("routePanelUsersEditSubmit", "/panel/users/edit/submit/", "extraData"), - View("routePanelAnalyticsViews", "/panel/analytics/views/"), + View("routePanelAnalyticsViews", "/panel/analytics/views/").Before("ParseForm"), View("routePanelAnalyticsRoutes", "/panel/analytics/routes/"), View("routePanelAnalyticsRouteViews", "/panel/analytics/route/", "extraData"), diff --git a/templates/panel-analytics-route-views.html b/templates/panel-analytics-route-views.html index fe513207..f9c09916 100644 --- a/templates/panel-analytics-route-views.html +++ b/templates/panel-analytics-route-views.html @@ -2,9 +2,18 @@
{{template "panel-menu.html" . }}
- +
+
+
+ {{.Route}} Views + +
+
+
diff --git a/templates/panel-analytics-views.html b/templates/panel-analytics-views.html index e25e8557..1bab82f1 100644 --- a/templates/panel-analytics-views.html +++ b/templates/panel-analytics-views.html @@ -2,12 +2,29 @@
{{template "panel-menu.html" . }}
-
- -
+
+
+
+ Views + +
+
+
-
+
+ {{/**}}
+ {{range .ViewItems}} +
+ {{.Time}} + {{.Count}} views +
+ {{end}} +
{{**/}}