Added view graphs for the individual routes.
Made some minor improvements to Cosora.
This commit is contained in:
parent
e259a575e9
commit
d0b6559df9
|
@ -92,24 +92,25 @@ var PreRenderHooks = map[string][]func(http.ResponseWriter, *http.Request, *User
|
||||||
"pre_render_ban": nil,
|
"pre_render_ban": nil,
|
||||||
"pre_render_ips": nil,
|
"pre_render_ips": nil,
|
||||||
|
|
||||||
"pre_render_panel_dashboard": nil,
|
"pre_render_panel_dashboard": nil,
|
||||||
"pre_render_panel_forums": nil,
|
"pre_render_panel_forums": nil,
|
||||||
"pre_render_panel_delete_forum": nil,
|
"pre_render_panel_delete_forum": nil,
|
||||||
"pre_render_panel_edit_forum": nil,
|
"pre_render_panel_edit_forum": nil,
|
||||||
"pre_render_panel_analytics": nil,
|
"pre_render_panel_analytics": nil,
|
||||||
"pre_render_panel_analytics_routes": nil,
|
"pre_render_panel_analytics_routes": nil,
|
||||||
"pre_render_panel_settings": nil,
|
"pre_render_panel_analytics_route_views": nil,
|
||||||
"pre_render_panel_setting": nil,
|
"pre_render_panel_settings": nil,
|
||||||
"pre_render_panel_word_filters": nil,
|
"pre_render_panel_setting": nil,
|
||||||
"pre_render_panel_word_filters_edit": nil,
|
"pre_render_panel_word_filters": nil,
|
||||||
"pre_render_panel_plugins": nil,
|
"pre_render_panel_word_filters_edit": nil,
|
||||||
"pre_render_panel_users": nil,
|
"pre_render_panel_plugins": nil,
|
||||||
"pre_render_panel_edit_user": nil,
|
"pre_render_panel_users": nil,
|
||||||
"pre_render_panel_groups": nil,
|
"pre_render_panel_edit_user": nil,
|
||||||
"pre_render_panel_edit_group": nil,
|
"pre_render_panel_groups": nil,
|
||||||
"pre_render_panel_edit_group_perms": nil,
|
"pre_render_panel_edit_group": nil,
|
||||||
"pre_render_panel_themes": nil,
|
"pre_render_panel_edit_group_perms": nil,
|
||||||
"pre_render_panel_mod_log": nil,
|
"pre_render_panel_themes": nil,
|
||||||
|
"pre_render_panel_mod_log": nil,
|
||||||
|
|
||||||
"pre_render_error": nil, // Note: This hook isn't run for a few errors whose templates are computed at startup and reused, such as InternalError. This hook is also not available in JS mode.
|
"pre_render_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,
|
"pre_render_security_error": nil,
|
||||||
|
|
|
@ -174,7 +174,17 @@ type PanelAnalyticsRoutesPage struct {
|
||||||
Header *HeaderVars
|
Header *HeaderVars
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
Zone string
|
Zone string
|
||||||
ItemList []PanelAnalyticsRoutesItem
|
ItemList []PanelAnalyticsRoutesItem
|
||||||
|
}
|
||||||
|
|
||||||
|
type PanelAnalyticsRoutePage struct {
|
||||||
|
Title string
|
||||||
|
CurrentUser User
|
||||||
|
Header *HeaderVars
|
||||||
|
Stats PanelStats
|
||||||
|
Zone string
|
||||||
|
Route string
|
||||||
|
PrimaryGraph PanelTimeGraph
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelThemesPage struct {
|
type PanelThemesPage struct {
|
||||||
|
|
156
gen_router.go
156
gen_router.go
|
@ -51,6 +51,7 @@ var RouteMap = map[string]interface{}{
|
||||||
"routePanelUsersEditSubmit": routePanelUsersEditSubmit,
|
"routePanelUsersEditSubmit": routePanelUsersEditSubmit,
|
||||||
"routePanelAnalyticsViews": routePanelAnalyticsViews,
|
"routePanelAnalyticsViews": routePanelAnalyticsViews,
|
||||||
"routePanelAnalyticsRoutes": routePanelAnalyticsRoutes,
|
"routePanelAnalyticsRoutes": routePanelAnalyticsRoutes,
|
||||||
|
"routePanelAnalyticsRouteViews": routePanelAnalyticsRouteViews,
|
||||||
"routePanelGroups": routePanelGroups,
|
"routePanelGroups": routePanelGroups,
|
||||||
"routePanelGroupsEdit": routePanelGroupsEdit,
|
"routePanelGroupsEdit": routePanelGroupsEdit,
|
||||||
"routePanelGroupsEditPerms": routePanelGroupsEditPerms,
|
"routePanelGroupsEditPerms": routePanelGroupsEditPerms,
|
||||||
|
@ -116,31 +117,32 @@ var routeMapEnum = map[string]int{
|
||||||
"routePanelUsersEditSubmit": 33,
|
"routePanelUsersEditSubmit": 33,
|
||||||
"routePanelAnalyticsViews": 34,
|
"routePanelAnalyticsViews": 34,
|
||||||
"routePanelAnalyticsRoutes": 35,
|
"routePanelAnalyticsRoutes": 35,
|
||||||
"routePanelGroups": 36,
|
"routePanelAnalyticsRouteViews": 36,
|
||||||
"routePanelGroupsEdit": 37,
|
"routePanelGroups": 37,
|
||||||
"routePanelGroupsEditPerms": 38,
|
"routePanelGroupsEdit": 38,
|
||||||
"routePanelGroupsEditSubmit": 39,
|
"routePanelGroupsEditPerms": 39,
|
||||||
"routePanelGroupsEditPermsSubmit": 40,
|
"routePanelGroupsEditSubmit": 40,
|
||||||
"routePanelGroupsCreateSubmit": 41,
|
"routePanelGroupsEditPermsSubmit": 41,
|
||||||
"routePanelBackups": 42,
|
"routePanelGroupsCreateSubmit": 42,
|
||||||
"routePanelLogsMod": 43,
|
"routePanelBackups": 43,
|
||||||
"routePanelDebug": 44,
|
"routePanelLogsMod": 44,
|
||||||
"routePanel": 45,
|
"routePanelDebug": 45,
|
||||||
"routeAccountEditCritical": 46,
|
"routePanel": 46,
|
||||||
"routeAccountEditCriticalSubmit": 47,
|
"routeAccountEditCritical": 47,
|
||||||
"routeAccountEditAvatar": 48,
|
"routeAccountEditCriticalSubmit": 48,
|
||||||
"routeAccountEditAvatarSubmit": 49,
|
"routeAccountEditAvatar": 49,
|
||||||
"routeAccountEditUsername": 50,
|
"routeAccountEditAvatarSubmit": 50,
|
||||||
"routeAccountEditUsernameSubmit": 51,
|
"routeAccountEditUsername": 51,
|
||||||
"routeAccountEditEmail": 52,
|
"routeAccountEditUsernameSubmit": 52,
|
||||||
"routeAccountEditEmailTokenSubmit": 53,
|
"routeAccountEditEmail": 53,
|
||||||
"routeProfile": 54,
|
"routeAccountEditEmailTokenSubmit": 54,
|
||||||
"routeBanSubmit": 55,
|
"routeProfile": 55,
|
||||||
"routeUnban": 56,
|
"routeBanSubmit": 56,
|
||||||
"routeActivate": 57,
|
"routeUnban": 57,
|
||||||
"routeIps": 58,
|
"routeActivate": 58,
|
||||||
"routeDynamic": 59,
|
"routeIps": 59,
|
||||||
"routeUploads": 60,
|
"routeDynamic": 60,
|
||||||
|
"routeUploads": 61,
|
||||||
}
|
}
|
||||||
var reverseRouteMapEnum = map[int]string{
|
var reverseRouteMapEnum = map[int]string{
|
||||||
0: "routeAPI",
|
0: "routeAPI",
|
||||||
|
@ -179,31 +181,32 @@ var reverseRouteMapEnum = map[int]string{
|
||||||
33: "routePanelUsersEditSubmit",
|
33: "routePanelUsersEditSubmit",
|
||||||
34: "routePanelAnalyticsViews",
|
34: "routePanelAnalyticsViews",
|
||||||
35: "routePanelAnalyticsRoutes",
|
35: "routePanelAnalyticsRoutes",
|
||||||
36: "routePanelGroups",
|
36: "routePanelAnalyticsRouteViews",
|
||||||
37: "routePanelGroupsEdit",
|
37: "routePanelGroups",
|
||||||
38: "routePanelGroupsEditPerms",
|
38: "routePanelGroupsEdit",
|
||||||
39: "routePanelGroupsEditSubmit",
|
39: "routePanelGroupsEditPerms",
|
||||||
40: "routePanelGroupsEditPermsSubmit",
|
40: "routePanelGroupsEditSubmit",
|
||||||
41: "routePanelGroupsCreateSubmit",
|
41: "routePanelGroupsEditPermsSubmit",
|
||||||
42: "routePanelBackups",
|
42: "routePanelGroupsCreateSubmit",
|
||||||
43: "routePanelLogsMod",
|
43: "routePanelBackups",
|
||||||
44: "routePanelDebug",
|
44: "routePanelLogsMod",
|
||||||
45: "routePanel",
|
45: "routePanelDebug",
|
||||||
46: "routeAccountEditCritical",
|
46: "routePanel",
|
||||||
47: "routeAccountEditCriticalSubmit",
|
47: "routeAccountEditCritical",
|
||||||
48: "routeAccountEditAvatar",
|
48: "routeAccountEditCriticalSubmit",
|
||||||
49: "routeAccountEditAvatarSubmit",
|
49: "routeAccountEditAvatar",
|
||||||
50: "routeAccountEditUsername",
|
50: "routeAccountEditAvatarSubmit",
|
||||||
51: "routeAccountEditUsernameSubmit",
|
51: "routeAccountEditUsername",
|
||||||
52: "routeAccountEditEmail",
|
52: "routeAccountEditUsernameSubmit",
|
||||||
53: "routeAccountEditEmailTokenSubmit",
|
53: "routeAccountEditEmail",
|
||||||
54: "routeProfile",
|
54: "routeAccountEditEmailTokenSubmit",
|
||||||
55: "routeBanSubmit",
|
55: "routeProfile",
|
||||||
56: "routeUnban",
|
56: "routeBanSubmit",
|
||||||
57: "routeActivate",
|
57: "routeUnban",
|
||||||
58: "routeIps",
|
58: "routeActivate",
|
||||||
59: "routeDynamic",
|
59: "routeIps",
|
||||||
60: "routeUploads",
|
60: "routeDynamic",
|
||||||
|
61: "routeUploads",
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Stop spilling these into the package scope?
|
// TODO: Stop spilling these into the package scope?
|
||||||
|
@ -577,14 +580,17 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
case "/panel/analytics/routes/":
|
case "/panel/analytics/routes/":
|
||||||
common.RouteViewCounter.Bump(35)
|
common.RouteViewCounter.Bump(35)
|
||||||
err = routePanelAnalyticsRoutes(w,req,user)
|
err = routePanelAnalyticsRoutes(w,req,user)
|
||||||
case "/panel/groups/":
|
case "/panel/analytics/route/":
|
||||||
common.RouteViewCounter.Bump(36)
|
common.RouteViewCounter.Bump(36)
|
||||||
|
err = routePanelAnalyticsRouteViews(w,req,user,extraData)
|
||||||
|
case "/panel/groups/":
|
||||||
|
common.RouteViewCounter.Bump(37)
|
||||||
err = routePanelGroups(w,req,user)
|
err = routePanelGroups(w,req,user)
|
||||||
case "/panel/groups/edit/":
|
case "/panel/groups/edit/":
|
||||||
common.RouteViewCounter.Bump(37)
|
common.RouteViewCounter.Bump(38)
|
||||||
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(38)
|
common.RouteViewCounter.Bump(39)
|
||||||
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)
|
||||||
|
@ -593,7 +599,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(39)
|
common.RouteViewCounter.Bump(40)
|
||||||
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)
|
||||||
|
@ -602,7 +608,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(40)
|
common.RouteViewCounter.Bump(41)
|
||||||
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)
|
||||||
|
@ -611,7 +617,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(41)
|
common.RouteViewCounter.Bump(42)
|
||||||
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)
|
||||||
|
@ -620,10 +626,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(42)
|
common.RouteViewCounter.Bump(43)
|
||||||
err = routePanelBackups(w,req,user,extraData)
|
err = routePanelBackups(w,req,user,extraData)
|
||||||
case "/panel/logs/mod/":
|
case "/panel/logs/mod/":
|
||||||
common.RouteViewCounter.Bump(43)
|
common.RouteViewCounter.Bump(44)
|
||||||
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)
|
||||||
|
@ -632,10 +638,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(44)
|
common.RouteViewCounter.Bump(45)
|
||||||
err = routePanelDebug(w,req,user)
|
err = routePanelDebug(w,req,user)
|
||||||
default:
|
default:
|
||||||
common.RouteViewCounter.Bump(45)
|
common.RouteViewCounter.Bump(46)
|
||||||
err = routePanel(w,req,user)
|
err = routePanel(w,req,user)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -650,7 +656,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(46)
|
common.RouteViewCounter.Bump(47)
|
||||||
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)
|
||||||
|
@ -665,7 +671,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(47)
|
common.RouteViewCounter.Bump(48)
|
||||||
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)
|
||||||
|
@ -674,7 +680,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(48)
|
common.RouteViewCounter.Bump(49)
|
||||||
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)
|
||||||
|
@ -683,7 +689,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(49)
|
common.RouteViewCounter.Bump(50)
|
||||||
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)
|
||||||
|
@ -692,7 +698,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(50)
|
common.RouteViewCounter.Bump(51)
|
||||||
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)
|
||||||
|
@ -707,7 +713,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(51)
|
common.RouteViewCounter.Bump(52)
|
||||||
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)
|
||||||
|
@ -716,7 +722,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(52)
|
common.RouteViewCounter.Bump(53)
|
||||||
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)
|
||||||
|
@ -731,11 +737,11 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(53)
|
common.RouteViewCounter.Bump(54)
|
||||||
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(54)
|
common.RouteViewCounter.Bump(55)
|
||||||
err = routeProfile(w,req,user)
|
err = routeProfile(w,req,user)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -756,7 +762,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(55)
|
common.RouteViewCounter.Bump(56)
|
||||||
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)
|
||||||
|
@ -771,7 +777,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(56)
|
common.RouteViewCounter.Bump(57)
|
||||||
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)
|
||||||
|
@ -786,7 +792,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(57)
|
common.RouteViewCounter.Bump(58)
|
||||||
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)
|
||||||
|
@ -795,7 +801,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(58)
|
common.RouteViewCounter.Bump(59)
|
||||||
err = routeIps(w,req,user)
|
err = routeIps(w,req,user)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -812,7 +818,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
common.NotFound(w,req)
|
common.NotFound(w,req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
common.RouteViewCounter.Bump(60)
|
common.RouteViewCounter.Bump(61)
|
||||||
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
|
||||||
|
@ -856,7 +862,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
router.RUnlock()
|
router.RUnlock()
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
common.RouteViewCounter.Bump(59) // TODO: Be more specific about *which* dynamic route it is
|
common.RouteViewCounter.Bump(60) // 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 {
|
||||||
|
|
|
@ -510,7 +510,7 @@ func routePanelAnalyticsRoutes(w http.ResponseWriter, r *http.Request, user comm
|
||||||
var routeMap = make(map[string]int)
|
var routeMap = make(map[string]int)
|
||||||
|
|
||||||
acc := qgen.Builder.Accumulator()
|
acc := qgen.Builder.Accumulator()
|
||||||
rows, err := acc.Select("viewchunks").Columns("count, createdAt, route").Where("route != ''").DateCutoff("createdAt", 1, "day").Query()
|
rows, err := acc.Select("viewchunks").Columns("count, route").Where("route != ''").DateCutoff("createdAt", 1, "day").Query()
|
||||||
if err != nil && err != ErrNoRows {
|
if err != nil && err != ErrNoRows {
|
||||||
return common.InternalError(err, w, r)
|
return common.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -518,15 +518,13 @@ func routePanelAnalyticsRoutes(w http.ResponseWriter, r *http.Request, user comm
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var count int
|
var count int
|
||||||
var createdAt time.Time
|
|
||||||
var route string
|
var route string
|
||||||
err := rows.Scan(&count, &createdAt, &route)
|
err := rows.Scan(&count, &route)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.InternalError(err, w, r)
|
return common.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("count: ", count)
|
log.Print("count: ", count)
|
||||||
log.Print("createdAt: ", createdAt)
|
|
||||||
log.Print("route: ", route)
|
log.Print("route: ", route)
|
||||||
routeMap[route] += count
|
routeMap[route] += count
|
||||||
}
|
}
|
||||||
|
@ -557,6 +555,81 @@ func routePanelAnalyticsRoutes(w http.ResponseWriter, r *http.Request, user comm
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user common.User, route string) common.RouteError {
|
||||||
|
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
headerVars.Stylesheets = append(headerVars.Stylesheets, "chartist/chartist.min.css")
|
||||||
|
headerVars.Scripts = append(headerVars.Scripts, "chartist/chartist.min.js")
|
||||||
|
|
||||||
|
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)
|
||||||
|
revLabelList = append(revLabelList, label)
|
||||||
|
viewMap[label] = 0
|
||||||
|
}
|
||||||
|
for _, value := range revLabelList {
|
||||||
|
labelList = append(labelList, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
var viewList []int64
|
||||||
|
log.Print("in routePanelAnalyticsRouteViews")
|
||||||
|
|
||||||
|
acc := qgen.Builder.Accumulator()
|
||||||
|
rows, err := acc.Select("viewchunks").Columns("count, createdAt").Where("route = ?").DateCutoff("createdAt", 6, "hour").Query(route)
|
||||||
|
if err != nil && err != ErrNoRows {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var count int64
|
||||||
|
var createdAt time.Time
|
||||||
|
err := rows.Scan(&count, &createdAt)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
log.Print("count: ", count)
|
||||||
|
log.Print("createdAt: ", createdAt)
|
||||||
|
|
||||||
|
var unixCreatedAt = createdAt.Unix()
|
||||||
|
log.Print("unixCreatedAt: ", unixCreatedAt)
|
||||||
|
for _, value := range labelList {
|
||||||
|
if unixCreatedAt > value {
|
||||||
|
viewMap[value] += count
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = rows.Err()
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, value := range revLabelList {
|
||||||
|
viewList = append(viewList, viewMap[value])
|
||||||
|
}
|
||||||
|
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}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
func routePanelSettings(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
func routePanelSettings(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 {
|
||||||
|
|
|
@ -91,6 +91,7 @@ func buildPanelRoutes() {
|
||||||
|
|
||||||
View("routePanelAnalyticsViews", "/panel/analytics/views/"),
|
View("routePanelAnalyticsViews", "/panel/analytics/views/"),
|
||||||
View("routePanelAnalyticsRoutes", "/panel/analytics/routes/"),
|
View("routePanelAnalyticsRoutes", "/panel/analytics/routes/"),
|
||||||
|
View("routePanelAnalyticsRouteViews", "/panel/analytics/route/", "extraData"),
|
||||||
|
|
||||||
View("routePanelGroups", "/panel/groups/"),
|
View("routePanelGroups", "/panel/groups/"),
|
||||||
View("routePanelGroupsEdit", "/panel/groups/edit/", "extraData"),
|
View("routePanelGroupsEdit", "/panel/groups/edit/", "extraData"),
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
{{template "header.html" . }}
|
{{template "header.html" . }}
|
||||||
<div class="colstack account">
|
<div class="colstack account account_emails">
|
||||||
{{template "account-menu.html" . }}
|
{{template "account-menu.html" . }}
|
||||||
<main class="colstack_right">
|
<main class="colstack_right">
|
||||||
<div class="colstack_item colstack_head rowhead">
|
<div class="colstack_item colstack_head rowhead">
|
||||||
<div class="rowitem"><h1>Emails</h1></div>
|
<div class="rowitem"><h1>Emails</h1></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="colstack_item">
|
<div class="colstack_item rowlist">
|
||||||
<!-- TODO: Do we need this inline CSS? -->
|
<!-- TODO: Do we need this inline CSS? -->
|
||||||
{{range .ItemList}}
|
{{range .ItemList}}
|
||||||
<div class="rowitem" style="font-weight: normal;">
|
<div class="rowitem" style="font-weight: normal;">
|
||||||
<a style="text-transform: none;">{{.Email}}</a>
|
<a style="text-transform: none;">{{.Email}}</a>
|
||||||
<span style="float: right">
|
<span style="float: right" class="to_right">
|
||||||
<span class="username">{{if .Primary}}Primary{{else}}Secondary{{end}}</span>
|
<span class="username">{{if .Primary}}Primary{{else}}Secondary{{end}}</span>
|
||||||
{{if .Validated}}<span class="username" style="color: green;">Verified</span>{{else}}<a class="username" style="color: crimson;">Resend Verification Email</a>{{end}}
|
{{if .Validated}}<span class="username" style="color: green;">Verified</span>{{else}}<a class="username" style="color: crimson;">Resend Verification Email</a>{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
{{template "header.html" . }}
|
||||||
|
<div class="colstack panel_stack">
|
||||||
|
{{template "panel-menu.html" . }}
|
||||||
|
<main id="panel_dashboard_right" class="colstack_right">
|
||||||
|
<div class="colstack_item colstack_head">
|
||||||
|
<div class="rowitem"><a>{{.Route}} Views</a></div>
|
||||||
|
</div>
|
||||||
|
<div id="panel_analytics_views" class="colstack_graph_holder">
|
||||||
|
<div class="ct-chart"></div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
let labels = [];
|
||||||
|
let rawLabels = [{{range .PrimaryGraph.Labels}}
|
||||||
|
{{.}},{{end}}
|
||||||
|
];
|
||||||
|
for(const i in rawLabels) {
|
||||||
|
let date = new Date(rawLabels[i]*1000);
|
||||||
|
console.log("date: ", date);
|
||||||
|
let minutes = "0" + date.getMinutes();
|
||||||
|
let label = date.getHours() + ":" + minutes.substr(-2);
|
||||||
|
console.log("label:", label);
|
||||||
|
labels.push(label);
|
||||||
|
}
|
||||||
|
labels = labels.reverse()
|
||||||
|
|
||||||
|
let seriesData = [{{range .PrimaryGraph.Series}}
|
||||||
|
{{.}},{{end}}
|
||||||
|
];
|
||||||
|
seriesData = seriesData.reverse();
|
||||||
|
|
||||||
|
Chartist.Line('.ct-chart', {
|
||||||
|
labels: labels,
|
||||||
|
series: [seriesData],
|
||||||
|
}, {
|
||||||
|
height: '250px',
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{{template "footer.html" . }}
|
|
@ -3,13 +3,13 @@
|
||||||
{{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">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem"><a>Routes</a></div>
|
<div class="rowitem"><a>Routes (24 hours)</a></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="panel_analytics_routes" class="colstack_item rowlist">
|
<div id="panel_analytics_routes" class="colstack_item rowlist">
|
||||||
{{range .ItemList}}
|
{{range .ItemList}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<div class="rowitem panel_compactrow editable_parent">
|
||||||
<a href="/panel/groups/edit/{{.Route}}" class="panel_upshift">{{.Route}}</a>
|
<a href="/panel/analytics/route/{{.Route}}" class="panel_upshift">{{.Route}}</a>
|
||||||
<span class="panel_compacttext to_right">{{.Count}}</span>
|
<span class="panel_compacttext to_right">{{.Count}} views</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
<form action="/panel/groups/create/?session={{.CurrentUser.Session}}" method="post">
|
<form action="/panel/groups/create/?session={{.CurrentUser.Session}}" method="post">
|
||||||
<div class="formrow">
|
<div class="formrow">
|
||||||
<div class="formitem formlabel"><a>Name</a></div>
|
<div class="formitem formlabel"><a>Name</a></div>
|
||||||
<div class="formitem"><input name="group-name" type="text" /></div>
|
<div class="formitem"><input name="group-name" type="text" placeholder="Administrator" /></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="formrow">
|
<div class="formrow">
|
||||||
<div class="formitem formlabel"><a>Type</a></div>
|
<div class="formitem formlabel"><a>Type</a></div>
|
||||||
|
|
|
@ -406,16 +406,15 @@ ul {
|
||||||
height: 27px;
|
height: 27px;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid var(--header-border-color);
|
|
||||||
outline: none;
|
|
||||||
}
|
}
|
||||||
.topic_name_row input, .ip_search_input {
|
.topic_name_row input, .ip_search_input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid var(--header-border-color);
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
input, select {
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid var(--header-border-color);
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
.topic_content_row textarea {
|
.topic_content_row textarea {
|
||||||
|
@ -423,11 +422,16 @@ ul {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.formbutton {
|
||||||
|
margin-top: 12px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
.quick_button_row .formitem {
|
.quick_button_row .formitem {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
.quick_button_row button, .quick_button_row label, .ip_search_search {
|
.quick_button_row button, .quick_button_row label, .ip_search_search, .formbutton {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
padding-top: 6px;
|
padding-top: 6px;
|
||||||
|
@ -443,6 +447,9 @@ ul {
|
||||||
background: hsl(209, 97%, 56%);
|
background: hsl(209, 97%, 56%);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
.quick_button_row button, .quick_button_row label, .ip_search_search {
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
.quick_button_row button, .quick_button_row label {
|
.quick_button_row button, .quick_button_row label {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
|
@ -463,12 +470,24 @@ label.uploadItem {
|
||||||
padding-left: 33px;
|
padding-left: 33px;
|
||||||
}
|
}
|
||||||
|
|
||||||
select, input, textarea, button {
|
button {
|
||||||
border: 1px solid var(--header-border-color);
|
border: 1px solid var(--header-border-color);
|
||||||
|
}
|
||||||
|
select, input, textarea, button {
|
||||||
background: var(--element-background-color);
|
background: var(--element-background-color);
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
color: hsl(0,0%,30%);
|
color: hsl(0,0%,30%);
|
||||||
}
|
}
|
||||||
|
input, select {
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
input:not(:focus):not([type="submit"]), select:not(:focus) {
|
||||||
|
color: var(--light-text-color);
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
outline: none;
|
||||||
|
border: 1px solid var(--header-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
.topic_reply_container {
|
.topic_reply_container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -1003,6 +1022,7 @@ select, input, textarea, button {
|
||||||
}
|
}
|
||||||
.formitem:only-child {
|
.formitem:only-child {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
.the_form .formitem:only-child button {
|
.the_form .formitem:only-child button {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
@ -1100,7 +1120,7 @@ select, input, textarea, button {
|
||||||
}
|
}
|
||||||
#themeSelectorSelect {
|
#themeSelectorSelect {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
margin-top: 2px;
|
margin-top: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.colstack_grid {
|
.colstack_grid {
|
||||||
|
|
Loading…
Reference in New Issue