From a66bab7c5172628e0fd2b5220bf896d453330133 Mon Sep 17 00:00:00 2001 From: Azareal Date: Thu, 18 Jan 2018 12:31:25 +0000 Subject: [PATCH] Added the global topic counter and associated graphs. Wildcards should work properly in robots.txt now Fixed the padding on the registration and login pages for Cosora. Moved the Websockets route into the new router. We now log more suspicious requests. Started moving routes into /routes/ Added the topicchunks table. --- bot_routes.go | 8 +- common/counters.go | 48 +++ gen_router.go | 543 ++++++++++++++------------ main.go | 6 +- member_routes.go | 1 + mod_routes.go | 48 +-- panel_routes.go | 75 +++- query_gen/tables.go | 9 + router_gen/main.go | 20 +- router_gen/route_impl.go | 4 + router_gen/routes.go | 7 +- routes/filler.txt | 1 - routes/topic.go | 55 +++ schema/mssql/query_topicchunks.sql | 4 + schema/mysql/query_topicchunks.sql | 4 + schema/pgsql/query_topicchunks.sql | 4 + templates/create_topic.html | 2 +- templates/login.html | 2 +- templates/panel-inner-menu.html | 3 + templates/panel_analytics_posts.html | 2 +- templates/panel_analytics_topics.html | 62 +++ templates/register.html | 2 +- themes/cosora/public/main.css | 16 + 23 files changed, 609 insertions(+), 317 deletions(-) delete mode 100644 routes/filler.txt create mode 100644 routes/topic.go create mode 100644 schema/mssql/query_topicchunks.sql create mode 100644 schema/mysql/query_topicchunks.sql create mode 100644 schema/pgsql/query_topicchunks.sql create mode 100644 templates/panel_analytics_topics.html diff --git a/bot_routes.go b/bot_routes.go index c9ce0978..ab3d63ba 100644 --- a/bot_routes.go +++ b/bot_routes.go @@ -15,11 +15,11 @@ import ( func routeRobotsTxt(w http.ResponseWriter, r *http.Request) common.RouteError { // TODO: Do we have to put * or something at the end of the paths? _, _ = w.Write([]byte(`User-agent: * -Disallow: /panel/ +Disallow: /panel/* Disallow: /topics/create/ -Disallow: /user/edit/ -Disallow: /accounts/ -Disallow: /report/ +Disallow: /user/edit/* +Disallow: /accounts/* +Disallow: /report/* `)) return nil } diff --git a/common/counters.go b/common/counters.go index 3870e40f..865150c8 100644 --- a/common/counters.go +++ b/common/counters.go @@ -13,6 +13,7 @@ var GlobalViewCounter *DefaultViewCounter var AgentViewCounter *DefaultAgentViewCounter var RouteViewCounter *DefaultRouteViewCounter var PostCounter *DefaultPostCounter +var TopicCounter *DefaultTopicCounter // Local counters var TopicViewCounter *DefaultTopicViewCounter @@ -111,6 +112,53 @@ func (counter *DefaultPostCounter) insertChunk(count int64) error { return err } +type DefaultTopicCounter struct { + buckets [2]int64 + currentBucket int64 + + insert *sql.Stmt +} + +func NewTopicCounter() (*DefaultTopicCounter, error) { + acc := qgen.Builder.Accumulator() + counter := &DefaultTopicCounter{ + currentBucket: 0, + insert: acc.Insert("topicchunks").Columns("count, createdAt").Fields("?,UTC_TIMESTAMP()").Prepare(), + } + AddScheduledFifteenMinuteTask(counter.Tick) + //AddScheduledSecondTask(counter.Tick) + AddShutdownTask(counter.Tick) + return counter, acc.FirstError() +} + +func (counter *DefaultTopicCounter) Tick() (err error) { + var oldBucket = counter.currentBucket + var nextBucket int64 // 0 + if counter.currentBucket == 0 { + nextBucket = 1 + } + atomic.AddInt64(&counter.buckets[oldBucket], counter.buckets[nextBucket]) + atomic.StoreInt64(&counter.buckets[nextBucket], 0) + atomic.StoreInt64(&counter.currentBucket, nextBucket) + + var previousViewChunk = counter.buckets[oldBucket] + atomic.AddInt64(&counter.buckets[oldBucket], -previousViewChunk) + return counter.insertChunk(previousViewChunk) +} + +func (counter *DefaultTopicCounter) Bump() { + atomic.AddInt64(&counter.buckets[counter.currentBucket], 1) +} + +func (counter *DefaultTopicCounter) insertChunk(count int64) error { + if count == 0 { + return nil + } + debugLogf("Inserting a topicchunk with a count of %d", count) + _, err := counter.insert.Exec(count) + return err +} + type RWMutexCounterBucket struct { counter int sync.RWMutex diff --git a/gen_router.go b/gen_router.go index a0b880cb..3c11718d 100644 --- a/gen_router.go +++ b/gen_router.go @@ -10,6 +10,7 @@ import ( "net/http" "./common" + "./routes" ) var ErrNoRoute = errors.New("That route doesn't exist.") @@ -22,6 +23,7 @@ var RouteMap = map[string]interface{}{ "routeForum": routeForum, "routeChangeTheme": routeChangeTheme, "routeShowAttachment": routeShowAttachment, + "routeWebsockets": routeWebsockets, "routeReportSubmit": routeReportSubmit, "routeTopicCreate": routeTopicCreate, "routeTopics": routeTopics, @@ -38,7 +40,7 @@ var RouteMap = map[string]interface{}{ "routePanelSettingEdit": routePanelSettingEdit, "routePanelSettingEditSubmit": routePanelSettingEditSubmit, "routePanelWordFilters": routePanelWordFilters, - "routePanelWordFiltersCreate": routePanelWordFiltersCreate, + "routePanelWordFiltersCreateSubmit": routePanelWordFiltersCreateSubmit, "routePanelWordFiltersEdit": routePanelWordFiltersEdit, "routePanelWordFiltersEditSubmit": routePanelWordFiltersEditSubmit, "routePanelWordFiltersDeleteSubmit": routePanelWordFiltersDeleteSubmit, @@ -57,6 +59,7 @@ var RouteMap = map[string]interface{}{ "routePanelAnalyticsRouteViews": routePanelAnalyticsRouteViews, "routePanelAnalyticsAgentViews": routePanelAnalyticsAgentViews, "routePanelAnalyticsPosts": routePanelAnalyticsPosts, + "routePanelAnalyticsTopics": routePanelAnalyticsTopics, "routePanelGroups": routePanelGroups, "routePanelGroupsEdit": routePanelGroupsEdit, "routePanelGroupsEditPerms": routePanelGroupsEditPerms, @@ -81,7 +84,7 @@ var RouteMap = map[string]interface{}{ "routeActivate": routeActivate, "routeIps": routeIps, "routeTopicCreateSubmit": routeTopicCreateSubmit, - "routeEditTopicSubmit": routeEditTopicSubmit, + "routes.EditTopicSubmit": routes.EditTopicSubmit, "routeDeleteTopicSubmit": routeDeleteTopicSubmit, "routeStickTopicSubmit": routeStickTopicSubmit, "routeUnstickTopicSubmit": routeUnstickTopicSubmit, @@ -115,88 +118,90 @@ var routeMapEnum = map[string]int{ "routeForum": 4, "routeChangeTheme": 5, "routeShowAttachment": 6, - "routeReportSubmit": 7, - "routeTopicCreate": 8, - "routeTopics": 9, - "routePanelForums": 10, - "routePanelForumsCreateSubmit": 11, - "routePanelForumsDelete": 12, - "routePanelForumsDeleteSubmit": 13, - "routePanelForumsEdit": 14, - "routePanelForumsEditSubmit": 15, - "routePanelForumsEditPermsSubmit": 16, - "routePanelForumsEditPermsAdvance": 17, - "routePanelForumsEditPermsAdvanceSubmit": 18, - "routePanelSettings": 19, - "routePanelSettingEdit": 20, - "routePanelSettingEditSubmit": 21, - "routePanelWordFilters": 22, - "routePanelWordFiltersCreate": 23, - "routePanelWordFiltersEdit": 24, - "routePanelWordFiltersEditSubmit": 25, - "routePanelWordFiltersDeleteSubmit": 26, - "routePanelThemes": 27, - "routePanelThemesSetDefault": 28, - "routePanelPlugins": 29, - "routePanelPluginsActivate": 30, - "routePanelPluginsDeactivate": 31, - "routePanelPluginsInstall": 32, - "routePanelUsers": 33, - "routePanelUsersEdit": 34, - "routePanelUsersEditSubmit": 35, - "routePanelAnalyticsViews": 36, - "routePanelAnalyticsRoutes": 37, - "routePanelAnalyticsAgents": 38, - "routePanelAnalyticsRouteViews": 39, - "routePanelAnalyticsAgentViews": 40, - "routePanelAnalyticsPosts": 41, - "routePanelGroups": 42, - "routePanelGroupsEdit": 43, - "routePanelGroupsEditPerms": 44, - "routePanelGroupsEditSubmit": 45, - "routePanelGroupsEditPermsSubmit": 46, - "routePanelGroupsCreateSubmit": 47, - "routePanelBackups": 48, - "routePanelLogsMod": 49, - "routePanelDebug": 50, - "routePanel": 51, - "routeAccountEditCritical": 52, - "routeAccountEditCriticalSubmit": 53, - "routeAccountEditAvatar": 54, - "routeAccountEditAvatarSubmit": 55, - "routeAccountEditUsername": 56, - "routeAccountEditUsernameSubmit": 57, - "routeAccountEditEmail": 58, - "routeAccountEditEmailTokenSubmit": 59, - "routeProfile": 60, - "routeBanSubmit": 61, - "routeUnban": 62, - "routeActivate": 63, - "routeIps": 64, - "routeTopicCreateSubmit": 65, - "routeEditTopicSubmit": 66, - "routeDeleteTopicSubmit": 67, - "routeStickTopicSubmit": 68, - "routeUnstickTopicSubmit": 69, - "routeLockTopicSubmit": 70, - "routeUnlockTopicSubmit": 71, - "routeMoveTopicSubmit": 72, - "routeLikeTopicSubmit": 73, - "routeTopicID": 74, - "routeCreateReplySubmit": 75, - "routeReplyEditSubmit": 76, - "routeReplyDeleteSubmit": 77, - "routeReplyLikeSubmit": 78, - "routeProfileReplyCreateSubmit": 79, - "routeProfileReplyEditSubmit": 80, - "routeProfileReplyDeleteSubmit": 81, - "routeLogin": 82, - "routeRegister": 83, - "routeLogout": 84, - "routeLoginSubmit": 85, - "routeRegisterSubmit": 86, - "routeDynamic": 87, - "routeUploads": 88, + "routeWebsockets": 7, + "routeReportSubmit": 8, + "routeTopicCreate": 9, + "routeTopics": 10, + "routePanelForums": 11, + "routePanelForumsCreateSubmit": 12, + "routePanelForumsDelete": 13, + "routePanelForumsDeleteSubmit": 14, + "routePanelForumsEdit": 15, + "routePanelForumsEditSubmit": 16, + "routePanelForumsEditPermsSubmit": 17, + "routePanelForumsEditPermsAdvance": 18, + "routePanelForumsEditPermsAdvanceSubmit": 19, + "routePanelSettings": 20, + "routePanelSettingEdit": 21, + "routePanelSettingEditSubmit": 22, + "routePanelWordFilters": 23, + "routePanelWordFiltersCreateSubmit": 24, + "routePanelWordFiltersEdit": 25, + "routePanelWordFiltersEditSubmit": 26, + "routePanelWordFiltersDeleteSubmit": 27, + "routePanelThemes": 28, + "routePanelThemesSetDefault": 29, + "routePanelPlugins": 30, + "routePanelPluginsActivate": 31, + "routePanelPluginsDeactivate": 32, + "routePanelPluginsInstall": 33, + "routePanelUsers": 34, + "routePanelUsersEdit": 35, + "routePanelUsersEditSubmit": 36, + "routePanelAnalyticsViews": 37, + "routePanelAnalyticsRoutes": 38, + "routePanelAnalyticsAgents": 39, + "routePanelAnalyticsRouteViews": 40, + "routePanelAnalyticsAgentViews": 41, + "routePanelAnalyticsPosts": 42, + "routePanelAnalyticsTopics": 43, + "routePanelGroups": 44, + "routePanelGroupsEdit": 45, + "routePanelGroupsEditPerms": 46, + "routePanelGroupsEditSubmit": 47, + "routePanelGroupsEditPermsSubmit": 48, + "routePanelGroupsCreateSubmit": 49, + "routePanelBackups": 50, + "routePanelLogsMod": 51, + "routePanelDebug": 52, + "routePanel": 53, + "routeAccountEditCritical": 54, + "routeAccountEditCriticalSubmit": 55, + "routeAccountEditAvatar": 56, + "routeAccountEditAvatarSubmit": 57, + "routeAccountEditUsername": 58, + "routeAccountEditUsernameSubmit": 59, + "routeAccountEditEmail": 60, + "routeAccountEditEmailTokenSubmit": 61, + "routeProfile": 62, + "routeBanSubmit": 63, + "routeUnban": 64, + "routeActivate": 65, + "routeIps": 66, + "routeTopicCreateSubmit": 67, + "routes.EditTopicSubmit": 68, + "routeDeleteTopicSubmit": 69, + "routeStickTopicSubmit": 70, + "routeUnstickTopicSubmit": 71, + "routeLockTopicSubmit": 72, + "routeUnlockTopicSubmit": 73, + "routeMoveTopicSubmit": 74, + "routeLikeTopicSubmit": 75, + "routeTopicID": 76, + "routeCreateReplySubmit": 77, + "routeReplyEditSubmit": 78, + "routeReplyDeleteSubmit": 79, + "routeReplyLikeSubmit": 80, + "routeProfileReplyCreateSubmit": 81, + "routeProfileReplyEditSubmit": 82, + "routeProfileReplyDeleteSubmit": 83, + "routeLogin": 84, + "routeRegister": 85, + "routeLogout": 86, + "routeLoginSubmit": 87, + "routeRegisterSubmit": 88, + "routeDynamic": 89, + "routeUploads": 90, } var reverseRouteMapEnum = map[int]string{ 0: "routeAPI", @@ -206,88 +211,90 @@ var reverseRouteMapEnum = map[int]string{ 4: "routeForum", 5: "routeChangeTheme", 6: "routeShowAttachment", - 7: "routeReportSubmit", - 8: "routeTopicCreate", - 9: "routeTopics", - 10: "routePanelForums", - 11: "routePanelForumsCreateSubmit", - 12: "routePanelForumsDelete", - 13: "routePanelForumsDeleteSubmit", - 14: "routePanelForumsEdit", - 15: "routePanelForumsEditSubmit", - 16: "routePanelForumsEditPermsSubmit", - 17: "routePanelForumsEditPermsAdvance", - 18: "routePanelForumsEditPermsAdvanceSubmit", - 19: "routePanelSettings", - 20: "routePanelSettingEdit", - 21: "routePanelSettingEditSubmit", - 22: "routePanelWordFilters", - 23: "routePanelWordFiltersCreate", - 24: "routePanelWordFiltersEdit", - 25: "routePanelWordFiltersEditSubmit", - 26: "routePanelWordFiltersDeleteSubmit", - 27: "routePanelThemes", - 28: "routePanelThemesSetDefault", - 29: "routePanelPlugins", - 30: "routePanelPluginsActivate", - 31: "routePanelPluginsDeactivate", - 32: "routePanelPluginsInstall", - 33: "routePanelUsers", - 34: "routePanelUsersEdit", - 35: "routePanelUsersEditSubmit", - 36: "routePanelAnalyticsViews", - 37: "routePanelAnalyticsRoutes", - 38: "routePanelAnalyticsAgents", - 39: "routePanelAnalyticsRouteViews", - 40: "routePanelAnalyticsAgentViews", - 41: "routePanelAnalyticsPosts", - 42: "routePanelGroups", - 43: "routePanelGroupsEdit", - 44: "routePanelGroupsEditPerms", - 45: "routePanelGroupsEditSubmit", - 46: "routePanelGroupsEditPermsSubmit", - 47: "routePanelGroupsCreateSubmit", - 48: "routePanelBackups", - 49: "routePanelLogsMod", - 50: "routePanelDebug", - 51: "routePanel", - 52: "routeAccountEditCritical", - 53: "routeAccountEditCriticalSubmit", - 54: "routeAccountEditAvatar", - 55: "routeAccountEditAvatarSubmit", - 56: "routeAccountEditUsername", - 57: "routeAccountEditUsernameSubmit", - 58: "routeAccountEditEmail", - 59: "routeAccountEditEmailTokenSubmit", - 60: "routeProfile", - 61: "routeBanSubmit", - 62: "routeUnban", - 63: "routeActivate", - 64: "routeIps", - 65: "routeTopicCreateSubmit", - 66: "routeEditTopicSubmit", - 67: "routeDeleteTopicSubmit", - 68: "routeStickTopicSubmit", - 69: "routeUnstickTopicSubmit", - 70: "routeLockTopicSubmit", - 71: "routeUnlockTopicSubmit", - 72: "routeMoveTopicSubmit", - 73: "routeLikeTopicSubmit", - 74: "routeTopicID", - 75: "routeCreateReplySubmit", - 76: "routeReplyEditSubmit", - 77: "routeReplyDeleteSubmit", - 78: "routeReplyLikeSubmit", - 79: "routeProfileReplyCreateSubmit", - 80: "routeProfileReplyEditSubmit", - 81: "routeProfileReplyDeleteSubmit", - 82: "routeLogin", - 83: "routeRegister", - 84: "routeLogout", - 85: "routeLoginSubmit", - 86: "routeRegisterSubmit", - 87: "routeDynamic", - 88: "routeUploads", + 7: "routeWebsockets", + 8: "routeReportSubmit", + 9: "routeTopicCreate", + 10: "routeTopics", + 11: "routePanelForums", + 12: "routePanelForumsCreateSubmit", + 13: "routePanelForumsDelete", + 14: "routePanelForumsDeleteSubmit", + 15: "routePanelForumsEdit", + 16: "routePanelForumsEditSubmit", + 17: "routePanelForumsEditPermsSubmit", + 18: "routePanelForumsEditPermsAdvance", + 19: "routePanelForumsEditPermsAdvanceSubmit", + 20: "routePanelSettings", + 21: "routePanelSettingEdit", + 22: "routePanelSettingEditSubmit", + 23: "routePanelWordFilters", + 24: "routePanelWordFiltersCreateSubmit", + 25: "routePanelWordFiltersEdit", + 26: "routePanelWordFiltersEditSubmit", + 27: "routePanelWordFiltersDeleteSubmit", + 28: "routePanelThemes", + 29: "routePanelThemesSetDefault", + 30: "routePanelPlugins", + 31: "routePanelPluginsActivate", + 32: "routePanelPluginsDeactivate", + 33: "routePanelPluginsInstall", + 34: "routePanelUsers", + 35: "routePanelUsersEdit", + 36: "routePanelUsersEditSubmit", + 37: "routePanelAnalyticsViews", + 38: "routePanelAnalyticsRoutes", + 39: "routePanelAnalyticsAgents", + 40: "routePanelAnalyticsRouteViews", + 41: "routePanelAnalyticsAgentViews", + 42: "routePanelAnalyticsPosts", + 43: "routePanelAnalyticsTopics", + 44: "routePanelGroups", + 45: "routePanelGroupsEdit", + 46: "routePanelGroupsEditPerms", + 47: "routePanelGroupsEditSubmit", + 48: "routePanelGroupsEditPermsSubmit", + 49: "routePanelGroupsCreateSubmit", + 50: "routePanelBackups", + 51: "routePanelLogsMod", + 52: "routePanelDebug", + 53: "routePanel", + 54: "routeAccountEditCritical", + 55: "routeAccountEditCriticalSubmit", + 56: "routeAccountEditAvatar", + 57: "routeAccountEditAvatarSubmit", + 58: "routeAccountEditUsername", + 59: "routeAccountEditUsernameSubmit", + 60: "routeAccountEditEmail", + 61: "routeAccountEditEmailTokenSubmit", + 62: "routeProfile", + 63: "routeBanSubmit", + 64: "routeUnban", + 65: "routeActivate", + 66: "routeIps", + 67: "routeTopicCreateSubmit", + 68: "routes.EditTopicSubmit", + 69: "routeDeleteTopicSubmit", + 70: "routeStickTopicSubmit", + 71: "routeUnstickTopicSubmit", + 72: "routeLockTopicSubmit", + 73: "routeUnlockTopicSubmit", + 74: "routeMoveTopicSubmit", + 75: "routeLikeTopicSubmit", + 76: "routeTopicID", + 77: "routeCreateReplySubmit", + 78: "routeReplyEditSubmit", + 79: "routeReplyDeleteSubmit", + 80: "routeReplyLikeSubmit", + 81: "routeProfileReplyCreateSubmit", + 82: "routeProfileReplyEditSubmit", + 83: "routeProfileReplyDeleteSubmit", + 84: "routeLogin", + 85: "routeRegister", + 86: "routeLogout", + 87: "routeLoginSubmit", + 88: "routeRegisterSubmit", + 89: "routeDynamic", + 90: "routeUploads", } var agentMapEnum = map[string]int{ "unknown": 0, @@ -394,8 +401,22 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { var prefix, extraData string prefix = req.URL.Path[0:strings.IndexByte(req.URL.Path[1:],'/') + 1] if req.URL.Path[len(req.URL.Path) - 1] != '/' { - // TODO: Cover more suspicious strings and at a lower layer than this and more efficiently - if strings.Contains(req.URL.Path,"'") || strings.Contains(req.URL.Path,";") || strings.Contains(req.URL.Path,"\"") || strings.Contains(req.URL.Path,"`") || strings.Contains(req.URL.Path,"%") { + // TODO: Cover more suspicious strings and at a lower layer than this + for _, char := range req.URL.Path { + if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) { + log.Print("Suspicious UA: ", req.UserAgent()) + log.Print("Method: ", req.Method) + for key, value := range req.Header { + for _, vvalue := range value { + log.Print("Header '" + key + "': " + vvalue + "!!") + } + } + log.Print("req.URL.Path: ", req.URL.Path) + log.Print("req.Referer(): ", req.Referer()) + log.Print("req.RemoteAddr: ", req.RemoteAddr) + } + } + if strings.Contains(req.URL.Path,"..") || strings.Contains(req.URL.Path,"--") { log.Print("Suspicious UA: ", req.UserAgent()) log.Print("Method: ", req.Method) for key, value := range req.Header { @@ -572,6 +593,13 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { if err != nil { router.handleError(err,w,req,user) } + case "/ws": + req.URL.Path += extraData + common.RouteViewCounter.Bump(7) + err = routeWebsockets(w,req,user) + if err != nil { + router.handleError(err,w,req,user) + } case "/report": err = common.NoBanned(w,req,user) if err != nil { @@ -593,7 +621,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(7) + common.RouteViewCounter.Bump(8) err = routeReportSubmit(w,req,user,extraData) } if err != nil { @@ -608,10 +636,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(8) + common.RouteViewCounter.Bump(9) err = routeTopicCreate(w,req,user,extraData) default: - common.RouteViewCounter.Bump(9) + common.RouteViewCounter.Bump(10) err = routeTopics(w,req,user) } if err != nil { @@ -626,7 +654,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { switch(req.URL.Path) { case "/panel/forums/": - common.RouteViewCounter.Bump(10) + common.RouteViewCounter.Bump(11) err = routePanelForums(w,req,user) case "/panel/forums/create/": err = common.NoSessionMismatch(w,req,user) @@ -635,7 +663,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(11) + common.RouteViewCounter.Bump(12) err = routePanelForumsCreateSubmit(w,req,user) case "/panel/forums/delete/": err = common.NoSessionMismatch(w,req,user) @@ -644,7 +672,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(12) + common.RouteViewCounter.Bump(13) err = routePanelForumsDelete(w,req,user,extraData) case "/panel/forums/delete/submit/": err = common.NoSessionMismatch(w,req,user) @@ -653,10 +681,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(13) + common.RouteViewCounter.Bump(14) err = routePanelForumsDeleteSubmit(w,req,user,extraData) case "/panel/forums/edit/": - common.RouteViewCounter.Bump(14) + common.RouteViewCounter.Bump(15) err = routePanelForumsEdit(w,req,user,extraData) case "/panel/forums/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -665,7 +693,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(15) + common.RouteViewCounter.Bump(16) err = routePanelForumsEditSubmit(w,req,user,extraData) case "/panel/forums/edit/perms/submit/": err = common.NoSessionMismatch(w,req,user) @@ -674,10 +702,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(16) + common.RouteViewCounter.Bump(17) err = routePanelForumsEditPermsSubmit(w,req,user,extraData) case "/panel/forums/edit/perms/": - common.RouteViewCounter.Bump(17) + common.RouteViewCounter.Bump(18) err = routePanelForumsEditPermsAdvance(w,req,user,extraData) case "/panel/forums/edit/perms/adv/submit/": err = common.NoSessionMismatch(w,req,user) @@ -686,13 +714,13 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(18) + common.RouteViewCounter.Bump(19) err = routePanelForumsEditPermsAdvanceSubmit(w,req,user,extraData) case "/panel/settings/": - common.RouteViewCounter.Bump(19) + common.RouteViewCounter.Bump(20) err = routePanelSettings(w,req,user) case "/panel/settings/edit/": - common.RouteViewCounter.Bump(20) + common.RouteViewCounter.Bump(21) err = routePanelSettingEdit(w,req,user,extraData) case "/panel/settings/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -701,10 +729,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(21) + common.RouteViewCounter.Bump(22) err = routePanelSettingEditSubmit(w,req,user,extraData) case "/panel/settings/word-filters/": - common.RouteViewCounter.Bump(22) + common.RouteViewCounter.Bump(23) err = routePanelWordFilters(w,req,user) case "/panel/settings/word-filters/create/": err = common.NoSessionMismatch(w,req,user) @@ -713,10 +741,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(23) - err = routePanelWordFiltersCreate(w,req,user) - case "/panel/settings/word-filters/edit/": common.RouteViewCounter.Bump(24) + err = routePanelWordFiltersCreateSubmit(w,req,user) + case "/panel/settings/word-filters/edit/": + common.RouteViewCounter.Bump(25) err = routePanelWordFiltersEdit(w,req,user,extraData) case "/panel/settings/word-filters/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -725,7 +753,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(25) + common.RouteViewCounter.Bump(26) err = routePanelWordFiltersEditSubmit(w,req,user,extraData) case "/panel/settings/word-filters/delete/submit/": err = common.NoSessionMismatch(w,req,user) @@ -734,10 +762,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(26) + common.RouteViewCounter.Bump(27) err = routePanelWordFiltersDeleteSubmit(w,req,user,extraData) case "/panel/themes/": - common.RouteViewCounter.Bump(27) + common.RouteViewCounter.Bump(28) err = routePanelThemes(w,req,user) case "/panel/themes/default/": err = common.NoSessionMismatch(w,req,user) @@ -746,10 +774,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(28) + common.RouteViewCounter.Bump(29) err = routePanelThemesSetDefault(w,req,user,extraData) case "/panel/plugins/": - common.RouteViewCounter.Bump(29) + common.RouteViewCounter.Bump(30) err = routePanelPlugins(w,req,user) case "/panel/plugins/activate/": err = common.NoSessionMismatch(w,req,user) @@ -758,7 +786,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(30) + common.RouteViewCounter.Bump(31) err = routePanelPluginsActivate(w,req,user,extraData) case "/panel/plugins/deactivate/": err = common.NoSessionMismatch(w,req,user) @@ -767,7 +795,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(31) + common.RouteViewCounter.Bump(32) err = routePanelPluginsDeactivate(w,req,user,extraData) case "/panel/plugins/install/": err = common.NoSessionMismatch(w,req,user) @@ -776,13 +804,13 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(32) + common.RouteViewCounter.Bump(33) err = routePanelPluginsInstall(w,req,user,extraData) case "/panel/users/": - common.RouteViewCounter.Bump(33) + common.RouteViewCounter.Bump(34) err = routePanelUsers(w,req,user) case "/panel/users/edit/": - common.RouteViewCounter.Bump(34) + common.RouteViewCounter.Bump(35) err = routePanelUsersEdit(w,req,user,extraData) case "/panel/users/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -791,7 +819,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(35) + common.RouteViewCounter.Bump(36) err = routePanelUsersEditSubmit(w,req,user,extraData) case "/panel/analytics/views/": err = common.ParseForm(w,req,user) @@ -800,7 +828,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(36) + common.RouteViewCounter.Bump(37) err = routePanelAnalyticsViews(w,req,user) case "/panel/analytics/routes/": err = common.ParseForm(w,req,user) @@ -809,7 +837,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(37) + common.RouteViewCounter.Bump(38) err = routePanelAnalyticsRoutes(w,req,user) case "/panel/analytics/agents/": err = common.ParseForm(w,req,user) @@ -818,13 +846,13 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(38) + common.RouteViewCounter.Bump(39) err = routePanelAnalyticsAgents(w,req,user) case "/panel/analytics/route/": - common.RouteViewCounter.Bump(39) + common.RouteViewCounter.Bump(40) err = routePanelAnalyticsRouteViews(w,req,user,extraData) case "/panel/analytics/agent/": - common.RouteViewCounter.Bump(40) + common.RouteViewCounter.Bump(41) err = routePanelAnalyticsAgentViews(w,req,user,extraData) case "/panel/analytics/posts/": err = common.ParseForm(w,req,user) @@ -833,16 +861,25 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(41) - err = routePanelAnalyticsPosts(w,req,user) - case "/panel/groups/": common.RouteViewCounter.Bump(42) + err = routePanelAnalyticsPosts(w,req,user) + case "/panel/analytics/topics/": + err = common.ParseForm(w,req,user) + if err != nil { + router.handleError(err,w,req,user) + return + } + + common.RouteViewCounter.Bump(43) + err = routePanelAnalyticsTopics(w,req,user) + case "/panel/groups/": + common.RouteViewCounter.Bump(44) err = routePanelGroups(w,req,user) case "/panel/groups/edit/": - common.RouteViewCounter.Bump(43) + common.RouteViewCounter.Bump(45) err = routePanelGroupsEdit(w,req,user,extraData) case "/panel/groups/edit/perms/": - common.RouteViewCounter.Bump(44) + common.RouteViewCounter.Bump(46) err = routePanelGroupsEditPerms(w,req,user,extraData) case "/panel/groups/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -851,7 +888,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(45) + common.RouteViewCounter.Bump(47) err = routePanelGroupsEditSubmit(w,req,user,extraData) case "/panel/groups/edit/perms/submit/": err = common.NoSessionMismatch(w,req,user) @@ -860,7 +897,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(46) + common.RouteViewCounter.Bump(48) err = routePanelGroupsEditPermsSubmit(w,req,user,extraData) case "/panel/groups/create/": err = common.NoSessionMismatch(w,req,user) @@ -869,7 +906,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(47) + common.RouteViewCounter.Bump(49) err = routePanelGroupsCreateSubmit(w,req,user) case "/panel/backups/": err = common.SuperAdminOnly(w,req,user) @@ -878,10 +915,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(48) + common.RouteViewCounter.Bump(50) err = routePanelBackups(w,req,user,extraData) case "/panel/logs/mod/": - common.RouteViewCounter.Bump(49) + common.RouteViewCounter.Bump(51) err = routePanelLogsMod(w,req,user) case "/panel/debug/": err = common.AdminOnly(w,req,user) @@ -890,10 +927,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(50) + common.RouteViewCounter.Bump(52) err = routePanelDebug(w,req,user) default: - common.RouteViewCounter.Bump(51) + common.RouteViewCounter.Bump(53) err = routePanel(w,req,user) } if err != nil { @@ -908,7 +945,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(52) + common.RouteViewCounter.Bump(54) err = routeAccountEditCritical(w,req,user) case "/user/edit/critical/submit/": err = common.NoSessionMismatch(w,req,user) @@ -923,7 +960,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(53) + common.RouteViewCounter.Bump(55) err = routeAccountEditCriticalSubmit(w,req,user) case "/user/edit/avatar/": err = common.MemberOnly(w,req,user) @@ -932,7 +969,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(54) + common.RouteViewCounter.Bump(56) err = routeAccountEditAvatar(w,req,user) case "/user/edit/avatar/submit/": err = common.MemberOnly(w,req,user) @@ -952,7 +989,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(55) + common.RouteViewCounter.Bump(57) err = routeAccountEditAvatarSubmit(w,req,user) case "/user/edit/username/": err = common.MemberOnly(w,req,user) @@ -961,7 +998,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(56) + common.RouteViewCounter.Bump(58) err = routeAccountEditUsername(w,req,user) case "/user/edit/username/submit/": err = common.NoSessionMismatch(w,req,user) @@ -976,7 +1013,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(57) + common.RouteViewCounter.Bump(59) err = routeAccountEditUsernameSubmit(w,req,user) case "/user/edit/email/": err = common.MemberOnly(w,req,user) @@ -985,7 +1022,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(58) + common.RouteViewCounter.Bump(60) err = routeAccountEditEmail(w,req,user) case "/user/edit/token/": err = common.NoSessionMismatch(w,req,user) @@ -1000,11 +1037,11 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(59) + common.RouteViewCounter.Bump(61) err = routeAccountEditEmailTokenSubmit(w,req,user,extraData) default: req.URL.Path += extraData - common.RouteViewCounter.Bump(60) + common.RouteViewCounter.Bump(62) err = routeProfile(w,req,user) } if err != nil { @@ -1025,7 +1062,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(61) + common.RouteViewCounter.Bump(63) err = routeBanSubmit(w,req,user,extraData) case "/users/unban/": err = common.NoSessionMismatch(w,req,user) @@ -1040,7 +1077,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(62) + common.RouteViewCounter.Bump(64) err = routeUnban(w,req,user,extraData) case "/users/activate/": err = common.NoSessionMismatch(w,req,user) @@ -1055,7 +1092,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(63) + common.RouteViewCounter.Bump(65) err = routeActivate(w,req,user,extraData) case "/users/ips/": err = common.MemberOnly(w,req,user) @@ -1064,7 +1101,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(64) + common.RouteViewCounter.Bump(66) err = routeIps(w,req,user) } if err != nil { @@ -1085,7 +1122,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(65) + common.RouteViewCounter.Bump(67) err = routeTopicCreateSubmit(w,req,user) case "/topic/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1100,8 +1137,8 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(66) - err = routeEditTopicSubmit(w,req,user,extraData) + common.RouteViewCounter.Bump(68) + err = routes.EditTopicSubmit(w,req,user,extraData) case "/topic/delete/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { @@ -1116,7 +1153,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } req.URL.Path += extraData - common.RouteViewCounter.Bump(67) + common.RouteViewCounter.Bump(69) err = routeDeleteTopicSubmit(w,req,user) case "/topic/stick/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1131,7 +1168,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(68) + common.RouteViewCounter.Bump(70) err = routeStickTopicSubmit(w,req,user,extraData) case "/topic/unstick/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1146,7 +1183,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(69) + common.RouteViewCounter.Bump(71) err = routeUnstickTopicSubmit(w,req,user,extraData) case "/topic/lock/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1162,7 +1199,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } req.URL.Path += extraData - common.RouteViewCounter.Bump(70) + common.RouteViewCounter.Bump(72) err = routeLockTopicSubmit(w,req,user) case "/topic/unlock/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1177,7 +1214,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(71) + common.RouteViewCounter.Bump(73) err = routeUnlockTopicSubmit(w,req,user,extraData) case "/topic/move/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1192,7 +1229,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(72) + common.RouteViewCounter.Bump(74) err = routeMoveTopicSubmit(w,req,user,extraData) case "/topic/like/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1207,10 +1244,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(73) + common.RouteViewCounter.Bump(75) err = routeLikeTopicSubmit(w,req,user,extraData) default: - common.RouteViewCounter.Bump(74) + common.RouteViewCounter.Bump(76) err = routeTopicID(w,req,user, extraData) } if err != nil { @@ -1236,7 +1273,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(75) + common.RouteViewCounter.Bump(77) err = routeCreateReplySubmit(w,req,user) case "/reply/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1251,7 +1288,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(76) + common.RouteViewCounter.Bump(78) err = routeReplyEditSubmit(w,req,user,extraData) case "/reply/delete/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1266,7 +1303,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(77) + common.RouteViewCounter.Bump(79) err = routeReplyDeleteSubmit(w,req,user,extraData) case "/reply/like/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1281,7 +1318,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(78) + common.RouteViewCounter.Bump(80) err = routeReplyLikeSubmit(w,req,user,extraData) } if err != nil { @@ -1302,7 +1339,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(79) + common.RouteViewCounter.Bump(81) err = routeProfileReplyCreateSubmit(w,req,user) case "/profile/reply/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1317,7 +1354,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(80) + common.RouteViewCounter.Bump(82) err = routeProfileReplyEditSubmit(w,req,user,extraData) case "/profile/reply/delete/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1332,7 +1369,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(81) + common.RouteViewCounter.Bump(83) err = routeProfileReplyDeleteSubmit(w,req,user,extraData) } if err != nil { @@ -1341,10 +1378,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { case "/accounts": switch(req.URL.Path) { case "/accounts/login/": - common.RouteViewCounter.Bump(82) + common.RouteViewCounter.Bump(84) err = routeLogin(w,req,user) case "/accounts/create/": - common.RouteViewCounter.Bump(83) + common.RouteViewCounter.Bump(85) err = routeRegister(w,req,user) case "/accounts/logout/": err = common.NoSessionMismatch(w,req,user) @@ -1359,7 +1396,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(84) + common.RouteViewCounter.Bump(86) err = routeLogout(w,req,user) case "/accounts/login/submit/": err = common.ParseForm(w,req,user) @@ -1368,7 +1405,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(85) + common.RouteViewCounter.Bump(87) err = routeLoginSubmit(w,req,user) case "/accounts/create/submit/": err = common.ParseForm(w,req,user) @@ -1377,7 +1414,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(86) + common.RouteViewCounter.Bump(88) err = routeRegisterSubmit(w,req,user) } if err != nil { @@ -1394,7 +1431,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { common.NotFound(w,req) return } - common.RouteViewCounter.Bump(88) + common.RouteViewCounter.Bump(90) req.URL.Path += extraData // TODO: Find a way to propagate errors up from this? router.UploadHandler(w,req) // TODO: Count these views @@ -1438,7 +1475,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { router.RUnlock() if ok { - common.RouteViewCounter.Bump(87) // TODO: Be more specific about *which* dynamic route it is + common.RouteViewCounter.Bump(89) // 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/main.go b/main.go index 3dda626b..e10f199d 100644 --- a/main.go +++ b/main.go @@ -96,6 +96,10 @@ func afterDBInit() (err error) { if err != nil { return err } + common.TopicCounter, err = common.NewTopicCounter() + if err != nil { + return err + } common.TopicViewCounter, err = common.NewDefaultTopicViewCounter() if err != nil { return err @@ -300,10 +304,8 @@ func main() { } }() - // TODO: Move these routes into the new routes list log.Print("Initialising the router") router = NewGenRouter(http.FileServer(http.Dir("./uploads"))) - router.HandleFunc("/ws/", routeWebsockets) log.Print("Initialising the plugins") common.InitPlugins() diff --git a/member_routes.go b/member_routes.go index db9810d5..027f9d8f 100644 --- a/member_routes.go +++ b/member_routes.go @@ -243,6 +243,7 @@ func routeTopicCreateSubmit(w http.ResponseWriter, r *http.Request, user common. } common.PostCounter.Bump() + common.TopicCounter.Bump() http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) return nil } diff --git a/mod_routes.go b/mod_routes.go index 4539624a..2382fad5 100644 --- a/mod_routes.go +++ b/mod_routes.go @@ -1,8 +1,6 @@ package main import ( - //"log" - //"fmt" "encoding/json" "html" "log" @@ -13,50 +11,6 @@ import ( "./common" ) -// TODO: Update the stats after edits so that we don't under or over decrement stats during deletes -// TODO: Disable stat updates in posts handled by plugin_guilds -func routeEditTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError { - isJs := (r.PostFormValue("js") == "1") - - tid, err := strconv.Atoi(stid) - if err != nil { - return common.PreErrorJSQ("The provided TopicID is not a valid number.", w, r, isJs) - } - - topic, err := common.Topics.Get(tid) - if err == ErrNoRows { - return common.PreErrorJSQ("The topic you tried to edit doesn't exist.", w, r, isJs) - } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) - } - - // TODO: Add hooks to make use of headerLite - _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) - if ferr != nil { - return ferr - } - if !user.Perms.ViewTopic || !user.Perms.EditTopic { - return common.NoPermissionsJSQ(w, r, user, isJs) - } - - err = topic.Update(r.PostFormValue("topic_name"), r.PostFormValue("topic_content")) - if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) - } - - err = common.Forums.UpdateLastTopic(topic.ID, user.ID, topic.ParentID) - if err != nil && err != ErrNoRows { - return common.InternalErrorJSQ(err, w, r, isJs) - } - - if !isJs { - http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) - } else { - _, _ = w.Write(successJSONBytes) - } - return nil -} - // TODO: Add support for soft-deletion and add a permission for hard delete in addition to the usual // TODO: Disable stat updates in posts handled by plugin_guilds func routeDeleteTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { @@ -462,7 +416,7 @@ func routeReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common. //log.Printf("Reply #%d was deleted by common.User #%d", rid, user.ID) if !isJs { - //http.Redirect(w,r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther) + http.Redirect(w, r, "/topic/"+strconv.Itoa(reply.ParentID), http.StatusSeeOther) } else { w.Write(successJSONBytes) } diff --git a/panel_routes.go b/panel_routes.go index 58570b7c..4d28336f 100644 --- a/panel_routes.go +++ b/panel_routes.go @@ -826,6 +826,79 @@ func routePanelAnalyticsAgentViews(w http.ResponseWriter, r *http.Request, user return panelRenderTemplate("panel_analytics_agent_views", w, r, user, &pi) } +func routePanelAnalyticsTopics(w http.ResponseWriter, r *http.Request, user common.User) 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") + + timeRange, err := panelAnalyticsTimeRange(r.FormValue("timeRange")) + if err != nil { + return common.LocalError(err.Error(), w, r, user) + } + + var revLabelList []int64 + var labelList []int64 + var viewMap = make(map[int64]int64) + var currentTime = time.Now().Unix() + + for i := 1; i <= timeRange.Slices; i++ { + var label = currentTime - int64(i*timeRange.SliceWidth) + revLabelList = append(revLabelList, label) + viewMap[label] = 0 + } + for _, value := range revLabelList { + labelList = append(labelList, value) + } + + var viewList []int64 + log.Print("in routePanelAnalyticsTopics") + + acc := qgen.Builder.Accumulator() + rows, err := acc.Select("topicchunks").Columns("count, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() + 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) + } + + var viewItems []common.PanelAnalyticsItem + for _, value := range revLabelList { + viewList = append(viewList, viewMap[value]) + viewItems = append(viewItems, common.PanelAnalyticsItem{Time: value, Count: viewMap[value]}) + } + graph := common.PanelTimeGraph{Series: viewList, Labels: labelList} + log.Printf("graph: %+v\n", graph) + + pi := common.PanelAnalyticsPage{common.GetTitlePhrase("panel_analytics"), user, headerVars, stats, "analytics", graph, viewItems, timeRange.Range} + return panelRenderTemplate("panel_analytics_topics", w, r, user, &pi) +} + func routePanelAnalyticsPosts(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { headerVars, stats, ferr := common.PanelUserCheck(w, r, &user) if ferr != nil { @@ -1110,7 +1183,7 @@ func routePanelWordFilters(w http.ResponseWriter, r *http.Request, user common.U return panelRenderTemplate("panel_word_filters", w, r, user, &pi) } -func routePanelWordFiltersCreate(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func routePanelWordFiltersCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { _, ferr := common.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr diff --git a/query_gen/tables.go b/query_gen/tables.go index 1d188dc4..43f0e20d 100644 --- a/query_gen/tables.go +++ b/query_gen/tables.go @@ -386,6 +386,15 @@ func createTables(adapter qgen.Adapter) error { ) */ + qgen.Install.CreateTable("topicchunks", "", "", + []qgen.DBTableColumn{ + qgen.DBTableColumn{"count", "int", 0, false, false, "0"}, + qgen.DBTableColumn{"createdAt", "datetime", 0, false, false, ""}, + // TODO: Add a column for the parent forum? + }, + []qgen.DBTableKey{}, + ) + qgen.Install.CreateTable("postchunks", "", "", []qgen.DBTableColumn{ qgen.DBTableColumn{"count", "int", 0, false, false, "0"}, diff --git a/router_gen/main.go b/router_gen/main.go index b69f569d..a44bd475 100644 --- a/router_gen/main.go +++ b/router_gen/main.go @@ -181,7 +181,6 @@ func main() { for id, agent := range tmplVars.AllAgentNames { tmplVars.AllAgentMap[agent] = id } - var graveSym = "`" var fileData = `// Code generated by. DO NOT EDIT. /* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ @@ -195,6 +194,7 @@ import ( "net/http" "./common" + "./routes" ) var ErrNoRoute = errors.New("That route doesn't exist.") @@ -285,8 +285,22 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { var prefix, extraData string prefix = req.URL.Path[0:strings.IndexByte(req.URL.Path[1:],'/') + 1] if req.URL.Path[len(req.URL.Path) - 1] != '/' { - // TODO: Cover more suspicious strings and at a lower layer than this and more efficiently - if strings.Contains(req.URL.Path,"'") || strings.Contains(req.URL.Path,";") || strings.Contains(req.URL.Path,"\"") || strings.Contains(req.URL.Path,"` + graveSym + `") || strings.Contains(req.URL.Path,"%") { + // TODO: Cover more suspicious strings and at a lower layer than this + for _, char := range req.URL.Path { + if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) { + log.Print("Suspicious UA: ", req.UserAgent()) + log.Print("Method: ", req.Method) + for key, value := range req.Header { + for _, vvalue := range value { + log.Print("Header '" + key + "': " + vvalue + "!!") + } + } + log.Print("req.URL.Path: ", req.URL.Path) + log.Print("req.Referer(): ", req.Referer()) + log.Print("req.RemoteAddr: ", req.RemoteAddr) + } + } + if strings.Contains(req.URL.Path,"..") || strings.Contains(req.URL.Path,"--") { log.Print("Suspicious UA: ", req.UserAgent()) log.Print("Method: ", req.Method) for key, value := range req.Header { diff --git a/router_gen/route_impl.go b/router_gen/route_impl.go index 64281f7b..fb3f8067 100644 --- a/router_gen/route_impl.go +++ b/router_gen/route_impl.go @@ -95,6 +95,10 @@ func AnonAction(fname string, path string, args ...string) *RouteImpl { return route(fname, path, args...).Before("ParseForm") } +func Special(fname string, path string, args ...string) *RouteImpl { + return route(fname, path, args...).LitBefore("req.URL.Path += extraData") +} + // Make this it's own type to force the user to manipulate methods on it to set parameters type uploadAction struct { Route *RouteImpl diff --git a/router_gen/routes.go b/router_gen/routes.go index f83bd55a..6cdad277 100644 --- a/router_gen/routes.go +++ b/router_gen/routes.go @@ -30,6 +30,8 @@ func routes() { buildReplyRoutes() buildProfileReplyRoutes() buildAccountRoutes() + + addRoute(Special("routeWebsockets", "/ws/")) } // TODO: Test the email token route @@ -64,7 +66,7 @@ func buildTopicRoutes() { topicGroup.Routes( View("routeTopicID", "/topic/", "extraData"), Action("routeTopicCreateSubmit", "/topic/create/submit/"), - Action("routeEditTopicSubmit", "/topic/edit/submit/", "extraData"), + Action("routes.EditTopicSubmit", "/topic/edit/submit/", "extraData"), Action("routeDeleteTopicSubmit", "/topic/delete/submit/").LitBefore("req.URL.Path += extraData"), Action("routeStickTopicSubmit", "/topic/stick/submit/", "extraData"), Action("routeUnstickTopicSubmit", "/topic/unstick/submit/", "extraData"), @@ -134,7 +136,7 @@ func buildPanelRoutes() { Action("routePanelSettingEditSubmit", "/panel/settings/edit/submit/", "extraData"), View("routePanelWordFilters", "/panel/settings/word-filters/"), - Action("routePanelWordFiltersCreate", "/panel/settings/word-filters/create/"), + Action("routePanelWordFiltersCreateSubmit", "/panel/settings/word-filters/create/"), View("routePanelWordFiltersEdit", "/panel/settings/word-filters/edit/", "extraData"), Action("routePanelWordFiltersEditSubmit", "/panel/settings/word-filters/edit/submit/", "extraData"), Action("routePanelWordFiltersDeleteSubmit", "/panel/settings/word-filters/delete/submit/", "extraData"), @@ -157,6 +159,7 @@ func buildPanelRoutes() { View("routePanelAnalyticsRouteViews", "/panel/analytics/route/", "extraData"), View("routePanelAnalyticsAgentViews", "/panel/analytics/agent/", "extraData"), View("routePanelAnalyticsPosts", "/panel/analytics/posts/").Before("ParseForm"), + View("routePanelAnalyticsTopics", "/panel/analytics/topics/").Before("ParseForm"), View("routePanelGroups", "/panel/groups/"), View("routePanelGroupsEdit", "/panel/groups/edit/", "extraData"), diff --git a/routes/filler.txt b/routes/filler.txt deleted file mode 100644 index 20e14b1e..00000000 --- a/routes/filler.txt +++ /dev/null @@ -1 +0,0 @@ -This file is here so that Git will include this folder in the repository. \ No newline at end of file diff --git a/routes/topic.go b/routes/topic.go new file mode 100644 index 00000000..b2fb1ade --- /dev/null +++ b/routes/topic.go @@ -0,0 +1,55 @@ +package routes + +import ( + "database/sql" + "net/http" + "strconv" + + "../common" +) + +var successJSONBytes = []byte(`{"success":"1"}`) + +// TODO: Update the stats after edits so that we don't under or over decrement stats during deletes +// TODO: Disable stat updates in posts handled by plugin_guilds +func EditTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError { + isJs := (r.PostFormValue("js") == "1") + + tid, err := strconv.Atoi(stid) + if err != nil { + return common.PreErrorJSQ("The provided TopicID is not a valid number.", w, r, isJs) + } + + topic, err := common.Topics.Get(tid) + if err == sql.ErrNoRows { + return common.PreErrorJSQ("The topic you tried to edit doesn't exist.", w, r, isJs) + } else if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + + // TODO: Add hooks to make use of headerLite + _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + if ferr != nil { + return ferr + } + if !user.Perms.ViewTopic || !user.Perms.EditTopic { + return common.NoPermissionsJSQ(w, r, user, isJs) + } + + err = topic.Update(r.PostFormValue("topic_name"), r.PostFormValue("topic_content")) + if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + + err = common.Forums.UpdateLastTopic(topic.ID, user.ID, topic.ParentID) + if err != nil && err != sql.ErrNoRows { + return common.InternalErrorJSQ(err, w, r, isJs) + } + + if !isJs { + http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) + } else { + _, _ = w.Write(successJSONBytes) + } + return nil +} diff --git a/schema/mssql/query_topicchunks.sql b/schema/mssql/query_topicchunks.sql new file mode 100644 index 00000000..6ca5dc53 --- /dev/null +++ b/schema/mssql/query_topicchunks.sql @@ -0,0 +1,4 @@ +CREATE TABLE [topicchunks] ( + [count] int DEFAULT 0 not null, + [createdAt] datetime not null +); \ No newline at end of file diff --git a/schema/mysql/query_topicchunks.sql b/schema/mysql/query_topicchunks.sql new file mode 100644 index 00000000..05a2dc46 --- /dev/null +++ b/schema/mysql/query_topicchunks.sql @@ -0,0 +1,4 @@ +CREATE TABLE `topicchunks` ( + `count` int DEFAULT 0 not null, + `createdAt` datetime not null +); \ No newline at end of file diff --git a/schema/pgsql/query_topicchunks.sql b/schema/pgsql/query_topicchunks.sql new file mode 100644 index 00000000..13253a19 --- /dev/null +++ b/schema/pgsql/query_topicchunks.sql @@ -0,0 +1,4 @@ +CREATE TABLE `topicchunks` ( + `count` int DEFAULT 0 not null, + `createdAt` timestamp not null +); \ No newline at end of file diff --git a/templates/create_topic.html b/templates/create_topic.html index 534030ce..1271bf2b 100644 --- a/templates/create_topic.html +++ b/templates/create_topic.html @@ -1,5 +1,5 @@ {{template "header.html" . }} -
+

Create Topic

diff --git a/templates/login.html b/templates/login.html index 8f5a66a1..c8f69772 100644 --- a/templates/login.html +++ b/templates/login.html @@ -1,5 +1,5 @@ {{template "header.html" . }} -
+

Login

diff --git a/templates/panel-inner-menu.html b/templates/panel-inner-menu.html index 927afbcd..cf144959 100644 --- a/templates/panel-inner-menu.html +++ b/templates/panel-inner-menu.html @@ -32,6 +32,9 @@ + diff --git a/templates/panel_analytics_posts.html b/templates/panel_analytics_posts.html index aea852f2..fcb8f2fc 100644 --- a/templates/panel_analytics_posts.html +++ b/templates/panel_analytics_posts.html @@ -5,7 +5,7 @@
- Posts + Post Counts + + + + + + +
+
+
+
+
+
+
+ +
+
+ {{range .ViewItems}} +
+ {{.Time}} + {{.Count}} views +
+ {{end}} +
+
+ + +{{template "footer.html" . }} diff --git a/templates/register.html b/templates/register.html index fb74226c..633ce4d8 100644 --- a/templates/register.html +++ b/templates/register.html @@ -1,5 +1,5 @@ {{template "header.html" . }} -
+

Create Account

diff --git a/themes/cosora/public/main.css b/themes/cosora/public/main.css index 7a3d8d60..ad6551a3 100644 --- a/themes/cosora/public/main.css +++ b/themes/cosora/public/main.css @@ -1138,6 +1138,22 @@ textarea { margin-left: auto; } +#create_topic_page .close_form, #create_topic_page .formlabel, #login_page .formlabel, #register_page .formlabel { + display: none; +} +#login_page .formrow:not(:first-child):not(:last-child), #register_page .formrow:not(:first-child):not(:last-child) { + margin-top: 4px; +} +#login_page .formrow:not(:first-child), #register_page .formrow:not(:first-child) { + padding-top: 3px; +} +#login_page .formrow:not(:last-child), #register_page .formrow:not(:last-child) { + padding-bottom: 0px; +} +#login_page .formrow, #register_page .formrow { + padding: 16px; +} + /* TODO: Highlight the one we're currently on? */ .pageset { display: flex;