From 60964868d4a145ebca7bfa6e46d657dae6da8c97 Mon Sep 17 00:00:00 2001 From: Azareal Date: Mon, 19 Feb 2018 04:26:01 +0000 Subject: [PATCH] Moved the counters to their own package. De-duped some of the logging code. Added per-route state to the not found errors. Exported debugDetail, debugDetailf, debugLog, and debugLogf. Tweaked the padding on Tempra Simple. Added panel submenus to Tempra Conflux. Added Chart CSS to Tempra Conflux. Fixed the padding and margins for the Control Panel in Cosora. Made Cosora's Control Panel a little more tablet friendly. Added the rowmsg CSS class to better style message rows. Removed the repetitive guard code for the pre-render hooks. Removed the repetitive guard code for the string-string hooks. We now capture views for routes.StaticFile Added the move action to the moderation logs. Added the viewchunks_forums table. Began work on Per-forum Views. I probably missed a few things in this changelog. --- alerts.go | 12 +- bot_routes.go | 10 +- common/common.go | 42 +- common/counters.go | 463 ------------------ common/counters/agents.go | 68 +++ common/counters/common.go | 42 ++ common/counters/forums.go | 86 ++++ common/counters/posts.go | 58 +++ common/{requests.go => counters/referrers.go} | 13 +- common/counters/requests.go | 60 +++ common/counters/routes.go | 66 +++ common/counters/systems.go | 65 +++ common/counters/topics.go | 58 +++ common/counters/topics_views.go | 116 +++++ common/email.go | 1 + common/errors.go | 30 +- common/files.go | 4 +- common/forum_perms_store.go | 33 +- common/forum_store.go | 2 +- common/group_store.go | 8 +- common/parser.go | 8 +- common/permissions.go | 4 +- common/phrases.go | 4 +- common/poll_store.go | 1 + common/routes_common.go | 4 +- common/themes.go | 6 +- common/user_store.go | 1 + common/widgets.go | 9 +- extend/guilds/lib/guilds.go | 9 +- gen_mssql.go | 4 +- gen_mysql.go | 4 +- gen_pgsql.go | 4 +- gen_router.go | 246 +++++----- main.go | 19 +- member_routes.go | 53 +- panel_routes.go | 100 ++-- query_gen/lib/mssql.go | 4 +- query_gen/lib/mysql.go | 4 +- query_gen/lib/pgsql.go | 4 +- query_gen/tables.go | 18 +- router.go | 2 +- router_gen/main.go | 56 ++- routes.go | 28 +- routes/account.go | 22 +- routes/misc.go | 22 +- routes/moderate.go | 4 +- routes/topic.go | 26 +- routes/topic_list.go | 6 +- schema/mssql/query_viewchunks_forums.sql | 5 + schema/mysql/query_viewchunks_forums.sql | 5 + schema/pgsql/query_viewchunks_forums.sql | 5 + template_list.go | 6 +- templates/are_you_sure.html | 2 +- templates/error.html | 2 +- templates/forum.html | 2 +- templates/forums.html | 2 +- templates/panel_analytics_agents.html | 2 +- templates/panel_analytics_posts.html | 2 +- templates/panel_analytics_referrers.html | 2 +- templates/panel_analytics_routes.html | 2 +- templates/panel_analytics_systems.html | 2 +- templates/panel_backups.html | 2 +- templates/panel_word_filters.html | 2 +- templates/topics.html | 2 +- themes/cosora/public/main.css | 14 +- themes/cosora/public/panel.css | 11 +- themes/tempra-conflux/public/panel.css | 20 +- themes/tempra-simple/public/media.partial.css | 6 +- 68 files changed, 1058 insertions(+), 947 deletions(-) delete mode 100644 common/counters.go create mode 100644 common/counters/agents.go create mode 100644 common/counters/common.go create mode 100644 common/counters/forums.go create mode 100644 common/counters/posts.go rename common/{requests.go => counters/referrers.go} (91%) create mode 100644 common/counters/requests.go create mode 100644 common/counters/routes.go create mode 100644 common/counters/systems.go create mode 100644 common/counters/topics.go create mode 100644 common/counters/topics_views.go create mode 100644 schema/mssql/query_viewchunks_forums.sql create mode 100644 schema/mysql/query_viewchunks_forums.sql create mode 100644 schema/pgsql/query_viewchunks_forums.sql diff --git a/alerts.go b/alerts.go index bdf5b664..07741251 100644 --- a/alerts.go +++ b/alerts.go @@ -58,9 +58,7 @@ func buildAlert(asid int, event string, elementType string, actorID int, targetU act = "created a new topic" topic, err := common.Topics.Get(elementID) if err != nil { - if common.Dev.DebugMode { - log.Print("Unable to find linked topic " + strconv.Itoa(elementID)) - } + common.DebugLogf("Unable to find linked topic %d", elementID) return "", errors.New("Unable to find the linked topic") } url = topic.Link @@ -73,9 +71,7 @@ func buildAlert(asid int, event string, elementType string, actorID int, targetU case "topic": topic, err := common.Topics.Get(elementID) if err != nil { - if common.Dev.DebugMode { - log.Print("Unable to find linked topic " + strconv.Itoa(elementID)) - } + common.DebugLogf("Unable to find linked topic %d", elementID) return "", errors.New("Unable to find the linked topic") } url = topic.Link @@ -87,9 +83,7 @@ func buildAlert(asid int, event string, elementType string, actorID int, targetU case "user": targetUser, err = common.Users.Get(elementID) if err != nil { - if common.Dev.DebugMode { - log.Print("Unable to find target user " + strconv.Itoa(elementID)) - } + common.DebugLogf("Unable to find target user %d", elementID) return "", errors.New("Unable to find the target user") } area = targetUser.Name diff --git a/bot_routes.go b/bot_routes.go index ab3d63ba..c747fe90 100644 --- a/bot_routes.go +++ b/bot_routes.go @@ -2,7 +2,6 @@ package main import ( "errors" - "log" "net/http" "strconv" "strings" @@ -79,10 +78,9 @@ func sitemapSwitch(w http.ResponseWriter, r *http.Request) common.RouteError { spath = strings.TrimSuffix(spath, ".xml") page, err := strconv.Atoi(spath) if err != nil { - if common.Dev.DebugMode { - log.Printf("Unable to convert string '%s' to integer in fuzzy route", spath) - } - return common.NotFound(w, r) + // ? What's this? Do we need it? Was it just a quick trace? + common.DebugLogf("Unable to convert string '%s' to integer in fuzzy route", spath) + return common.NotFound(w, r, nil) } return fuzzy.Handle(w, r, page) } @@ -90,7 +88,7 @@ func sitemapSwitch(w http.ResponseWriter, r *http.Request) common.RouteError { route, ok := sitemapRoutes[path] if !ok { - return common.NotFound(w, r) + return common.NotFound(w, r, nil) } return route(w, r) } diff --git a/common/common.go b/common/common.go index c02a8cdb..f19bd51a 100644 --- a/common/common.go +++ b/common/common.go @@ -84,60 +84,26 @@ func (inits dbInits) Add(init ...func(acc *qgen.Accumulator) error) { DbInits = dbInits(append(DbInits, init...)) } -func debugDetail(args ...interface{}) { +func DebugDetail(args ...interface{}) { if Dev.SuperDebug { log.Print(args...) } } -func debugDetailf(str string, args ...interface{}) { +func DebugDetailf(str string, args ...interface{}) { if Dev.SuperDebug { log.Printf(str, args...) } } -func debugLog(args ...interface{}) { +func DebugLog(args ...interface{}) { if Dev.DebugMode { log.Print(args...) } } -func debugLogf(str string, args ...interface{}) { +func DebugLogf(str string, args ...interface{}) { if Dev.DebugMode { log.Printf(str, args...) } } - -// TODO: Make a neater API for this -var routeMapEnum map[string]int -var reverseRouteMapEnum map[int]string - -func SetRouteMapEnum(rme map[string]int) { - routeMapEnum = rme -} - -func SetReverseRouteMapEnum(rrme map[int]string) { - reverseRouteMapEnum = rrme -} - -var agentMapEnum map[string]int -var reverseAgentMapEnum map[int]string - -func SetAgentMapEnum(ame map[string]int) { - agentMapEnum = ame -} - -func SetReverseAgentMapEnum(rame map[int]string) { - reverseAgentMapEnum = rame -} - -var osMapEnum map[string]int -var reverseOSMapEnum map[int]string - -func SetOSMapEnum(osme map[string]int) { - osMapEnum = osme -} - -func SetReverseOSMapEnum(rosme map[int]string) { - reverseOSMapEnum = rosme -} diff --git a/common/counters.go b/common/counters.go deleted file mode 100644 index c342ea1a..00000000 --- a/common/counters.go +++ /dev/null @@ -1,463 +0,0 @@ -package common - -import ( - "database/sql" - "sync" - "sync/atomic" - - "../query_gen/lib" -) - -// Global counters -var GlobalViewCounter *DefaultViewCounter -var AgentViewCounter *DefaultAgentViewCounter -var OSViewCounter *DefaultOSViewCounter -var RouteViewCounter *DefaultRouteViewCounter -var PostCounter *DefaultPostCounter -var TopicCounter *DefaultTopicCounter - -// Local counters -var TopicViewCounter *DefaultTopicViewCounter - -type DefaultViewCounter struct { - buckets [2]int64 - currentBucket int64 - - insert *sql.Stmt -} - -func NewGlobalViewCounter() (*DefaultViewCounter, error) { - acc := qgen.Builder.Accumulator() - counter := &DefaultViewCounter{ - currentBucket: 0, - insert: acc.Insert("viewchunks").Columns("count, createdAt").Fields("?,UTC_TIMESTAMP()").Prepare(), - } - AddScheduledFifteenMinuteTask(counter.Tick) // This is run once every fifteen minutes to match the frequency of the RouteViewCounter - //AddScheduledSecondTask(counter.Tick) - AddShutdownTask(counter.Tick) - return counter, acc.FirstError() -} - -func (counter *DefaultViewCounter) 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 *DefaultViewCounter) Bump() { - atomic.AddInt64(&counter.buckets[counter.currentBucket], 1) -} - -func (counter *DefaultViewCounter) insertChunk(count int64) error { - if count == 0 { - return nil - } - debugLogf("Inserting a viewchunk with a count of %d", count) - _, err := counter.insert.Exec(count) - return err -} - -type DefaultPostCounter struct { - buckets [2]int64 - currentBucket int64 - - insert *sql.Stmt -} - -func NewPostCounter() (*DefaultPostCounter, error) { - acc := qgen.Builder.Accumulator() - counter := &DefaultPostCounter{ - currentBucket: 0, - insert: acc.Insert("postchunks").Columns("count, createdAt").Fields("?,UTC_TIMESTAMP()").Prepare(), - } - AddScheduledFifteenMinuteTask(counter.Tick) - //AddScheduledSecondTask(counter.Tick) - AddShutdownTask(counter.Tick) - return counter, acc.FirstError() -} - -func (counter *DefaultPostCounter) 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 *DefaultPostCounter) Bump() { - atomic.AddInt64(&counter.buckets[counter.currentBucket], 1) -} - -func (counter *DefaultPostCounter) insertChunk(count int64) error { - if count == 0 { - return nil - } - debugLogf("Inserting a postchunk with a count of %d", count) - _, err := counter.insert.Exec(count) - 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 -} - -type DefaultAgentViewCounter struct { - agentBuckets []*RWMutexCounterBucket //[AgentID]count - insert *sql.Stmt -} - -func NewDefaultAgentViewCounter() (*DefaultAgentViewCounter, error) { - acc := qgen.Builder.Accumulator() - var agentBuckets = make([]*RWMutexCounterBucket, len(agentMapEnum)) - for bucketID, _ := range agentBuckets { - agentBuckets[bucketID] = &RWMutexCounterBucket{counter: 0} - } - counter := &DefaultAgentViewCounter{ - agentBuckets: agentBuckets, - insert: acc.Insert("viewchunks_agents").Columns("count, createdAt, browser").Fields("?,UTC_TIMESTAMP(),?").Prepare(), - } - AddScheduledFifteenMinuteTask(counter.Tick) - //AddScheduledSecondTask(counter.Tick) - AddShutdownTask(counter.Tick) - return counter, acc.FirstError() -} - -func (counter *DefaultAgentViewCounter) Tick() error { - for agentID, agentBucket := range counter.agentBuckets { - var count int - agentBucket.RLock() - count = agentBucket.counter - agentBucket.counter = 0 - agentBucket.RUnlock() - - err := counter.insertChunk(count, agentID) // TODO: Bulk insert for speed? - if err != nil { - return err - } - } - return nil -} - -func (counter *DefaultAgentViewCounter) insertChunk(count int, agent int) error { - if count == 0 { - return nil - } - var agentName = reverseAgentMapEnum[agent] - debugLogf("Inserting a viewchunk with a count of %d for agent %s (%d)", count, agentName, agent) - _, err := counter.insert.Exec(count, agentName) - return err -} - -func (counter *DefaultAgentViewCounter) Bump(agent int) { - // TODO: Test this check - debugDetail("counter.agentBuckets[", agent, "]: ", counter.agentBuckets[agent]) - if len(counter.agentBuckets) <= agent || agent < 0 { - return - } - counter.agentBuckets[agent].Lock() - counter.agentBuckets[agent].counter++ - counter.agentBuckets[agent].Unlock() -} - -type DefaultOSViewCounter struct { - osBuckets []*RWMutexCounterBucket //[OSID]count - insert *sql.Stmt -} - -func NewDefaultOSViewCounter() (*DefaultOSViewCounter, error) { - acc := qgen.Builder.Accumulator() - var osBuckets = make([]*RWMutexCounterBucket, len(osMapEnum)) - for bucketID, _ := range osBuckets { - osBuckets[bucketID] = &RWMutexCounterBucket{counter: 0} - } - counter := &DefaultOSViewCounter{ - osBuckets: osBuckets, - insert: acc.Insert("viewchunks_systems").Columns("count, createdAt, system").Fields("?,UTC_TIMESTAMP(),?").Prepare(), - } - AddScheduledFifteenMinuteTask(counter.Tick) - //AddScheduledSecondTask(counter.Tick) - AddShutdownTask(counter.Tick) - return counter, acc.FirstError() -} - -func (counter *DefaultOSViewCounter) Tick() error { - for osID, osBucket := range counter.osBuckets { - var count int - osBucket.RLock() - count = osBucket.counter - osBucket.counter = 0 // TODO: Add a SetZero method to reduce the amount of duplicate code between the OS and agent counters? - osBucket.RUnlock() - - err := counter.insertChunk(count, osID) // TODO: Bulk insert for speed? - if err != nil { - return err - } - } - return nil -} - -func (counter *DefaultOSViewCounter) insertChunk(count int, os int) error { - if count == 0 { - return nil - } - var osName = reverseOSMapEnum[os] - debugLogf("Inserting a viewchunk with a count of %d for OS %s (%d)", count, osName, os) - _, err := counter.insert.Exec(count, osName) - return err -} - -func (counter *DefaultOSViewCounter) Bump(os int) { - // TODO: Test this check - debugDetail("counter.osBuckets[", os, "]: ", counter.osBuckets[os]) - if len(counter.osBuckets) <= os || os < 0 { - return - } - counter.osBuckets[os].Lock() - counter.osBuckets[os].counter++ - counter.osBuckets[os].Unlock() -} - -type DefaultRouteViewCounter struct { - routeBuckets []*RWMutexCounterBucket //[RouteID]count - insert *sql.Stmt -} - -func NewDefaultRouteViewCounter() (*DefaultRouteViewCounter, error) { - acc := qgen.Builder.Accumulator() - var routeBuckets = make([]*RWMutexCounterBucket, len(routeMapEnum)) - for bucketID, _ := range routeBuckets { - routeBuckets[bucketID] = &RWMutexCounterBucket{counter: 0} - } - counter := &DefaultRouteViewCounter{ - routeBuckets: routeBuckets, - insert: acc.Insert("viewchunks").Columns("count, createdAt, route").Fields("?,UTC_TIMESTAMP(),?").Prepare(), - } - AddScheduledFifteenMinuteTask(counter.Tick) // There could be a lot of routes, so we don't want to be running this every second - //AddScheduledSecondTask(counter.Tick) - AddShutdownTask(counter.Tick) - return counter, acc.FirstError() -} - -func (counter *DefaultRouteViewCounter) Tick() error { - for routeID, routeBucket := range counter.routeBuckets { - var count int - routeBucket.RLock() - count = routeBucket.counter - routeBucket.counter = 0 - routeBucket.RUnlock() - - err := counter.insertChunk(count, routeID) // TODO: Bulk insert for speed? - if err != nil { - return err - } - } - return nil -} - -func (counter *DefaultRouteViewCounter) insertChunk(count int, route int) error { - if count == 0 { - return nil - } - var routeName = reverseRouteMapEnum[route] - debugLogf("Inserting a viewchunk with a count of %d for route %s (%d)", count, routeName, route) - _, err := counter.insert.Exec(count, routeName) - return err -} - -func (counter *DefaultRouteViewCounter) Bump(route int) { - // TODO: Test this check - debugDetail("counter.routeBuckets[", route, "]: ", counter.routeBuckets[route]) - if len(counter.routeBuckets) <= route || route < 0 { - return - } - counter.routeBuckets[route].Lock() - counter.routeBuckets[route].counter++ - counter.routeBuckets[route].Unlock() -} - -// TODO: The ForumViewCounter and TopicViewCounter - -// TODO: Unload forum counters without any views over the past 15 minutes, if the admin has configured the forumstore with a cap and it's been hit? -// Forums can be reloaded from the database at any time, so we want to keep the counters separate from them -type ForumViewCounter struct { - buckets [2]int64 - currentBucket int64 -} - -/*func (counter *ForumViewCounter) insertChunk(count int, forum int) error { - if count == 0 { - return nil - } - debugLogf("Inserting a viewchunk with a count of %d for forum %d", count, forum) - _, err := counter.insert.Exec(count, forum) - return err -}*/ - -// TODO: Use two odd-even maps for now, and move to something more concurrent later, maybe a sharded map? -type DefaultTopicViewCounter struct { - oddTopics map[int]*RWMutexCounterBucket // map[tid]struct{counter,sync.RWMutex} - evenTopics map[int]*RWMutexCounterBucket - oddLock sync.RWMutex - evenLock sync.RWMutex - - update *sql.Stmt -} - -func NewDefaultTopicViewCounter() (*DefaultTopicViewCounter, error) { - acc := qgen.Builder.Accumulator() - counter := &DefaultTopicViewCounter{ - oddTopics: make(map[int]*RWMutexCounterBucket), - evenTopics: make(map[int]*RWMutexCounterBucket), - update: acc.Update("topics").Set("views = views + ?").Where("tid = ?").Prepare(), - } - AddScheduledFifteenMinuteTask(counter.Tick) // Who knows how many topics we have queued up, we probably don't want this running too frequently - //AddScheduledSecondTask(counter.Tick) - AddShutdownTask(counter.Tick) - return counter, acc.FirstError() -} - -func (counter *DefaultTopicViewCounter) Tick() error { - counter.oddLock.RLock() - oddTopics := counter.oddTopics - counter.oddLock.RUnlock() - for topicID, topic := range oddTopics { - var count int - topic.RLock() - count = topic.counter - topic.RUnlock() - // TODO: Only delete the bucket when it's zero to avoid hitting popular topics? - counter.oddLock.Lock() - delete(counter.oddTopics, topicID) - counter.oddLock.Unlock() - err := counter.insertChunk(count, topicID) - if err != nil { - return err - } - } - - counter.evenLock.RLock() - evenTopics := counter.evenTopics - counter.evenLock.RUnlock() - for topicID, topic := range evenTopics { - var count int - topic.RLock() - count = topic.counter - topic.RUnlock() - // TODO: Only delete the bucket when it's zero to avoid hitting popular topics? - counter.evenLock.Lock() - delete(counter.evenTopics, topicID) - counter.evenLock.Unlock() - err := counter.insertChunk(count, topicID) - if err != nil { - return err - } - } - - return nil -} - -// TODO: Optimise this further. E.g. Using IN() on every one view topic. Rinse and repeat for two views, three views, four views and five views. -func (counter *DefaultTopicViewCounter) insertChunk(count int, topicID int) error { - if count == 0 { - return nil - } - debugLogf("Inserting %d views into topic %d", count, topicID) - _, err := counter.update.Exec(count, topicID) - return err -} - -func (counter *DefaultTopicViewCounter) Bump(topicID int) { - // Is the ID even? - if topicID%2 == 0 { - counter.evenLock.RLock() - topic, ok := counter.evenTopics[topicID] - counter.evenLock.RUnlock() - if ok { - topic.Lock() - topic.counter++ - topic.Unlock() - } else { - counter.evenLock.Lock() - counter.evenTopics[topicID] = &RWMutexCounterBucket{counter: 1} - counter.evenLock.Unlock() - } - return - } - - counter.oddLock.RLock() - topic, ok := counter.oddTopics[topicID] - counter.oddLock.RUnlock() - if ok { - topic.Lock() - topic.counter++ - topic.Unlock() - } else { - counter.oddLock.Lock() - counter.oddTopics[topicID] = &RWMutexCounterBucket{counter: 1} - counter.oddLock.Unlock() - } -} diff --git a/common/counters/agents.go b/common/counters/agents.go new file mode 100644 index 00000000..2f2f2008 --- /dev/null +++ b/common/counters/agents.go @@ -0,0 +1,68 @@ +package counters + +import ( + "database/sql" + + ".." + "../../query_gen/lib" +) + +var AgentViewCounter *DefaultAgentViewCounter + +type DefaultAgentViewCounter struct { + agentBuckets []*RWMutexCounterBucket //[AgentID]count + insert *sql.Stmt +} + +func NewDefaultAgentViewCounter() (*DefaultAgentViewCounter, error) { + acc := qgen.Builder.Accumulator() + var agentBuckets = make([]*RWMutexCounterBucket, len(agentMapEnum)) + for bucketID, _ := range agentBuckets { + agentBuckets[bucketID] = &RWMutexCounterBucket{counter: 0} + } + counter := &DefaultAgentViewCounter{ + agentBuckets: agentBuckets, + insert: acc.Insert("viewchunks_agents").Columns("count, createdAt, browser").Fields("?,UTC_TIMESTAMP(),?").Prepare(), + } + common.AddScheduledFifteenMinuteTask(counter.Tick) + //common.AddScheduledSecondTask(counter.Tick) + common.AddShutdownTask(counter.Tick) + return counter, acc.FirstError() +} + +func (counter *DefaultAgentViewCounter) Tick() error { + for agentID, agentBucket := range counter.agentBuckets { + var count int + agentBucket.RLock() + count = agentBucket.counter + agentBucket.counter = 0 + agentBucket.RUnlock() + + err := counter.insertChunk(count, agentID) // TODO: Bulk insert for speed? + if err != nil { + return err + } + } + return nil +} + +func (counter *DefaultAgentViewCounter) insertChunk(count int, agent int) error { + if count == 0 { + return nil + } + var agentName = reverseAgentMapEnum[agent] + common.DebugLogf("Inserting a viewchunk with a count of %d for agent %s (%d)", count, agentName, agent) + _, err := counter.insert.Exec(count, agentName) + return err +} + +func (counter *DefaultAgentViewCounter) Bump(agent int) { + // TODO: Test this check + common.DebugDetail("counter.agentBuckets[", agent, "]: ", counter.agentBuckets[agent]) + if len(counter.agentBuckets) <= agent || agent < 0 { + return + } + counter.agentBuckets[agent].Lock() + counter.agentBuckets[agent].counter++ + counter.agentBuckets[agent].Unlock() +} diff --git a/common/counters/common.go b/common/counters/common.go new file mode 100644 index 00000000..7b331191 --- /dev/null +++ b/common/counters/common.go @@ -0,0 +1,42 @@ +package counters + +import "sync" + +type RWMutexCounterBucket struct { + counter int + sync.RWMutex +} + +// TODO: Make a neater API for this +var routeMapEnum map[string]int +var reverseRouteMapEnum map[int]string + +func SetRouteMapEnum(rme map[string]int) { + routeMapEnum = rme +} + +func SetReverseRouteMapEnum(rrme map[int]string) { + reverseRouteMapEnum = rrme +} + +var agentMapEnum map[string]int +var reverseAgentMapEnum map[int]string + +func SetAgentMapEnum(ame map[string]int) { + agentMapEnum = ame +} + +func SetReverseAgentMapEnum(rame map[int]string) { + reverseAgentMapEnum = rame +} + +var osMapEnum map[string]int +var reverseOSMapEnum map[int]string + +func SetOSMapEnum(osme map[string]int) { + osMapEnum = osme +} + +func SetReverseOSMapEnum(rosme map[int]string) { + reverseOSMapEnum = rosme +} diff --git a/common/counters/forums.go b/common/counters/forums.go new file mode 100644 index 00000000..296b832e --- /dev/null +++ b/common/counters/forums.go @@ -0,0 +1,86 @@ +package counters + +import ( + "database/sql" + "sync" + + ".." + "../../query_gen/lib" +) + +// TODO: The forum view counter + +// TODO: Unload forum counters without any views over the past 15 minutes, if the admin has configured the forumstore with a cap and it's been hit? +// Forums can be reloaded from the database at any time, so we want to keep the counters separate from them +type DefaultForumViewCounter struct { + oddMap map[int]*RWMutexCounterBucket // map[fid]struct{counter,sync.RWMutex} + evenMap map[int]*RWMutexCounterBucket + oddLock sync.RWMutex + evenLock sync.RWMutex + + insert *sql.Stmt +} + +func NewDefaultForumViewCounter() (*DefaultForumViewCounter, error) { + acc := qgen.Builder.Accumulator() + counter := &DefaultForumViewCounter{ + oddMap: make(map[int]*RWMutexCounterBucket), + evenMap: make(map[int]*RWMutexCounterBucket), + insert: acc.Insert("viewchunks_forums").Columns("count, createdAt, forum").Fields("?,UTC_TIMESTAMP(),?").Prepare(), + } + common.AddScheduledFifteenMinuteTask(counter.Tick) // There could be a lot of routes, so we don't want to be running this every second + //AddScheduledSecondTask(counter.Tick) + common.AddShutdownTask(counter.Tick) + return counter, acc.FirstError() +} + +func (counter *DefaultForumViewCounter) Tick() error { + counter.oddLock.RLock() + oddMap := counter.oddMap + counter.oddLock.RUnlock() + for forumID, forum := range oddMap { + var count int + forum.RLock() + count = forum.counter + forum.RUnlock() + // TODO: Only delete the bucket when it's zero to avoid hitting popular forums? + counter.oddLock.Lock() + delete(counter.oddMap, forumID) + counter.oddLock.Unlock() + err := counter.insertChunk(count, forumID) + if err != nil { + return err + } + } + + counter.evenLock.RLock() + evenMap := counter.evenMap + counter.evenLock.RUnlock() + for forumID, forum := range evenMap { + var count int + forum.RLock() + count = forum.counter + forum.RUnlock() + // TODO: Only delete the bucket when it's zero to avoid hitting popular forums? + counter.evenLock.Lock() + delete(counter.evenMap, forumID) + counter.evenLock.Unlock() + err := counter.insertChunk(count, forumID) + if err != nil { + return err + } + } + + return nil +} + +func (counter *DefaultForumViewCounter) insertChunk(count int, forum int) error { + if count == 0 { + return nil + } + common.DebugLogf("Inserting a viewchunk with a count of %d for forum %d", count, forum) + _, err := counter.insert.Exec(count, forum) + return err +} + +// TODO: Add a forum counter backed by two maps which grow as forums are created but never shrinks diff --git a/common/counters/posts.go b/common/counters/posts.go new file mode 100644 index 00000000..c4a8ae45 --- /dev/null +++ b/common/counters/posts.go @@ -0,0 +1,58 @@ +package counters + +import ( + "database/sql" + "sync/atomic" + + ".." + "../../query_gen/lib" +) + +var PostCounter *DefaultPostCounter + +type DefaultPostCounter struct { + buckets [2]int64 + currentBucket int64 + + insert *sql.Stmt +} + +func NewPostCounter() (*DefaultPostCounter, error) { + acc := qgen.Builder.Accumulator() + counter := &DefaultPostCounter{ + currentBucket: 0, + insert: acc.Insert("postchunks").Columns("count, createdAt").Fields("?,UTC_TIMESTAMP()").Prepare(), + } + common.AddScheduledFifteenMinuteTask(counter.Tick) + //common.AddScheduledSecondTask(counter.Tick) + common.AddShutdownTask(counter.Tick) + return counter, acc.FirstError() +} + +func (counter *DefaultPostCounter) 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 *DefaultPostCounter) Bump() { + atomic.AddInt64(&counter.buckets[counter.currentBucket], 1) +} + +func (counter *DefaultPostCounter) insertChunk(count int64) error { + if count == 0 { + return nil + } + common.DebugLogf("Inserting a postchunk with a count of %d", count) + _, err := counter.insert.Exec(count) + return err +} diff --git a/common/requests.go b/common/counters/referrers.go similarity index 91% rename from common/requests.go rename to common/counters/referrers.go index 52ac3bbe..f9c7d5b6 100644 --- a/common/requests.go +++ b/common/counters/referrers.go @@ -1,11 +1,12 @@ -package common +package counters import ( "database/sql" "sync" "sync/atomic" - "../query_gen/lib" + ".." + "../../query_gen/lib" ) var ReferrerTracker *DefaultReferrerTracker @@ -35,9 +36,9 @@ func NewDefaultReferrerTracker() (*DefaultReferrerTracker, error) { even: make(map[string]*ReferrerItem), insert: acc.Insert("viewchunks_referrers").Columns("count, createdAt, domain").Fields("?,UTC_TIMESTAMP(),?").Prepare(), // TODO: Do something more efficient than doing a query for each referrer } - AddScheduledFifteenMinuteTask(refTracker.Tick) - //AddScheduledSecondTask(refTracker.Tick) - AddShutdownTask(refTracker.Tick) + common.AddScheduledFifteenMinuteTask(refTracker.Tick) + //common.AddScheduledSecondTask(refTracker.Tick) + common.AddShutdownTask(refTracker.Tick) return refTracker, acc.FirstError() } @@ -92,7 +93,7 @@ func (ref *DefaultReferrerTracker) insertChunk(referrer string, count int64) err if count == 0 { return nil } - debugDetailf("Inserting a viewchunk with a count of %d for referrer %s", count, referrer) + common.DebugDetailf("Inserting a viewchunk with a count of %d for referrer %s", count, referrer) _, err := ref.insert.Exec(count, referrer) return err } diff --git a/common/counters/requests.go b/common/counters/requests.go new file mode 100644 index 00000000..13c2921d --- /dev/null +++ b/common/counters/requests.go @@ -0,0 +1,60 @@ +package counters + +import ( + "database/sql" + "sync/atomic" + + ".." + "../../query_gen/lib" +) + +// TODO: Rename this? +var GlobalViewCounter *DefaultViewCounter + +// TODO: Rename this and shard it? +type DefaultViewCounter struct { + buckets [2]int64 + currentBucket int64 + + insert *sql.Stmt +} + +func NewGlobalViewCounter() (*DefaultViewCounter, error) { + acc := qgen.Builder.Accumulator() + counter := &DefaultViewCounter{ + currentBucket: 0, + insert: acc.Insert("viewchunks").Columns("count, createdAt").Fields("?,UTC_TIMESTAMP()").Prepare(), + } + common.AddScheduledFifteenMinuteTask(counter.Tick) // This is run once every fifteen minutes to match the frequency of the RouteViewCounter + //common.AddScheduledSecondTask(counter.Tick) + common.AddShutdownTask(counter.Tick) + return counter, acc.FirstError() +} + +func (counter *DefaultViewCounter) 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 *DefaultViewCounter) Bump() { + atomic.AddInt64(&counter.buckets[counter.currentBucket], 1) +} + +func (counter *DefaultViewCounter) insertChunk(count int64) error { + if count == 0 { + return nil + } + common.DebugLogf("Inserting a viewchunk with a count of %d", count) + _, err := counter.insert.Exec(count) + return err +} diff --git a/common/counters/routes.go b/common/counters/routes.go new file mode 100644 index 00000000..22fe2566 --- /dev/null +++ b/common/counters/routes.go @@ -0,0 +1,66 @@ +package counters + +import "database/sql" +import ".." +import "../../query_gen/lib" + +var RouteViewCounter *DefaultRouteViewCounter + +// TODO: Make this lockless? +type DefaultRouteViewCounter struct { + routeBuckets []*RWMutexCounterBucket //[RouteID]count + insert *sql.Stmt +} + +func NewDefaultRouteViewCounter() (*DefaultRouteViewCounter, error) { + acc := qgen.Builder.Accumulator() + var routeBuckets = make([]*RWMutexCounterBucket, len(routeMapEnum)) + for bucketID, _ := range routeBuckets { + routeBuckets[bucketID] = &RWMutexCounterBucket{counter: 0} + } + counter := &DefaultRouteViewCounter{ + routeBuckets: routeBuckets, + insert: acc.Insert("viewchunks").Columns("count, createdAt, route").Fields("?,UTC_TIMESTAMP(),?").Prepare(), + } + common.AddScheduledFifteenMinuteTask(counter.Tick) // There could be a lot of routes, so we don't want to be running this every second + //common.AddScheduledSecondTask(counter.Tick) + common.AddShutdownTask(counter.Tick) + return counter, acc.FirstError() +} + +func (counter *DefaultRouteViewCounter) Tick() error { + for routeID, routeBucket := range counter.routeBuckets { + var count int + routeBucket.RLock() + count = routeBucket.counter + routeBucket.counter = 0 + routeBucket.RUnlock() + + err := counter.insertChunk(count, routeID) // TODO: Bulk insert for speed? + if err != nil { + return err + } + } + return nil +} + +func (counter *DefaultRouteViewCounter) insertChunk(count int, route int) error { + if count == 0 { + return nil + } + var routeName = reverseRouteMapEnum[route] + common.DebugLogf("Inserting a viewchunk with a count of %d for route %s (%d)", count, routeName, route) + _, err := counter.insert.Exec(count, routeName) + return err +} + +func (counter *DefaultRouteViewCounter) Bump(route int) { + // TODO: Test this check + common.DebugDetail("counter.routeBuckets[", route, "]: ", counter.routeBuckets[route]) + if len(counter.routeBuckets) <= route || route < 0 { + return + } + counter.routeBuckets[route].Lock() + counter.routeBuckets[route].counter++ + counter.routeBuckets[route].Unlock() +} diff --git a/common/counters/systems.go b/common/counters/systems.go new file mode 100644 index 00000000..b24aa364 --- /dev/null +++ b/common/counters/systems.go @@ -0,0 +1,65 @@ +package counters + +import "database/sql" +import ".." +import "../../query_gen/lib" + +var OSViewCounter *DefaultOSViewCounter + +type DefaultOSViewCounter struct { + osBuckets []*RWMutexCounterBucket //[OSID]count + insert *sql.Stmt +} + +func NewDefaultOSViewCounter() (*DefaultOSViewCounter, error) { + acc := qgen.Builder.Accumulator() + var osBuckets = make([]*RWMutexCounterBucket, len(osMapEnum)) + for bucketID, _ := range osBuckets { + osBuckets[bucketID] = &RWMutexCounterBucket{counter: 0} + } + counter := &DefaultOSViewCounter{ + osBuckets: osBuckets, + insert: acc.Insert("viewchunks_systems").Columns("count, createdAt, system").Fields("?,UTC_TIMESTAMP(),?").Prepare(), + } + common.AddScheduledFifteenMinuteTask(counter.Tick) + //common.AddScheduledSecondTask(counter.Tick) + common.AddShutdownTask(counter.Tick) + return counter, acc.FirstError() +} + +func (counter *DefaultOSViewCounter) Tick() error { + for osID, osBucket := range counter.osBuckets { + var count int + osBucket.RLock() + count = osBucket.counter + osBucket.counter = 0 // TODO: Add a SetZero method to reduce the amount of duplicate code between the OS and agent counters? + osBucket.RUnlock() + + err := counter.insertChunk(count, osID) // TODO: Bulk insert for speed? + if err != nil { + return err + } + } + return nil +} + +func (counter *DefaultOSViewCounter) insertChunk(count int, os int) error { + if count == 0 { + return nil + } + var osName = reverseOSMapEnum[os] + common.DebugLogf("Inserting a viewchunk with a count of %d for OS %s (%d)", count, osName, os) + _, err := counter.insert.Exec(count, osName) + return err +} + +func (counter *DefaultOSViewCounter) Bump(os int) { + // TODO: Test this check + common.DebugDetail("counter.osBuckets[", os, "]: ", counter.osBuckets[os]) + if len(counter.osBuckets) <= os || os < 0 { + return + } + counter.osBuckets[os].Lock() + counter.osBuckets[os].counter++ + counter.osBuckets[os].Unlock() +} diff --git a/common/counters/topics.go b/common/counters/topics.go new file mode 100644 index 00000000..3387e01b --- /dev/null +++ b/common/counters/topics.go @@ -0,0 +1,58 @@ +package counters + +import ( + "database/sql" + "sync/atomic" + + ".." + "../../query_gen/lib" +) + +var TopicCounter *DefaultTopicCounter + +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(), + } + common.AddScheduledFifteenMinuteTask(counter.Tick) + //common.AddScheduledSecondTask(counter.Tick) + common.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 + } + common.DebugLogf("Inserting a topicchunk with a count of %d", count) + _, err := counter.insert.Exec(count) + return err +} diff --git a/common/counters/topics_views.go b/common/counters/topics_views.go new file mode 100644 index 00000000..31555a4d --- /dev/null +++ b/common/counters/topics_views.go @@ -0,0 +1,116 @@ +package counters + +import ( + "database/sql" + "sync" + + ".." + "../../query_gen/lib" +) + +var TopicViewCounter *DefaultTopicViewCounter + +// TODO: Use two odd-even maps for now, and move to something more concurrent later, maybe a sharded map? +type DefaultTopicViewCounter struct { + oddTopics map[int]*RWMutexCounterBucket // map[tid]struct{counter,sync.RWMutex} + evenTopics map[int]*RWMutexCounterBucket + oddLock sync.RWMutex + evenLock sync.RWMutex + + update *sql.Stmt +} + +func NewDefaultTopicViewCounter() (*DefaultTopicViewCounter, error) { + acc := qgen.Builder.Accumulator() + counter := &DefaultTopicViewCounter{ + oddTopics: make(map[int]*RWMutexCounterBucket), + evenTopics: make(map[int]*RWMutexCounterBucket), + update: acc.Update("topics").Set("views = views + ?").Where("tid = ?").Prepare(), + } + common.AddScheduledFifteenMinuteTask(counter.Tick) // Who knows how many topics we have queued up, we probably don't want this running too frequently + //common.AddScheduledSecondTask(counter.Tick) + common.AddShutdownTask(counter.Tick) + return counter, acc.FirstError() +} + +func (counter *DefaultTopicViewCounter) Tick() error { + counter.oddLock.RLock() + oddTopics := counter.oddTopics + counter.oddLock.RUnlock() + for topicID, topic := range oddTopics { + var count int + topic.RLock() + count = topic.counter + topic.RUnlock() + // TODO: Only delete the bucket when it's zero to avoid hitting popular topics? + counter.oddLock.Lock() + delete(counter.oddTopics, topicID) + counter.oddLock.Unlock() + err := counter.insertChunk(count, topicID) + if err != nil { + return err + } + } + + counter.evenLock.RLock() + evenTopics := counter.evenTopics + counter.evenLock.RUnlock() + for topicID, topic := range evenTopics { + var count int + topic.RLock() + count = topic.counter + topic.RUnlock() + // TODO: Only delete the bucket when it's zero to avoid hitting popular topics? + counter.evenLock.Lock() + delete(counter.evenTopics, topicID) + counter.evenLock.Unlock() + err := counter.insertChunk(count, topicID) + if err != nil { + return err + } + } + + return nil +} + +// TODO: Optimise this further. E.g. Using IN() on every one view topic. Rinse and repeat for two views, three views, four views and five views. +func (counter *DefaultTopicViewCounter) insertChunk(count int, topicID int) error { + if count == 0 { + return nil + } + common.DebugLogf("Inserting %d views into topic %d", count, topicID) + _, err := counter.update.Exec(count, topicID) + return err +} + +func (counter *DefaultTopicViewCounter) Bump(topicID int) { + // Is the ID even? + if topicID%2 == 0 { + counter.evenLock.RLock() + topic, ok := counter.evenTopics[topicID] + counter.evenLock.RUnlock() + if ok { + topic.Lock() + topic.counter++ + topic.Unlock() + } else { + counter.evenLock.Lock() + counter.evenTopics[topicID] = &RWMutexCounterBucket{counter: 1} + counter.evenLock.Unlock() + } + return + } + + counter.oddLock.RLock() + topic, ok := counter.oddTopics[topicID] + counter.oddLock.RUnlock() + if ok { + topic.Lock() + topic.counter++ + topic.Unlock() + } else { + counter.oddLock.Lock() + counter.oddTopics[topicID] = &RWMutexCounterBucket{counter: 1} + counter.oddLock.Unlock() + } +} diff --git a/common/email.go b/common/email.go index a6bf7de0..bd69d79f 100644 --- a/common/email.go +++ b/common/email.go @@ -29,6 +29,7 @@ func SendValidationEmail(username string, email string, token string) bool { // TODO: Add support for TLS func SendEmail(email string, subject string, msg string) bool { // This hook is useful for plugin_sendmail or for testing tools. Possibly to hook it into some sort of mail server? + // TODO: Abstract this if Vhooks["email_send_intercept"] != nil { return Vhooks["email_send_intercept"](email, subject, msg).(bool) } diff --git a/common/errors.go b/common/errors.go index 88896abb..245ac182 100644 --- a/common/errors.go +++ b/common/errors.go @@ -238,10 +238,8 @@ func LoginRequiredJS(w http.ResponseWriter, r *http.Request, user User) RouteErr func SecurityError(w http.ResponseWriter, r *http.Request, user User) RouteError { w.WriteHeader(403) pi := Page{"Security Error", user, DefaultHeaderVar(), tList, "There was a security issue with your request."} - if PreRenderHooks["pre_render_security_error"] != nil { - if RunPreRenderHook("pre_render_security_error", w, r, &user, &pi) { - return nil - } + if RunPreRenderHook("pre_render_security_error", w, r, &user, &pi) { + return nil } err := Templates.ExecuteTemplate(w, "error.html", pi) if err != nil { @@ -253,22 +251,28 @@ func SecurityError(w http.ResponseWriter, r *http.Request, user User) RouteError // NotFound is used when the requested page doesn't exist // ? - Add a JSQ and JS version of this? // ? - Add a user parameter? -func NotFound(w http.ResponseWriter, r *http.Request) RouteError { - return CustomError("The requested page doesn't exist.", 404, "Not Found", w, r, GuestUser) +func NotFound(w http.ResponseWriter, r *http.Request, headerVars *HeaderVars) RouteError { + return CustomError("The requested page doesn't exist.", 404, "Not Found", w, r, headerVars, GuestUser) } // CustomError lets us make custom error types which aren't covered by the generic functions above -func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) RouteError { +func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, headerVars *HeaderVars, user User) RouteError { + if headerVars == nil { + headerVars = DefaultHeaderVar() + } w.WriteHeader(errcode) - pi := Page{errtitle, user, DefaultHeaderVar(), tList, errmsg} + pi := Page{errtitle, user, headerVars, tList, errmsg} handleErrorTemplate(w, r, pi) return HandledRouteError() } // CustomErrorJSQ is a version of CustomError which lets us handle both JSON and regular pages depending on how it's being accessed -func CustomErrorJSQ(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User, isJs bool) RouteError { +func CustomErrorJSQ(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, headerVars *HeaderVars, user User, isJs bool) RouteError { if !isJs { - return CustomError(errmsg, errcode, errtitle, w, r, user) + if headerVars == nil { + headerVars = DefaultHeaderVar() + } + return CustomError(errmsg, errcode, errtitle, w, r, headerVars, user) } return CustomErrorJS(errmsg, errcode, w, r, user) } @@ -283,10 +287,8 @@ func CustomErrorJS(errmsg string, errcode int, w http.ResponseWriter, r *http.Re func handleErrorTemplate(w http.ResponseWriter, r *http.Request, pi Page) { //LogError(errors.New("error happened")) // TODO: What to do about this hook? - if PreRenderHooks["pre_render_error"] != nil { - if RunPreRenderHook("pre_render_error", w, r, &pi.CurrentUser, &pi) { - return - } + if RunPreRenderHook("pre_render_error", w, r, &pi.CurrentUser, &pi) { + return } err := Templates.ExecuteTemplate(w, "error.html", pi) if err != nil { diff --git a/common/files.go b/common/files.go index 44e68586..a8a37a5f 100644 --- a/common/files.go +++ b/common/files.go @@ -51,7 +51,7 @@ func (list SFileList) Init() error { list.Set("/static/"+path, SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}) - debugLogf("Added the '%s' static file.", path) + DebugLogf("Added the '%s' static file.", path) return nil }) } @@ -76,7 +76,7 @@ func (list SFileList) Add(path string, prefix string) error { list.Set("/static"+path, SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}) - debugLogf("Added the '%s' static file", path) + DebugLogf("Added the '%s' static file", path) return nil } diff --git a/common/forum_perms_store.go b/common/forum_perms_store.go index 7f49653f..f6f48713 100644 --- a/common/forum_perms_store.go +++ b/common/forum_perms_store.go @@ -3,7 +3,6 @@ package common import ( "database/sql" "encoding/json" - "log" "sync" "../query_gen/lib" @@ -46,15 +45,15 @@ func (fps *MemoryForumPermsStore) Init() error { if err != nil { return err } - debugDetail("fids: ", fids) + DebugDetail("fids: ", fids) rows, err := fps.get.Query() if err != nil { return err } defer rows.Close() - debugLog("Adding the forum permissions") - debugDetail("forumPerms[gid][fid]") + DebugLog("Adding the forum permissions") + DebugDetail("forumPerms[gid][fid]") forumPerms = make(map[int]map[int]*ForumPerms) for rows.Next() { @@ -74,9 +73,9 @@ func (fps *MemoryForumPermsStore) Init() error { forumPerms[gid] = make(map[int]*ForumPerms) } - debugDetail("gid: ", gid) - debugDetail("fid: ", fid) - debugDetailf("perms: %+v\n", pperms) + DebugDetail("gid: ", gid) + DebugDetail("fid: ", fid) + DebugDetailf("perms: %+v\n", pperms) forumPerms[gid][fid] = pperms } @@ -84,7 +83,7 @@ func (fps *MemoryForumPermsStore) Init() error { } func (fps *MemoryForumPermsStore) parseForumPerm(perms []byte) (pperms *ForumPerms, err error) { - debugDetail("perms: ", string(perms)) + DebugDetail("perms: ", string(perms)) pperms = BlankForumPerms() err = json.Unmarshal(perms, &pperms) pperms.ExtData = make(map[string]bool) @@ -96,7 +95,7 @@ func (fps *MemoryForumPermsStore) parseForumPerm(perms []byte) (pperms *ForumPer func (fps *MemoryForumPermsStore) Reload(fid int) error { fps.updateMutex.Lock() defer fps.updateMutex.Unlock() - debugLogf("Reloading the forum permissions for forum #%d", fid) + DebugLogf("Reloading the forum permissions for forum #%d", fid) fids, err := Forums.GetAllIDs() if err != nil { return err @@ -159,22 +158,20 @@ func (fps *MemoryForumPermsStore) cascadePermSetToGroups(forumPerms map[int]map[ } for _, group := range groups { - debugLogf("Updating the forum permissions for Group #%d", group.ID) + DebugLogf("Updating the forum permissions for Group #%d", group.ID) group.Forums = []*ForumPerms{BlankForumPerms()} group.CanSee = []int{} fps.cascadePermSetToGroup(forumPerms, group, fids) - if Dev.SuperDebug { - log.Printf("group.CanSee (length %d): %+v \n", len(group.CanSee), group.CanSee) - log.Printf("group.Forums (length %d): %+v\n", len(group.Forums), group.Forums) - } + DebugDetailf("group.CanSee (length %d): %+v \n", len(group.CanSee), group.CanSee) + DebugDetailf("group.Forums (length %d): %+v\n", len(group.Forums), group.Forums) } return nil } func (fps *MemoryForumPermsStore) cascadePermSetToGroup(forumPerms map[int]map[int]*ForumPerms, group *Group, fids []int) { for _, fid := range fids { - debugDetailf("Forum #%+v\n", fid) + DebugDetailf("Forum #%+v\n", fid) forumPerm, ok := forumPerms[group.ID][fid] if ok { //log.Printf("Overriding permissions for forum #%d",fid) @@ -192,9 +189,9 @@ func (fps *MemoryForumPermsStore) cascadePermSetToGroup(forumPerms map[int]map[i group.CanSee = append(group.CanSee, fid) } - debugDetail("group.ID: ", group.ID) - debugDetailf("forumPerm: %+v\n", forumPerm) - debugDetail("group.CanSee: ", group.CanSee) + DebugDetail("group.ID: ", group.ID) + DebugDetailf("forumPerm: %+v\n", forumPerm) + DebugDetail("group.CanSee: ", group.CanSee) } } diff --git a/common/forum_store.go b/common/forum_store.go index fb75e931..0d428374 100644 --- a/common/forum_store.go +++ b/common/forum_store.go @@ -109,7 +109,7 @@ func (mfs *MemoryForumStore) LoadForums() error { } if forum.Name == "" { - debugLog("Adding a placeholder forum") + DebugLog("Adding a placeholder forum") } else { log.Printf("Adding the '%s' forum", forum.Name) } diff --git a/common/group_store.go b/common/group_store.go index 06f1aac7..1ae74aaa 100644 --- a/common/group_store.go +++ b/common/group_store.go @@ -88,7 +88,7 @@ func (mgs *MemoryGroupStore) LoadGroups() error { } mgs.groupCount = i - debugLog("Binding the Not Loggedin Group") + DebugLog("Binding the Not Loggedin Group") GuestPerms = mgs.dirtyGetUnsafe(6).Perms return nil } @@ -162,9 +162,7 @@ func (mgs *MemoryGroupStore) initGroup(group *Group) error { log.Print("bad group perms: ", group.PermissionsText) return err } - if Dev.DebugMode { - log.Printf(group.Name+": %+v\n", group.Perms) - } + DebugLogf(group.Name+": %+v\n", group.Perms) err = json.Unmarshal(group.PluginPermsText, &group.PluginPerms) if err != nil { @@ -172,7 +170,7 @@ func (mgs *MemoryGroupStore) initGroup(group *Group) error { log.Print("bad group plugin perms: ", group.PluginPermsText) return err } - debugLogf(group.Name+": %+v\n", group.PluginPerms) + DebugLogf(group.Name+": %+v\n", group.PluginPerms) //group.Perms.ExtData = make(map[string]bool) // TODO: Can we optimise the bit where this cascades down to the user now? diff --git a/common/parser.go b/common/parser.go index e4c33137..1eb7b87c 100644 --- a/common/parser.go +++ b/common/parser.go @@ -173,9 +173,7 @@ func PreparseMessage(msg string) string { msg = strings.Replace(msg, "

", "", -1) msg = strings.Replace(msg, "
", "\n\n", -1) msg = strings.TrimSpace(msg) // There are a few useful cases for having spaces, but I'd like to stop the WYSIWYG from inserting random lines here and there - if Sshooks["preparse_preassign"] != nil { - msg = RunSshook("preparse_preassign", msg) - } + msg = RunSshook("preparse_preassign", msg) msg = html.EscapeString(msg) msg = strings.Replace(msg, " ", "", -1) @@ -573,9 +571,7 @@ func ParseMessage(msg string, sectionID int, sectionType string /*, user User*/) //log.Print("msg",`"`+msg+`"`) msg = strings.Replace(msg, "\n", "
", -1) - if Sshooks["parse_assign"] != nil { - msg = RunSshook("parse_assign", msg) - } + msg = RunSshook("parse_assign", msg) return msg } diff --git a/common/permissions.go b/common/permissions.go index d7064ed8..2fde3313 100644 --- a/common/permissions.go +++ b/common/permissions.go @@ -136,8 +136,8 @@ func init() { } GuestUser.Perms = GuestPerms - debugLogf("Guest Perms: %+v\n", GuestPerms) - debugLogf("All Perms: %+v\n", AllPerms) + DebugLogf("Guest Perms: %+v\n", GuestPerms) + DebugLogf("All Perms: %+v\n", AllPerms) } func StripInvalidGroupForumPreset(preset string) string { diff --git a/common/phrases.go b/common/phrases.go index fc947a3c..558aa5ea 100644 --- a/common/phrases.go +++ b/common/phrases.go @@ -65,9 +65,7 @@ func InitPhrases() error { var ext = filepath.Ext("/langs/" + path) if ext != ".json" { - if Dev.DebugMode { - log.Printf("Found a '%s' in /langs/", ext) - } + log.Printf("Found a '%s' in /langs/", ext) return nil } diff --git a/common/poll_store.go b/common/poll_store.go index d5ac3f3e..2e2a3985 100644 --- a/common/poll_store.go +++ b/common/poll_store.go @@ -189,6 +189,7 @@ func (store *DefaultPollStore) BulkGetMap(ids []int) (list map[int]*Poll, err er // We probably don't need this, but it might be useful in case of bugs in BulkCascadeGetMap if sidList == "" { + // TODO: Bulk log this if Dev.DebugMode { log.Print("This data is sampled later in the BulkCascadeGetMap function, so it might miss the cached IDs") log.Print("idCount", idCount) diff --git a/common/routes_common.go b/common/routes_common.go index 47a17e49..ace95c1f 100644 --- a/common/routes_common.go +++ b/common/routes_common.go @@ -52,7 +52,7 @@ func forumUserCheck(w http.ResponseWriter, r *http.Request, user *User, fid int) return headerVars, rerr } if !Forums.Exists(fid) { - return headerVars, NotFound(w, r) + return headerVars, NotFound(w, r, headerVars) } if VhookSkippable["forum_check_pre_perms"] != nil { @@ -353,7 +353,7 @@ func HandleUploadRoute(w http.ResponseWriter, r *http.Request, user User, maxFil // TODO: Reuse this code more if r.ContentLength > int64(maxFileSize) { size, unit := ConvertByteUnit(float64(maxFileSize)) - return CustomError("Your upload is too big. Your files need to be smaller than "+strconv.Itoa(int(size))+unit+".", http.StatusExpectationFailed, "Error", w, r, user) + return CustomError("Your upload is too big. Your files need to be smaller than "+strconv.Itoa(int(size))+unit+".", http.StatusExpectationFailed, "Error", w, r, nil, user) } r.Body = http.MaxBytesReader(w, r.Body, int64(maxFileSize)) diff --git a/common/themes.go b/common/themes.go index b7488341..c8690c44 100644 --- a/common/themes.go +++ b/common/themes.go @@ -169,7 +169,7 @@ func InitThemes() error { } if theme.FullImage != "" { - debugLog("Adding theme image") + DebugLog("Adding theme image") err = StaticFiles.Add("./themes/"+themeName+"/"+theme.FullImage, "./themes/"+themeName) if err != nil { return err @@ -206,7 +206,7 @@ func (theme *Theme) LoadStaticFiles() error { func (theme *Theme) AddThemeStaticFiles() error { // TODO: Use a function instead of a closure to make this more testable? What about a function call inside the closure to take the theme variable into account? return filepath.Walk("./themes/"+theme.Name+"/public", func(path string, f os.FileInfo, err error) error { - debugLog("Attempting to add static file '" + path + "' for default theme '" + theme.Name + "'") + DebugLog("Attempting to add static file '" + path + "' for default theme '" + theme.Name + "'") if err != nil { return err } @@ -236,7 +236,7 @@ func (theme *Theme) AddThemeStaticFiles() error { gzipData := compressBytesGzip(data) StaticFiles.Set("/static/"+theme.Name+path, SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}) - debugLog("Added the '/" + theme.Name + path + "' static file for theme " + theme.Name + ".") + DebugLog("Added the '/" + theme.Name + path + "' static file for theme " + theme.Name + ".") return nil }) } diff --git a/common/user_store.go b/common/user_store.go index 2fd8a514..64a7fae5 100644 --- a/common/user_store.go +++ b/common/user_store.go @@ -155,6 +155,7 @@ func (mus *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err erro // We probably don't need this, but it might be useful in case of bugs in BulkCascadeGetMap if sidList == "" { + // TODO: Bulk log this if Dev.DebugMode { log.Print("This data is sampled later in the BulkCascadeGetMap function, so it might miss the cached IDs") log.Print("idCount", idCount) diff --git a/common/widgets.go b/common/widgets.go index 143ff407..8e547d6a 100644 --- a/common/widgets.go +++ b/common/widgets.go @@ -6,7 +6,6 @@ import ( "database/sql" "encoding/json" "html/template" - "log" "strings" "sync" @@ -215,11 +214,9 @@ func InitWidgets() error { Docks.Footer = footerWidgets widgetUpdateMutex.Unlock() - if Dev.SuperDebug { - log.Print("Docks.LeftSidebar", Docks.LeftSidebar) - log.Print("Docks.RightSidebar", Docks.RightSidebar) - log.Print("Docks.Footer", Docks.Footer) - } + DebugLog("Docks.LeftSidebar", Docks.LeftSidebar) + DebugLog("Docks.RightSidebar", Docks.RightSidebar) + DebugLog("Docks.Footer", Docks.Footer) return nil } diff --git a/extend/guilds/lib/guilds.go b/extend/guilds/lib/guilds.go index 78035934..f7b66c34 100644 --- a/extend/guilds/lib/guilds.go +++ b/extend/guilds/lib/guilds.go @@ -215,8 +215,9 @@ func MiddleViewGuild(w http.ResponseWriter, r *http.Request, user common.User) c if err != nil { return common.LocalError("Bad guild", w, r, user) } + // TODO: Build and pass headerVars if !guildItem.Active { - return common.NotFound(w, r) + return common.NotFound(w, r, nil) } return nil @@ -357,11 +358,9 @@ func RouteMemberList(w http.ResponseWriter, r *http.Request, user common.User) c pi := MemberListPage{"Guild Member List", user, headerVars, guildMembers, guildItem, 0, 0} // A plugin with plugins. Pluginception! - if common.PreRenderHooks["pre_render_guilds_member_list"] != nil { - if common.RunPreRenderHook("pre_render_guilds_member_list", w, r, &user, &pi) { + if common.RunPreRenderHook("pre_render_guilds_member_list", w, r, &user, &pi) { return nil } - } err = common.RunThemeTemplate(headerVars.Theme.Name, "guilds_member_list", pi, w) if err != nil { return common.InternalError(err, w, r) @@ -446,7 +445,7 @@ func ForumCheck(args ...interface{}) (skip bool, rerr common.RouteError) { return true, common.InternalError(errors.New("Unable to find the parent group for a forum"), w, r) } if !guildItem.Active { - return true, common.NotFound(w, r) + return true, common.NotFound(w, r, nil) // TODO: Can we pull headerVars out of args? } r = r.WithContext(context.WithValue(r.Context(), "guilds_current_group", guildItem)) } diff --git a/gen_mssql.go b/gen_mssql.go index 805df442..be837151 100644 --- a/gen_mssql.go +++ b/gen_mssql.go @@ -64,9 +64,7 @@ type Stmts struct { // nolint func _gen_mssql() (err error) { - if common.Dev.DebugMode { - log.Print("Building the generated statements") - } + common.DebugLog("Building the generated statements") log.Print("Preparing getPassword statement.") stmts.getPassword, err = db.Prepare("SELECT [password],[salt] FROM [users] WHERE [uid] = ?1") diff --git a/gen_mysql.go b/gen_mysql.go index 2d2ed881..b5be4b99 100644 --- a/gen_mysql.go +++ b/gen_mysql.go @@ -66,9 +66,7 @@ type Stmts struct { // nolint func _gen_mysql() (err error) { - if common.Dev.DebugMode { - log.Print("Building the generated statements") - } + common.DebugLog("Building the generated statements") log.Print("Preparing getPassword statement.") stmts.getPassword, err = db.Prepare("SELECT `password`,`salt` FROM `users` WHERE `uid` = ?") diff --git a/gen_pgsql.go b/gen_pgsql.go index 2e42523c..8f19d5e7 100644 --- a/gen_pgsql.go +++ b/gen_pgsql.go @@ -34,9 +34,7 @@ type Stmts struct { // nolint func _gen_pgsql() (err error) { - if common.Dev.DebugMode { - log.Print("Building the generated statements") - } + common.DebugLog("Building the generated statements") log.Print("Preparing editReply statement.") stmts.editReply, err = db.Prepare("UPDATE `replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?") diff --git a/gen_router.go b/gen_router.go index 03dab123..4dec4f8a 100644 --- a/gen_router.go +++ b/gen_router.go @@ -10,6 +10,7 @@ import ( "net/http" "./common" + "./common/counters" "./routes" ) @@ -113,6 +114,7 @@ var RouteMap = map[string]interface{}{ "routes.AccountRegisterSubmit": routes.AccountRegisterSubmit, "routeDynamic": routeDynamic, "routeUploads": routeUploads, + "routes.StaticFile": routes.StaticFile, "BadRoute": BadRoute, } @@ -215,7 +217,8 @@ var routeMapEnum = map[string]int{ "routes.AccountRegisterSubmit": 94, "routeDynamic": 95, "routeUploads": 96, - "BadRoute": 97, + "routes.StaticFile": 97, + "BadRoute": 98, } var reverseRouteMapEnum = map[int]string{ 0: "routeAPI", @@ -315,7 +318,8 @@ var reverseRouteMapEnum = map[int]string{ 94: "routes.AccountRegisterSubmit", 95: "routeDynamic", 96: "routeUploads", - 97: "BadRoute", + 97: "routes.StaticFile", + 98: "BadRoute", } var osMapEnum = map[string]int{ "unknown": 0, @@ -428,12 +432,12 @@ var markToAgent = map[string]string{ // TODO: Stop spilling these into the package scope? func init() { - common.SetRouteMapEnum(routeMapEnum) - common.SetReverseRouteMapEnum(reverseRouteMapEnum) - common.SetAgentMapEnum(agentMapEnum) - common.SetReverseAgentMapEnum(reverseAgentMapEnum) - common.SetOSMapEnum(osMapEnum) - common.SetReverseOSMapEnum(reverseOSMapEnum) + counters.SetRouteMapEnum(routeMapEnum) + counters.SetReverseRouteMapEnum(reverseRouteMapEnum) + counters.SetAgentMapEnum(agentMapEnum) + counters.SetReverseAgentMapEnum(reverseAgentMapEnum) + counters.SetOSMapEnum(osMapEnum) + counters.SetReverseOSMapEnum(reverseOSMapEnum) } type GenRouter struct { @@ -500,7 +504,7 @@ func (router *GenRouter) DumpRequest(req *http.Request) { func (router *GenRouter) SuspiciousRequest(req *http.Request) { log.Print("Suspicious Request") router.DumpRequest(req) - common.AgentViewCounter.Bump(26) + counters.AgentViewCounter.Bump(26) } // TODO: Pass the default route or config struct to the router rather than accessing it via a package global @@ -533,7 +537,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { w.Write([]byte("")) log.Print("Malformed Request") router.DumpRequest(req) - common.AgentViewCounter.Bump(25) + counters.AgentViewCounter.Bump(25) return } @@ -563,8 +567,11 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { log.Print("before routes.StaticFile") router.DumpRequest(req) } + // Increment the request counter + counters.GlobalViewCounter.Bump() if prefix == "/static" { + counters.RouteViewCounter.Bump(97) req.URL.Path += extraData routes.StaticFile(w, req) return @@ -573,15 +580,12 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { log.Print("before PreRoute") } - // Increment the global view counter - common.GlobalViewCounter.Bump() - // Track the user agents. Unfortunately, everyone pretends to be Mozilla, so this'll be a little less efficient than I would like. // TODO: Add a setting to disable this? // TODO: Use a more efficient detector instead of smashing every possible combination in ua := strings.TrimSpace(strings.Replace(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36","",-1)) // Noise, no one's going to be running this and it would require some sort of agent ranking system to determine which identifier should be prioritised over another if ua == "" { - common.AgentViewCounter.Bump(24) + counters.AgentViewCounter.Bump(24) if common.Dev.DebugMode { log.Print("Blank UA: ", req.UserAgent()) router.DumpRequest(req) @@ -681,15 +685,15 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } if agent == "" { - common.AgentViewCounter.Bump(0) + counters.AgentViewCounter.Bump(0) if common.Dev.DebugMode { log.Print("Unknown UA: ", req.UserAgent()) router.DumpRequest(req) } } else { - common.AgentViewCounter.Bump(agentMapEnum[agent]) + counters.AgentViewCounter.Bump(agentMapEnum[agent]) } - common.OSViewCounter.Bump(osMapEnum[os]) + counters.OSViewCounter.Bump(osMapEnum[os]) } referrer := req.Header.Get("Referer") // Check the 'referrer' header too? :P @@ -699,7 +703,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { referrer = strings.Split(referrer,"/")[0] portless := strings.Split(referrer,":")[0] if portless != "localhost" && portless != "127.0.0.1" && portless != common.Site.Host { - common.ReferrerTracker.Bump(referrer) + counters.ReferrerTracker.Bump(referrer) } } @@ -716,31 +720,31 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { var err common.RouteError switch(prefix) { case "/api": - common.RouteViewCounter.Bump(0) + counters.RouteViewCounter.Bump(0) err = routeAPI(w,req,user) if err != nil { router.handleError(err,w,req,user) } case "/overview": - common.RouteViewCounter.Bump(1) + counters.RouteViewCounter.Bump(1) err = routes.Overview(w,req,user) if err != nil { router.handleError(err,w,req,user) } case "/pages": - common.RouteViewCounter.Bump(2) + counters.RouteViewCounter.Bump(2) err = routes.CustomPage(w,req,user,extraData) if err != nil { router.handleError(err,w,req,user) } case "/forums": - common.RouteViewCounter.Bump(3) + counters.RouteViewCounter.Bump(3) err = routeForums(w,req,user) if err != nil { router.handleError(err,w,req,user) } case "/forum": - common.RouteViewCounter.Bump(4) + counters.RouteViewCounter.Bump(4) err = routeForum(w,req,user,extraData) if err != nil { router.handleError(err,w,req,user) @@ -752,7 +756,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(5) + counters.RouteViewCounter.Bump(5) err = routeChangeTheme(w,req,user) if err != nil { router.handleError(err,w,req,user) @@ -764,14 +768,14 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(6) + counters.RouteViewCounter.Bump(6) err = routeShowAttachment(w,req,user,extraData) if err != nil { router.handleError(err,w,req,user) } case "/ws": req.URL.Path += extraData - common.RouteViewCounter.Bump(7) + counters.RouteViewCounter.Bump(7) err = routeWebsockets(w,req,user) if err != nil { router.handleError(err,w,req,user) @@ -797,7 +801,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(8) + counters.RouteViewCounter.Bump(8) err = routeReportSubmit(w,req,user,extraData) } if err != nil { @@ -812,10 +816,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(9) + counters.RouteViewCounter.Bump(9) err = routes.CreateTopic(w,req,user,extraData) default: - common.RouteViewCounter.Bump(10) + counters.RouteViewCounter.Bump(10) err = routes.TopicList(w,req,user) } if err != nil { @@ -830,7 +834,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { switch(req.URL.Path) { case "/panel/forums/": - common.RouteViewCounter.Bump(11) + counters.RouteViewCounter.Bump(11) err = routePanelForums(w,req,user) case "/panel/forums/create/": err = common.NoSessionMismatch(w,req,user) @@ -839,7 +843,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(12) + counters.RouteViewCounter.Bump(12) err = routePanelForumsCreateSubmit(w,req,user) case "/panel/forums/delete/": err = common.NoSessionMismatch(w,req,user) @@ -848,7 +852,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(13) + counters.RouteViewCounter.Bump(13) err = routePanelForumsDelete(w,req,user,extraData) case "/panel/forums/delete/submit/": err = common.NoSessionMismatch(w,req,user) @@ -857,10 +861,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(14) + counters.RouteViewCounter.Bump(14) err = routePanelForumsDeleteSubmit(w,req,user,extraData) case "/panel/forums/edit/": - common.RouteViewCounter.Bump(15) + counters.RouteViewCounter.Bump(15) err = routePanelForumsEdit(w,req,user,extraData) case "/panel/forums/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -869,7 +873,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(16) + counters.RouteViewCounter.Bump(16) err = routePanelForumsEditSubmit(w,req,user,extraData) case "/panel/forums/edit/perms/submit/": err = common.NoSessionMismatch(w,req,user) @@ -878,10 +882,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(17) + counters.RouteViewCounter.Bump(17) err = routePanelForumsEditPermsSubmit(w,req,user,extraData) case "/panel/forums/edit/perms/": - common.RouteViewCounter.Bump(18) + counters.RouteViewCounter.Bump(18) err = routePanelForumsEditPermsAdvance(w,req,user,extraData) case "/panel/forums/edit/perms/adv/submit/": err = common.NoSessionMismatch(w,req,user) @@ -890,13 +894,13 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(19) + counters.RouteViewCounter.Bump(19) err = routePanelForumsEditPermsAdvanceSubmit(w,req,user,extraData) case "/panel/settings/": - common.RouteViewCounter.Bump(20) + counters.RouteViewCounter.Bump(20) err = routePanelSettings(w,req,user) case "/panel/settings/edit/": - common.RouteViewCounter.Bump(21) + counters.RouteViewCounter.Bump(21) err = routePanelSettingEdit(w,req,user,extraData) case "/panel/settings/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -905,10 +909,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(22) + counters.RouteViewCounter.Bump(22) err = routePanelSettingEditSubmit(w,req,user,extraData) case "/panel/settings/word-filters/": - common.RouteViewCounter.Bump(23) + counters.RouteViewCounter.Bump(23) err = routePanelWordFilters(w,req,user) case "/panel/settings/word-filters/create/": err = common.NoSessionMismatch(w,req,user) @@ -917,10 +921,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(24) + counters.RouteViewCounter.Bump(24) err = routePanelWordFiltersCreateSubmit(w,req,user) case "/panel/settings/word-filters/edit/": - common.RouteViewCounter.Bump(25) + counters.RouteViewCounter.Bump(25) err = routePanelWordFiltersEdit(w,req,user,extraData) case "/panel/settings/word-filters/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -929,7 +933,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(26) + counters.RouteViewCounter.Bump(26) err = routePanelWordFiltersEditSubmit(w,req,user,extraData) case "/panel/settings/word-filters/delete/submit/": err = common.NoSessionMismatch(w,req,user) @@ -938,10 +942,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(27) + counters.RouteViewCounter.Bump(27) err = routePanelWordFiltersDeleteSubmit(w,req,user,extraData) case "/panel/themes/": - common.RouteViewCounter.Bump(28) + counters.RouteViewCounter.Bump(28) err = routePanelThemes(w,req,user) case "/panel/themes/default/": err = common.NoSessionMismatch(w,req,user) @@ -950,10 +954,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(29) + counters.RouteViewCounter.Bump(29) err = routePanelThemesSetDefault(w,req,user,extraData) case "/panel/plugins/": - common.RouteViewCounter.Bump(30) + counters.RouteViewCounter.Bump(30) err = routePanelPlugins(w,req,user) case "/panel/plugins/activate/": err = common.NoSessionMismatch(w,req,user) @@ -962,7 +966,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(31) + counters.RouteViewCounter.Bump(31) err = routePanelPluginsActivate(w,req,user,extraData) case "/panel/plugins/deactivate/": err = common.NoSessionMismatch(w,req,user) @@ -971,7 +975,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(32) + counters.RouteViewCounter.Bump(32) err = routePanelPluginsDeactivate(w,req,user,extraData) case "/panel/plugins/install/": err = common.NoSessionMismatch(w,req,user) @@ -980,13 +984,13 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(33) + counters.RouteViewCounter.Bump(33) err = routePanelPluginsInstall(w,req,user,extraData) case "/panel/users/": - common.RouteViewCounter.Bump(34) + counters.RouteViewCounter.Bump(34) err = routePanelUsers(w,req,user) case "/panel/users/edit/": - common.RouteViewCounter.Bump(35) + counters.RouteViewCounter.Bump(35) err = routePanelUsersEdit(w,req,user,extraData) case "/panel/users/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -995,7 +999,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(36) + counters.RouteViewCounter.Bump(36) err = routePanelUsersEditSubmit(w,req,user,extraData) case "/panel/analytics/views/": err = common.ParseForm(w,req,user) @@ -1004,7 +1008,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(37) + counters.RouteViewCounter.Bump(37) err = routePanelAnalyticsViews(w,req,user) case "/panel/analytics/routes/": err = common.ParseForm(w,req,user) @@ -1013,7 +1017,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(38) + counters.RouteViewCounter.Bump(38) err = routePanelAnalyticsRoutes(w,req,user) case "/panel/analytics/agents/": err = common.ParseForm(w,req,user) @@ -1022,7 +1026,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(39) + counters.RouteViewCounter.Bump(39) err = routePanelAnalyticsAgents(w,req,user) case "/panel/analytics/systems/": err = common.ParseForm(w,req,user) @@ -1031,7 +1035,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(40) + counters.RouteViewCounter.Bump(40) err = routePanelAnalyticsSystems(w,req,user) case "/panel/analytics/referrers/": err = common.ParseForm(w,req,user) @@ -1040,19 +1044,19 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(41) + counters.RouteViewCounter.Bump(41) err = routePanelAnalyticsReferrers(w,req,user) case "/panel/analytics/route/": - common.RouteViewCounter.Bump(42) + counters.RouteViewCounter.Bump(42) err = routePanelAnalyticsRouteViews(w,req,user,extraData) case "/panel/analytics/agent/": - common.RouteViewCounter.Bump(43) + counters.RouteViewCounter.Bump(43) err = routePanelAnalyticsAgentViews(w,req,user,extraData) case "/panel/analytics/system/": - common.RouteViewCounter.Bump(44) + counters.RouteViewCounter.Bump(44) err = routePanelAnalyticsSystemViews(w,req,user,extraData) case "/panel/analytics/referrer/": - common.RouteViewCounter.Bump(45) + counters.RouteViewCounter.Bump(45) err = routePanelAnalyticsReferrerViews(w,req,user,extraData) case "/panel/analytics/posts/": err = common.ParseForm(w,req,user) @@ -1061,7 +1065,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(46) + counters.RouteViewCounter.Bump(46) err = routePanelAnalyticsPosts(w,req,user) case "/panel/analytics/topics/": err = common.ParseForm(w,req,user) @@ -1070,16 +1074,16 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(47) + counters.RouteViewCounter.Bump(47) err = routePanelAnalyticsTopics(w,req,user) case "/panel/groups/": - common.RouteViewCounter.Bump(48) + counters.RouteViewCounter.Bump(48) err = routePanelGroups(w,req,user) case "/panel/groups/edit/": - common.RouteViewCounter.Bump(49) + counters.RouteViewCounter.Bump(49) err = routePanelGroupsEdit(w,req,user,extraData) case "/panel/groups/edit/perms/": - common.RouteViewCounter.Bump(50) + counters.RouteViewCounter.Bump(50) err = routePanelGroupsEditPerms(w,req,user,extraData) case "/panel/groups/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1088,7 +1092,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(51) + counters.RouteViewCounter.Bump(51) err = routePanelGroupsEditSubmit(w,req,user,extraData) case "/panel/groups/edit/perms/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1097,7 +1101,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(52) + counters.RouteViewCounter.Bump(52) err = routePanelGroupsEditPermsSubmit(w,req,user,extraData) case "/panel/groups/create/": err = common.NoSessionMismatch(w,req,user) @@ -1106,7 +1110,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(53) + counters.RouteViewCounter.Bump(53) err = routePanelGroupsCreateSubmit(w,req,user) case "/panel/backups/": err = common.SuperAdminOnly(w,req,user) @@ -1115,10 +1119,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(54) + counters.RouteViewCounter.Bump(54) err = routePanelBackups(w,req,user,extraData) case "/panel/logs/mod/": - common.RouteViewCounter.Bump(55) + counters.RouteViewCounter.Bump(55) err = routePanelLogsMod(w,req,user) case "/panel/debug/": err = common.AdminOnly(w,req,user) @@ -1127,10 +1131,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(56) + counters.RouteViewCounter.Bump(56) err = routePanelDebug(w,req,user) default: - common.RouteViewCounter.Bump(57) + counters.RouteViewCounter.Bump(57) err = routePanelDashboard(w,req,user) } if err != nil { @@ -1145,7 +1149,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(58) + counters.RouteViewCounter.Bump(58) err = routes.AccountEditCritical(w,req,user) case "/user/edit/critical/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1160,7 +1164,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(59) + counters.RouteViewCounter.Bump(59) err = routeAccountEditCriticalSubmit(w,req,user) case "/user/edit/avatar/": err = common.MemberOnly(w,req,user) @@ -1169,7 +1173,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(60) + counters.RouteViewCounter.Bump(60) err = routeAccountEditAvatar(w,req,user) case "/user/edit/avatar/submit/": err = common.MemberOnly(w,req,user) @@ -1189,7 +1193,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(61) + counters.RouteViewCounter.Bump(61) err = routeAccountEditAvatarSubmit(w,req,user) case "/user/edit/username/": err = common.MemberOnly(w,req,user) @@ -1198,7 +1202,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(62) + counters.RouteViewCounter.Bump(62) err = routeAccountEditUsername(w,req,user) case "/user/edit/username/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1213,7 +1217,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(63) + counters.RouteViewCounter.Bump(63) err = routeAccountEditUsernameSubmit(w,req,user) case "/user/edit/email/": err = common.MemberOnly(w,req,user) @@ -1222,7 +1226,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(64) + counters.RouteViewCounter.Bump(64) err = routeAccountEditEmail(w,req,user) case "/user/edit/token/": err = common.NoSessionMismatch(w,req,user) @@ -1237,11 +1241,11 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(65) + counters.RouteViewCounter.Bump(65) err = routeAccountEditEmailTokenSubmit(w,req,user,extraData) default: req.URL.Path += extraData - common.RouteViewCounter.Bump(66) + counters.RouteViewCounter.Bump(66) err = routeProfile(w,req,user) } if err != nil { @@ -1262,7 +1266,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(67) + counters.RouteViewCounter.Bump(67) err = routes.BanUserSubmit(w,req,user,extraData) case "/users/unban/": err = common.NoSessionMismatch(w,req,user) @@ -1277,7 +1281,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(68) + counters.RouteViewCounter.Bump(68) err = routes.UnbanUser(w,req,user,extraData) case "/users/activate/": err = common.NoSessionMismatch(w,req,user) @@ -1292,7 +1296,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(69) + counters.RouteViewCounter.Bump(69) err = routes.ActivateUser(w,req,user,extraData) case "/users/ips/": err = common.MemberOnly(w,req,user) @@ -1301,7 +1305,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(70) + counters.RouteViewCounter.Bump(70) err = routes.IPSearch(w,req,user) } if err != nil { @@ -1327,7 +1331,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(71) + counters.RouteViewCounter.Bump(71) err = routes.CreateTopicSubmit(w,req,user) case "/topic/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1342,7 +1346,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(72) + counters.RouteViewCounter.Bump(72) err = routes.EditTopicSubmit(w,req,user,extraData) case "/topic/delete/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1358,7 +1362,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } req.URL.Path += extraData - common.RouteViewCounter.Bump(73) + counters.RouteViewCounter.Bump(73) err = routes.DeleteTopicSubmit(w,req,user) case "/topic/stick/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1373,7 +1377,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(74) + counters.RouteViewCounter.Bump(74) err = routes.StickTopicSubmit(w,req,user,extraData) case "/topic/unstick/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1388,7 +1392,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(75) + counters.RouteViewCounter.Bump(75) err = routes.UnstickTopicSubmit(w,req,user,extraData) case "/topic/lock/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1404,7 +1408,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } req.URL.Path += extraData - common.RouteViewCounter.Bump(76) + counters.RouteViewCounter.Bump(76) err = routes.LockTopicSubmit(w,req,user) case "/topic/unlock/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1419,7 +1423,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(77) + counters.RouteViewCounter.Bump(77) err = routes.UnlockTopicSubmit(w,req,user,extraData) case "/topic/move/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1434,7 +1438,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(78) + counters.RouteViewCounter.Bump(78) err = routes.MoveTopicSubmit(w,req,user,extraData) case "/topic/like/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1449,10 +1453,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(79) + counters.RouteViewCounter.Bump(79) err = routeLikeTopicSubmit(w,req,user,extraData) default: - common.RouteViewCounter.Bump(80) + counters.RouteViewCounter.Bump(80) err = routes.ViewTopic(w,req,user, extraData) } if err != nil { @@ -1478,7 +1482,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(81) + counters.RouteViewCounter.Bump(81) err = routeCreateReplySubmit(w,req,user) case "/reply/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1493,7 +1497,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(82) + counters.RouteViewCounter.Bump(82) err = routes.ReplyEditSubmit(w,req,user,extraData) case "/reply/delete/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1508,7 +1512,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(83) + counters.RouteViewCounter.Bump(83) err = routes.ReplyDeleteSubmit(w,req,user,extraData) case "/reply/like/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1523,7 +1527,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(84) + counters.RouteViewCounter.Bump(84) err = routeReplyLikeSubmit(w,req,user,extraData) } if err != nil { @@ -1544,7 +1548,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(85) + counters.RouteViewCounter.Bump(85) err = routeProfileReplyCreateSubmit(w,req,user) case "/profile/reply/edit/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1559,7 +1563,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(86) + counters.RouteViewCounter.Bump(86) err = routes.ProfileReplyEditSubmit(w,req,user,extraData) case "/profile/reply/delete/submit/": err = common.NoSessionMismatch(w,req,user) @@ -1574,7 +1578,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(87) + counters.RouteViewCounter.Bump(87) err = routes.ProfileReplyDeleteSubmit(w,req,user,extraData) } if err != nil { @@ -1595,10 +1599,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(88) + counters.RouteViewCounter.Bump(88) err = routes.PollVote(w,req,user,extraData) case "/poll/results/": - common.RouteViewCounter.Bump(89) + counters.RouteViewCounter.Bump(89) err = routes.PollResults(w,req,user,extraData) } if err != nil { @@ -1607,10 +1611,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { case "/accounts": switch(req.URL.Path) { case "/accounts/login/": - common.RouteViewCounter.Bump(90) + counters.RouteViewCounter.Bump(90) err = routes.AccountLogin(w,req,user) case "/accounts/create/": - common.RouteViewCounter.Bump(91) + counters.RouteViewCounter.Bump(91) err = routes.AccountRegister(w,req,user) case "/accounts/logout/": err = common.NoSessionMismatch(w,req,user) @@ -1625,7 +1629,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(92) + counters.RouteViewCounter.Bump(92) err = routeLogout(w,req,user) case "/accounts/login/submit/": err = common.ParseForm(w,req,user) @@ -1634,7 +1638,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(93) + counters.RouteViewCounter.Bump(93) err = routes.AccountLoginSubmit(w,req,user) case "/accounts/create/submit/": err = common.ParseForm(w,req,user) @@ -1643,7 +1647,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - common.RouteViewCounter.Bump(94) + counters.RouteViewCounter.Bump(94) err = routes.AccountRegisterSubmit(w,req,user) } if err != nil { @@ -1657,10 +1661,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { }*/ case "/uploads": if extraData == "" { - common.NotFound(w,req) + common.NotFound(w,req,nil) return } - common.RouteViewCounter.Bump(96) + counters.RouteViewCounter.Bump(96) req.URL.Path += extraData // TODO: Find a way to propagate errors up from this? router.UploadHandler(w,req) // TODO: Count these views @@ -1682,7 +1686,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return*/ } if extraData != "" { - common.NotFound(w,req) + common.NotFound(w,req,nil) return } @@ -1690,10 +1694,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { if !ok { // TODO: Make this a startup error not a runtime one log.Print("Unable to find the default route") - common.NotFound(w,req) + common.NotFound(w,req,nil) return } - common.RouteViewCounter.Bump(routeMapEnum[common.Config.DefaultRoute]) + counters.RouteViewCounter.Bump(routeMapEnum[common.Config.DefaultRoute]) handle.(func(http.ResponseWriter, *http.Request, common.User) common.RouteError)(w,req,user) default: @@ -1703,7 +1707,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { router.RUnlock() if ok { - common.RouteViewCounter.Bump(95) // TODO: Be more specific about *which* dynamic route it is + counters.RouteViewCounter.Bump(95) // TODO: Be more specific about *which* dynamic route it is req.URL.Path += extraData err = handle(w,req,user) if err != nil { @@ -1717,7 +1721,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { if strings.Contains(lowerPath,"admin") || strings.Contains(lowerPath,"sql") || strings.Contains(lowerPath,"manage") || strings.Contains(lowerPath,"//") || strings.Contains(lowerPath,"\\\\") || strings.Contains(lowerPath,"wp") || strings.Contains(lowerPath,"wordpress") || strings.Contains(lowerPath,"config") || strings.Contains(lowerPath,"setup") || strings.Contains(lowerPath,"install") || strings.Contains(lowerPath,"update") || strings.Contains(lowerPath,"php") { router.SuspiciousRequest(req) } - common.RouteViewCounter.Bump(97) - common.NotFound(w,req) + counters.RouteViewCounter.Bump(98) + common.NotFound(w,req,nil) } } diff --git a/main.go b/main.go index 104805eb..97aa40e9 100644 --- a/main.go +++ b/main.go @@ -16,8 +16,9 @@ import ( "strings" "syscall" "time" - //"runtime/pprof" + "./common" + "./common/counters" "github.com/fsnotify/fsnotify" ) @@ -101,35 +102,35 @@ func afterDBInit() (err error) { return err } - common.GlobalViewCounter, err = common.NewGlobalViewCounter() + counters.GlobalViewCounter, err = counters.NewGlobalViewCounter() if err != nil { return err } - common.AgentViewCounter, err = common.NewDefaultAgentViewCounter() + counters.AgentViewCounter, err = counters.NewDefaultAgentViewCounter() if err != nil { return err } - common.OSViewCounter, err = common.NewDefaultOSViewCounter() + counters.OSViewCounter, err = counters.NewDefaultOSViewCounter() if err != nil { return err } - common.RouteViewCounter, err = common.NewDefaultRouteViewCounter() + counters.RouteViewCounter, err = counters.NewDefaultRouteViewCounter() if err != nil { return err } - common.PostCounter, err = common.NewPostCounter() + counters.PostCounter, err = counters.NewPostCounter() if err != nil { return err } - common.TopicCounter, err = common.NewTopicCounter() + counters.TopicCounter, err = counters.NewTopicCounter() if err != nil { return err } - common.TopicViewCounter, err = common.NewDefaultTopicViewCounter() + counters.TopicViewCounter, err = counters.NewDefaultTopicViewCounter() if err != nil { return err } - common.ReferrerTracker, err = common.NewDefaultReferrerTracker() + counters.ReferrerTracker, err = counters.NewDefaultReferrerTracker() if err != nil { return err } diff --git a/member_routes.go b/member_routes.go index 742f937e..e352740a 100644 --- a/member_routes.go +++ b/member_routes.go @@ -14,6 +14,7 @@ import ( "strings" "./common" + "./common/counters" ) func routeCreateReplySubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { @@ -194,7 +195,7 @@ func routeCreateReplySubmit(w http.ResponseWriter, r *http.Request, user common. return common.InternalError(err, w, r) } - common.PostCounter.Bump() + counters.PostCounter.Bump() return nil } @@ -348,7 +349,7 @@ func routeProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user return common.InternalError(err, w, r) } - common.PostCounter.Bump() + counters.PostCounter.Bump() http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther) return nil } @@ -398,7 +399,7 @@ func routeReportSubmit(w http.ResponseWriter, r *http.Request, user common.User, } else if itemType == "topic" { err = stmts.getTopicBasic.QueryRow(itemID).Scan(&title, &content) if err == ErrNoRows { - return common.NotFound(w, r) + return common.NotFound(w, r, nil) } else if err != nil { return common.InternalError(err, w, r) } @@ -439,7 +440,7 @@ func routeReportSubmit(w http.ResponseWriter, r *http.Request, user common.User, if err != nil && err != ErrNoRows { return common.InternalError(err, w, r) } - common.PostCounter.Bump() + counters.PostCounter.Bump() http.Redirect(w, r, "/topic/"+strconv.FormatInt(lastID, 10), http.StatusSeeOther) return nil @@ -479,10 +480,8 @@ func routeAccountEditCriticalSubmit(w http.ResponseWriter, r *http.Request, user headerVars.NoticeList = append(headerVars.NoticeList, "Your password was successfully updated") pi := common.Page{"Edit Password", user, headerVars, tList, nil} - if common.PreRenderHooks["pre_render_account_own_edit_critical"] != nil { - if common.RunPreRenderHook("pre_render_account_own_edit_critical", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_account_own_edit_critical", w, r, &user, &pi) { + return nil } err = common.Templates.ExecuteTemplate(w, "account_own_edit.html", pi) if err != nil { @@ -498,10 +497,8 @@ func routeAccountEditAvatar(w http.ResponseWriter, r *http.Request, user common. } pi := common.Page{"Edit Avatar", user, headerVars, tList, nil} - if common.PreRenderHooks["pre_render_account_own_edit_avatar"] != nil { - if common.RunPreRenderHook("pre_render_account_own_edit_avatar", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_account_own_edit_avatar", w, r, &user, &pi) { + return nil } err := common.Templates.ExecuteTemplate(w, "account_own_edit_avatar.html", pi) if err != nil { @@ -573,10 +570,8 @@ func routeAccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user c headerVars.NoticeList = append(headerVars.NoticeList, "Your avatar was successfully updated") pi := common.Page{"Edit Avatar", user, headerVars, tList, nil} - if common.PreRenderHooks["pre_render_account_own_edit_avatar"] != nil { - if common.RunPreRenderHook("pre_render_account_own_edit_avatar", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_account_own_edit_avatar", w, r, &user, &pi) { + return nil } err = common.Templates.ExecuteTemplate(w, "account_own_edit_avatar.html", pi) if err != nil { @@ -592,10 +587,8 @@ func routeAccountEditUsername(w http.ResponseWriter, r *http.Request, user commo } pi := common.Page{"Edit Username", user, headerVars, tList, user.Name} - if common.PreRenderHooks["pre_render_account_own_edit_username"] != nil { - if common.RunPreRenderHook("pre_render_account_own_edit_username", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_account_own_edit_username", w, r, &user, &pi) { + return nil } err := common.Templates.ExecuteTemplate(w, "account_own_edit_username.html", pi) if err != nil { @@ -619,10 +612,8 @@ func routeAccountEditUsernameSubmit(w http.ResponseWriter, r *http.Request, user headerVars.NoticeList = append(headerVars.NoticeList, "Your username was successfully updated") pi := common.Page{"Edit Username", user, headerVars, tList, nil} - if common.PreRenderHooks["pre_render_account_own_edit_username"] != nil { - if common.RunPreRenderHook("pre_render_account_own_edit_username", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_account_own_edit_username", w, r, &user, &pi) { + return nil } err = common.Templates.ExecuteTemplate(w, "account_own_edit_username.html", pi) if err != nil { @@ -674,10 +665,8 @@ func routeAccountEditEmail(w http.ResponseWriter, r *http.Request, user common.U } pi := common.Page{"Email Manager", user, headerVars, emailList, nil} - if common.PreRenderHooks["pre_render_account_own_edit_email"] != nil { - if common.RunPreRenderHook("pre_render_account_own_edit_email", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_account_own_edit_email", w, r, &user, &pi) { + return nil } err = common.Templates.ExecuteTemplate(w, "account_own_edit_email.html", pi) if err != nil { @@ -746,10 +735,8 @@ func routeAccountEditEmailTokenSubmit(w http.ResponseWriter, r *http.Request, us } headerVars.NoticeList = append(headerVars.NoticeList, "Your email was successfully verified") pi := common.Page{"Email Manager", user, headerVars, emailList, nil} - if common.PreRenderHooks["pre_render_account_own_edit_email"] != nil { - if common.RunPreRenderHook("pre_render_account_own_edit_email", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_account_own_edit_email", w, r, &user, &pi) { + return nil } err = common.Templates.ExecuteTemplate(w, "account_own_edit_email.html", pi) if err != nil { @@ -786,7 +773,7 @@ func routeShowAttachment(w http.ResponseWriter, r *http.Request, user common.Use var originID, uploadedBy int err = stmts.getAttachment.QueryRow(filename, sectionID, sectionTable).Scan(§ionID, §ionTable, &originID, &originTable, &uploadedBy, &filename) if err == ErrNoRows { - return common.NotFound(w, r) + return common.NotFound(w, r, nil) } else if err != nil { return common.InternalError(err, w, r) } diff --git a/panel_routes.go b/panel_routes.go index 35943c4d..668a8266 100644 --- a/panel_routes.go +++ b/panel_routes.go @@ -31,10 +31,8 @@ func panelSuccessRedirect(dest string, w http.ResponseWriter, r *http.Request, i return nil } func panelRenderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, user common.User, pi interface{}) common.RouteError { - if common.PreRenderHooks["pre_render_"+tmplName] != nil { - if common.RunPreRenderHook("pre_render_"+tmplName, w, r, &user, pi) { - return nil - } + if common.RunPreRenderHook("pre_render_"+tmplName, w, r, &user, pi) { + return nil } err := common.Templates.ExecuteTemplate(w, tmplName+".html", pi) if err != nil { @@ -253,10 +251,8 @@ func routePanelForumsDelete(w http.ResponseWriter, r *http.Request, user common. yousure := common.AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid), confirmMsg} pi := common.PanelPage{common.GetTitlePhrase("panel_delete_forum"), user, headerVars, stats, "forums", tList, yousure} - if common.PreRenderHooks["pre_render_panel_delete_forum"] != nil { - if common.RunPreRenderHook("pre_render_panel_delete_forum", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_panel_delete_forum", w, r, &user, &pi) { + return nil } err = common.Templates.ExecuteTemplate(w, "are_you_sure.html", pi) if err != nil { @@ -330,10 +326,8 @@ func routePanelForumsEdit(w http.ResponseWriter, r *http.Request, user common.Us } pi := common.PanelEditForumPage{common.GetTitlePhrase("panel_edit_forum"), user, headerVars, stats, "forums", forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, gplist} - if common.PreRenderHooks["pre_render_panel_edit_forum"] != nil { - if common.RunPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) { + return nil } err = common.Templates.ExecuteTemplate(w, "panel-forum-edit.html", pi) if err != nil { @@ -493,10 +487,8 @@ func routePanelForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, us addNameLangToggle("MoveTopic", forumPerms.MoveTopic) pi := common.PanelEditForumGroupPage{common.GetTitlePhrase("panel_edit_forum"), user, headerVars, stats, "forums", forum.ID, gid, forum.Name, forum.Desc, forum.Active, forum.Preset, formattedPermList} - if common.PreRenderHooks["pre_render_panel_edit_forum"] != nil { - if common.RunPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) { + return nil } err = common.Templates.ExecuteTemplate(w, "panel-forum-edit-perms.html", pi) if err != nil { @@ -801,6 +793,7 @@ func routePanelAnalyticsAgentViews(w http.ResponseWriter, r *http.Request, user } var unixCreatedAt = createdAt.Unix() + // TODO: Bulk log this if common.Dev.SuperDebug { log.Print("count: ", count) log.Print("createdAt: ", createdAt) @@ -883,6 +876,7 @@ func routePanelAnalyticsSystemViews(w http.ResponseWriter, r *http.Request, user } var unixCreatedAt = createdAt.Unix() + // TODO: Bulk log this if common.Dev.SuperDebug { log.Print("count: ", count) log.Print("createdAt: ", createdAt) @@ -964,6 +958,7 @@ func routePanelAnalyticsReferrerViews(w http.ResponseWriter, r *http.Request, us } var unixCreatedAt = createdAt.Unix() + // TODO: Bulk log this if common.Dev.SuperDebug { log.Print("count: ", count) log.Print("createdAt: ", createdAt) @@ -1038,6 +1033,7 @@ func routePanelAnalyticsTopics(w http.ResponseWriter, r *http.Request, user comm } var unixCreatedAt = createdAt.Unix() + // TODO: Bulk log this if common.Dev.SuperDebug { log.Print("count: ", count) log.Print("createdAt: ", createdAt) @@ -1171,6 +1167,7 @@ func routePanelAnalyticsRoutes(w http.ResponseWriter, r *http.Request, user comm return common.InternalError(err, w, r) } + // TODO: Bulk log this if common.Dev.SuperDebug { log.Print("count: ", count) log.Print("route: ", route) @@ -1222,6 +1219,7 @@ func routePanelAnalyticsAgents(w http.ResponseWriter, r *http.Request, user comm return common.InternalError(err, w, r) } + // TODO: Bulk log this if common.Dev.SuperDebug { log.Print("count: ", count) log.Print("agent: ", agent) @@ -1278,6 +1276,7 @@ func routePanelAnalyticsSystems(w http.ResponseWriter, r *http.Request, user com return common.InternalError(err, w, r) } + // TODO: Bulk log this if common.Dev.SuperDebug { log.Print("count: ", count) log.Print("system: ", system) @@ -1334,6 +1333,7 @@ func routePanelAnalyticsReferrers(w http.ResponseWriter, r *http.Request, user c return common.InternalError(err, w, r) } + // TODO: Bulk log this if common.Dev.SuperDebug { log.Print("count: ", count) log.Print("domain: ", domain) @@ -1850,10 +1850,8 @@ func routePanelUsersEdit(w http.ResponseWriter, r *http.Request, user common.Use } pi := common.PanelPage{common.GetTitlePhrase("panel_edit_user"), user, headerVars, stats, "users", groupList, targetUser} - if common.PreRenderHooks["pre_render_panel_edit_user"] != nil { - if common.RunPreRenderHook("pre_render_panel_edit_user", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_panel_edit_user", w, r, &user, &pi) { + return nil } err = common.Templates.ExecuteTemplate(w, "panel-user-edit.html", pi) if err != nil { @@ -2015,7 +2013,7 @@ func routePanelGroupsEdit(w http.ResponseWriter, r *http.Request, user common.Us group, err := common.Groups.Get(gid) if err == ErrNoRows { //log.Print("aaaaa monsters") - return common.NotFound(w, r) + return common.NotFound(w, r, headerVars) } else if err != nil { return common.InternalError(err, w, r) } @@ -2044,10 +2042,8 @@ func routePanelGroupsEdit(w http.ResponseWriter, r *http.Request, user common.Us disableRank := !user.Perms.EditGroupGlobalPerms || (group.ID == 6) pi := common.PanelEditGroupPage{common.GetTitlePhrase("panel_edit_group"), user, headerVars, stats, "groups", group.ID, group.Name, group.Tag, rank, disableRank} - if common.PreRenderHooks["pre_render_panel_edit_group"] != nil { - if common.RunPreRenderHook("pre_render_panel_edit_group", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_panel_edit_group", w, r, &user, &pi) { + return nil } err = common.Templates.ExecuteTemplate(w, "panel-group-edit.html", pi) if err != nil { @@ -2073,7 +2069,7 @@ func routePanelGroupsEditPerms(w http.ResponseWriter, r *http.Request, user comm group, err := common.Groups.Get(gid) if err == ErrNoRows { //log.Print("aaaaa monsters") - return common.NotFound(w, r) + return common.NotFound(w, r, headerVars) } else if err != nil { return common.InternalError(err, w, r) } @@ -2132,10 +2128,8 @@ func routePanelGroupsEditPerms(w http.ResponseWriter, r *http.Request, user comm addGlobalPerm("UploadFiles", group.Perms.UploadFiles) pi := common.PanelEditGroupPermsPage{common.GetTitlePhrase("panel_edit_group"), user, headerVars, stats, "groups", group.ID, group.Name, localPerms, globalPerms} - if common.PreRenderHooks["pre_render_panel_edit_group_perms"] != nil { - if common.RunPreRenderHook("pre_render_panel_edit_group_perms", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_panel_edit_group_perms", w, r, &user, &pi) { + return nil } err = common.Templates.ExecuteTemplate(w, "panel-group-edit-perms.html", pi) if err != nil { @@ -2161,7 +2155,7 @@ func routePanelGroupsEditSubmit(w http.ResponseWriter, r *http.Request, user com group, err := common.Groups.Get(gid) if err == ErrNoRows { //log.Print("aaaaa monsters") - return common.NotFound(w, r) + return common.NotFound(w, r, nil) } else if err != nil { return common.InternalError(err, w, r) } @@ -2252,7 +2246,7 @@ func routePanelGroupsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use group, err := common.Groups.Get(gid) if err == ErrNoRows { //log.Print("aaaaa monsters o.o") - return common.NotFound(w, r) + return common.NotFound(w, r, nil) } else if err != nil { return common.InternalError(err, w, r) } @@ -2444,7 +2438,7 @@ func routePanelBackups(w http.ResponseWriter, r *http.Request, user common.User, if ext == ".sql" { info, err := os.Stat("./backups/" + backupURL) if err != nil { - return common.NotFound(w, r) + return common.NotFound(w, r, headerVars) } // TODO: Change the served filename to gosora_backup_%timestamp%.sql, the time the file was generated, not when it was modified aka what the name of it should be w.Header().Set("Content-Disposition", "attachment; filename=gosora_backup.sql") @@ -2453,7 +2447,7 @@ func routePanelBackups(w http.ResponseWriter, r *http.Request, user common.User, http.ServeFile(w, r, "./backups/"+backupURL) return nil } - return common.NotFound(w, r) + return common.NotFound(w, r, headerVars) } var backupList []common.BackupItem @@ -2487,23 +2481,34 @@ func handleUnknownTopic(topic *common.Topic, err error) *common.Topic { return topic } +// TODO: Move the log building logic into /common/ and it's own abstraction +func topicElementTypeAction(action string, elementType string, elementID int, actor *common.User, topic *common.Topic) (out string) { + if action == "delete" { + return fmt.Sprintf("Topic #%d was deleted by %s", elementID, actor.Link, actor.Name) + } + + switch action { + case "lock": + out = "%s was locked by %s" + case "unlock": + out = "%s was reopened by %s" + case "stick": + out = "%s was pinned by %s" + case "unstick": + out = "%s was unpinned by %s" + case "move": + out = "%s was moved by %s" // TODO: Add where it was moved to, we'll have to change the source data for that, most likely? Investigate that and try to work this in + default: + return fmt.Sprintf("Unknown action '%s' on elementType '%s' by %s", action, elementType, actor.Link, actor.Name) + } + return fmt.Sprintf(out, topic.Link, topic.Title, actor.Link, actor.Name) +} + func modlogsElementType(action string, elementType string, elementID int, actor *common.User) (out string) { switch elementType { case "topic": topic := handleUnknownTopic(common.Topics.Get(elementID)) - switch action { - case "lock": - out = "%s was locked by %s" - case "unlock": - out = "%s was reopened by %s" - case "stick": - out = "%s was pinned by %s" - case "unstick": - out = "%s was unpinned by %s" - case "delete": - return fmt.Sprintf("Topic #%d was deleted by %s", elementID, actor.Link, actor.Name) - } - out = fmt.Sprintf(out, topic.Link, topic.Title, actor.Link, actor.Name) + out = topicElementTypeAction(action, elementType, elementID, actor, topic) case "user": targetUser := handleUnknownUser(common.Users.Get(elementID)) switch action { @@ -2521,6 +2526,7 @@ func modlogsElementType(action string, elementType string, elementID int, actor out = fmt.Sprintf("A reply in %s was deleted by %s", topic.Link, topic.Title, actor.Link, actor.Name) } } + if out == "" { out = fmt.Sprintf("Unknown action '%s' on elementType '%s' by %s", action, elementType, actor.Link, actor.Name) } diff --git a/query_gen/lib/mssql.go b/query_gen/lib/mssql.go index ef21ce1d..b9d4fcfe 100644 --- a/query_gen/lib/mssql.go +++ b/query_gen/lib/mssql.go @@ -1123,9 +1123,7 @@ type Stmts struct { // nolint func _gen_mssql() (err error) { - if common.Dev.DebugMode { - log.Print("Building the generated statements") - } + common.DebugLog("Building the generated statements") ` + body + ` return nil } diff --git a/query_gen/lib/mysql.go b/query_gen/lib/mysql.go index 8686ff17..433f9d6c 100644 --- a/query_gen/lib/mysql.go +++ b/query_gen/lib/mysql.go @@ -684,9 +684,7 @@ type Stmts struct { // nolint func _gen_mysql() (err error) { - if common.Dev.DebugMode { - log.Print("Building the generated statements") - } + common.DebugLog("Building the generated statements") ` + body + ` return nil } diff --git a/query_gen/lib/pgsql.go b/query_gen/lib/pgsql.go index fa676e12..ae9a3e44 100644 --- a/query_gen/lib/pgsql.go +++ b/query_gen/lib/pgsql.go @@ -381,9 +381,7 @@ type Stmts struct { // nolint func _gen_pgsql() (err error) { - if common.Dev.DebugMode { - log.Print("Building the generated statements") - } + common.DebugLog("Building the generated statements") ` + body + ` return nil } diff --git a/query_gen/tables.go b/query_gen/tables.go index 9965b948..5a99b42c 100644 --- a/query_gen/tables.go +++ b/query_gen/tables.go @@ -433,16 +433,14 @@ func createTables(adapter qgen.Adapter) error { []qgen.DBTableKey{}, ) - /* - qgen.Install.CreateTable("viewchunks_forums", "", "", - []qgen.DBTableColumn{ - qgen.DBTableColumn{"count", "int", 0, false, false, "0"}, - qgen.DBTableColumn{"createdAt", "datetime", 0, false, false, ""}, - qgen.DBTableColumn{"forum", "int", 0, false, false, ""}, - }, - []qgen.DBTableKey{}, - ) - */ + qgen.Install.CreateTable("viewchunks_forums", "", "", + []qgen.DBTableColumn{ + qgen.DBTableColumn{"count", "int", 0, false, false, "0"}, + qgen.DBTableColumn{"createdAt", "datetime", 0, false, false, ""}, + qgen.DBTableColumn{"forum", "int", 0, false, false, ""}, + }, + []qgen.DBTableKey{}, + ) qgen.Install.CreateTable("topicchunks", "", "", []qgen.DBTableColumn{ diff --git a/router.go b/router.go index a966dff2..d3a58801 100644 --- a/router.go +++ b/router.go @@ -63,5 +63,5 @@ func (router *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } //log.Print("req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/')]",req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/')]) - common.NotFound(w, req) + common.NotFound(w, req,nil) } diff --git a/router_gen/main.go b/router_gen/main.go index 9ad0c57d..fee0ee16 100644 --- a/router_gen/main.go +++ b/router_gen/main.go @@ -70,7 +70,7 @@ func main() { var end = len(route.Path) - 1 out += "\n\t\tcase \"" + route.Path[0:end] + "\":" out += runBefore(route.RunBefore, 4) - out += "\n\t\t\tcommon.RouteViewCounter.Bump(" + strconv.Itoa(allRouteMap[route.Name]) + ")" + out += "\n\t\t\tcounters.RouteViewCounter.Bump(" + strconv.Itoa(allRouteMap[route.Name]) + ")" out += "\n\t\t\terr = " + route.Name + "(w,req,user" for _, item := range route.Vars { out += "," + item @@ -128,7 +128,7 @@ func main() { } } } - out += "\n\t\t\t\t\tcommon.RouteViewCounter.Bump(" + strconv.Itoa(allRouteMap[route.Name]) + ")" + out += "\n\t\t\t\t\tcounters.RouteViewCounter.Bump(" + strconv.Itoa(allRouteMap[route.Name]) + ")" out += "\n\t\t\t\t\terr = " + route.Name + "(w,req,user" for _, item := range route.Vars { out += "," + item @@ -140,7 +140,7 @@ func main() { mapIt(defaultRoute.Name) out += "\n\t\t\t\tdefault:" out += runBefore(defaultRoute.RunBefore, 4) - out += "\n\t\t\t\t\tcommon.RouteViewCounter.Bump(" + strconv.Itoa(allRouteMap[defaultRoute.Name]) + ")" + out += "\n\t\t\t\t\tcounters.RouteViewCounter.Bump(" + strconv.Itoa(allRouteMap[defaultRoute.Name]) + ")" out += "\n\t\t\t\t\terr = " + defaultRoute.Name + "(w,req,user" for _, item := range defaultRoute.Vars { out += ", " + item @@ -157,6 +157,7 @@ func main() { // Stubs for us to refer to these routes through mapIt("routeDynamic") mapIt("routeUploads") + mapIt("routes.StaticFile") mapIt("BadRoute") tmplVars.AllRouteNames = allRouteNames tmplVars.AllRouteMap = allRouteMap @@ -224,6 +225,7 @@ import ( "net/http" "./common" + "./common/counters" "./routes" ) @@ -287,12 +289,12 @@ var markToAgent = map[string]string{ // TODO: Stop spilling these into the package scope? func init() { - common.SetRouteMapEnum(routeMapEnum) - common.SetReverseRouteMapEnum(reverseRouteMapEnum) - common.SetAgentMapEnum(agentMapEnum) - common.SetReverseAgentMapEnum(reverseAgentMapEnum) - common.SetOSMapEnum(osMapEnum) - common.SetReverseOSMapEnum(reverseOSMapEnum) + counters.SetRouteMapEnum(routeMapEnum) + counters.SetReverseRouteMapEnum(reverseRouteMapEnum) + counters.SetAgentMapEnum(agentMapEnum) + counters.SetReverseAgentMapEnum(reverseAgentMapEnum) + counters.SetOSMapEnum(osMapEnum) + counters.SetReverseOSMapEnum(reverseOSMapEnum) } type GenRouter struct { @@ -359,7 +361,7 @@ func (router *GenRouter) DumpRequest(req *http.Request) { func (router *GenRouter) SuspiciousRequest(req *http.Request) { log.Print("Suspicious Request") router.DumpRequest(req) - common.AgentViewCounter.Bump({{.AllAgentMap.suspicious}}) + counters.AgentViewCounter.Bump({{.AllAgentMap.suspicious}}) } // TODO: Pass the default route or config struct to the router rather than accessing it via a package global @@ -392,7 +394,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { w.Write([]byte("")) log.Print("Malformed Request") router.DumpRequest(req) - common.AgentViewCounter.Bump({{.AllAgentMap.malformed}}) + counters.AgentViewCounter.Bump({{.AllAgentMap.malformed}}) return } @@ -422,8 +424,11 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { log.Print("before routes.StaticFile") router.DumpRequest(req) } + // Increment the request counter + counters.GlobalViewCounter.Bump() if prefix == "/static" { + counters.RouteViewCounter.Bump({{ index .AllRouteMap "routes.StaticFile" }}) req.URL.Path += extraData routes.StaticFile(w, req) return @@ -432,15 +437,12 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { log.Print("before PreRoute") } - // Increment the global view counter - common.GlobalViewCounter.Bump() - // Track the user agents. Unfortunately, everyone pretends to be Mozilla, so this'll be a little less efficient than I would like. // TODO: Add a setting to disable this? // TODO: Use a more efficient detector instead of smashing every possible combination in ua := strings.TrimSpace(strings.Replace(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36","",-1)) // Noise, no one's going to be running this and it would require some sort of agent ranking system to determine which identifier should be prioritised over another if ua == "" { - common.AgentViewCounter.Bump({{.AllAgentMap.blank}}) + counters.AgentViewCounter.Bump({{.AllAgentMap.blank}}) if common.Dev.DebugMode { log.Print("Blank UA: ", req.UserAgent()) router.DumpRequest(req) @@ -540,15 +542,15 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } if agent == "" { - common.AgentViewCounter.Bump({{.AllAgentMap.unknown}}) + counters.AgentViewCounter.Bump({{.AllAgentMap.unknown}}) if common.Dev.DebugMode { log.Print("Unknown UA: ", req.UserAgent()) router.DumpRequest(req) } } else { - common.AgentViewCounter.Bump(agentMapEnum[agent]) + counters.AgentViewCounter.Bump(agentMapEnum[agent]) } - common.OSViewCounter.Bump(osMapEnum[os]) + counters.OSViewCounter.Bump(osMapEnum[os]) } referrer := req.Header.Get("Referer") // Check the 'referrer' header too? :P @@ -558,7 +560,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { referrer = strings.Split(referrer,"/")[0] portless := strings.Split(referrer,":")[0] if portless != "localhost" && portless != "127.0.0.1" && portless != common.Site.Host { - common.ReferrerTracker.Bump(referrer) + counters.ReferrerTracker.Bump(referrer) } } @@ -582,10 +584,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { }*/ case "/uploads": if extraData == "" { - common.NotFound(w,req) + common.NotFound(w,req,nil) return } - common.RouteViewCounter.Bump({{.AllRouteMap.routeUploads}}) + counters.RouteViewCounter.Bump({{.AllRouteMap.routeUploads}}) req.URL.Path += extraData // TODO: Find a way to propagate errors up from this? router.UploadHandler(w,req) // TODO: Count these views @@ -607,7 +609,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return*/ } if extraData != "" { - common.NotFound(w,req) + common.NotFound(w,req,nil) return } @@ -615,10 +617,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { if !ok { // TODO: Make this a startup error not a runtime one log.Print("Unable to find the default route") - common.NotFound(w,req) + common.NotFound(w,req,nil) return } - common.RouteViewCounter.Bump(routeMapEnum[common.Config.DefaultRoute]) + counters.RouteViewCounter.Bump(routeMapEnum[common.Config.DefaultRoute]) handle.(func(http.ResponseWriter, *http.Request, common.User) common.RouteError)(w,req,user) default: @@ -628,7 +630,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { router.RUnlock() if ok { - common.RouteViewCounter.Bump({{.AllRouteMap.routeDynamic}}) // TODO: Be more specific about *which* dynamic route it is + counters.RouteViewCounter.Bump({{.AllRouteMap.routeDynamic}}) // TODO: Be more specific about *which* dynamic route it is req.URL.Path += extraData err = handle(w,req,user) if err != nil { @@ -642,8 +644,8 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { if strings.Contains(lowerPath,"admin") || strings.Contains(lowerPath,"sql") || strings.Contains(lowerPath,"manage") || strings.Contains(lowerPath,"//") || strings.Contains(lowerPath,"\\\\") || strings.Contains(lowerPath,"wp") || strings.Contains(lowerPath,"wordpress") || strings.Contains(lowerPath,"config") || strings.Contains(lowerPath,"setup") || strings.Contains(lowerPath,"install") || strings.Contains(lowerPath,"update") || strings.Contains(lowerPath,"php") { router.SuspiciousRequest(req) } - common.RouteViewCounter.Bump({{.AllRouteMap.BadRoute}}) - common.NotFound(w,req) + counters.RouteViewCounter.Bump({{.AllRouteMap.BadRoute}}) + common.NotFound(w,req,nil) } } ` diff --git a/routes.go b/routes.go index 25d79803..5f9b2e0b 100644 --- a/routes.go +++ b/routes.go @@ -64,15 +64,15 @@ func routeForum(w http.ResponseWriter, r *http.Request, user common.User, sfid s if !user.Perms.ViewTopic { return common.NoPermissions(w, r, user) } + headerVars.Zone = "view_forum" // TODO: Fix this double-check forum, err := common.Forums.Get(fid) if err == ErrNoRows { - return common.NotFound(w, r) + return common.NotFound(w, r, headerVars) } else if err != nil { return common.InternalError(err, w, r) } - headerVars.Zone = "view_forum" // TODO: Does forum.TopicCount take the deleted items into consideration for guests? We don't have soft-delete yet, only hard-delete offset, page, lastPage := common.PageOffset(forum.TopicCount, page, common.Config.ItemsPerPage) @@ -130,10 +130,8 @@ func routeForum(w http.ResponseWriter, r *http.Request, user common.User, sfid s pageList := common.Paginate(forum.TopicCount, common.Config.ItemsPerPage, 5) pi := common.ForumPage{forum.Name, user, headerVars, topicList, forum, pageList, page, lastPage} - if common.PreRenderHooks["pre_render_forum"] != nil { - if common.RunPreRenderHook("pre_render_forum", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_forum", w, r, &user, &pi) { + return nil } err = common.RunThemeTemplate(headerVars.Theme.Name, "forum", pi, w) if err != nil { @@ -180,18 +178,14 @@ func routeForums(w http.ResponseWriter, r *http.Request, user common.User) commo } else { forum.LastTopicTime = "" } - if common.Hooks["forums_frow_assign"] != nil { - common.RunHook("forums_frow_assign", &forum) - } + common.RunHook("forums_frow_assign", &forum) forumList = append(forumList, forum) } } pi := common.ForumsPage{common.GetTitlePhrase("forums"), user, headerVars, forumList} - if common.PreRenderHooks["pre_render_forum_list"] != nil { - if common.RunPreRenderHook("pre_render_forum_list", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_forum_list", w, r, &user, &pi) { + return nil } err = common.RunThemeTemplate(headerVars.Theme.Name, "forums", pi, w) if err != nil { @@ -233,7 +227,7 @@ func routeProfile(w http.ResponseWriter, r *http.Request, user common.User) comm // TODO: Add a shared function for checking for ErrNoRows and internal erroring if it's not that case? puser, err = common.Users.Get(pid) if err == ErrNoRows { - return common.NotFound(w, r) + return common.NotFound(w, r, headerVars) } else if err != nil { return common.InternalError(err, w, r) } @@ -288,10 +282,8 @@ func routeProfile(w http.ResponseWriter, r *http.Request, user common.User) comm // TODO: Add a phrase for this title ppage := common.ProfilePage{puser.Name + "'s Profile", user, headerVars, replyList, *puser} - if common.PreRenderHooks["pre_render_profile"] != nil { - if common.RunPreRenderHook("pre_render_profile", w, r, &user, &ppage) { - return nil - } + if common.RunPreRenderHook("pre_render_profile", w, r, &user, &ppage) { + return nil } err = common.RunThemeTemplate(headerVars.Theme.Name, "profile", ppage, w) diff --git a/routes/account.go b/routes/account.go index 7684809d..e3ef6656 100644 --- a/routes/account.go +++ b/routes/account.go @@ -22,10 +22,8 @@ func AccountLogin(w http.ResponseWriter, r *http.Request, user common.User) comm return common.LocalError("You're already logged in.", w, r, user) } pi := common.Page{common.GetTitlePhrase("login"), user, headerVars, tList, nil} - if common.PreRenderHooks["pre_render_login"] != nil { - if common.RunPreRenderHook("pre_render_login", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_login", w, r, &user, &pi) { + return nil } err := common.Templates.ExecuteTemplate(w, "login.html", pi) if err != nil { @@ -83,10 +81,8 @@ func AccountRegister(w http.ResponseWriter, r *http.Request, user common.User) c return common.LocalError("You're already logged in.", w, r, user) } pi := common.Page{common.GetTitlePhrase("register"), user, headerVars, tList, nil} - if common.PreRenderHooks["pre_render_register"] != nil { - if common.RunPreRenderHook("pre_render_register", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_register", w, r, &user, &pi) { + return nil } err := common.Templates.ExecuteTemplate(w, "register.html", pi) if err != nil { @@ -124,9 +120,7 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.U } confirmPassword := r.PostFormValue("confirm_password") - if common.Dev.DebugMode { - log.Print("Registration Attempt! Username: " + username) // TODO: Add more controls over what is logged when? - } + common.DebugLog("Registration Attempt! Username: " + username) // TODO: Add more controls over what is logged when? // Do the two inputted passwords match..? if password != confirmPassword { @@ -187,10 +181,8 @@ func AccountEditCritical(w http.ResponseWriter, r *http.Request, user common.Use } pi := common.Page{"Edit Password", user, headerVars, tList, nil} - if common.PreRenderHooks["pre_render_account_own_edit_critical"] != nil { - if common.RunPreRenderHook("pre_render_account_own_edit_critical", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_account_own_edit_critical", w, r, &user, &pi) { + return nil } err := common.Templates.ExecuteTemplate(w, "account_own_edit.html", pi) if err != nil { diff --git a/routes/misc.go b/routes/misc.go index 39955f1e..677583ba 100644 --- a/routes/misc.go +++ b/routes/misc.go @@ -3,7 +3,6 @@ package routes import ( "bytes" "io" - "log" "net/http" "strconv" "strings" @@ -18,9 +17,7 @@ var cacheControlMaxAge = "max-age=" + strconv.Itoa(common.Day) // TODO: Make thi func StaticFile(w http.ResponseWriter, r *http.Request) { file, ok := common.StaticFiles.Get(r.URL.Path) if !ok { - if common.Dev.DebugMode { - log.Printf("Failed to find '%s'", r.URL.Path) - } + common.DebugLogf("Failed to find '%s'", r.URL.Path) w.WriteHeader(http.StatusNotFound) return } @@ -55,12 +52,9 @@ func Overview(w http.ResponseWriter, r *http.Request, user common.User) common.R headerVars.Zone = "overview" pi := common.Page{common.GetTitlePhrase("overview"), user, headerVars, tList, nil} - if common.PreRenderHooks["pre_render_overview"] != nil { - if common.RunPreRenderHook("pre_render_overview", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_overview", w, r, &user, &pi) { + return nil } - err := common.Templates.ExecuteTemplate(w, "overview.html", pi) if err != nil { return common.InternalError(err, w, r) @@ -73,19 +67,17 @@ func CustomPage(w http.ResponseWriter, r *http.Request, user common.User, name s if ferr != nil { return ferr } + headerVars.Zone = "custom_page" // ! Is this safe? if common.Templates.Lookup("page_"+name+".html") == nil { - return common.NotFound(w, r) + return common.NotFound(w, r, headerVars) } - headerVars.Zone = "custom_page" pi := common.Page{common.GetTitlePhrase("page"), user, headerVars, tList, nil} // TODO: Pass the page name to the pre-render hook? - if common.PreRenderHooks["pre_render_custom_page"] != nil { - if common.RunPreRenderHook("pre_render_custom_page", w, r, &user, &pi) { - return nil - } + if common.RunPreRenderHook("pre_render_custom_page", w, r, &user, &pi) { + return nil } err := common.Templates.ExecuteTemplate(w, "page_"+name+".html", pi) diff --git a/routes/moderate.go b/routes/moderate.go index db850b86..1116e003 100644 --- a/routes/moderate.go +++ b/routes/moderate.go @@ -31,11 +31,9 @@ func IPSearch(w http.ResponseWriter, r *http.Request, user common.User) common.R } pi := common.IPSearchPage{common.GetTitlePhrase("ip-search"), user, headerVars, userList, ip} - if common.PreRenderHooks["pre_render_ip_search"] != nil { - if common.RunPreRenderHook("pre_render_ip_search", w, r, &user, &pi) { + if common.RunPreRenderHook("pre_render_ip_search", w, r, &user, &pi) { return nil } - } err = common.Templates.ExecuteTemplate(w, "ip-search.html", pi) if err != nil { return common.InternalError(err, w, r) diff --git a/routes/topic.go b/routes/topic.go index 037e55dd..42d9d9f9 100644 --- a/routes/topic.go +++ b/routes/topic.go @@ -15,6 +15,7 @@ import ( "strings" "../common" + "../common/counters" "../query_gen/lib" ) @@ -54,7 +55,7 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, urlBit // Get the topic... topic, err := common.GetTopicUser(tid) if err == sql.ErrNoRows { - return common.NotFound(w, r) + return common.NotFound(w, r, nil) // TODO: Can we add a simplified invocation of headerVars here? This is likely to be an extremely common NotFound } else if err != nil { return common.InternalError(err, w, r) } @@ -182,16 +183,14 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, urlBit } } - if common.PreRenderHooks["pre_render_view_topic"] != nil { - if common.RunPreRenderHook("pre_render_view_topic", w, r, &user, &tpage) { - return nil - } + if common.RunPreRenderHook("pre_render_view_topic", w, r, &user, &tpage) { + return nil } err = common.RunThemeTemplate(headerVars.Theme.Name, "topic", tpage, w) if err != nil { return common.InternalError(err, w, r) } - common.TopicViewCounter.Bump(topic.ID) // TODO: Move this into the router? + counters.TopicViewCounter.Bump(topic.ID) // TODO: Move this into the router? return nil } @@ -256,6 +255,7 @@ func CreateTopic(w http.ResponseWriter, r *http.Request, user common.User, sfid forum := common.Forums.DirtyGet(ffid) if forum.Name != "" && forum.Active { fcopy := forum.Copy() + // TODO: Abstract this if common.Hooks["topic_create_frow_assign"] != nil { // TODO: Add the skip feature to all the other row based hooks? if common.RunHook("topic_create_frow_assign", &fcopy).(bool) { @@ -267,10 +267,8 @@ func CreateTopic(w http.ResponseWriter, r *http.Request, user common.User, sfid } ctpage := common.CreateTopicPage{"Create Topic", user, headerVars, forumList, fid} - if common.PreRenderHooks["pre_render_create_topic"] != nil { - if common.RunPreRenderHook("pre_render_create_topic", w, r, &user, &ctpage) { - return nil - } + if common.RunPreRenderHook("pre_render_create_topic", w, r, &user, &ctpage) { + return nil } err = common.RunThemeTemplate(headerVars.Theme.Name, "create_topic", ctpage, w) @@ -382,9 +380,7 @@ func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) } for _, file := range files { - if common.Dev.DebugMode { - log.Print("file.Filename ", file.Filename) - } + common.DebugLog("file.Filename ", file.Filename) extarr := strings.Split(file.Filename, ".") if len(extarr) < 2 { return common.LocalError("Bad file", w, r, user) @@ -441,8 +437,8 @@ func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) } } - common.PostCounter.Bump() - common.TopicCounter.Bump() + counters.PostCounter.Bump() + counters.TopicCounter.Bump() http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) return nil } diff --git a/routes/topic_list.go b/routes/topic_list.go index 0aed72ae..d8f1ddc1 100644 --- a/routes/topic_list.go +++ b/routes/topic_list.go @@ -43,15 +43,13 @@ func TopicList(w http.ResponseWriter, r *http.Request, user common.User) common. //log.Printf("topicList: %+v\n", topicList) //log.Printf("forumList: %+v\n", forumList) if len(topicList) == 0 { - return common.NotFound(w, r) + return common.NotFound(w, r, headerVars) } pi := common.TopicsPage{common.GetTitlePhrase("topics"), user, headerVars, topicList, forumList, common.Config.DefaultForum, pageList, page, lastPage} - if common.PreRenderHooks["pre_render_topic_list"] != nil { - if common.RunPreRenderHook("pre_render_topic_list", w, r, &user, &pi) { + if common.RunPreRenderHook("pre_render_topic_list", w, r, &user, &pi) { return nil } - } err = common.RunThemeTemplate(headerVars.Theme.Name, "topics", pi, w) if err != nil { return common.InternalError(err, w, r) diff --git a/schema/mssql/query_viewchunks_forums.sql b/schema/mssql/query_viewchunks_forums.sql new file mode 100644 index 00000000..56e54bdd --- /dev/null +++ b/schema/mssql/query_viewchunks_forums.sql @@ -0,0 +1,5 @@ +CREATE TABLE [viewchunks_forums] ( + [count] int DEFAULT 0 not null, + [createdAt] datetime not null, + [forum] int not null +); \ No newline at end of file diff --git a/schema/mysql/query_viewchunks_forums.sql b/schema/mysql/query_viewchunks_forums.sql new file mode 100644 index 00000000..34c01a71 --- /dev/null +++ b/schema/mysql/query_viewchunks_forums.sql @@ -0,0 +1,5 @@ +CREATE TABLE `viewchunks_forums` ( + `count` int DEFAULT 0 not null, + `createdAt` datetime not null, + `forum` int not null +); \ No newline at end of file diff --git a/schema/pgsql/query_viewchunks_forums.sql b/schema/pgsql/query_viewchunks_forums.sql new file mode 100644 index 00000000..60d539a0 --- /dev/null +++ b/schema/pgsql/query_viewchunks_forums.sql @@ -0,0 +1,5 @@ +CREATE TABLE `viewchunks_forums` ( + `count` int DEFAULT 0 not null, + `createdAt` timestamp not null, + `forum` int not null +); \ No newline at end of file diff --git a/template_list.go b/template_list.go index 138a12f4..f0336911 100644 --- a/template_list.go +++ b/template_list.go @@ -921,7 +921,7 @@ var forums_20 = []byte(`
`) -var forums_21 = []byte(`
You don't have access to any forums.
`) +var forums_21 = []byte(`
You don't have access to any forums.
`) var forums_22 = []byte(` @@ -1104,7 +1104,7 @@ var topics_58 = []byte(` `) -var topics_59 = []byte(`
There aren't any topics yet.`) +var topics_59 = []byte(`
There aren't any topics yet.`) var topics_60 = []byte(` Start one?`) var topics_61 = []byte(`
`) var topics_62 = []byte(` @@ -1279,7 +1279,7 @@ var forum_50 = []byte(`
`) -var forum_51 = []byte(`
There aren't any topics in this forum yet.`) +var forum_51 = []byte(`
There aren't any topics in this forum yet.`) var forum_52 = []byte(` Start one?`) var forum_54 = []byte(`
`) diff --git a/templates/are_you_sure.html b/templates/are_you_sure.html index df1dfa7b..c5fba07b 100644 --- a/templates/are_you_sure.html +++ b/templates/are_you_sure.html @@ -4,7 +4,7 @@

Are you sure?

-
{{.Something.Message}}

+
{{.Something.Message}}

Continue
diff --git a/templates/error.html b/templates/error.html index 5572a1e0..10f1c515 100644 --- a/templates/error.html +++ b/templates/error.html @@ -4,7 +4,7 @@

An error has occured

-
{{.Something}}
+
{{.Something}}
{{template "footer.html" . }} diff --git a/templates/forum.html b/templates/forum.html index d506ca9c..b7b76ec9 100644 --- a/templates/forum.html +++ b/templates/forum.html @@ -98,7 +98,7 @@ {{.RelativeLastReplyAt}} - {{else}}
There aren't any topics in this forum yet.{{if .CurrentUser.Perms.CreateTopic}} Start one?{{end}}
{{end}} + {{else}}
There aren't any topics in this forum yet.{{if .CurrentUser.Perms.CreateTopic}} Start one?{{end}}
{{end}} {{if gt .LastPage 1}} diff --git a/templates/forums.html b/templates/forums.html index b8de4a45..3b130c36 100644 --- a/templates/forums.html +++ b/templates/forums.html @@ -25,7 +25,7 @@
- {{else}}
You don't have access to any forums.
{{end}} + {{else}}
You don't have access to any forums.
{{end}} diff --git a/templates/panel_analytics_agents.html b/templates/panel_analytics_agents.html index 44d2bc4e..aea783a0 100644 --- a/templates/panel_analytics_agents.html +++ b/templates/panel_analytics_agents.html @@ -22,7 +22,7 @@ {{.FriendlyAgent}} {{.Count}} views - {{end}} + {{else}}
No user agents could be found in the selected time range
{{end}} diff --git a/templates/panel_analytics_posts.html b/templates/panel_analytics_posts.html index 1aa02f2a..16d04fbb 100644 --- a/templates/panel_analytics_posts.html +++ b/templates/panel_analytics_posts.html @@ -28,7 +28,7 @@ {{.Time}} {{.Count}} views - {{end}} + {{else}}
No posts could be found in the selected time range
{{end}} diff --git a/templates/panel_analytics_referrers.html b/templates/panel_analytics_referrers.html index 9ad69dc4..72c079aa 100644 --- a/templates/panel_analytics_referrers.html +++ b/templates/panel_analytics_referrers.html @@ -22,7 +22,7 @@ {{.Agent}} {{.Count}} views - {{end}} + {{else}}
No referrers could be found in the selected time range
{{end}} diff --git a/templates/panel_analytics_routes.html b/templates/panel_analytics_routes.html index ed960cc1..f2e4cbe0 100644 --- a/templates/panel_analytics_routes.html +++ b/templates/panel_analytics_routes.html @@ -22,7 +22,7 @@ {{.Route}} {{.Count}} views - {{end}} + {{else}}
No route view counts could be found in the selected time range
{{end}} diff --git a/templates/panel_analytics_systems.html b/templates/panel_analytics_systems.html index 92c683b0..af80a0ea 100644 --- a/templates/panel_analytics_systems.html +++ b/templates/panel_analytics_systems.html @@ -22,7 +22,7 @@ {{.FriendlyAgent}} {{.Count}} views - {{end}} + {{else}}
No operating systems could be found in the selected time range
{{end}} diff --git a/templates/panel_backups.html b/templates/panel_backups.html index ffb5fdc9..40740dd6 100644 --- a/templates/panel_backups.html +++ b/templates/panel_backups.html @@ -14,7 +14,7 @@ {{else}} -
There aren't any backups available at this time.
+
There aren't any backups available at this time.
{{end}} diff --git a/templates/panel_word_filters.html b/templates/panel_word_filters.html index 556225de..e724338b 100644 --- a/templates/panel_word_filters.html +++ b/templates/panel_word_filters.html @@ -19,7 +19,7 @@ {{else}} -
+ {{end}} diff --git a/templates/topics.html b/templates/topics.html index 7ed93f4d..b6ebd30c 100644 --- a/templates/topics.html +++ b/templates/topics.html @@ -123,7 +123,7 @@ {{.RelativeLastReplyAt}}
- {{else}}
There aren't any topics yet.{{if .CurrentUser.Perms.CreateTopic}} Start one?{{end}}
{{end}} + {{else}}
There aren't any topics yet.{{if .CurrentUser.Perms.CreateTopic}} Start one?{{end}}
{{end}} {{if gt .LastPage 1}} diff --git a/themes/cosora/public/main.css b/themes/cosora/public/main.css index c9a2feff..c86dd64b 100644 --- a/themes/cosora/public/main.css +++ b/themes/cosora/public/main.css @@ -232,6 +232,7 @@ ul { margin-left: 12px; } /* TODO: Reduce the number of nots */ +/* TODO: Apply the property to the rowitem on the colstack_head rather than the container itself */ .rowblock:not(.topic_list):not(.forum_list):not(.post_container):not(.topic_reply_container), .colstack_head, .topic_row .rowitem, .forum_list .rowitem { background-color: var(--element-background-color); } @@ -269,6 +270,15 @@ h1, h3 { margin-bottom: 0px; } +.rowmsg.rowitem { + padding: 12px; +} +.topic_list .rowmsg.rowitem, +.forum_list .rowmsg.rowitem { + border: 1px solid var(--element-border-color); + border-bottom: 2px solid var(--element-border-color); +} + .colstack { display: flex; } @@ -692,8 +702,8 @@ textarea { margin-bottom: 8px; padding: 4px; display: flex; - border: 1px solid var(--element-border-color); - border-bottom: 2px solid var(--element-border-color); + border: 1px solid var(--element-border-color); + border-bottom: 2px solid var(--element-border-color); } .rowlist .rowitem { background-color: var(--element-background-color); diff --git a/themes/cosora/public/panel.css b/themes/cosora/public/panel.css index 0a126829..1094412f 100644 --- a/themes/cosora/public/panel.css +++ b/themes/cosora/public/panel.css @@ -39,12 +39,15 @@ } .colstack_right { margin-right: 14px; - margin-top: -4px; + /*margin-top: -4px;*/ margin-bottom: 14px; } .footer { margin-top: 0px; } +.colstack_right .colstack_head:not(:first-child) { + margin-top: 14px; +} .complex_rowlist { background-color: inherit !important; @@ -210,4 +213,10 @@ .pageset { margin-left: 16px; +} + +@media(max-width: 999px) { + .colstack_left { + margin-top: -14.5px; + } } \ No newline at end of file diff --git a/themes/tempra-conflux/public/panel.css b/themes/tempra-conflux/public/panel.css index c2621aa0..33818c8d 100644 --- a/themes/tempra-conflux/public/panel.css +++ b/themes/tempra-conflux/public/panel.css @@ -1,4 +1,10 @@ -/* Control Panel */ +/*.submenu { + padding-left: 18px; +}*/ +.submenu:before { + content:"–"; + margin-right: 8px; +} .edit_button:before { content: "Edit"; @@ -97,6 +103,18 @@ padding-right: 2px; } +.ct_chart { + padding-left: 10px; + padding-top: 18px; + padding-bottom: 2px; + padding-right: 10px; + margin-bottom: 12px; + + background-color: white; + border: 1px solid var(--main-border-color); + border-bottom: 1.5px inset var(--main-border-color); +} + @media(max-width: 1300px) { .theme_row { background-image: none !important; } } diff --git a/themes/tempra-simple/public/media.partial.css b/themes/tempra-simple/public/media.partial.css index 0f8fe378..40b2195a 100644 --- a/themes/tempra-simple/public/media.partial.css +++ b/themes/tempra-simple/public/media.partial.css @@ -20,7 +20,7 @@ } ul { height: 30px; - margin-top: 8px; + margin-top: 14px; } .menu_left, .menu_right { padding-right: 9px; } .menu_alerts { @@ -30,8 +30,8 @@ } body { - padding-left: 4px; - padding-right: 4px; + padding-left: 12px; + padding-right: 12px; margin: 0px !important; width: 100% !important; height: 100% !important;