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.
This commit is contained in:
parent
d0b6559df9
commit
c7aec90612
|
@ -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.
|
|
@ -154,6 +154,11 @@ type PanelTimeGraph struct {
|
||||||
Labels []int64 // unixtimes for the bottom, gets converted into 1:00, 2:00, etc. with JS
|
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 {
|
type PanelAnalyticsPage struct {
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
|
@ -161,6 +166,8 @@ type PanelAnalyticsPage struct {
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
Zone string
|
Zone string
|
||||||
PrimaryGraph PanelTimeGraph
|
PrimaryGraph PanelTimeGraph
|
||||||
|
ViewItems []PanelAnalyticsItem
|
||||||
|
TimeRange string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelAnalyticsRoutesItem struct {
|
type PanelAnalyticsRoutesItem struct {
|
||||||
|
@ -185,6 +192,7 @@ type PanelAnalyticsRoutePage struct {
|
||||||
Zone string
|
Zone string
|
||||||
Route string
|
Route string
|
||||||
PrimaryGraph PanelTimeGraph
|
PrimaryGraph PanelTimeGraph
|
||||||
|
TimeRange string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelThemesPage struct {
|
type PanelThemesPage struct {
|
||||||
|
|
|
@ -278,7 +278,7 @@ func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) {
|
||||||
|
|
||||||
h := w.Header()
|
h := w.Header()
|
||||||
h.Set("X-Frame-Options", "deny")
|
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
|
// TODO: Set the content policy header
|
||||||
|
|
||||||
return *usercpy, true
|
return *usercpy, true
|
||||||
|
|
|
@ -45,16 +45,17 @@ type User struct {
|
||||||
Perms Perms
|
Perms Perms
|
||||||
PluginPerms map[string]bool
|
PluginPerms map[string]bool
|
||||||
Session string
|
Session string
|
||||||
Loggedin bool
|
//AuthToken string
|
||||||
Avatar string
|
Loggedin bool
|
||||||
Message string
|
Avatar string
|
||||||
URLPrefix string // Move this to another table? Create a user lite?
|
Message string
|
||||||
URLName string
|
URLPrefix string // Move this to another table? Create a user lite?
|
||||||
Tag string
|
URLName string
|
||||||
Level int
|
Tag string
|
||||||
Score int
|
Level int
|
||||||
LastIP string // ! This part of the UserCache data might fall out of date
|
Score int
|
||||||
TempGroup int
|
LastIP string // ! This part of the UserCache data might fall out of date
|
||||||
|
TempGroup int
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserStmts struct {
|
type UserStmts struct {
|
||||||
|
|
282
gen_router.go
282
gen_router.go
|
@ -32,6 +32,7 @@ var RouteMap = map[string]interface{}{
|
||||||
"routePanelForumsEdit": routePanelForumsEdit,
|
"routePanelForumsEdit": routePanelForumsEdit,
|
||||||
"routePanelForumsEditSubmit": routePanelForumsEditSubmit,
|
"routePanelForumsEditSubmit": routePanelForumsEditSubmit,
|
||||||
"routePanelForumsEditPermsSubmit": routePanelForumsEditPermsSubmit,
|
"routePanelForumsEditPermsSubmit": routePanelForumsEditPermsSubmit,
|
||||||
|
"routePanelForumsEditPermsAdvance": routePanelForumsEditPermsAdvance,
|
||||||
"routePanelSettings": routePanelSettings,
|
"routePanelSettings": routePanelSettings,
|
||||||
"routePanelSettingEdit": routePanelSettingEdit,
|
"routePanelSettingEdit": routePanelSettingEdit,
|
||||||
"routePanelSettingEditSubmit": routePanelSettingEditSubmit,
|
"routePanelSettingEditSubmit": routePanelSettingEditSubmit,
|
||||||
|
@ -98,51 +99,52 @@ var routeMapEnum = map[string]int{
|
||||||
"routePanelForumsEdit": 14,
|
"routePanelForumsEdit": 14,
|
||||||
"routePanelForumsEditSubmit": 15,
|
"routePanelForumsEditSubmit": 15,
|
||||||
"routePanelForumsEditPermsSubmit": 16,
|
"routePanelForumsEditPermsSubmit": 16,
|
||||||
"routePanelSettings": 17,
|
"routePanelForumsEditPermsAdvance": 17,
|
||||||
"routePanelSettingEdit": 18,
|
"routePanelSettings": 18,
|
||||||
"routePanelSettingEditSubmit": 19,
|
"routePanelSettingEdit": 19,
|
||||||
"routePanelWordFilters": 20,
|
"routePanelSettingEditSubmit": 20,
|
||||||
"routePanelWordFiltersCreate": 21,
|
"routePanelWordFilters": 21,
|
||||||
"routePanelWordFiltersEdit": 22,
|
"routePanelWordFiltersCreate": 22,
|
||||||
"routePanelWordFiltersEditSubmit": 23,
|
"routePanelWordFiltersEdit": 23,
|
||||||
"routePanelWordFiltersDeleteSubmit": 24,
|
"routePanelWordFiltersEditSubmit": 24,
|
||||||
"routePanelThemes": 25,
|
"routePanelWordFiltersDeleteSubmit": 25,
|
||||||
"routePanelThemesSetDefault": 26,
|
"routePanelThemes": 26,
|
||||||
"routePanelPlugins": 27,
|
"routePanelThemesSetDefault": 27,
|
||||||
"routePanelPluginsActivate": 28,
|
"routePanelPlugins": 28,
|
||||||
"routePanelPluginsDeactivate": 29,
|
"routePanelPluginsActivate": 29,
|
||||||
"routePanelPluginsInstall": 30,
|
"routePanelPluginsDeactivate": 30,
|
||||||
"routePanelUsers": 31,
|
"routePanelPluginsInstall": 31,
|
||||||
"routePanelUsersEdit": 32,
|
"routePanelUsers": 32,
|
||||||
"routePanelUsersEditSubmit": 33,
|
"routePanelUsersEdit": 33,
|
||||||
"routePanelAnalyticsViews": 34,
|
"routePanelUsersEditSubmit": 34,
|
||||||
"routePanelAnalyticsRoutes": 35,
|
"routePanelAnalyticsViews": 35,
|
||||||
"routePanelAnalyticsRouteViews": 36,
|
"routePanelAnalyticsRoutes": 36,
|
||||||
"routePanelGroups": 37,
|
"routePanelAnalyticsRouteViews": 37,
|
||||||
"routePanelGroupsEdit": 38,
|
"routePanelGroups": 38,
|
||||||
"routePanelGroupsEditPerms": 39,
|
"routePanelGroupsEdit": 39,
|
||||||
"routePanelGroupsEditSubmit": 40,
|
"routePanelGroupsEditPerms": 40,
|
||||||
"routePanelGroupsEditPermsSubmit": 41,
|
"routePanelGroupsEditSubmit": 41,
|
||||||
"routePanelGroupsCreateSubmit": 42,
|
"routePanelGroupsEditPermsSubmit": 42,
|
||||||
"routePanelBackups": 43,
|
"routePanelGroupsCreateSubmit": 43,
|
||||||
"routePanelLogsMod": 44,
|
"routePanelBackups": 44,
|
||||||
"routePanelDebug": 45,
|
"routePanelLogsMod": 45,
|
||||||
"routePanel": 46,
|
"routePanelDebug": 46,
|
||||||
"routeAccountEditCritical": 47,
|
"routePanel": 47,
|
||||||
"routeAccountEditCriticalSubmit": 48,
|
"routeAccountEditCritical": 48,
|
||||||
"routeAccountEditAvatar": 49,
|
"routeAccountEditCriticalSubmit": 49,
|
||||||
"routeAccountEditAvatarSubmit": 50,
|
"routeAccountEditAvatar": 50,
|
||||||
"routeAccountEditUsername": 51,
|
"routeAccountEditAvatarSubmit": 51,
|
||||||
"routeAccountEditUsernameSubmit": 52,
|
"routeAccountEditUsername": 52,
|
||||||
"routeAccountEditEmail": 53,
|
"routeAccountEditUsernameSubmit": 53,
|
||||||
"routeAccountEditEmailTokenSubmit": 54,
|
"routeAccountEditEmail": 54,
|
||||||
"routeProfile": 55,
|
"routeAccountEditEmailTokenSubmit": 55,
|
||||||
"routeBanSubmit": 56,
|
"routeProfile": 56,
|
||||||
"routeUnban": 57,
|
"routeBanSubmit": 57,
|
||||||
"routeActivate": 58,
|
"routeUnban": 58,
|
||||||
"routeIps": 59,
|
"routeActivate": 59,
|
||||||
"routeDynamic": 60,
|
"routeIps": 60,
|
||||||
"routeUploads": 61,
|
"routeDynamic": 61,
|
||||||
|
"routeUploads": 62,
|
||||||
}
|
}
|
||||||
var reverseRouteMapEnum = map[int]string{
|
var reverseRouteMapEnum = map[int]string{
|
||||||
0: "routeAPI",
|
0: "routeAPI",
|
||||||
|
@ -162,51 +164,52 @@ var reverseRouteMapEnum = map[int]string{
|
||||||
14: "routePanelForumsEdit",
|
14: "routePanelForumsEdit",
|
||||||
15: "routePanelForumsEditSubmit",
|
15: "routePanelForumsEditSubmit",
|
||||||
16: "routePanelForumsEditPermsSubmit",
|
16: "routePanelForumsEditPermsSubmit",
|
||||||
17: "routePanelSettings",
|
17: "routePanelForumsEditPermsAdvance",
|
||||||
18: "routePanelSettingEdit",
|
18: "routePanelSettings",
|
||||||
19: "routePanelSettingEditSubmit",
|
19: "routePanelSettingEdit",
|
||||||
20: "routePanelWordFilters",
|
20: "routePanelSettingEditSubmit",
|
||||||
21: "routePanelWordFiltersCreate",
|
21: "routePanelWordFilters",
|
||||||
22: "routePanelWordFiltersEdit",
|
22: "routePanelWordFiltersCreate",
|
||||||
23: "routePanelWordFiltersEditSubmit",
|
23: "routePanelWordFiltersEdit",
|
||||||
24: "routePanelWordFiltersDeleteSubmit",
|
24: "routePanelWordFiltersEditSubmit",
|
||||||
25: "routePanelThemes",
|
25: "routePanelWordFiltersDeleteSubmit",
|
||||||
26: "routePanelThemesSetDefault",
|
26: "routePanelThemes",
|
||||||
27: "routePanelPlugins",
|
27: "routePanelThemesSetDefault",
|
||||||
28: "routePanelPluginsActivate",
|
28: "routePanelPlugins",
|
||||||
29: "routePanelPluginsDeactivate",
|
29: "routePanelPluginsActivate",
|
||||||
30: "routePanelPluginsInstall",
|
30: "routePanelPluginsDeactivate",
|
||||||
31: "routePanelUsers",
|
31: "routePanelPluginsInstall",
|
||||||
32: "routePanelUsersEdit",
|
32: "routePanelUsers",
|
||||||
33: "routePanelUsersEditSubmit",
|
33: "routePanelUsersEdit",
|
||||||
34: "routePanelAnalyticsViews",
|
34: "routePanelUsersEditSubmit",
|
||||||
35: "routePanelAnalyticsRoutes",
|
35: "routePanelAnalyticsViews",
|
||||||
36: "routePanelAnalyticsRouteViews",
|
36: "routePanelAnalyticsRoutes",
|
||||||
37: "routePanelGroups",
|
37: "routePanelAnalyticsRouteViews",
|
||||||
38: "routePanelGroupsEdit",
|
38: "routePanelGroups",
|
||||||
39: "routePanelGroupsEditPerms",
|
39: "routePanelGroupsEdit",
|
||||||
40: "routePanelGroupsEditSubmit",
|
40: "routePanelGroupsEditPerms",
|
||||||
41: "routePanelGroupsEditPermsSubmit",
|
41: "routePanelGroupsEditSubmit",
|
||||||
42: "routePanelGroupsCreateSubmit",
|
42: "routePanelGroupsEditPermsSubmit",
|
||||||
43: "routePanelBackups",
|
43: "routePanelGroupsCreateSubmit",
|
||||||
44: "routePanelLogsMod",
|
44: "routePanelBackups",
|
||||||
45: "routePanelDebug",
|
45: "routePanelLogsMod",
|
||||||
46: "routePanel",
|
46: "routePanelDebug",
|
||||||
47: "routeAccountEditCritical",
|
47: "routePanel",
|
||||||
48: "routeAccountEditCriticalSubmit",
|
48: "routeAccountEditCritical",
|
||||||
49: "routeAccountEditAvatar",
|
49: "routeAccountEditCriticalSubmit",
|
||||||
50: "routeAccountEditAvatarSubmit",
|
50: "routeAccountEditAvatar",
|
||||||
51: "routeAccountEditUsername",
|
51: "routeAccountEditAvatarSubmit",
|
||||||
52: "routeAccountEditUsernameSubmit",
|
52: "routeAccountEditUsername",
|
||||||
53: "routeAccountEditEmail",
|
53: "routeAccountEditUsernameSubmit",
|
||||||
54: "routeAccountEditEmailTokenSubmit",
|
54: "routeAccountEditEmail",
|
||||||
55: "routeProfile",
|
55: "routeAccountEditEmailTokenSubmit",
|
||||||
56: "routeBanSubmit",
|
56: "routeProfile",
|
||||||
57: "routeUnban",
|
57: "routeBanSubmit",
|
||||||
58: "routeActivate",
|
58: "routeUnban",
|
||||||
59: "routeIps",
|
59: "routeActivate",
|
||||||
60: "routeDynamic",
|
60: "routeIps",
|
||||||
61: "routeUploads",
|
61: "routeDynamic",
|
||||||
|
62: "routeUploads",
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Stop spilling these into the package scope?
|
// 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)
|
common.RouteViewCounter.Bump(16)
|
||||||
err = routePanelForumsEditPermsSubmit(w,req,user,extraData)
|
err = routePanelForumsEditPermsSubmit(w,req,user,extraData)
|
||||||
case "/panel/settings/":
|
case "/panel/forums/edit/perms/":
|
||||||
common.RouteViewCounter.Bump(17)
|
common.RouteViewCounter.Bump(17)
|
||||||
|
err = routePanelForumsEditPermsAdvance(w,req,user,extraData)
|
||||||
|
case "/panel/settings/":
|
||||||
|
common.RouteViewCounter.Bump(18)
|
||||||
err = routePanelSettings(w,req,user)
|
err = routePanelSettings(w,req,user)
|
||||||
case "/panel/settings/edit/":
|
case "/panel/settings/edit/":
|
||||||
common.RouteViewCounter.Bump(18)
|
common.RouteViewCounter.Bump(19)
|
||||||
err = routePanelSettingEdit(w,req,user,extraData)
|
err = routePanelSettingEdit(w,req,user,extraData)
|
||||||
case "/panel/settings/edit/submit/":
|
case "/panel/settings/edit/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -482,10 +488,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(19)
|
common.RouteViewCounter.Bump(20)
|
||||||
err = routePanelSettingEditSubmit(w,req,user,extraData)
|
err = routePanelSettingEditSubmit(w,req,user,extraData)
|
||||||
case "/panel/settings/word-filters/":
|
case "/panel/settings/word-filters/":
|
||||||
common.RouteViewCounter.Bump(20)
|
common.RouteViewCounter.Bump(21)
|
||||||
err = routePanelWordFilters(w,req,user)
|
err = routePanelWordFilters(w,req,user)
|
||||||
case "/panel/settings/word-filters/create/":
|
case "/panel/settings/word-filters/create/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -494,10 +500,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(21)
|
common.RouteViewCounter.Bump(22)
|
||||||
err = routePanelWordFiltersCreate(w,req,user)
|
err = routePanelWordFiltersCreate(w,req,user)
|
||||||
case "/panel/settings/word-filters/edit/":
|
case "/panel/settings/word-filters/edit/":
|
||||||
common.RouteViewCounter.Bump(22)
|
common.RouteViewCounter.Bump(23)
|
||||||
err = routePanelWordFiltersEdit(w,req,user,extraData)
|
err = routePanelWordFiltersEdit(w,req,user,extraData)
|
||||||
case "/panel/settings/word-filters/edit/submit/":
|
case "/panel/settings/word-filters/edit/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -506,7 +512,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(23)
|
common.RouteViewCounter.Bump(24)
|
||||||
err = routePanelWordFiltersEditSubmit(w,req,user,extraData)
|
err = routePanelWordFiltersEditSubmit(w,req,user,extraData)
|
||||||
case "/panel/settings/word-filters/delete/submit/":
|
case "/panel/settings/word-filters/delete/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -515,10 +521,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(24)
|
common.RouteViewCounter.Bump(25)
|
||||||
err = routePanelWordFiltersDeleteSubmit(w,req,user,extraData)
|
err = routePanelWordFiltersDeleteSubmit(w,req,user,extraData)
|
||||||
case "/panel/themes/":
|
case "/panel/themes/":
|
||||||
common.RouteViewCounter.Bump(25)
|
common.RouteViewCounter.Bump(26)
|
||||||
err = routePanelThemes(w,req,user)
|
err = routePanelThemes(w,req,user)
|
||||||
case "/panel/themes/default/":
|
case "/panel/themes/default/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -527,10 +533,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(26)
|
common.RouteViewCounter.Bump(27)
|
||||||
err = routePanelThemesSetDefault(w,req,user,extraData)
|
err = routePanelThemesSetDefault(w,req,user,extraData)
|
||||||
case "/panel/plugins/":
|
case "/panel/plugins/":
|
||||||
common.RouteViewCounter.Bump(27)
|
common.RouteViewCounter.Bump(28)
|
||||||
err = routePanelPlugins(w,req,user)
|
err = routePanelPlugins(w,req,user)
|
||||||
case "/panel/plugins/activate/":
|
case "/panel/plugins/activate/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -539,7 +545,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(28)
|
common.RouteViewCounter.Bump(29)
|
||||||
err = routePanelPluginsActivate(w,req,user,extraData)
|
err = routePanelPluginsActivate(w,req,user,extraData)
|
||||||
case "/panel/plugins/deactivate/":
|
case "/panel/plugins/deactivate/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -548,7 +554,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(29)
|
common.RouteViewCounter.Bump(30)
|
||||||
err = routePanelPluginsDeactivate(w,req,user,extraData)
|
err = routePanelPluginsDeactivate(w,req,user,extraData)
|
||||||
case "/panel/plugins/install/":
|
case "/panel/plugins/install/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -557,13 +563,13 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(30)
|
common.RouteViewCounter.Bump(31)
|
||||||
err = routePanelPluginsInstall(w,req,user,extraData)
|
err = routePanelPluginsInstall(w,req,user,extraData)
|
||||||
case "/panel/users/":
|
case "/panel/users/":
|
||||||
common.RouteViewCounter.Bump(31)
|
common.RouteViewCounter.Bump(32)
|
||||||
err = routePanelUsers(w,req,user)
|
err = routePanelUsers(w,req,user)
|
||||||
case "/panel/users/edit/":
|
case "/panel/users/edit/":
|
||||||
common.RouteViewCounter.Bump(32)
|
common.RouteViewCounter.Bump(33)
|
||||||
err = routePanelUsersEdit(w,req,user,extraData)
|
err = routePanelUsersEdit(w,req,user,extraData)
|
||||||
case "/panel/users/edit/submit/":
|
case "/panel/users/edit/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -572,25 +578,31 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(33)
|
common.RouteViewCounter.Bump(34)
|
||||||
err = routePanelUsersEditSubmit(w,req,user,extraData)
|
err = routePanelUsersEditSubmit(w,req,user,extraData)
|
||||||
case "/panel/analytics/views/":
|
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)
|
err = routePanelAnalyticsViews(w,req,user)
|
||||||
case "/panel/analytics/routes/":
|
case "/panel/analytics/routes/":
|
||||||
common.RouteViewCounter.Bump(35)
|
common.RouteViewCounter.Bump(36)
|
||||||
err = routePanelAnalyticsRoutes(w,req,user)
|
err = routePanelAnalyticsRoutes(w,req,user)
|
||||||
case "/panel/analytics/route/":
|
case "/panel/analytics/route/":
|
||||||
common.RouteViewCounter.Bump(36)
|
common.RouteViewCounter.Bump(37)
|
||||||
err = routePanelAnalyticsRouteViews(w,req,user,extraData)
|
err = routePanelAnalyticsRouteViews(w,req,user,extraData)
|
||||||
case "/panel/groups/":
|
case "/panel/groups/":
|
||||||
common.RouteViewCounter.Bump(37)
|
common.RouteViewCounter.Bump(38)
|
||||||
err = routePanelGroups(w,req,user)
|
err = routePanelGroups(w,req,user)
|
||||||
case "/panel/groups/edit/":
|
case "/panel/groups/edit/":
|
||||||
common.RouteViewCounter.Bump(38)
|
common.RouteViewCounter.Bump(39)
|
||||||
err = routePanelGroupsEdit(w,req,user,extraData)
|
err = routePanelGroupsEdit(w,req,user,extraData)
|
||||||
case "/panel/groups/edit/perms/":
|
case "/panel/groups/edit/perms/":
|
||||||
common.RouteViewCounter.Bump(39)
|
common.RouteViewCounter.Bump(40)
|
||||||
err = routePanelGroupsEditPerms(w,req,user,extraData)
|
err = routePanelGroupsEditPerms(w,req,user,extraData)
|
||||||
case "/panel/groups/edit/submit/":
|
case "/panel/groups/edit/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -599,7 +611,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(40)
|
common.RouteViewCounter.Bump(41)
|
||||||
err = routePanelGroupsEditSubmit(w,req,user,extraData)
|
err = routePanelGroupsEditSubmit(w,req,user,extraData)
|
||||||
case "/panel/groups/edit/perms/submit/":
|
case "/panel/groups/edit/perms/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -608,7 +620,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(41)
|
common.RouteViewCounter.Bump(42)
|
||||||
err = routePanelGroupsEditPermsSubmit(w,req,user,extraData)
|
err = routePanelGroupsEditPermsSubmit(w,req,user,extraData)
|
||||||
case "/panel/groups/create/":
|
case "/panel/groups/create/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -617,7 +629,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(42)
|
common.RouteViewCounter.Bump(43)
|
||||||
err = routePanelGroupsCreateSubmit(w,req,user)
|
err = routePanelGroupsCreateSubmit(w,req,user)
|
||||||
case "/panel/backups/":
|
case "/panel/backups/":
|
||||||
err = common.SuperAdminOnly(w,req,user)
|
err = common.SuperAdminOnly(w,req,user)
|
||||||
|
@ -626,10 +638,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(43)
|
common.RouteViewCounter.Bump(44)
|
||||||
err = routePanelBackups(w,req,user,extraData)
|
err = routePanelBackups(w,req,user,extraData)
|
||||||
case "/panel/logs/mod/":
|
case "/panel/logs/mod/":
|
||||||
common.RouteViewCounter.Bump(44)
|
common.RouteViewCounter.Bump(45)
|
||||||
err = routePanelLogsMod(w,req,user)
|
err = routePanelLogsMod(w,req,user)
|
||||||
case "/panel/debug/":
|
case "/panel/debug/":
|
||||||
err = common.AdminOnly(w,req,user)
|
err = common.AdminOnly(w,req,user)
|
||||||
|
@ -638,10 +650,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(45)
|
common.RouteViewCounter.Bump(46)
|
||||||
err = routePanelDebug(w,req,user)
|
err = routePanelDebug(w,req,user)
|
||||||
default:
|
default:
|
||||||
common.RouteViewCounter.Bump(46)
|
common.RouteViewCounter.Bump(47)
|
||||||
err = routePanel(w,req,user)
|
err = routePanel(w,req,user)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -656,7 +668,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(47)
|
common.RouteViewCounter.Bump(48)
|
||||||
err = routeAccountEditCritical(w,req,user)
|
err = routeAccountEditCritical(w,req,user)
|
||||||
case "/user/edit/critical/submit/":
|
case "/user/edit/critical/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -671,7 +683,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(48)
|
common.RouteViewCounter.Bump(49)
|
||||||
err = routeAccountEditCriticalSubmit(w,req,user)
|
err = routeAccountEditCriticalSubmit(w,req,user)
|
||||||
case "/user/edit/avatar/":
|
case "/user/edit/avatar/":
|
||||||
err = common.MemberOnly(w,req,user)
|
err = common.MemberOnly(w,req,user)
|
||||||
|
@ -680,7 +692,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(49)
|
common.RouteViewCounter.Bump(50)
|
||||||
err = routeAccountEditAvatar(w,req,user)
|
err = routeAccountEditAvatar(w,req,user)
|
||||||
case "/user/edit/avatar/submit/":
|
case "/user/edit/avatar/submit/":
|
||||||
err = common.MemberOnly(w,req,user)
|
err = common.MemberOnly(w,req,user)
|
||||||
|
@ -689,7 +701,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(50)
|
common.RouteViewCounter.Bump(51)
|
||||||
err = routeAccountEditAvatarSubmit(w,req,user)
|
err = routeAccountEditAvatarSubmit(w,req,user)
|
||||||
case "/user/edit/username/":
|
case "/user/edit/username/":
|
||||||
err = common.MemberOnly(w,req,user)
|
err = common.MemberOnly(w,req,user)
|
||||||
|
@ -698,7 +710,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(51)
|
common.RouteViewCounter.Bump(52)
|
||||||
err = routeAccountEditUsername(w,req,user)
|
err = routeAccountEditUsername(w,req,user)
|
||||||
case "/user/edit/username/submit/":
|
case "/user/edit/username/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -713,7 +725,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(52)
|
common.RouteViewCounter.Bump(53)
|
||||||
err = routeAccountEditUsernameSubmit(w,req,user)
|
err = routeAccountEditUsernameSubmit(w,req,user)
|
||||||
case "/user/edit/email/":
|
case "/user/edit/email/":
|
||||||
err = common.MemberOnly(w,req,user)
|
err = common.MemberOnly(w,req,user)
|
||||||
|
@ -722,7 +734,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(53)
|
common.RouteViewCounter.Bump(54)
|
||||||
err = routeAccountEditEmail(w,req,user)
|
err = routeAccountEditEmail(w,req,user)
|
||||||
case "/user/edit/token/":
|
case "/user/edit/token/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -737,11 +749,11 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(54)
|
common.RouteViewCounter.Bump(55)
|
||||||
err = routeAccountEditEmailTokenSubmit(w,req,user,extraData)
|
err = routeAccountEditEmailTokenSubmit(w,req,user,extraData)
|
||||||
default:
|
default:
|
||||||
req.URL.Path += extraData
|
req.URL.Path += extraData
|
||||||
common.RouteViewCounter.Bump(55)
|
common.RouteViewCounter.Bump(56)
|
||||||
err = routeProfile(w,req,user)
|
err = routeProfile(w,req,user)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -762,7 +774,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(56)
|
common.RouteViewCounter.Bump(57)
|
||||||
err = routeBanSubmit(w,req,user,extraData)
|
err = routeBanSubmit(w,req,user,extraData)
|
||||||
case "/users/unban/":
|
case "/users/unban/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -777,7 +789,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(57)
|
common.RouteViewCounter.Bump(58)
|
||||||
err = routeUnban(w,req,user,extraData)
|
err = routeUnban(w,req,user,extraData)
|
||||||
case "/users/activate/":
|
case "/users/activate/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
|
@ -792,7 +804,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(58)
|
common.RouteViewCounter.Bump(59)
|
||||||
err = routeActivate(w,req,user,extraData)
|
err = routeActivate(w,req,user,extraData)
|
||||||
case "/users/ips/":
|
case "/users/ips/":
|
||||||
err = common.MemberOnly(w,req,user)
|
err = common.MemberOnly(w,req,user)
|
||||||
|
@ -801,7 +813,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(59)
|
common.RouteViewCounter.Bump(60)
|
||||||
err = routeIps(w,req,user)
|
err = routeIps(w,req,user)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -818,7 +830,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
common.NotFound(w,req)
|
common.NotFound(w,req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
common.RouteViewCounter.Bump(61)
|
common.RouteViewCounter.Bump(62)
|
||||||
req.URL.Path += extraData
|
req.URL.Path += extraData
|
||||||
// TODO: Find a way to propagate errors up from this?
|
// TODO: Find a way to propagate errors up from this?
|
||||||
router.UploadHandler(w,req) // TODO: Count these views
|
router.UploadHandler(w,req) // TODO: Count these views
|
||||||
|
@ -862,7 +874,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
router.RUnlock()
|
router.RUnlock()
|
||||||
|
|
||||||
if ok {
|
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
|
req.URL.Path += extraData
|
||||||
err = handle(w,req,user)
|
err = handle(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
116
panel_routes.go
116
panel_routes.go
|
@ -427,6 +427,58 @@ func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use
|
||||||
return nil
|
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 {
|
func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||||
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
|
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
|
||||||
if ferr != nil {
|
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.Stylesheets = append(headerVars.Stylesheets, "chartist/chartist.min.css")
|
||||||
headerVars.Scripts = append(headerVars.Scripts, "chartist/chartist.min.js")
|
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 revLabelList []int64
|
||||||
var labelList []int64
|
var labelList []int64
|
||||||
var viewMap = make(map[int64]int64)
|
var viewMap = make(map[int64]int64)
|
||||||
var currentTime = time.Now().Unix()
|
var currentTime = time.Now().Unix()
|
||||||
|
|
||||||
for i := 1; i <= 12; i++ {
|
for i := 1; i <= timeSlices; i++ {
|
||||||
var label = currentTime - int64(i*60*30)
|
var label = currentTime - int64(i*sliceWidth)
|
||||||
revLabelList = append(revLabelList, label)
|
revLabelList = append(revLabelList, label)
|
||||||
viewMap[label] = 0
|
viewMap[label] = 0
|
||||||
}
|
}
|
||||||
|
@ -453,7 +528,7 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo
|
||||||
log.Print("in routePanelAnalyticsViews")
|
log.Print("in routePanelAnalyticsViews")
|
||||||
|
|
||||||
acc := qgen.Builder.Accumulator()
|
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 {
|
if err != nil && err != ErrNoRows {
|
||||||
return common.InternalError(err, w, r)
|
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)
|
return common.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var viewItems []common.PanelAnalyticsItem
|
||||||
for _, value := range revLabelList {
|
for _, value := range revLabelList {
|
||||||
viewList = append(viewList, viewMap[value])
|
viewList = append(viewList, viewMap[value])
|
||||||
|
viewItems = append(viewItems, common.PanelAnalyticsItem{Time: value, Count: viewMap[value]})
|
||||||
}
|
}
|
||||||
graph := common.PanelTimeGraph{Series: viewList, Labels: labelList}
|
graph := common.PanelTimeGraph{Series: viewList, Labels: labelList}
|
||||||
log.Printf("graph: %+v\n", graph)
|
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.PreRenderHooks["pre_render_panel_analytics"] != nil {
|
||||||
if common.RunPreRenderHook("pre_render_panel_analytics", w, r, &user, &pi) {
|
if common.RunPreRenderHook("pre_render_panel_analytics", w, r, &user, &pi) {
|
||||||
return nil
|
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.Stylesheets = append(headerVars.Stylesheets, "chartist/chartist.min.css")
|
||||||
headerVars.Scripts = append(headerVars.Scripts, "chartist/chartist.min.js")
|
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 revLabelList []int64
|
||||||
var labelList []int64
|
var labelList []int64
|
||||||
var viewMap = make(map[int64]int64)
|
var viewMap = make(map[int64]int64)
|
||||||
var currentTime = time.Now().Unix()
|
var currentTime = time.Now().Unix()
|
||||||
|
|
||||||
for i := 1; i <= 12; i++ {
|
for i := 1; i <= timeSlices; i++ {
|
||||||
var label = currentTime - int64(i*60*30)
|
var label = currentTime - int64(i*sliceWidth)
|
||||||
revLabelList = append(revLabelList, label)
|
revLabelList = append(revLabelList, label)
|
||||||
viewMap[label] = 0
|
viewMap[label] = 0
|
||||||
}
|
}
|
||||||
|
@ -581,7 +681,7 @@ func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user
|
||||||
log.Print("in routePanelAnalyticsRouteViews")
|
log.Print("in routePanelAnalyticsRouteViews")
|
||||||
|
|
||||||
acc := qgen.Builder.Accumulator()
|
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 {
|
if err != nil && err != ErrNoRows {
|
||||||
return common.InternalError(err, w, r)
|
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}
|
graph := common.PanelTimeGraph{Series: viewList, Labels: labelList}
|
||||||
log.Printf("graph: %+v\n", graph)
|
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.PreRenderHooks["pre_render_panel_analytics_route_views"] != nil {
|
||||||
if common.RunPreRenderHook("pre_render_panel_analytics_route_views", w, r, &user, &pi) {
|
if common.RunPreRenderHook("pre_render_panel_analytics_route_views", w, r, &user, &pi) {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -248,15 +248,13 @@ $(document).ready(function(){
|
||||||
$(this).closest('.deletable_block').remove();
|
$(this).closest('.deletable_block').remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".edit_item").click(function(event)
|
$(".edit_item").click(function(event){
|
||||||
{
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let blockParent = $(this).closest('.editable_parent');
|
let blockParent = $(this).closest('.editable_parent');
|
||||||
let block = blockParent.find('.editable_block').eq(0);
|
let block = blockParent.find('.editable_block').eq(0);
|
||||||
block.html("<textarea style='width: 99%;' name='edit_item'>" + block.html() + "</textarea><br /><a href='" + $(this).closest('a').attr("href") + "'><button class='submit_edit' type='submit'>Update</button></a>");
|
block.html("<textarea style='width: 99%;' name='edit_item'>" + block.html() + "</textarea><br /><a href='" + $(this).closest('a').attr("href") + "'><button class='submit_edit' type='submit'>Update</button></a>");
|
||||||
|
|
||||||
$(".submit_edit").click(function(event)
|
$(".submit_edit").click(function(event){
|
||||||
{
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let blockParent = $(this).closest('.editable_parent');
|
let blockParent = $(this).closest('.editable_parent');
|
||||||
let block = blockParent.find('.editable_block').eq(0);
|
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)
|
$(".edit_field").click(function(event)
|
||||||
{
|
{
|
||||||
event.preventDefault();
|
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) {
|
this.onkeyup = function(event) {
|
||||||
if(event.which == 37) this.querySelectorAll("#prevFloat a")[0].click();
|
if(event.which == 37) this.querySelectorAll("#prevFloat a")[0].click();
|
||||||
if(event.which == 39) this.querySelectorAll("#nextFloat a")[0].click();
|
if(event.which == 39) this.querySelectorAll("#nextFloat a")[0].click();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,6 +17,7 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
qgen.DBTableColumn{"createdAt", "createdAt", 0, false, false, ""},
|
qgen.DBTableColumn{"createdAt", "createdAt", 0, false, false, ""},
|
||||||
qgen.DBTableColumn{"lastActiveAt", "datetime", 0, false, false, ""},
|
qgen.DBTableColumn{"lastActiveAt", "datetime", 0, false, false, ""},
|
||||||
qgen.DBTableColumn{"session", "varchar", 200, 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{"last_ip", "varchar", 200, false, false, "0.0.0.0.0"},
|
||||||
qgen.DBTableColumn{"email", "varchar", 200, false, false, "''"},
|
qgen.DBTableColumn{"email", "varchar", 200, false, false, "''"},
|
||||||
qgen.DBTableColumn{"avatar", "varchar", 100, false, false, "''"},
|
qgen.DBTableColumn{"avatar", "varchar", 100, false, false, "''"},
|
||||||
|
|
|
@ -66,6 +66,7 @@ func buildPanelRoutes() {
|
||||||
View("routePanelForumsEdit", "/panel/forums/edit/", "extraData"),
|
View("routePanelForumsEdit", "/panel/forums/edit/", "extraData"),
|
||||||
Action("routePanelForumsEditSubmit", "/panel/forums/edit/submit/", "extraData"),
|
Action("routePanelForumsEditSubmit", "/panel/forums/edit/submit/", "extraData"),
|
||||||
Action("routePanelForumsEditPermsSubmit", "/panel/forums/edit/perms/submit/", "extraData"),
|
Action("routePanelForumsEditPermsSubmit", "/panel/forums/edit/perms/submit/", "extraData"),
|
||||||
|
View("routePanelForumsEditPermsAdvance", "/panel/forums/edit/perms/", "extraData"),
|
||||||
|
|
||||||
View("routePanelSettings", "/panel/settings/"),
|
View("routePanelSettings", "/panel/settings/"),
|
||||||
View("routePanelSettingEdit", "/panel/settings/edit/", "extraData"),
|
View("routePanelSettingEdit", "/panel/settings/edit/", "extraData"),
|
||||||
|
@ -89,7 +90,7 @@ func buildPanelRoutes() {
|
||||||
View("routePanelUsersEdit", "/panel/users/edit/", "extraData"),
|
View("routePanelUsersEdit", "/panel/users/edit/", "extraData"),
|
||||||
Action("routePanelUsersEditSubmit", "/panel/users/edit/submit/", "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("routePanelAnalyticsRoutes", "/panel/analytics/routes/"),
|
||||||
View("routePanelAnalyticsRouteViews", "/panel/analytics/route/", "extraData"),
|
View("routePanelAnalyticsRouteViews", "/panel/analytics/route/", "extraData"),
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,18 @@
|
||||||
<div class="colstack panel_stack">
|
<div class="colstack panel_stack">
|
||||||
{{template "panel-menu.html" . }}
|
{{template "panel-menu.html" . }}
|
||||||
<main id="panel_dashboard_right" class="colstack_right">
|
<main id="panel_dashboard_right" class="colstack_right">
|
||||||
<div class="colstack_item colstack_head">
|
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/route/{{.Route}}" method="get">
|
||||||
<div class="rowitem"><a>{{.Route}} Views</a></div>
|
<div class="colstack_item colstack_head">
|
||||||
</div>
|
<div class="rowitem">
|
||||||
|
<a>{{.Route}} Views</a>
|
||||||
|
<select class="timeRangeSelector to_right" name="timeRange">
|
||||||
|
<option val="one-day"{{if eq .TimeRange "one-day"}} selected{{end}}>1 day</option>
|
||||||
|
<option val="twelve-hours"{{if eq .TimeRange "twelve-hours"}} selected{{end}}>12 hours</option>
|
||||||
|
<option val="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>6 hours</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
<div id="panel_analytics_views" class="colstack_graph_holder">
|
<div id="panel_analytics_views" class="colstack_graph_holder">
|
||||||
<div class="ct-chart"></div>
|
<div class="ct-chart"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,12 +2,29 @@
|
||||||
<div class="colstack panel_stack">
|
<div class="colstack panel_stack">
|
||||||
{{template "panel-menu.html" . }}
|
{{template "panel-menu.html" . }}
|
||||||
<main id="panel_dashboard_right" class="colstack_right">
|
<main id="panel_dashboard_right" class="colstack_right">
|
||||||
<div class="colstack_item colstack_head">
|
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/views/" method="get">
|
||||||
<div class="rowitem"><a>Views</a></div>
|
<div class="colstack_item colstack_head">
|
||||||
</div>
|
<div class="rowitem">
|
||||||
|
<a>Views</a>
|
||||||
|
<select class="timeRangeSelector to_right" name="timeRange">
|
||||||
|
<option val="one-day"{{if eq .TimeRange "one-day"}} selected{{end}}>1 day</option>
|
||||||
|
<option val="twelve-hours"{{if eq .TimeRange "twelve-hours"}} selected{{end}}>12 hours</option>
|
||||||
|
<option val="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>6 hours</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
<div id="panel_analytics_views" class="colstack_graph_holder">
|
<div id="panel_analytics_views" class="colstack_graph_holder">
|
||||||
<div class="ct-chart"></div>
|
<div class="ct_chart"></div>
|
||||||
</div>
|
</div>
|
||||||
|
{{/**}}<div id="panel_analytics_views_table" class="colstack_item rowlist">
|
||||||
|
{{range .ViewItems}}
|
||||||
|
<div class="rowitem panel_compactrow editable_parent">
|
||||||
|
<a class="panel_upshift unix_to_minute_time">{{.Time}}</a>
|
||||||
|
<span class="panel_compacttext to_right">{{.Count}} views</span>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>{{**/}}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
@ -30,7 +47,7 @@ let seriesData = [{{range .PrimaryGraph.Series}}
|
||||||
];
|
];
|
||||||
seriesData = seriesData.reverse();
|
seriesData = seriesData.reverse();
|
||||||
|
|
||||||
Chartist.Line('.ct-chart', {
|
Chartist.Line('.ct_chart', {
|
||||||
labels: labels,
|
labels: labels,
|
||||||
series: [seriesData],
|
series: [seriesData],
|
||||||
}, {
|
}, {
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
{{template "header.html" . }}
|
||||||
|
<div class="colstack panel_stack">
|
||||||
|
{{template "panel-menu.html" . }}
|
||||||
|
|
||||||
|
<main class="colstack_right">
|
||||||
|
<div class="colstack_item colstack_head">
|
||||||
|
<div class="rowitem"><h1>{{.Name}} Forum</h1></div>
|
||||||
|
</div>
|
||||||
|
<form action="/panel/groups/edit/perms/submit/{{.ID}}?session={{.CurrentUser.Session}}" method="post">
|
||||||
|
<div class="colstack_item rowlist formlist panel_forum_perms">
|
||||||
|
{{range .Perms}}
|
||||||
|
<div class="formrow">
|
||||||
|
<div class="formitem">
|
||||||
|
<a>{{.LangStr}}</a>
|
||||||
|
<div class="to_right">
|
||||||
|
<select name="forum-perm-{{.Name}}">
|
||||||
|
<option{{if .Toggle}} selected{{end}} value=1>Yes</option>
|
||||||
|
<option{{if not .Toggle}} selected{{end}} value=0>No</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
<div class="formrow">
|
||||||
|
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">Update Forum</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
{{template "footer.html" . }}
|
|
@ -16,13 +16,13 @@
|
||||||
<div class="rowitem"><h1>{{.Name}} Group</h1></div>
|
<div class="rowitem"><h1>{{.Name}} Group</h1></div>
|
||||||
</div>
|
</div>
|
||||||
<form action="/panel/groups/edit/perms/submit/{{.ID}}?session={{.CurrentUser.Session}}" method="post">
|
<form action="/panel/groups/edit/perms/submit/{{.ID}}?session={{.CurrentUser.Session}}" method="post">
|
||||||
<div id="panel_group" class="colstack_item rowlist formlist">
|
{{if .CurrentUser.Perms.EditGroupLocalPerms}}
|
||||||
{{if .CurrentUser.Perms.EditGroupLocalPerms}}
|
<div class="colstack_item rowlist formlist panel_group_perms">
|
||||||
{{range .LocalPerms}}
|
{{range .LocalPerms}}
|
||||||
<div class="formrow">
|
<div class="formrow">
|
||||||
<div class="formitem">
|
<div class="formitem">
|
||||||
<a>{{.LangStr}}</a>
|
<a>{{.LangStr}}</a>
|
||||||
<div style="float: right;">
|
<div class="to_right">
|
||||||
<select name="group-perm-{{.Name}}">
|
<select name="group-perm-{{.Name}}">
|
||||||
<option{{if .Toggle}} selected{{end}} value=1>Yes</option>
|
<option{{if .Toggle}} selected{{end}} value=1>Yes</option>
|
||||||
<option{{if not .Toggle}} selected{{end}} value=0>No</option>
|
<option{{if not .Toggle}} selected{{end}} value=0>No</option>
|
||||||
|
@ -31,21 +31,21 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
|
||||||
<div class="formrow">
|
<div class="formrow">
|
||||||
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">Update Group</button></div>
|
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">Update Group</button></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{if .CurrentUser.Perms.EditGroupGlobalPerms}}
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem"><h1>Extended Permissions</h1></div>
|
<div class="rowitem"><h1>Extended Permissions</h1></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="colstack_item rowlist formlist">
|
<div class="colstack_item rowlist formlist panel_group_perms">
|
||||||
{{if .CurrentUser.Perms.EditGroupGlobalPerms}}
|
|
||||||
{{range .GlobalPerms}}
|
{{range .GlobalPerms}}
|
||||||
<div class="formrow">
|
<div class="formrow">
|
||||||
<div class="formitem">
|
<div class="formitem">
|
||||||
<a>{{.LangStr}}</a>
|
<a>{{.LangStr}}</a>
|
||||||
<div style="float: right;">
|
<div class="to_right">
|
||||||
<select name="group-perm-{{.Name}}">
|
<select name="group-perm-{{.Name}}">
|
||||||
<option{{if .Toggle}} selected{{end}} value=1>Yes</option>
|
<option{{if .Toggle}} selected{{end}} value=1>Yes</option>
|
||||||
<option{{if not .Toggle}} selected{{end}} value=0>No</option>
|
<option{{if not .Toggle}} selected{{end}} value=0>No</option>
|
||||||
|
@ -54,11 +54,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
|
||||||
<div class="formrow">
|
<div class="formrow">
|
||||||
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">Update Group</button></div>
|
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">Update Group</button></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -92,6 +92,10 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel_group_perms .formitem a {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
#panel_word_filters .itemSeparator:before {
|
#panel_word_filters .itemSeparator:before {
|
||||||
content: "|";
|
content: "|";
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
|
@ -164,8 +168,11 @@
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
}
|
}
|
||||||
.ct-series-a .ct-bar, .ct-series-a .ct-line, .ct-series-a .ct-point, .ct-series-a .ct-slice-donut {
|
.ct-series-a .ct-bar, .ct-series-a .ct-line, .ct-series-a .ct-point, .ct-series-a .ct-slice-donut {
|
||||||
stroke: hsl(359,98%,53%) !important;
|
stroke: hsl(359,98%,33%) !important;
|
||||||
}
|
}
|
||||||
.ct-point {
|
.ct-point {
|
||||||
stroke: hsl(359,98%,33%) !important;
|
stroke: hsl(359,98%,53%) !important;
|
||||||
|
}
|
||||||
|
.ct-point:hover {
|
||||||
|
stroke: hsl(359,98%,50%) !important;
|
||||||
}
|
}
|
Loading…
Reference in New Issue