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}} -
+
You don't have any word filters yet.
{{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;