diff --git a/common/extend.go b/common/extend.go index 344cf692..3516cbe6 100644 --- a/common/extend.go +++ b/common/extend.go @@ -97,6 +97,7 @@ var PreRenderHooks = map[string][]func(http.ResponseWriter, *http.Request, *User "pre_render_panel_delete_forum": nil, "pre_render_panel_edit_forum": nil, "pre_render_panel_analytics": nil, + "pre_render_panel_analytics_routes": nil, "pre_render_panel_settings": nil, "pre_render_panel_setting": nil, "pre_render_panel_word_filters": nil, diff --git a/common/pages.go b/common/pages.go index ca49e263..67b8f6a1 100644 --- a/common/pages.go +++ b/common/pages.go @@ -163,6 +163,20 @@ type PanelAnalyticsPage struct { PrimaryGraph PanelTimeGraph } +type PanelAnalyticsRoutesItem struct { + Route string + Count int +} + +type PanelAnalyticsRoutesPage struct { + Title string + CurrentUser User + Header *HeaderVars + Stats PanelStats + Zone string + ItemList []PanelAnalyticsRoutesItem +} + type PanelThemesPage struct { Title string CurrentUser User diff --git a/gen_router.go b/gen_router.go index 3efcf90c..86fae437 100644 --- a/gen_router.go +++ b/gen_router.go @@ -50,6 +50,7 @@ var RouteMap = map[string]interface{}{ "routePanelUsersEdit": routePanelUsersEdit, "routePanelUsersEditSubmit": routePanelUsersEditSubmit, "routePanelAnalyticsViews": routePanelAnalyticsViews, + "routePanelAnalyticsRoutes": routePanelAnalyticsRoutes, "routePanelGroups": routePanelGroups, "routePanelGroupsEdit": routePanelGroupsEdit, "routePanelGroupsEditPerms": routePanelGroupsEditPerms, @@ -114,31 +115,32 @@ var routeMapEnum = map[string]int{ "routePanelUsersEdit": 32, "routePanelUsersEditSubmit": 33, "routePanelAnalyticsViews": 34, - "routePanelGroups": 35, - "routePanelGroupsEdit": 36, - "routePanelGroupsEditPerms": 37, - "routePanelGroupsEditSubmit": 38, - "routePanelGroupsEditPermsSubmit": 39, - "routePanelGroupsCreateSubmit": 40, - "routePanelBackups": 41, - "routePanelLogsMod": 42, - "routePanelDebug": 43, - "routePanel": 44, - "routeAccountEditCritical": 45, - "routeAccountEditCriticalSubmit": 46, - "routeAccountEditAvatar": 47, - "routeAccountEditAvatarSubmit": 48, - "routeAccountEditUsername": 49, - "routeAccountEditUsernameSubmit": 50, - "routeAccountEditEmail": 51, - "routeAccountEditEmailTokenSubmit": 52, - "routeProfile": 53, - "routeBanSubmit": 54, - "routeUnban": 55, - "routeActivate": 56, - "routeIps": 57, - "routeDynamic": 58, - "routeUploads": 59, + "routePanelAnalyticsRoutes": 35, + "routePanelGroups": 36, + "routePanelGroupsEdit": 37, + "routePanelGroupsEditPerms": 38, + "routePanelGroupsEditSubmit": 39, + "routePanelGroupsEditPermsSubmit": 40, + "routePanelGroupsCreateSubmit": 41, + "routePanelBackups": 42, + "routePanelLogsMod": 43, + "routePanelDebug": 44, + "routePanel": 45, + "routeAccountEditCritical": 46, + "routeAccountEditCriticalSubmit": 47, + "routeAccountEditAvatar": 48, + "routeAccountEditAvatarSubmit": 49, + "routeAccountEditUsername": 50, + "routeAccountEditUsernameSubmit": 51, + "routeAccountEditEmail": 52, + "routeAccountEditEmailTokenSubmit": 53, + "routeProfile": 54, + "routeBanSubmit": 55, + "routeUnban": 56, + "routeActivate": 57, + "routeIps": 58, + "routeDynamic": 59, + "routeUploads": 60, } var reverseRouteMapEnum = map[int]string{ 0: "routeAPI", @@ -176,31 +178,32 @@ var reverseRouteMapEnum = map[int]string{ 32: "routePanelUsersEdit", 33: "routePanelUsersEditSubmit", 34: "routePanelAnalyticsViews", - 35: "routePanelGroups", - 36: "routePanelGroupsEdit", - 37: "routePanelGroupsEditPerms", - 38: "routePanelGroupsEditSubmit", - 39: "routePanelGroupsEditPermsSubmit", - 40: "routePanelGroupsCreateSubmit", - 41: "routePanelBackups", - 42: "routePanelLogsMod", - 43: "routePanelDebug", - 44: "routePanel", - 45: "routeAccountEditCritical", - 46: "routeAccountEditCriticalSubmit", - 47: "routeAccountEditAvatar", - 48: "routeAccountEditAvatarSubmit", - 49: "routeAccountEditUsername", - 50: "routeAccountEditUsernameSubmit", - 51: "routeAccountEditEmail", - 52: "routeAccountEditEmailTokenSubmit", - 53: "routeProfile", - 54: "routeBanSubmit", - 55: "routeUnban", - 56: "routeActivate", - 57: "routeIps", - 58: "routeDynamic", - 59: "routeUploads", + 35: "routePanelAnalyticsRoutes", + 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", } // TODO: Stop spilling these into the package scope? @@ -571,14 +574,17 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { case "/panel/analytics/views/": common.RouteViewCounter.Bump(34) err = routePanelAnalyticsViews(w,req,user) - case "/panel/groups/": + case "/panel/analytics/routes/": common.RouteViewCounter.Bump(35) + err = routePanelAnalyticsRoutes(w,req,user) + case "/panel/groups/": + common.RouteViewCounter.Bump(36) err = routePanelGroups(w,req,user) case "/panel/groups/edit/": - common.RouteViewCounter.Bump(36) + common.RouteViewCounter.Bump(37) err = routePanelGroupsEdit(w,req,user,extraData) case "/panel/groups/edit/perms/": - common.RouteViewCounter.Bump(37) + common.RouteViewCounter.Bump(38) err = routePanelGroupsEditPerms(w,req,user,extraData) case "/panel/groups/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -587,7 +593,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(38) + common.RouteViewCounter.Bump(39) err = routePanelGroupsEditSubmit(w,req,user,extraData) case "/panel/groups/edit/perms/submit/": err = common.NoSessionMismatch(w,req,user) @@ -596,7 +602,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(39) + common.RouteViewCounter.Bump(40) err = routePanelGroupsEditPermsSubmit(w,req,user,extraData) case "/panel/groups/create/": err = common.NoSessionMismatch(w,req,user) @@ -605,7 +611,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(40) + common.RouteViewCounter.Bump(41) err = routePanelGroupsCreateSubmit(w,req,user) case "/panel/backups/": err = common.SuperAdminOnly(w,req,user) @@ -614,10 +620,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(41) + common.RouteViewCounter.Bump(42) err = routePanelBackups(w,req,user,extraData) case "/panel/logs/mod/": - common.RouteViewCounter.Bump(42) + common.RouteViewCounter.Bump(43) err = routePanelLogsMod(w,req,user) case "/panel/debug/": err = common.AdminOnly(w,req,user) @@ -626,10 +632,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(43) + common.RouteViewCounter.Bump(44) err = routePanelDebug(w,req,user) default: - common.RouteViewCounter.Bump(44) + common.RouteViewCounter.Bump(45) err = routePanel(w,req,user) } if err != nil { @@ -644,7 +650,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(45) + common.RouteViewCounter.Bump(46) err = routeAccountEditCritical(w,req,user) case "/user/edit/critical/submit/": err = common.NoSessionMismatch(w,req,user) @@ -659,7 +665,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(46) + common.RouteViewCounter.Bump(47) err = routeAccountEditCriticalSubmit(w,req,user) case "/user/edit/avatar/": err = common.MemberOnly(w,req,user) @@ -668,7 +674,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(47) + common.RouteViewCounter.Bump(48) err = routeAccountEditAvatar(w,req,user) case "/user/edit/avatar/submit/": err = common.MemberOnly(w,req,user) @@ -677,7 +683,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(48) + common.RouteViewCounter.Bump(49) err = routeAccountEditAvatarSubmit(w,req,user) case "/user/edit/username/": err = common.MemberOnly(w,req,user) @@ -686,7 +692,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(49) + common.RouteViewCounter.Bump(50) err = routeAccountEditUsername(w,req,user) case "/user/edit/username/submit/": err = common.NoSessionMismatch(w,req,user) @@ -701,7 +707,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(50) + common.RouteViewCounter.Bump(51) err = routeAccountEditUsernameSubmit(w,req,user) case "/user/edit/email/": err = common.MemberOnly(w,req,user) @@ -710,7 +716,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(51) + common.RouteViewCounter.Bump(52) err = routeAccountEditEmail(w,req,user) case "/user/edit/token/": err = common.NoSessionMismatch(w,req,user) @@ -725,11 +731,11 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(52) + common.RouteViewCounter.Bump(53) err = routeAccountEditEmailTokenSubmit(w,req,user,extraData) default: req.URL.Path += extraData - common.RouteViewCounter.Bump(53) + common.RouteViewCounter.Bump(54) err = routeProfile(w,req,user) } if err != nil { @@ -750,7 +756,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(54) + common.RouteViewCounter.Bump(55) err = routeBanSubmit(w,req,user,extraData) case "/users/unban/": err = common.NoSessionMismatch(w,req,user) @@ -765,7 +771,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(55) + common.RouteViewCounter.Bump(56) err = routeUnban(w,req,user,extraData) case "/users/activate/": err = common.NoSessionMismatch(w,req,user) @@ -780,7 +786,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(56) + common.RouteViewCounter.Bump(57) err = routeActivate(w,req,user,extraData) case "/users/ips/": err = common.MemberOnly(w,req,user) @@ -789,7 +795,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(57) + common.RouteViewCounter.Bump(58) err = routeIps(w,req,user) } if err != nil { @@ -806,7 +812,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { common.NotFound(w,req) return } - common.RouteViewCounter.Bump(59) + common.RouteViewCounter.Bump(60) req.URL.Path += extraData // TODO: Find a way to propagate errors up from this? router.UploadHandler(w,req) // TODO: Count these views @@ -850,7 +856,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { router.RUnlock() if ok { - common.RouteViewCounter.Bump(58) // TODO: Be more specific about *which* dynamic route it is + common.RouteViewCounter.Bump(59) // 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 c1a11407..fe4b76b1 100644 --- a/panel_routes.go +++ b/panel_routes.go @@ -450,26 +450,24 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo } var viewList []int64 + log.Print("in routePanelAnalyticsViews") acc := qgen.Builder.Accumulator() - rows, err := acc.Select("viewchunks").Columns("count, createdAt, route").Where("route = ''").DateCutoff("createdAt", 6, "hour").Query() + rows, err := acc.Select("viewchunks").Columns("count, createdAt").Where("route = ''").DateCutoff("createdAt", 6, "hour").Query() if err != nil && err != ErrNoRows { return common.InternalError(err, w, r) } defer rows.Close() for rows.Next() { - log.Print("WE HAVE ROWS") var count int64 var createdAt time.Time - var route string - err := rows.Scan(&count, &createdAt, &route) + err := rows.Scan(&count, &createdAt) if err != nil { return common.InternalError(err, w, r) } log.Print("count: ", count) log.Print("createdAt: ", createdAt) - log.Print("route: ", route) var unixCreatedAt = createdAt.Unix() log.Print("unixCreatedAt: ", unixCreatedAt) @@ -504,6 +502,61 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo return nil } +func routePanelAnalyticsRoutes(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) + if ferr != nil { + return ferr + } + var routeMap = make(map[string]int) + + acc := qgen.Builder.Accumulator() + rows, err := acc.Select("viewchunks").Columns("count, createdAt, route").Where("route != ''").DateCutoff("createdAt", 1, "day").Query() + if err != nil && err != ErrNoRows { + return common.InternalError(err, w, r) + } + defer rows.Close() + + for rows.Next() { + var count int + var createdAt time.Time + var route string + err := rows.Scan(&count, &createdAt, &route) + if err != nil { + return common.InternalError(err, w, r) + } + + log.Print("count: ", count) + log.Print("createdAt: ", createdAt) + log.Print("route: ", route) + routeMap[route] += count + } + err = rows.Err() + if err != nil { + return common.InternalError(err, w, r) + } + + // TODO: Sort this slice + var routeItems []common.PanelAnalyticsRoutesItem + for route, count := range routeMap { + routeItems = append(routeItems, common.PanelAnalyticsRoutesItem{ + Route: route, + Count: count, + }) + } + + pi := common.PanelAnalyticsRoutesPage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", routeItems} + if common.PreRenderHooks["pre_render_panel_analytics_routes"] != nil { + if common.RunPreRenderHook("pre_render_panel_analytics_routes", w, r, &user, &pi) { + return nil + } + } + err = common.Templates.ExecuteTemplate(w, "panel-analytics-routes.html", pi) + if err != nil { + return common.InternalError(err, w, r) + } + return nil +} + func routePanelSettings(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { diff --git a/router_gen/routes.go b/router_gen/routes.go index e1874667..503e08c5 100644 --- a/router_gen/routes.go +++ b/router_gen/routes.go @@ -90,6 +90,7 @@ func buildPanelRoutes() { Action("routePanelUsersEditSubmit", "/panel/users/edit/submit/", "extraData"), View("routePanelAnalyticsViews", "/panel/analytics/views/"), + View("routePanelAnalyticsRoutes", "/panel/analytics/routes/"), View("routePanelGroups", "/panel/groups/"), View("routePanelGroupsEdit", "/panel/groups/edit/", "extraData"), diff --git a/templates/panel-analytics-routes.html b/templates/panel-analytics-routes.html new file mode 100644 index 00000000..36d8274b --- /dev/null +++ b/templates/panel-analytics-routes.html @@ -0,0 +1,18 @@ +{{template "header.html" . }} +