Moved the counters to their own package.

De-duped some of the logging code.
Added per-route state to the not found errors.
Exported debugDetail, debugDetailf, debugLog, and debugLogf.
Tweaked the padding on Tempra Simple.
Added panel submenus to Tempra Conflux.
Added Chart CSS to Tempra Conflux.
Fixed the padding and margins for the Control Panel in Cosora.
Made Cosora's Control Panel a little more tablet friendly.
Added the rowmsg CSS class to better style message rows.
Removed the repetitive guard code for the pre-render hooks.
Removed the repetitive guard code for the string-string hooks.
We now capture views for routes.StaticFile
Added the move action to the moderation logs.

Added the viewchunks_forums table.
Began work on Per-forum Views.
I probably missed a few things in this changelog.
This commit is contained in:
Azareal 2018-02-19 04:26:01 +00:00
parent be47066770
commit 60964868d4
68 changed files with 1058 additions and 947 deletions

View File

@ -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

View File

@ -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)
}

View File

@ -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
}

View File

@ -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()
}
}

68
common/counters/agents.go Normal file
View File

@ -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()
}

42
common/counters/common.go Normal file
View File

@ -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
}

86
common/counters/forums.go Normal file
View File

@ -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

58
common/counters/posts.go Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

66
common/counters/routes.go Normal file
View File

@ -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()
}

View File

@ -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()
}

58
common/counters/topics.go Normal file
View File

@ -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
}

View File

@ -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()
}
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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?

View File

@ -173,9 +173,7 @@ func PreparseMessage(msg string) string {
msg = strings.Replace(msg, "</p>", "", -1)
msg = strings.Replace(msg, "<br>", "\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, "&nbsp;", "", -1)
@ -573,9 +571,7 @@ func ParseMessage(msg string, sectionID int, sectionType string /*, user User*/)
//log.Print("msg",`"`+msg+`"`)
msg = strings.Replace(msg, "\n", "<br>", -1)
if Sshooks["parse_assign"] != nil {
msg = RunSshook("parse_assign", msg)
}
msg = RunSshook("parse_assign", msg)
return msg
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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)

View File

@ -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))

View File

@ -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
})
}

View File

@ -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)

View File

@ -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
}

View File

@ -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))
}

View File

@ -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")

View File

@ -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` = ?")

View File

@ -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` = ?")

View File

@ -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)
}
}

19
main.go
View File

@ -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
}

View File

@ -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(&sectionID, &sectionTable, &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)
}

View File

@ -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 <a href='%s'>%s</a>", elementID, actor.Link, actor.Name)
}
switch action {
case "lock":
out = "<a href='%s'>%s</a> was locked by <a href='%s'>%s</a>"
case "unlock":
out = "<a href='%s'>%s</a> was reopened by <a href='%s'>%s</a>"
case "stick":
out = "<a href='%s'>%s</a> was pinned by <a href='%s'>%s</a>"
case "unstick":
out = "<a href='%s'>%s</a> was unpinned by <a href='%s'>%s</a>"
case "move":
out = "<a href='%s'>%s</a> was moved by <a href='%s'>%s</a>" // 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 <a href='%s'>%s</a>", 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 = "<a href='%s'>%s</a> was locked by <a href='%s'>%s</a>"
case "unlock":
out = "<a href='%s'>%s</a> was reopened by <a href='%s'>%s</a>"
case "stick":
out = "<a href='%s'>%s</a> was pinned by <a href='%s'>%s</a>"
case "unstick":
out = "<a href='%s'>%s</a> was unpinned by <a href='%s'>%s</a>"
case "delete":
return fmt.Sprintf("Topic #%d was deleted by <a href='%s'>%s</a>", 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 <a href='%s'>%s</a> was deleted by <a href='%s'>%s</a>", topic.Link, topic.Title, actor.Link, actor.Name)
}
}
if out == "" {
out = fmt.Sprintf("Unknown action '%s' on elementType '%s' by <a href='%s'>%s</a>", action, elementType, actor.Link, actor.Name)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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{

View File

@ -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)
}

View File

@ -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)
}
}
`

View File

@ -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)

View File

@ -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 {

View File

@ -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)

View File

@ -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)

View File

@ -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
}

View File

@ -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)

View File

@ -0,0 +1,5 @@
CREATE TABLE [viewchunks_forums] (
[count] int DEFAULT 0 not null,
[createdAt] datetime not null,
[forum] int not null
);

View File

@ -0,0 +1,5 @@
CREATE TABLE `viewchunks_forums` (
`count` int DEFAULT 0 not null,
`createdAt` datetime not null,
`forum` int not null
);

View File

@ -0,0 +1,5 @@
CREATE TABLE `viewchunks_forums` (
`count` int DEFAULT 0 not null,
`createdAt` timestamp not null,
`forum` int not null
);

View File

@ -921,7 +921,7 @@ var forums_20 = []byte(`
<div style="clear: both;"></div>
</div>
`)
var forums_21 = []byte(`<div class="rowitem passive">You don't have access to any forums.</div>`)
var forums_21 = []byte(`<div class="rowitem passive rowmsg">You don't have access to any forums.</div>`)
var forums_22 = []byte(`
</div>
@ -1104,7 +1104,7 @@ var topics_58 = []byte(`</span>
</span>
</div>
</div>`)
var topics_59 = []byte(`<div class="rowitem passive">There aren't any topics yet.`)
var topics_59 = []byte(`<div class="rowitem passive rowmsg">There aren't any topics yet.`)
var topics_60 = []byte(` <a href="/topics/create/">Start one?</a>`)
var topics_61 = []byte(`</div>`)
var topics_62 = []byte(`
@ -1279,7 +1279,7 @@ var forum_50 = []byte(`</span>
</span>
</div>
</div>`)
var forum_51 = []byte(`<div class="rowitem passive">There aren't any topics in this forum yet.`)
var forum_51 = []byte(`<div class="rowitem passive rowmsg">There aren't any topics in this forum yet.`)
var forum_52 = []byte(` <a href="/topics/create/`)
var forum_53 = []byte(`">Start one?</a>`)
var forum_54 = []byte(`</div>`)

View File

@ -4,7 +4,7 @@
<div class="rowitem"><h1>Are you sure?</h1></div>
</div>
<div class="rowblock">
<div class="rowitem passive">{{.Something.Message}}<br /><br />
<div class="rowitem passive rowmsg">{{.Something.Message}}<br /><br />
<a class="username" href="{{.Something.URL}}?session={{.CurrentUser.Session}}">Continue</a>
</div>
</div>

View File

@ -4,7 +4,7 @@
<div class="rowitem"><h1>An error has occured</h1></div>
</div>
<div class="rowblock">
<div class="rowitem passive">{{.Something}}</div>
<div class="rowitem passive rowmsg">{{.Something}}</div>
</div>
</main>
{{template "footer.html" . }}

View File

@ -98,7 +98,7 @@
<span class="rowsmall lastReplyAt">{{.RelativeLastReplyAt}}</span>
</span>
</div>
</div>{{else}}<div class="rowitem passive">There aren't any topics in this forum yet.{{if .CurrentUser.Perms.CreateTopic}} <a href="/topics/create/{{.Forum.ID}}">Start one?</a>{{end}}</div>{{end}}
</div>{{else}}<div class="rowitem passive rowmsg">There aren't any topics in this forum yet.{{if .CurrentUser.Perms.CreateTopic}} <a href="/topics/create/{{.Forum.ID}}">Start one?</a>{{end}}</div>{{end}}
</div>
{{if gt .LastPage 1}}

View File

@ -25,7 +25,7 @@
</span>
<div style="clear: both;"></div>
</div>
{{else}}<div class="rowitem passive">You don't have access to any forums.</div>{{end}}
{{else}}<div class="rowitem passive rowmsg">You don't have access to any forums.</div>{{end}}
</div>
</main>

View File

@ -22,7 +22,7 @@
<a href="/panel/analytics/agent/{{.Agent}}" class="panel_upshift">{{.FriendlyAgent}}</a>
<span class="panel_compacttext to_right">{{.Count}} views</span>
</div>
{{end}}
{{else}}<div class="rowitem passive rowmsg">No user agents could be found in the selected time range</div>{{end}}
</div>
</main>
</div>

View File

@ -28,7 +28,7 @@
<a class="panel_upshift unix_to_24_hour_time">{{.Time}}</a>
<span class="panel_compacttext to_right">{{.Count}} views</span>
</div>
{{end}}
{{else}}<div class="rowitem passive rowmsg">No posts could be found in the selected time range</div>{{end}}
</div>
</main>
</div>

View File

@ -22,7 +22,7 @@
<a href="/panel/analytics/referrer/{{.Agent}}" class="panel_upshift">{{.Agent}}</a>
<span class="panel_compacttext to_right">{{.Count}} views</span>
</div>
{{end}}
{{else}}<div class="rowitem passive rowmsg">No referrers could be found in the selected time range</div>{{end}}
</div>
</main>
</div>

View File

@ -22,7 +22,7 @@
<a href="/panel/analytics/route/{{.Route}}" class="panel_upshift">{{.Route}}</a>
<span class="panel_compacttext to_right">{{.Count}} views</span>
</div>
{{end}}
{{else}}<div class="rowitem passive rowmsg">No route view counts could be found in the selected time range</div>{{end}}
</div>
</main>
</div>

View File

@ -22,7 +22,7 @@
<a href="/panel/analytics/system/{{.Agent}}" class="panel_upshift">{{.FriendlyAgent}}</a>
<span class="panel_compacttext to_right">{{.Count}} views</span>
</div>
{{end}}
{{else}}<div class="rowitem passive rowmsg">No operating systems could be found in the selected time range</div>{{end}}
</div>
</main>
</div>

View File

@ -14,7 +14,7 @@
</span>
</div>
{{else}}
<div class="rowitem">There aren't any backups available at this time.</div>
<div class="rowitem rowmsg">There aren't any backups available at this time.</div>
{{end}}
</div>
</main>

View File

@ -19,7 +19,7 @@
</span>
</div>
{{else}}
<div class="rowitem editable_parent">
<div class="rowitem editable_parent rowmsg">
<a>You don't have any word filters yet.</a>
</div>
{{end}}

View File

@ -123,7 +123,7 @@
<span class="rowsmall lastReplyAt">{{.RelativeLastReplyAt}}</span>
</span>
</div>
</div>{{else}}<div class="rowitem passive">There aren't any topics yet.{{if .CurrentUser.Perms.CreateTopic}} <a href="/topics/create/">Start one?</a>{{end}}</div>{{end}}
</div>{{else}}<div class="rowitem passive rowmsg">There aren't any topics yet.{{if .CurrentUser.Perms.CreateTopic}} <a href="/topics/create/">Start one?</a>{{end}}</div>{{end}}
</div>
{{if gt .LastPage 1}}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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; }
}

View File

@ -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;