diff --git a/common/counters/topics_views.go b/common/counters/topics_views.go index 1b814d8f..81993ba0 100644 --- a/common/counters/topics_views.go +++ b/common/counters/topics_views.go @@ -2,11 +2,14 @@ package counters import ( "database/sql" + "strconv" + "strings" "sync" "sync/atomic" + "time" c "github.com/Azareal/Gosora/common" - "github.com/Azareal/Gosora/query_gen" + qgen "github.com/Azareal/Gosora/query_gen" "github.com/pkg/errors" ) @@ -19,19 +22,40 @@ type DefaultTopicViewCounter struct { oddLock sync.RWMutex evenLock sync.RWMutex - update *sql.Stmt + weekState byte + + update *sql.Stmt + resetOdd *sql.Stmt + resetEven *sql.Stmt + resetBoth *sql.Stmt } func NewDefaultTopicViewCounter() (*DefaultTopicViewCounter, error) { acc := qgen.NewAcc() + t := "topics" co := &DefaultTopicViewCounter{ oddTopics: make(map[int]*RWMutexCounterBucket), evenTopics: make(map[int]*RWMutexCounterBucket), - update: acc.Update("topics").Set("views = views + ?").Where("tid = ?").Prepare(), + + //update: acc.Update(t).Set("views=views+?").Where("tid=?").Prepare(), + update: acc.Update(t).Set("views=views+?,weekEvenViews=weekEvenViews+?,weekOddViews=weekOddViews+?").Where("tid=?").Prepare(), + resetOdd: acc.Update(t).Set("weekOddViews=0").Prepare(), + resetEven: acc.Update(t).Set("weekEvenViews=0").Prepare(), + resetBoth: acc.Update(t).Set("weekOddViews=0,weekEvenViews=0").Prepare(), } - c.AddScheduledFifteenMinuteTask(co.Tick) // Who knows how many topics we have queued up, we probably don't want this running too frequently - //c.AddScheduledSecondTask(co.Tick) - c.AddShutdownTask(co.Tick) + err := co.WeekResetInit() + if err != nil { + return co, err + } + + addTick := func(f func() error) { + c.AddScheduledFifteenMinuteTask(f) // Who knows how many topics we have queued up, we probably don't want this running too frequently + //c.AddScheduledSecondTask(f) + c.AddShutdownTask(f) + } + addTick(co.Tick) + addTick(co.WeekResetTick) + return co, acc.FirstError() } @@ -50,30 +74,87 @@ func (co *DefaultTopicViewCounter) Tick() error { l.Lock() delete(m, topicID) l.Unlock() - err := co.insertChunk(count, topicID) - if err != nil { - return errors.Wrap(errors.WithStack(err),"topicview counter") + e := co.insertChunk(count, topicID) + if e != nil { + return errors.Wrap(errors.WithStack(e), "topicview counter") } l.RLock() } l.RUnlock() return nil } - err := cLoop(&co.oddLock,co.oddTopics) + err := cLoop(&co.oddLock, co.oddTopics) if err != nil { return err } - return cLoop(&co.evenLock,co.evenTopics) + return cLoop(&co.evenLock, co.evenTopics) +} + +func (co *DefaultTopicViewCounter) WeekResetInit() error { + lastWeekResetStr, e := c.Meta.Get("lastWeekReset") + if e != nil && e != sql.ErrNoRows { + return e + } + + spl := strings.Split(lastWeekResetStr, "-") + if len(spl) <= 1 { + return nil + } + weekState, e := strconv.Atoi(spl[1]) + if e != nil { + return e + } + co.weekState = byte(weekState) + + unixLastWeekReset, e := strconv.ParseInt(spl[0], 10, 64) + if e != nil { + return e + } + resetTime := time.Unix(unixLastWeekReset, 0) + if time.Since(resetTime).Hours() >= (24 * 7) { + _, e = co.resetBoth.Exec() + } + return e +} + +func (co *DefaultTopicViewCounter) WeekResetTick() (e error) { + now := time.Now() + _, week := now.ISOWeek() + if week != int(co.weekState) { + if week%2 == 0 { // is even? + _, e = co.resetOdd.Exec() + } else { + _, e = co.resetEven.Exec() + } + co.weekState = byte(week) + } + // TODO: Retry? + if e != nil { + return e + } + return c.Meta.Set("lastWeekReset", strconv.FormatInt(now.Unix(), 10)+"-"+strconv.Itoa(week)) } // 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 (co *DefaultTopicViewCounter) insertChunk(count int, topicID int) error { +func (co *DefaultTopicViewCounter) insertChunk(count, topicID int) (err error) { if count == 0 { return nil } c.DebugLogf("Inserting %d views into topic %d", count, topicID) - _, err := co.update.Exec(count, topicID) + even, odd := 0, 0 + _, week := time.Now().ISOWeek() + if week%2 == 0 { // is even? + even += count + } else { + odd += count + } + + if true { + _, err = co.update.Exec(count, even, odd, topicID) + } else { + _, err = co.update.Exec(count, topicID) + } if err == sql.ErrNoRows { return nil } else if err != nil { @@ -81,15 +162,15 @@ func (co *DefaultTopicViewCounter) insertChunk(count int, topicID int) error { } // TODO: Add a way to disable this for extra speed ;) - tcache := c.Topics.GetCache() - if tcache != nil { - topic, err := tcache.Get(topicID) + tc := c.Topics.GetCache() + if tc != nil { + t, err := tc.Get(topicID) if err == sql.ErrNoRows { return nil } else if err != nil { return err } - atomic.AddInt64(&topic.ViewCount, int64(count)) + atomic.AddInt64(&t.ViewCount, int64(count)) } return nil @@ -99,12 +180,12 @@ func (co *DefaultTopicViewCounter) Bump(topicID int) { // Is the ID even? if topicID%2 == 0 { co.evenLock.RLock() - topic, ok := co.evenTopics[topicID] + t, ok := co.evenTopics[topicID] co.evenLock.RUnlock() if ok { - topic.Lock() - topic.counter++ - topic.Unlock() + t.Lock() + t.counter++ + t.Unlock() } else { co.evenLock.Lock() co.evenTopics[topicID] = &RWMutexCounterBucket{counter: 1} @@ -114,12 +195,12 @@ func (co *DefaultTopicViewCounter) Bump(topicID int) { } co.oddLock.RLock() - topic, ok := co.oddTopics[topicID] + t, ok := co.oddTopics[topicID] co.oddLock.RUnlock() if ok { - topic.Lock() - topic.counter++ - topic.Unlock() + t.Lock() + t.counter++ + t.Unlock() } else { co.oddLock.Lock() co.oddTopics[topicID] = &RWMutexCounterBucket{counter: 1} diff --git a/common/pages.go b/common/pages.go index f899add9..54a7f668 100644 --- a/common/pages.go +++ b/common/pages.go @@ -419,6 +419,7 @@ type BasePanelPage struct { Stats PanelStats Zone string ReportForumID int + DebugAdmin bool } type PanelPage struct { *BasePanelPage @@ -789,6 +790,15 @@ type PanelDebugPage struct { Disk DebugPageDisk } +type PanelDebugTaskTask struct { + Name string + Type int // 0 = halfsec, 1 = sec, 2 = fifteenmin, 3 = hour, 4 = shutdown +} +type PanelDebugTaskPage struct { + *BasePanelPage + Tasks []PanelDebugTaskTask +} + type PageSimple struct { Title string Something interface{} diff --git a/common/poll_store.go b/common/poll_store.go index 53f4a7d8..c9be2997 100644 --- a/common/poll_store.go +++ b/common/poll_store.go @@ -57,17 +57,17 @@ func NewDefaultPollStore(cache PollCache) (*DefaultPollStore, error) { get: acc.Select(p).Columns("parentID, parentTable, type, options, votes").Where("pollID=?").Prepare(), exists: acc.Select(p).Columns("pollID").Where("pollID=?").Prepare(), createPoll: acc.Insert(p).Columns("parentID, parentTable, type, options").Fields("?,?,?,?").Prepare(), - createPollOption: acc.Insert("polls_options").Columns("pollID, option, votes").Fields("?,?,0").Prepare(), + createPollOption: acc.Insert("polls_options").Columns("pollID,option,votes").Fields("?,?,0").Prepare(), //count: acc.SimpleCount(p, "", ""), }, acc.FirstError() } func (s *DefaultPollStore) Exists(id int) bool { - err := s.exists.QueryRow(id).Scan(&id) - if err != nil && err != ErrNoRows { - LogError(err) + e := s.exists.QueryRow(id).Scan(&id) + if e != nil && e != ErrNoRows { + LogError(e) } - return err != ErrNoRows + return e != ErrNoRows } func (s *DefaultPollStore) Get(id int) (*Poll, error) { @@ -198,33 +198,33 @@ func (s *DefaultPollStore) Reload(id int) error { } func (s *DefaultPollStore) unpackOptionsMap(rawOptions map[int]string) []PollOption { - options := make([]PollOption, len(rawOptions)) - for id, option := range rawOptions { - options[id] = PollOption{id, option} + opts := make([]PollOption, len(rawOptions)) + for id, opt := range rawOptions { + opts[id] = PollOption{id, opt} } - return options + return opts } // TODO: Use a transaction for this -func (s *DefaultPollStore) Create(parent Pollable, pollType int, pollOptions map[int]string) (id int, err error) { +func (s *DefaultPollStore) Create(parent Pollable, pollType int, pollOptions map[int]string) (id int, e error) { // TODO: Move the option names into the polls_options table and get rid of this json sludge? - pollOptionsTxt, err := json.Marshal(pollOptions) - if err != nil { - return 0, err + pollOptionsTxt, e := json.Marshal(pollOptions) + if e != nil { + return 0, e } - res, err := s.createPoll.Exec(parent.GetID(), parent.GetTable(), pollType, pollOptionsTxt) - if err != nil { - return 0, err + res, e := s.createPoll.Exec(parent.GetID(), parent.GetTable(), pollType, pollOptionsTxt) + if e != nil { + return 0, e } - lastID, err := res.LastInsertId() - if err != nil { - return 0, err + lastID, e := res.LastInsertId() + if e != nil { + return 0, e } for i := 0; i < len(pollOptions); i++ { - _, err := s.createPollOption.Exec(lastID, i) - if err != nil { - return 0, err + _, e := s.createPollOption.Exec(lastID, i) + if e != nil { + return 0, e } } diff --git a/common/template_init.go b/common/template_init.go index b26bfc8f..48c308b9 100644 --- a/common/template_init.go +++ b/common/template_init.go @@ -227,7 +227,7 @@ func compileCommons(c *tmpl.CTemplateSet, head, head2 *Header, forumList []Forum }*/ var topicsList []TopicsRowMut - topic := Topic{1, "/topic/topic-title.1", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 1, "classname", 0, "", nil} + topic := Topic{1, "/topic/topic-title.1", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 1, 1, "classname", 0, "", nil} topicsList = append(topicsList, TopicsRowMut{&TopicsRow{topic, 1, user2, "", 0, user3, "General", "/forum/general.2"}, false}) topicListPage := TopicListPage{htitle("Topic List"), topicsList, forumList, Config.DefaultForum, TopicListSort{"lastupdated", false}, []int{1}, QuickTools{false, false, false}, Paginator{[]int{1}, 1, 1}} o.Add("topics", "c.TopicListPage", topicListPage) @@ -311,7 +311,7 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string t.Add("profile", "c.ProfilePage", ppage) var topicsList []TopicsRowMut - topic := Topic{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 1, "classname", 0, "", nil} + topic := Topic{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 1, 1, "classname", 0, "", nil} topicsList = append(topicsList, TopicsRowMut{&TopicsRow{topic, 0, user2, "", 0, user3, "General", "/forum/general.2"}, false}) topicListPage := TopicListPage{htitle("Topic List"), topicsList, forumList, Config.DefaultForum, TopicListSort{"lastupdated", false}, []int{1}, QuickTools{false, false, false}, Paginator{[]int{1}, 1, 1}} @@ -375,7 +375,7 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string convoListPage := ConvoListPage{header, cRows, Paginator{[]int{1}, 1, 1}} t.AddStd("convos", "c.ConvoListPage", convoListPage) - basePage := &BasePanelPage{header, PanelStats{}, "dashboard", ReportForumID} + basePage := &BasePanelPage{header, PanelStats{}, "dashboard", ReportForumID, true} t.AddStd("panel", "c.Panel", Panel{basePage, "panel_dashboard_right", "", "panel_dashboard", inter}) ges := []GridElement{GridElement{"", "", "", 1, "grid_istat", "", "", ""}} t.AddStd("panel_dashboard", "c.DashGrids", DashGrids{ges, ges}) @@ -540,7 +540,7 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri t := TItemHold(make(map[string]TItem)) - topic := Topic{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 0, "classname", 1, "", nil} + topic := Topic{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 0, 1, "classname", 1, "", nil} topicsRow := TopicsRowMut{&TopicsRow{topic, 0, user2, "", 0, user3, "General", "/forum/general.2"}, false} t.AddStd("topics_topic", "c.TopicsRowMut", topicsRow) diff --git a/common/topic.go b/common/topic.go index 809e0b56..0727921e 100644 --- a/common/topic.go +++ b/common/topic.go @@ -45,6 +45,7 @@ type Topic struct { PostCount int LikeCount int AttachCount int + WeekViews int ClassName string // CSS Class Name Poll int Data string // Used for report metadata @@ -1137,6 +1138,7 @@ func GetTopicUser(user *User, tid int) (tu TopicUser, err error) { tu.Tag = Groups.DirtyGet(tu.Group).Tag if tcache != nil { + // TODO: weekly views theTopic := Topic{ID: tu.ID, Link: tu.Link, Title: tu.Title, Content: tu.Content, CreatedBy: tu.CreatedBy, IsClosed: tu.IsClosed, Sticky: tu.Sticky, CreatedAt: tu.CreatedAt, LastReplyAt: tu.LastReplyAt, LastReplyID: tu.LastReplyID, ParentID: tu.ParentID, IP: tu.IP, ViewCount: tu.ViewCount, PostCount: tu.PostCount, LikeCount: tu.LikeCount, AttachCount: tu.AttachCount, Poll: tu.Poll} //log.Printf("theTopic: %+v\n", theTopic) _ = tcache.Set(&theTopic) diff --git a/common/topic_list.go b/common/topic_list.go index 1d51ab7a..fc1d5c23 100644 --- a/common/topic_list.go +++ b/common/topic_list.go @@ -370,13 +370,12 @@ func (tList *DefaultTopicList) getListByForum(f *Forum, page, orderby int) (topi // TODO: Use something other than TopicsRow as we don't need to store the forum name and link on each and every topic item? reqUserList := make(map[int]bool) for rows.Next() { - t := TopicsRow{Topic: Topic{ID: 0}} + t := TopicsRow{Topic: Topic{ParentID: f.ID}} err := rows.Scan(&t.ID, &t.Title, &t.Content, &t.CreatedBy, &t.IsClosed, &t.Sticky, &t.CreatedAt, &t.LastReplyAt, &t.LastReplyBy, &t.LastReplyID, &t.ViewCount, &t.PostCount, &t.LikeCount) if err != nil { return nil, Paginator{nil, 1, 1}, err } - t.ParentID = f.ID t.Link = BuildTopicURL(NameToSlug(t.Title), t.ID) // TODO: Create a specialised function with a bit less overhead for getting the last page for a post count _, _, lastPage := PageOffset(t.PostCount, 1, Config.ItemsPerPage) @@ -575,9 +574,9 @@ func (tList *DefaultTopicList) getList(page, orderby, topicCount int, argList [] _, week := now.ISOWeek() day := int(now.Weekday()) + 1 if week%2 == 0 { // is even? - cols = "tid,title,content,createdBy,is_closed,sticky,createdAt,lastReplyAt,lastReplyBy,lastReplyID,parentID,views,postCount,likeCount,attachCount,poll,data,(weekEvenViews+((weekOddViews/7)*" + strconv.Itoa(day) + ")) AS weekViews" + cols = "tid,title,content,createdBy,is_closed,sticky,createdAt,lastReplyAt,lastReplyBy,lastReplyID,parentID,views,postCount,likeCount,attachCount,poll,data,FLOOR(weekEvenViews+((weekOddViews/7)*" + strconv.Itoa(day) + ")) AS weekViews" } else { - cols = "tid,title,content,createdBy,is_closed,sticky,createdAt,lastReplyAt,lastReplyBy,lastReplyID,parentID,views,postCount,likeCount,attachCount,poll,data,(weekOddViews+((weekEvenViews/7)*" + strconv.Itoa(day) + ")) AS weekViews" + cols = "tid,title,content,createdBy,is_closed,sticky,createdAt,lastReplyAt,lastReplyBy,lastReplyID,parentID,views,postCount,likeCount,attachCount,poll,data,FLOOR(weekOddViews+((weekEvenViews/7)*" + strconv.Itoa(day) + ")) AS weekViews" } topicCount, err = ArgQToWeekViewTopicCount(argList, qlist) if err != nil { @@ -596,7 +595,7 @@ func (tList *DefaultTopicList) getList(page, orderby, topicCount int, argList [] tList.qLock.RUnlock() if stmt == nil { orderq = "views DESC,lastReplyAt DESC,createdBy DESC" - cols = "tid,title,content,createdBy,is_closed,sticky,createdAt,lastReplyAt,lastReplyBy,lastReplyID,parentID,views,postCount,likeCount,attachCount,poll,data" + cols = "tid,title,content,createdBy,is_closed,sticky,createdAt,lastReplyAt,lastReplyBy,lastReplyID,parentID,views,postCount,likeCount,attachCount,poll,data,weekEvenViews" } default: tList.qLock2.RLock() @@ -604,7 +603,7 @@ func (tList *DefaultTopicList) getList(page, orderby, topicCount int, argList [] tList.qLock2.RUnlock() if stmt == nil { orderq = "sticky DESC,lastReplyAt DESC,createdBy DESC" - cols = "tid,title,content,createdBy,is_closed,sticky,createdAt,lastReplyAt,lastReplyBy,lastReplyID,parentID,views,postCount,likeCount,attachCount,poll,data" + cols = "tid,title,content,createdBy,is_closed,sticky,createdAt,lastReplyAt,lastReplyBy,lastReplyID,parentID,views,postCount,likeCount,attachCount,poll,data,weekEvenViews" } } offset, page, lastPage := PageOffset(topicCount, page, Config.ItemsPerPage) @@ -636,10 +635,12 @@ func (tList *DefaultTopicList) getList(page, orderby, topicCount int, argList [] // TODO: Embed Topic structs in TopicsRow to make it easier for us to reuse this work in the topic cache t := TopicsRow{} //var weekViews []uint8 - err := rows.Scan(&t.ID, &t.Title, &t.Content, &t.CreatedBy, &t.IsClosed, &t.Sticky, &t.CreatedAt, &t.LastReplyAt, &t.LastReplyBy, &t.LastReplyID, &t.ParentID, &t.ViewCount, &t.PostCount, &t.LikeCount, &t.AttachCount, &t.Poll, &t.Data /*, &weekViews*/) + err := rows.Scan(&t.ID, &t.Title, &t.Content, &t.CreatedBy, &t.IsClosed, &t.Sticky, &t.CreatedAt, &t.LastReplyAt, &t.LastReplyBy, &t.LastReplyID, &t.ParentID, &t.ViewCount, &t.PostCount, &t.LikeCount, &t.AttachCount, &t.Poll, &t.Data, &t.WeekViews) if err != nil { return nil, Paginator{nil, 1, 1}, err } + //t.WeekViews = int(weekViews[0]) + //log.Printf("t: %+v\n", t) //log.Printf("weekViews: %+v\n", weekViews) t.Link = BuildTopicURL(NameToSlug(t.Title), t.ID) @@ -666,7 +667,7 @@ func (tList *DefaultTopicList) getList(page, orderby, topicCount int, argList [] // Avoid the extra queries on topic list pages, if we already have what we want... hRids := false if tc != nil { - if t, err := tc.Get(t.ID); err == nil { + if t, e := tc.Get(t.ID); e == nil { hRids = len(t.Rids) != 0 } } diff --git a/gen_router.go b/gen_router.go index b3f52d7c..c04c5fa7 100644 --- a/gen_router.go +++ b/gen_router.go @@ -41,6 +41,7 @@ var RouteMap = map[string]interface{}{ "routeAPI": routeAPI, "routes.ReportSubmit": routes.ReportSubmit, "routes.TopicListMostViewed": routes.TopicListMostViewed, + "routes.TopicListWeekViews": routes.TopicListWeekViews, "routes.CreateTopic": routes.CreateTopic, "routes.TopicList": routes.TopicList, "panel.Forums": panel.Forums, @@ -121,6 +122,7 @@ var RouteMap = map[string]interface{}{ "panel.LogsMod": panel.LogsMod, "panel.LogsAdmin": panel.LogsAdmin, "panel.Debug": panel.Debug, + "panel.DebugTasks": panel.DebugTasks, "panel.Dashboard": panel.Dashboard, "routes.AccountEdit": routes.AccountEdit, "routes.AccountEditPassword": routes.AccountEditPassword, @@ -219,166 +221,168 @@ var routeMapEnum = map[string]int{ "routeAPI": 11, "routes.ReportSubmit": 12, "routes.TopicListMostViewed": 13, - "routes.CreateTopic": 14, - "routes.TopicList": 15, - "panel.Forums": 16, - "panel.ForumsCreateSubmit": 17, - "panel.ForumsDelete": 18, - "panel.ForumsDeleteSubmit": 19, - "panel.ForumsOrderSubmit": 20, - "panel.ForumsEdit": 21, - "panel.ForumsEditSubmit": 22, - "panel.ForumsEditPermsSubmit": 23, - "panel.ForumsEditPermsAdvance": 24, - "panel.ForumsEditPermsAdvanceSubmit": 25, - "panel.Settings": 26, - "panel.SettingEdit": 27, - "panel.SettingEditSubmit": 28, - "panel.WordFilters": 29, - "panel.WordFiltersCreateSubmit": 30, - "panel.WordFiltersEdit": 31, - "panel.WordFiltersEditSubmit": 32, - "panel.WordFiltersDeleteSubmit": 33, - "panel.Pages": 34, - "panel.PagesCreateSubmit": 35, - "panel.PagesEdit": 36, - "panel.PagesEditSubmit": 37, - "panel.PagesDeleteSubmit": 38, - "panel.Themes": 39, - "panel.ThemesSetDefault": 40, - "panel.ThemesMenus": 41, - "panel.ThemesMenusEdit": 42, - "panel.ThemesMenuItemEdit": 43, - "panel.ThemesMenuItemEditSubmit": 44, - "panel.ThemesMenuItemCreateSubmit": 45, - "panel.ThemesMenuItemDeleteSubmit": 46, - "panel.ThemesMenuItemOrderSubmit": 47, - "panel.ThemesWidgets": 48, - "panel.ThemesWidgetsEditSubmit": 49, - "panel.ThemesWidgetsCreateSubmit": 50, - "panel.ThemesWidgetsDeleteSubmit": 51, - "panel.Plugins": 52, - "panel.PluginsActivate": 53, - "panel.PluginsDeactivate": 54, - "panel.PluginsInstall": 55, - "panel.Users": 56, - "panel.UsersEdit": 57, - "panel.UsersEditSubmit": 58, - "panel.UsersAvatarSubmit": 59, - "panel.UsersAvatarRemoveSubmit": 60, - "panel.AnalyticsViews": 61, - "panel.AnalyticsRoutes": 62, - "panel.AnalyticsRoutesPerf": 63, - "panel.AnalyticsAgents": 64, - "panel.AnalyticsSystems": 65, - "panel.AnalyticsLanguages": 66, - "panel.AnalyticsReferrers": 67, - "panel.AnalyticsRouteViews": 68, - "panel.AnalyticsAgentViews": 69, - "panel.AnalyticsForumViews": 70, - "panel.AnalyticsSystemViews": 71, - "panel.AnalyticsLanguageViews": 72, - "panel.AnalyticsReferrerViews": 73, - "panel.AnalyticsPosts": 74, - "panel.AnalyticsMemory": 75, - "panel.AnalyticsActiveMemory": 76, - "panel.AnalyticsTopics": 77, - "panel.AnalyticsForums": 78, - "panel.AnalyticsPerf": 79, - "panel.Groups": 80, - "panel.GroupsEdit": 81, - "panel.GroupsEditPromotions": 82, - "panel.GroupsPromotionsCreateSubmit": 83, - "panel.GroupsPromotionsDeleteSubmit": 84, - "panel.GroupsEditPerms": 85, - "panel.GroupsEditSubmit": 86, - "panel.GroupsEditPermsSubmit": 87, - "panel.GroupsCreateSubmit": 88, - "panel.Backups": 89, - "panel.LogsRegs": 90, - "panel.LogsMod": 91, - "panel.LogsAdmin": 92, - "panel.Debug": 93, - "panel.Dashboard": 94, - "routes.AccountEdit": 95, - "routes.AccountEditPassword": 96, - "routes.AccountEditPasswordSubmit": 97, - "routes.AccountEditAvatarSubmit": 98, - "routes.AccountEditRevokeAvatarSubmit": 99, - "routes.AccountEditUsernameSubmit": 100, - "routes.AccountEditPrivacy": 101, - "routes.AccountEditPrivacySubmit": 102, - "routes.AccountEditMFA": 103, - "routes.AccountEditMFASetup": 104, - "routes.AccountEditMFASetupSubmit": 105, - "routes.AccountEditMFADisableSubmit": 106, - "routes.AccountEditEmail": 107, - "routes.AccountEditEmailTokenSubmit": 108, - "routes.AccountLogins": 109, - "routes.AccountBlocked": 110, - "routes.LevelList": 111, - "routes.Convos": 112, - "routes.ConvosCreate": 113, - "routes.Convo": 114, - "routes.ConvosCreateSubmit": 115, - "routes.ConvosCreateReplySubmit": 116, - "routes.ConvosDeleteReplySubmit": 117, - "routes.ConvosEditReplySubmit": 118, - "routes.RelationsBlockCreate": 119, - "routes.RelationsBlockCreateSubmit": 120, - "routes.RelationsBlockRemove": 121, - "routes.RelationsBlockRemoveSubmit": 122, - "routes.ViewProfile": 123, - "routes.BanUserSubmit": 124, - "routes.UnbanUser": 125, - "routes.ActivateUser": 126, - "routes.IPSearch": 127, - "routes.DeletePostsSubmit": 128, - "routes.CreateTopicSubmit": 129, - "routes.EditTopicSubmit": 130, - "routes.DeleteTopicSubmit": 131, - "routes.StickTopicSubmit": 132, - "routes.UnstickTopicSubmit": 133, - "routes.LockTopicSubmit": 134, - "routes.UnlockTopicSubmit": 135, - "routes.MoveTopicSubmit": 136, - "routes.LikeTopicSubmit": 137, - "routes.UnlikeTopicSubmit": 138, - "routes.AddAttachToTopicSubmit": 139, - "routes.RemoveAttachFromTopicSubmit": 140, - "routes.ViewTopic": 141, - "routes.CreateReplySubmit": 142, - "routes.ReplyEditSubmit": 143, - "routes.ReplyDeleteSubmit": 144, - "routes.ReplyLikeSubmit": 145, - "routes.ReplyUnlikeSubmit": 146, - "routes.AddAttachToReplySubmit": 147, - "routes.RemoveAttachFromReplySubmit": 148, - "routes.ProfileReplyCreateSubmit": 149, - "routes.ProfileReplyEditSubmit": 150, - "routes.ProfileReplyDeleteSubmit": 151, - "routes.PollVote": 152, - "routes.PollResults": 153, - "routes.AccountLogin": 154, - "routes.AccountRegister": 155, - "routes.AccountLogout": 156, - "routes.AccountLoginSubmit": 157, - "routes.AccountLoginMFAVerify": 158, - "routes.AccountLoginMFAVerifySubmit": 159, - "routes.AccountRegisterSubmit": 160, - "routes.AccountPasswordReset": 161, - "routes.AccountPasswordResetSubmit": 162, - "routes.AccountPasswordResetToken": 163, - "routes.AccountPasswordResetTokenSubmit": 164, - "routes.DynamicRoute": 165, - "routes.UploadedFile": 166, - "routes.StaticFile": 167, - "routes.RobotsTxt": 168, - "routes.SitemapXml": 169, - "routes.OpenSearchXml": 170, - "routes.Favicon": 171, - "routes.BadRoute": 172, - "routes.HTTPSRedirect": 173, + "routes.TopicListWeekViews": 14, + "routes.CreateTopic": 15, + "routes.TopicList": 16, + "panel.Forums": 17, + "panel.ForumsCreateSubmit": 18, + "panel.ForumsDelete": 19, + "panel.ForumsDeleteSubmit": 20, + "panel.ForumsOrderSubmit": 21, + "panel.ForumsEdit": 22, + "panel.ForumsEditSubmit": 23, + "panel.ForumsEditPermsSubmit": 24, + "panel.ForumsEditPermsAdvance": 25, + "panel.ForumsEditPermsAdvanceSubmit": 26, + "panel.Settings": 27, + "panel.SettingEdit": 28, + "panel.SettingEditSubmit": 29, + "panel.WordFilters": 30, + "panel.WordFiltersCreateSubmit": 31, + "panel.WordFiltersEdit": 32, + "panel.WordFiltersEditSubmit": 33, + "panel.WordFiltersDeleteSubmit": 34, + "panel.Pages": 35, + "panel.PagesCreateSubmit": 36, + "panel.PagesEdit": 37, + "panel.PagesEditSubmit": 38, + "panel.PagesDeleteSubmit": 39, + "panel.Themes": 40, + "panel.ThemesSetDefault": 41, + "panel.ThemesMenus": 42, + "panel.ThemesMenusEdit": 43, + "panel.ThemesMenuItemEdit": 44, + "panel.ThemesMenuItemEditSubmit": 45, + "panel.ThemesMenuItemCreateSubmit": 46, + "panel.ThemesMenuItemDeleteSubmit": 47, + "panel.ThemesMenuItemOrderSubmit": 48, + "panel.ThemesWidgets": 49, + "panel.ThemesWidgetsEditSubmit": 50, + "panel.ThemesWidgetsCreateSubmit": 51, + "panel.ThemesWidgetsDeleteSubmit": 52, + "panel.Plugins": 53, + "panel.PluginsActivate": 54, + "panel.PluginsDeactivate": 55, + "panel.PluginsInstall": 56, + "panel.Users": 57, + "panel.UsersEdit": 58, + "panel.UsersEditSubmit": 59, + "panel.UsersAvatarSubmit": 60, + "panel.UsersAvatarRemoveSubmit": 61, + "panel.AnalyticsViews": 62, + "panel.AnalyticsRoutes": 63, + "panel.AnalyticsRoutesPerf": 64, + "panel.AnalyticsAgents": 65, + "panel.AnalyticsSystems": 66, + "panel.AnalyticsLanguages": 67, + "panel.AnalyticsReferrers": 68, + "panel.AnalyticsRouteViews": 69, + "panel.AnalyticsAgentViews": 70, + "panel.AnalyticsForumViews": 71, + "panel.AnalyticsSystemViews": 72, + "panel.AnalyticsLanguageViews": 73, + "panel.AnalyticsReferrerViews": 74, + "panel.AnalyticsPosts": 75, + "panel.AnalyticsMemory": 76, + "panel.AnalyticsActiveMemory": 77, + "panel.AnalyticsTopics": 78, + "panel.AnalyticsForums": 79, + "panel.AnalyticsPerf": 80, + "panel.Groups": 81, + "panel.GroupsEdit": 82, + "panel.GroupsEditPromotions": 83, + "panel.GroupsPromotionsCreateSubmit": 84, + "panel.GroupsPromotionsDeleteSubmit": 85, + "panel.GroupsEditPerms": 86, + "panel.GroupsEditSubmit": 87, + "panel.GroupsEditPermsSubmit": 88, + "panel.GroupsCreateSubmit": 89, + "panel.Backups": 90, + "panel.LogsRegs": 91, + "panel.LogsMod": 92, + "panel.LogsAdmin": 93, + "panel.Debug": 94, + "panel.DebugTasks": 95, + "panel.Dashboard": 96, + "routes.AccountEdit": 97, + "routes.AccountEditPassword": 98, + "routes.AccountEditPasswordSubmit": 99, + "routes.AccountEditAvatarSubmit": 100, + "routes.AccountEditRevokeAvatarSubmit": 101, + "routes.AccountEditUsernameSubmit": 102, + "routes.AccountEditPrivacy": 103, + "routes.AccountEditPrivacySubmit": 104, + "routes.AccountEditMFA": 105, + "routes.AccountEditMFASetup": 106, + "routes.AccountEditMFASetupSubmit": 107, + "routes.AccountEditMFADisableSubmit": 108, + "routes.AccountEditEmail": 109, + "routes.AccountEditEmailTokenSubmit": 110, + "routes.AccountLogins": 111, + "routes.AccountBlocked": 112, + "routes.LevelList": 113, + "routes.Convos": 114, + "routes.ConvosCreate": 115, + "routes.Convo": 116, + "routes.ConvosCreateSubmit": 117, + "routes.ConvosCreateReplySubmit": 118, + "routes.ConvosDeleteReplySubmit": 119, + "routes.ConvosEditReplySubmit": 120, + "routes.RelationsBlockCreate": 121, + "routes.RelationsBlockCreateSubmit": 122, + "routes.RelationsBlockRemove": 123, + "routes.RelationsBlockRemoveSubmit": 124, + "routes.ViewProfile": 125, + "routes.BanUserSubmit": 126, + "routes.UnbanUser": 127, + "routes.ActivateUser": 128, + "routes.IPSearch": 129, + "routes.DeletePostsSubmit": 130, + "routes.CreateTopicSubmit": 131, + "routes.EditTopicSubmit": 132, + "routes.DeleteTopicSubmit": 133, + "routes.StickTopicSubmit": 134, + "routes.UnstickTopicSubmit": 135, + "routes.LockTopicSubmit": 136, + "routes.UnlockTopicSubmit": 137, + "routes.MoveTopicSubmit": 138, + "routes.LikeTopicSubmit": 139, + "routes.UnlikeTopicSubmit": 140, + "routes.AddAttachToTopicSubmit": 141, + "routes.RemoveAttachFromTopicSubmit": 142, + "routes.ViewTopic": 143, + "routes.CreateReplySubmit": 144, + "routes.ReplyEditSubmit": 145, + "routes.ReplyDeleteSubmit": 146, + "routes.ReplyLikeSubmit": 147, + "routes.ReplyUnlikeSubmit": 148, + "routes.AddAttachToReplySubmit": 149, + "routes.RemoveAttachFromReplySubmit": 150, + "routes.ProfileReplyCreateSubmit": 151, + "routes.ProfileReplyEditSubmit": 152, + "routes.ProfileReplyDeleteSubmit": 153, + "routes.PollVote": 154, + "routes.PollResults": 155, + "routes.AccountLogin": 156, + "routes.AccountRegister": 157, + "routes.AccountLogout": 158, + "routes.AccountLoginSubmit": 159, + "routes.AccountLoginMFAVerify": 160, + "routes.AccountLoginMFAVerifySubmit": 161, + "routes.AccountRegisterSubmit": 162, + "routes.AccountPasswordReset": 163, + "routes.AccountPasswordResetSubmit": 164, + "routes.AccountPasswordResetToken": 165, + "routes.AccountPasswordResetTokenSubmit": 166, + "routes.DynamicRoute": 167, + "routes.UploadedFile": 168, + "routes.StaticFile": 169, + "routes.RobotsTxt": 170, + "routes.SitemapXml": 171, + "routes.OpenSearchXml": 172, + "routes.Favicon": 173, + "routes.BadRoute": 174, + "routes.HTTPSRedirect": 175, } var reverseRouteMapEnum = map[int]string{ 0: "routes.Error", @@ -395,166 +399,168 @@ var reverseRouteMapEnum = map[int]string{ 11: "routeAPI", 12: "routes.ReportSubmit", 13: "routes.TopicListMostViewed", - 14: "routes.CreateTopic", - 15: "routes.TopicList", - 16: "panel.Forums", - 17: "panel.ForumsCreateSubmit", - 18: "panel.ForumsDelete", - 19: "panel.ForumsDeleteSubmit", - 20: "panel.ForumsOrderSubmit", - 21: "panel.ForumsEdit", - 22: "panel.ForumsEditSubmit", - 23: "panel.ForumsEditPermsSubmit", - 24: "panel.ForumsEditPermsAdvance", - 25: "panel.ForumsEditPermsAdvanceSubmit", - 26: "panel.Settings", - 27: "panel.SettingEdit", - 28: "panel.SettingEditSubmit", - 29: "panel.WordFilters", - 30: "panel.WordFiltersCreateSubmit", - 31: "panel.WordFiltersEdit", - 32: "panel.WordFiltersEditSubmit", - 33: "panel.WordFiltersDeleteSubmit", - 34: "panel.Pages", - 35: "panel.PagesCreateSubmit", - 36: "panel.PagesEdit", - 37: "panel.PagesEditSubmit", - 38: "panel.PagesDeleteSubmit", - 39: "panel.Themes", - 40: "panel.ThemesSetDefault", - 41: "panel.ThemesMenus", - 42: "panel.ThemesMenusEdit", - 43: "panel.ThemesMenuItemEdit", - 44: "panel.ThemesMenuItemEditSubmit", - 45: "panel.ThemesMenuItemCreateSubmit", - 46: "panel.ThemesMenuItemDeleteSubmit", - 47: "panel.ThemesMenuItemOrderSubmit", - 48: "panel.ThemesWidgets", - 49: "panel.ThemesWidgetsEditSubmit", - 50: "panel.ThemesWidgetsCreateSubmit", - 51: "panel.ThemesWidgetsDeleteSubmit", - 52: "panel.Plugins", - 53: "panel.PluginsActivate", - 54: "panel.PluginsDeactivate", - 55: "panel.PluginsInstall", - 56: "panel.Users", - 57: "panel.UsersEdit", - 58: "panel.UsersEditSubmit", - 59: "panel.UsersAvatarSubmit", - 60: "panel.UsersAvatarRemoveSubmit", - 61: "panel.AnalyticsViews", - 62: "panel.AnalyticsRoutes", - 63: "panel.AnalyticsRoutesPerf", - 64: "panel.AnalyticsAgents", - 65: "panel.AnalyticsSystems", - 66: "panel.AnalyticsLanguages", - 67: "panel.AnalyticsReferrers", - 68: "panel.AnalyticsRouteViews", - 69: "panel.AnalyticsAgentViews", - 70: "panel.AnalyticsForumViews", - 71: "panel.AnalyticsSystemViews", - 72: "panel.AnalyticsLanguageViews", - 73: "panel.AnalyticsReferrerViews", - 74: "panel.AnalyticsPosts", - 75: "panel.AnalyticsMemory", - 76: "panel.AnalyticsActiveMemory", - 77: "panel.AnalyticsTopics", - 78: "panel.AnalyticsForums", - 79: "panel.AnalyticsPerf", - 80: "panel.Groups", - 81: "panel.GroupsEdit", - 82: "panel.GroupsEditPromotions", - 83: "panel.GroupsPromotionsCreateSubmit", - 84: "panel.GroupsPromotionsDeleteSubmit", - 85: "panel.GroupsEditPerms", - 86: "panel.GroupsEditSubmit", - 87: "panel.GroupsEditPermsSubmit", - 88: "panel.GroupsCreateSubmit", - 89: "panel.Backups", - 90: "panel.LogsRegs", - 91: "panel.LogsMod", - 92: "panel.LogsAdmin", - 93: "panel.Debug", - 94: "panel.Dashboard", - 95: "routes.AccountEdit", - 96: "routes.AccountEditPassword", - 97: "routes.AccountEditPasswordSubmit", - 98: "routes.AccountEditAvatarSubmit", - 99: "routes.AccountEditRevokeAvatarSubmit", - 100: "routes.AccountEditUsernameSubmit", - 101: "routes.AccountEditPrivacy", - 102: "routes.AccountEditPrivacySubmit", - 103: "routes.AccountEditMFA", - 104: "routes.AccountEditMFASetup", - 105: "routes.AccountEditMFASetupSubmit", - 106: "routes.AccountEditMFADisableSubmit", - 107: "routes.AccountEditEmail", - 108: "routes.AccountEditEmailTokenSubmit", - 109: "routes.AccountLogins", - 110: "routes.AccountBlocked", - 111: "routes.LevelList", - 112: "routes.Convos", - 113: "routes.ConvosCreate", - 114: "routes.Convo", - 115: "routes.ConvosCreateSubmit", - 116: "routes.ConvosCreateReplySubmit", - 117: "routes.ConvosDeleteReplySubmit", - 118: "routes.ConvosEditReplySubmit", - 119: "routes.RelationsBlockCreate", - 120: "routes.RelationsBlockCreateSubmit", - 121: "routes.RelationsBlockRemove", - 122: "routes.RelationsBlockRemoveSubmit", - 123: "routes.ViewProfile", - 124: "routes.BanUserSubmit", - 125: "routes.UnbanUser", - 126: "routes.ActivateUser", - 127: "routes.IPSearch", - 128: "routes.DeletePostsSubmit", - 129: "routes.CreateTopicSubmit", - 130: "routes.EditTopicSubmit", - 131: "routes.DeleteTopicSubmit", - 132: "routes.StickTopicSubmit", - 133: "routes.UnstickTopicSubmit", - 134: "routes.LockTopicSubmit", - 135: "routes.UnlockTopicSubmit", - 136: "routes.MoveTopicSubmit", - 137: "routes.LikeTopicSubmit", - 138: "routes.UnlikeTopicSubmit", - 139: "routes.AddAttachToTopicSubmit", - 140: "routes.RemoveAttachFromTopicSubmit", - 141: "routes.ViewTopic", - 142: "routes.CreateReplySubmit", - 143: "routes.ReplyEditSubmit", - 144: "routes.ReplyDeleteSubmit", - 145: "routes.ReplyLikeSubmit", - 146: "routes.ReplyUnlikeSubmit", - 147: "routes.AddAttachToReplySubmit", - 148: "routes.RemoveAttachFromReplySubmit", - 149: "routes.ProfileReplyCreateSubmit", - 150: "routes.ProfileReplyEditSubmit", - 151: "routes.ProfileReplyDeleteSubmit", - 152: "routes.PollVote", - 153: "routes.PollResults", - 154: "routes.AccountLogin", - 155: "routes.AccountRegister", - 156: "routes.AccountLogout", - 157: "routes.AccountLoginSubmit", - 158: "routes.AccountLoginMFAVerify", - 159: "routes.AccountLoginMFAVerifySubmit", - 160: "routes.AccountRegisterSubmit", - 161: "routes.AccountPasswordReset", - 162: "routes.AccountPasswordResetSubmit", - 163: "routes.AccountPasswordResetToken", - 164: "routes.AccountPasswordResetTokenSubmit", - 165: "routes.DynamicRoute", - 166: "routes.UploadedFile", - 167: "routes.StaticFile", - 168: "routes.RobotsTxt", - 169: "routes.SitemapXml", - 170: "routes.OpenSearchXml", - 171: "routes.Favicon", - 172: "routes.BadRoute", - 173: "routes.HTTPSRedirect", + 14: "routes.TopicListWeekViews", + 15: "routes.CreateTopic", + 16: "routes.TopicList", + 17: "panel.Forums", + 18: "panel.ForumsCreateSubmit", + 19: "panel.ForumsDelete", + 20: "panel.ForumsDeleteSubmit", + 21: "panel.ForumsOrderSubmit", + 22: "panel.ForumsEdit", + 23: "panel.ForumsEditSubmit", + 24: "panel.ForumsEditPermsSubmit", + 25: "panel.ForumsEditPermsAdvance", + 26: "panel.ForumsEditPermsAdvanceSubmit", + 27: "panel.Settings", + 28: "panel.SettingEdit", + 29: "panel.SettingEditSubmit", + 30: "panel.WordFilters", + 31: "panel.WordFiltersCreateSubmit", + 32: "panel.WordFiltersEdit", + 33: "panel.WordFiltersEditSubmit", + 34: "panel.WordFiltersDeleteSubmit", + 35: "panel.Pages", + 36: "panel.PagesCreateSubmit", + 37: "panel.PagesEdit", + 38: "panel.PagesEditSubmit", + 39: "panel.PagesDeleteSubmit", + 40: "panel.Themes", + 41: "panel.ThemesSetDefault", + 42: "panel.ThemesMenus", + 43: "panel.ThemesMenusEdit", + 44: "panel.ThemesMenuItemEdit", + 45: "panel.ThemesMenuItemEditSubmit", + 46: "panel.ThemesMenuItemCreateSubmit", + 47: "panel.ThemesMenuItemDeleteSubmit", + 48: "panel.ThemesMenuItemOrderSubmit", + 49: "panel.ThemesWidgets", + 50: "panel.ThemesWidgetsEditSubmit", + 51: "panel.ThemesWidgetsCreateSubmit", + 52: "panel.ThemesWidgetsDeleteSubmit", + 53: "panel.Plugins", + 54: "panel.PluginsActivate", + 55: "panel.PluginsDeactivate", + 56: "panel.PluginsInstall", + 57: "panel.Users", + 58: "panel.UsersEdit", + 59: "panel.UsersEditSubmit", + 60: "panel.UsersAvatarSubmit", + 61: "panel.UsersAvatarRemoveSubmit", + 62: "panel.AnalyticsViews", + 63: "panel.AnalyticsRoutes", + 64: "panel.AnalyticsRoutesPerf", + 65: "panel.AnalyticsAgents", + 66: "panel.AnalyticsSystems", + 67: "panel.AnalyticsLanguages", + 68: "panel.AnalyticsReferrers", + 69: "panel.AnalyticsRouteViews", + 70: "panel.AnalyticsAgentViews", + 71: "panel.AnalyticsForumViews", + 72: "panel.AnalyticsSystemViews", + 73: "panel.AnalyticsLanguageViews", + 74: "panel.AnalyticsReferrerViews", + 75: "panel.AnalyticsPosts", + 76: "panel.AnalyticsMemory", + 77: "panel.AnalyticsActiveMemory", + 78: "panel.AnalyticsTopics", + 79: "panel.AnalyticsForums", + 80: "panel.AnalyticsPerf", + 81: "panel.Groups", + 82: "panel.GroupsEdit", + 83: "panel.GroupsEditPromotions", + 84: "panel.GroupsPromotionsCreateSubmit", + 85: "panel.GroupsPromotionsDeleteSubmit", + 86: "panel.GroupsEditPerms", + 87: "panel.GroupsEditSubmit", + 88: "panel.GroupsEditPermsSubmit", + 89: "panel.GroupsCreateSubmit", + 90: "panel.Backups", + 91: "panel.LogsRegs", + 92: "panel.LogsMod", + 93: "panel.LogsAdmin", + 94: "panel.Debug", + 95: "panel.DebugTasks", + 96: "panel.Dashboard", + 97: "routes.AccountEdit", + 98: "routes.AccountEditPassword", + 99: "routes.AccountEditPasswordSubmit", + 100: "routes.AccountEditAvatarSubmit", + 101: "routes.AccountEditRevokeAvatarSubmit", + 102: "routes.AccountEditUsernameSubmit", + 103: "routes.AccountEditPrivacy", + 104: "routes.AccountEditPrivacySubmit", + 105: "routes.AccountEditMFA", + 106: "routes.AccountEditMFASetup", + 107: "routes.AccountEditMFASetupSubmit", + 108: "routes.AccountEditMFADisableSubmit", + 109: "routes.AccountEditEmail", + 110: "routes.AccountEditEmailTokenSubmit", + 111: "routes.AccountLogins", + 112: "routes.AccountBlocked", + 113: "routes.LevelList", + 114: "routes.Convos", + 115: "routes.ConvosCreate", + 116: "routes.Convo", + 117: "routes.ConvosCreateSubmit", + 118: "routes.ConvosCreateReplySubmit", + 119: "routes.ConvosDeleteReplySubmit", + 120: "routes.ConvosEditReplySubmit", + 121: "routes.RelationsBlockCreate", + 122: "routes.RelationsBlockCreateSubmit", + 123: "routes.RelationsBlockRemove", + 124: "routes.RelationsBlockRemoveSubmit", + 125: "routes.ViewProfile", + 126: "routes.BanUserSubmit", + 127: "routes.UnbanUser", + 128: "routes.ActivateUser", + 129: "routes.IPSearch", + 130: "routes.DeletePostsSubmit", + 131: "routes.CreateTopicSubmit", + 132: "routes.EditTopicSubmit", + 133: "routes.DeleteTopicSubmit", + 134: "routes.StickTopicSubmit", + 135: "routes.UnstickTopicSubmit", + 136: "routes.LockTopicSubmit", + 137: "routes.UnlockTopicSubmit", + 138: "routes.MoveTopicSubmit", + 139: "routes.LikeTopicSubmit", + 140: "routes.UnlikeTopicSubmit", + 141: "routes.AddAttachToTopicSubmit", + 142: "routes.RemoveAttachFromTopicSubmit", + 143: "routes.ViewTopic", + 144: "routes.CreateReplySubmit", + 145: "routes.ReplyEditSubmit", + 146: "routes.ReplyDeleteSubmit", + 147: "routes.ReplyLikeSubmit", + 148: "routes.ReplyUnlikeSubmit", + 149: "routes.AddAttachToReplySubmit", + 150: "routes.RemoveAttachFromReplySubmit", + 151: "routes.ProfileReplyCreateSubmit", + 152: "routes.ProfileReplyEditSubmit", + 153: "routes.ProfileReplyDeleteSubmit", + 154: "routes.PollVote", + 155: "routes.PollResults", + 156: "routes.AccountLogin", + 157: "routes.AccountRegister", + 158: "routes.AccountLogout", + 159: "routes.AccountLoginSubmit", + 160: "routes.AccountLoginMFAVerify", + 161: "routes.AccountLoginMFAVerifySubmit", + 162: "routes.AccountRegisterSubmit", + 163: "routes.AccountPasswordReset", + 164: "routes.AccountPasswordResetSubmit", + 165: "routes.AccountPasswordResetToken", + 166: "routes.AccountPasswordResetTokenSubmit", + 167: "routes.DynamicRoute", + 168: "routes.UploadedFile", + 169: "routes.StaticFile", + 170: "routes.RobotsTxt", + 171: "routes.SitemapXml", + 172: "routes.OpenSearchXml", + 173: "routes.Favicon", + 174: "routes.BadRoute", + 175: "routes.HTTPSRedirect", } var osMapEnum = map[string]int{ "unknown": 0, @@ -896,7 +902,7 @@ type HTTPSRedirect struct {} func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) { w.Header().Set("Connection", "close") - co.RouteViewCounter.Bump(173) + co.RouteViewCounter.Bump(175) dest := "https://" + req.Host + req.URL.String() http.Redirect(w, req, dest, http.StatusTemporaryRedirect) } @@ -1111,7 +1117,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { if prefix == "/s" { //old prefix: /static if !c.Config.DisableAnalytics { - co.RouteViewCounter.Bump(167) + co.RouteViewCounter.Bump(169) } routes.StaticFile(w, req) return @@ -1228,7 +1234,11 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { agent = 6 } case 58: - r.SuspiciousRequest(req,"Vuln Scanner") + w.WriteHeader(200) // 400 + w.Write([]byte("")) + r.DumpRequest(req,"Blocked Scanner") + co.AgentViewCounter.Bump(58) + return } if agent == 0 { @@ -1482,6 +1492,13 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.TopicListMostViewed(w,req,user,h) co.RouteViewCounter.Bump3(13, cn) + case "/topics/week-views/": + h, err := c.UserCheckNano(w,req,user,cn) + if err != nil { + return err + } + err = routes.TopicListWeekViews(w,req,user,h) + co.RouteViewCounter.Bump3(14, cn) case "/topics/create/": err = c.MemberOnly(w,req,user) if err != nil { @@ -1493,14 +1510,14 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.CreateTopic(w,req,user,h,extraData) - co.RouteViewCounter.Bump3(14, cn) + co.RouteViewCounter.Bump3(15, cn) default: h, err := c.UserCheckNano(w,req,user,cn) if err != nil { return err } err = routes.TopicList(w,req,user, h) - co.RouteViewCounter.Bump3(15, cn) + co.RouteViewCounter.Bump3(16, cn) } case "/panel": err = c.SuperModOnly(w,req,user) @@ -1511,7 +1528,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * switch(req.URL.Path) { case "/panel/forums/": err = panel.Forums(w,req,user) - co.RouteViewCounter.Bump3(16, cn) + co.RouteViewCounter.Bump3(17, cn) case "/panel/forums/create/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1519,7 +1536,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ForumsCreateSubmit(w,req,user) - co.RouteViewCounter.Bump3(17, cn) + co.RouteViewCounter.Bump3(18, cn) case "/panel/forums/delete/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1527,7 +1544,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ForumsDelete(w,req,user,extraData) - co.RouteViewCounter.Bump3(18, cn) + co.RouteViewCounter.Bump3(19, cn) case "/panel/forums/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1535,7 +1552,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ForumsDeleteSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(19, cn) + co.RouteViewCounter.Bump3(20, cn) case "/panel/forums/order/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1543,10 +1560,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ForumsOrderSubmit(w,req,user) - co.RouteViewCounter.Bump3(20, cn) + co.RouteViewCounter.Bump3(21, cn) case "/panel/forums/edit/": err = panel.ForumsEdit(w,req,user,extraData) - co.RouteViewCounter.Bump3(21, cn) + co.RouteViewCounter.Bump3(22, cn) case "/panel/forums/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1554,7 +1571,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ForumsEditSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(22, cn) + co.RouteViewCounter.Bump3(23, cn) case "/panel/forums/edit/perms/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1562,10 +1579,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ForumsEditPermsSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(23, cn) + co.RouteViewCounter.Bump3(24, cn) case "/panel/forums/edit/perms/": err = panel.ForumsEditPermsAdvance(w,req,user,extraData) - co.RouteViewCounter.Bump3(24, cn) + co.RouteViewCounter.Bump3(25, cn) case "/panel/forums/edit/perms/adv/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1573,13 +1590,13 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ForumsEditPermsAdvanceSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(25, cn) + co.RouteViewCounter.Bump3(26, cn) case "/panel/settings/": err = panel.Settings(w,req,user) - co.RouteViewCounter.Bump3(26, cn) + co.RouteViewCounter.Bump3(27, cn) case "/panel/settings/edit/": err = panel.SettingEdit(w,req,user,extraData) - co.RouteViewCounter.Bump3(27, cn) + co.RouteViewCounter.Bump3(28, cn) case "/panel/settings/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1587,10 +1604,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.SettingEditSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(28, cn) + co.RouteViewCounter.Bump3(29, cn) case "/panel/settings/word-filters/": err = panel.WordFilters(w,req,user) - co.RouteViewCounter.Bump3(29, cn) + co.RouteViewCounter.Bump3(30, cn) case "/panel/settings/word-filters/create/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1598,10 +1615,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.WordFiltersCreateSubmit(w,req,user) - co.RouteViewCounter.Bump3(30, cn) + co.RouteViewCounter.Bump3(31, cn) case "/panel/settings/word-filters/edit/": err = panel.WordFiltersEdit(w,req,user,extraData) - co.RouteViewCounter.Bump3(31, cn) + co.RouteViewCounter.Bump3(32, cn) case "/panel/settings/word-filters/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1609,7 +1626,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.WordFiltersEditSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(32, cn) + co.RouteViewCounter.Bump3(33, cn) case "/panel/settings/word-filters/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1617,7 +1634,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.WordFiltersDeleteSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(33, cn) + co.RouteViewCounter.Bump3(34, cn) case "/panel/pages/": err = c.AdminOnly(w,req,user) if err != nil { @@ -1625,7 +1642,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.Pages(w,req,user) - co.RouteViewCounter.Bump3(34, cn) + co.RouteViewCounter.Bump3(35, cn) case "/panel/pages/create/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1638,7 +1655,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.PagesCreateSubmit(w,req,user) - co.RouteViewCounter.Bump3(35, cn) + co.RouteViewCounter.Bump3(36, cn) case "/panel/pages/edit/": err = c.AdminOnly(w,req,user) if err != nil { @@ -1646,7 +1663,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.PagesEdit(w,req,user,extraData) - co.RouteViewCounter.Bump3(36, cn) + co.RouteViewCounter.Bump3(37, cn) case "/panel/pages/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1659,7 +1676,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.PagesEditSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(37, cn) + co.RouteViewCounter.Bump3(38, cn) case "/panel/pages/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1672,10 +1689,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.PagesDeleteSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(38, cn) + co.RouteViewCounter.Bump3(39, cn) case "/panel/themes/": err = panel.Themes(w,req,user) - co.RouteViewCounter.Bump3(39, cn) + co.RouteViewCounter.Bump3(40, cn) case "/panel/themes/default/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1683,16 +1700,16 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ThemesSetDefault(w,req,user,extraData) - co.RouteViewCounter.Bump3(40, cn) + co.RouteViewCounter.Bump3(41, cn) case "/panel/themes/menus/": err = panel.ThemesMenus(w,req,user) - co.RouteViewCounter.Bump3(41, cn) + co.RouteViewCounter.Bump3(42, cn) case "/panel/themes/menus/edit/": err = panel.ThemesMenusEdit(w,req,user,extraData) - co.RouteViewCounter.Bump3(42, cn) + co.RouteViewCounter.Bump3(43, cn) case "/panel/themes/menus/item/edit/": err = panel.ThemesMenuItemEdit(w,req,user,extraData) - co.RouteViewCounter.Bump3(43, cn) + co.RouteViewCounter.Bump3(44, cn) case "/panel/themes/menus/item/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1700,7 +1717,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ThemesMenuItemEditSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(44, cn) + co.RouteViewCounter.Bump3(45, cn) case "/panel/themes/menus/item/create/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1708,7 +1725,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ThemesMenuItemCreateSubmit(w,req,user) - co.RouteViewCounter.Bump3(45, cn) + co.RouteViewCounter.Bump3(46, cn) case "/panel/themes/menus/item/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1716,7 +1733,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ThemesMenuItemDeleteSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(46, cn) + co.RouteViewCounter.Bump3(47, cn) case "/panel/themes/menus/item/order/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1724,10 +1741,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ThemesMenuItemOrderSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(47, cn) + co.RouteViewCounter.Bump3(48, cn) case "/panel/themes/widgets/": err = panel.ThemesWidgets(w,req,user) - co.RouteViewCounter.Bump3(48, cn) + co.RouteViewCounter.Bump3(49, cn) case "/panel/themes/widgets/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1735,7 +1752,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ThemesWidgetsEditSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(49, cn) + co.RouteViewCounter.Bump3(50, cn) case "/panel/themes/widgets/create/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1743,7 +1760,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ThemesWidgetsCreateSubmit(w,req,user) - co.RouteViewCounter.Bump3(50, cn) + co.RouteViewCounter.Bump3(51, cn) case "/panel/themes/widgets/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1751,10 +1768,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.ThemesWidgetsDeleteSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(51, cn) + co.RouteViewCounter.Bump3(52, cn) case "/panel/plugins/": err = panel.Plugins(w,req,user) - co.RouteViewCounter.Bump3(52, cn) + co.RouteViewCounter.Bump3(53, cn) case "/panel/plugins/activate/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1762,7 +1779,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.PluginsActivate(w,req,user,extraData) - co.RouteViewCounter.Bump3(53, cn) + co.RouteViewCounter.Bump3(54, cn) case "/panel/plugins/deactivate/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1770,7 +1787,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.PluginsDeactivate(w,req,user,extraData) - co.RouteViewCounter.Bump3(54, cn) + co.RouteViewCounter.Bump3(55, cn) case "/panel/plugins/install/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1778,13 +1795,13 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.PluginsInstall(w,req,user,extraData) - co.RouteViewCounter.Bump3(55, cn) + co.RouteViewCounter.Bump3(56, cn) case "/panel/users/": err = panel.Users(w,req,user) - co.RouteViewCounter.Bump3(56, cn) + co.RouteViewCounter.Bump3(57, cn) case "/panel/users/edit/": err = panel.UsersEdit(w,req,user,extraData) - co.RouteViewCounter.Bump3(57, cn) + co.RouteViewCounter.Bump3(58, cn) case "/panel/users/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1792,7 +1809,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.UsersEditSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(58, cn) + co.RouteViewCounter.Bump3(59, cn) case "/panel/users/avatar/submit/": err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize)) if err != nil { @@ -1804,7 +1821,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.UsersAvatarSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(59, cn) + co.RouteViewCounter.Bump3(60, cn) case "/panel/users/avatar/remove/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1812,7 +1829,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.UsersAvatarRemoveSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(60, cn) + co.RouteViewCounter.Bump3(61, cn) case "/panel/analytics/views/": err = c.ParseForm(w,req,user) if err != nil { @@ -1820,7 +1837,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsViews(w,req,user) - co.RouteViewCounter.Bump3(61, cn) + co.RouteViewCounter.Bump3(62, cn) case "/panel/analytics/routes/": err = c.ParseForm(w,req,user) if err != nil { @@ -1828,7 +1845,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsRoutes(w,req,user) - co.RouteViewCounter.Bump3(62, cn) + co.RouteViewCounter.Bump3(63, cn) case "/panel/analytics/routes-perf/": err = c.ParseForm(w,req,user) if err != nil { @@ -1836,7 +1853,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsRoutesPerf(w,req,user) - co.RouteViewCounter.Bump3(63, cn) + co.RouteViewCounter.Bump3(64, cn) case "/panel/analytics/agents/": err = c.ParseForm(w,req,user) if err != nil { @@ -1844,7 +1861,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsAgents(w,req,user) - co.RouteViewCounter.Bump3(64, cn) + co.RouteViewCounter.Bump3(65, cn) case "/panel/analytics/systems/": err = c.ParseForm(w,req,user) if err != nil { @@ -1852,7 +1869,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsSystems(w,req,user) - co.RouteViewCounter.Bump3(65, cn) + co.RouteViewCounter.Bump3(66, cn) case "/panel/analytics/langs/": err = c.ParseForm(w,req,user) if err != nil { @@ -1860,7 +1877,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsLanguages(w,req,user) - co.RouteViewCounter.Bump3(66, cn) + co.RouteViewCounter.Bump3(67, cn) case "/panel/analytics/referrers/": err = c.ParseForm(w,req,user) if err != nil { @@ -1868,25 +1885,25 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsReferrers(w,req,user) - co.RouteViewCounter.Bump3(67, cn) + co.RouteViewCounter.Bump3(68, cn) case "/panel/analytics/route/": err = panel.AnalyticsRouteViews(w,req,user,extraData) - co.RouteViewCounter.Bump3(68, cn) + co.RouteViewCounter.Bump3(69, cn) case "/panel/analytics/agent/": err = panel.AnalyticsAgentViews(w,req,user,extraData) - co.RouteViewCounter.Bump3(69, cn) + co.RouteViewCounter.Bump3(70, cn) case "/panel/analytics/forum/": err = panel.AnalyticsForumViews(w,req,user,extraData) - co.RouteViewCounter.Bump3(70, cn) + co.RouteViewCounter.Bump3(71, cn) case "/panel/analytics/system/": err = panel.AnalyticsSystemViews(w,req,user,extraData) - co.RouteViewCounter.Bump3(71, cn) + co.RouteViewCounter.Bump3(72, cn) case "/panel/analytics/lang/": err = panel.AnalyticsLanguageViews(w,req,user,extraData) - co.RouteViewCounter.Bump3(72, cn) + co.RouteViewCounter.Bump3(73, cn) case "/panel/analytics/referrer/": err = panel.AnalyticsReferrerViews(w,req,user,extraData) - co.RouteViewCounter.Bump3(73, cn) + co.RouteViewCounter.Bump3(74, cn) case "/panel/analytics/posts/": err = c.ParseForm(w,req,user) if err != nil { @@ -1894,7 +1911,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsPosts(w,req,user) - co.RouteViewCounter.Bump3(74, cn) + co.RouteViewCounter.Bump3(75, cn) case "/panel/analytics/memory/": err = c.ParseForm(w,req,user) if err != nil { @@ -1902,7 +1919,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsMemory(w,req,user) - co.RouteViewCounter.Bump3(75, cn) + co.RouteViewCounter.Bump3(76, cn) case "/panel/analytics/active-memory/": err = c.ParseForm(w,req,user) if err != nil { @@ -1910,7 +1927,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsActiveMemory(w,req,user) - co.RouteViewCounter.Bump3(76, cn) + co.RouteViewCounter.Bump3(77, cn) case "/panel/analytics/topics/": err = c.ParseForm(w,req,user) if err != nil { @@ -1918,7 +1935,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsTopics(w,req,user) - co.RouteViewCounter.Bump3(77, cn) + co.RouteViewCounter.Bump3(78, cn) case "/panel/analytics/forums/": err = c.ParseForm(w,req,user) if err != nil { @@ -1926,7 +1943,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsForums(w,req,user) - co.RouteViewCounter.Bump3(78, cn) + co.RouteViewCounter.Bump3(79, cn) case "/panel/analytics/perf/": err = c.ParseForm(w,req,user) if err != nil { @@ -1934,16 +1951,16 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.AnalyticsPerf(w,req,user) - co.RouteViewCounter.Bump3(79, cn) + co.RouteViewCounter.Bump3(80, cn) case "/panel/groups/": err = panel.Groups(w,req,user) - co.RouteViewCounter.Bump3(80, cn) + co.RouteViewCounter.Bump3(81, cn) case "/panel/groups/edit/": err = panel.GroupsEdit(w,req,user,extraData) - co.RouteViewCounter.Bump3(81, cn) + co.RouteViewCounter.Bump3(82, cn) case "/panel/groups/edit/promotions/": err = panel.GroupsEditPromotions(w,req,user,extraData) - co.RouteViewCounter.Bump3(82, cn) + co.RouteViewCounter.Bump3(83, cn) case "/panel/groups/promotions/create/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1951,7 +1968,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.GroupsPromotionsCreateSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(83, cn) + co.RouteViewCounter.Bump3(84, cn) case "/panel/groups/promotions/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1959,10 +1976,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.GroupsPromotionsDeleteSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(84, cn) + co.RouteViewCounter.Bump3(85, cn) case "/panel/groups/edit/perms/": err = panel.GroupsEditPerms(w,req,user,extraData) - co.RouteViewCounter.Bump3(85, cn) + co.RouteViewCounter.Bump3(86, cn) case "/panel/groups/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1970,7 +1987,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.GroupsEditSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(86, cn) + co.RouteViewCounter.Bump3(87, cn) case "/panel/groups/edit/perms/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1978,7 +1995,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.GroupsEditPermsSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(87, cn) + co.RouteViewCounter.Bump3(88, cn) case "/panel/groups/create/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -1986,7 +2003,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.GroupsCreateSubmit(w,req,user) - co.RouteViewCounter.Bump3(88, cn) + co.RouteViewCounter.Bump3(89, cn) case "/panel/backups/": err = c.SuperAdminOnly(w,req,user) if err != nil { @@ -1999,16 +2016,16 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * w.Header().Del("Content-Encoding") } err = panel.Backups(w,req,user,extraData) - co.RouteViewCounter.Bump3(89, cn) + co.RouteViewCounter.Bump3(90, cn) case "/panel/logs/regs/": err = panel.LogsRegs(w,req,user) - co.RouteViewCounter.Bump3(90, cn) + co.RouteViewCounter.Bump3(91, cn) case "/panel/logs/mod/": err = panel.LogsMod(w,req,user) - co.RouteViewCounter.Bump3(91, cn) + co.RouteViewCounter.Bump3(92, cn) case "/panel/logs/admin/": err = panel.LogsAdmin(w,req,user) - co.RouteViewCounter.Bump3(92, cn) + co.RouteViewCounter.Bump3(93, cn) case "/panel/debug/": err = c.AdminOnly(w,req,user) if err != nil { @@ -2016,10 +2033,18 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = panel.Debug(w,req,user) - co.RouteViewCounter.Bump3(93, cn) + co.RouteViewCounter.Bump3(94, cn) + case "/panel/debug/tasks/": + err = c.AdminOnly(w,req,user) + if err != nil { + return err + } + + err = panel.DebugTasks(w,req,user) + co.RouteViewCounter.Bump3(95, cn) default: err = panel.Dashboard(w,req,user) - co.RouteViewCounter.Bump3(94, cn) + co.RouteViewCounter.Bump3(96, cn) } case "/user": switch(req.URL.Path) { @@ -2034,7 +2059,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.AccountEdit(w,req,user,h) - co.RouteViewCounter.Bump3(95, cn) + co.RouteViewCounter.Bump3(97, cn) case "/user/edit/password/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2046,7 +2071,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.AccountEditPassword(w,req,user,h) - co.RouteViewCounter.Bump3(96, cn) + co.RouteViewCounter.Bump3(98, cn) case "/user/edit/password/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2059,7 +2084,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountEditPasswordSubmit(w,req,user) - co.RouteViewCounter.Bump3(97, cn) + co.RouteViewCounter.Bump3(99, cn) case "/user/edit/avatar/submit/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2076,7 +2101,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountEditAvatarSubmit(w,req,user) - co.RouteViewCounter.Bump3(98, cn) + co.RouteViewCounter.Bump3(100, cn) case "/user/edit/avatar/revoke/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2089,7 +2114,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountEditRevokeAvatarSubmit(w,req,user) - co.RouteViewCounter.Bump3(99, cn) + co.RouteViewCounter.Bump3(101, cn) case "/user/edit/username/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2102,7 +2127,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountEditUsernameSubmit(w,req,user) - co.RouteViewCounter.Bump3(100, cn) + co.RouteViewCounter.Bump3(102, cn) case "/user/edit/privacy/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2114,7 +2139,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.AccountEditPrivacy(w,req,user,h) - co.RouteViewCounter.Bump3(101, cn) + co.RouteViewCounter.Bump3(103, cn) case "/user/edit/privacy/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2127,7 +2152,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountEditPrivacySubmit(w,req,user) - co.RouteViewCounter.Bump3(102, cn) + co.RouteViewCounter.Bump3(104, cn) case "/user/edit/mfa/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2139,7 +2164,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.AccountEditMFA(w,req,user,h) - co.RouteViewCounter.Bump3(103, cn) + co.RouteViewCounter.Bump3(105, cn) case "/user/edit/mfa/setup/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2151,7 +2176,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.AccountEditMFASetup(w,req,user,h) - co.RouteViewCounter.Bump3(104, cn) + co.RouteViewCounter.Bump3(106, cn) case "/user/edit/mfa/setup/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2164,7 +2189,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountEditMFASetupSubmit(w,req,user) - co.RouteViewCounter.Bump3(105, cn) + co.RouteViewCounter.Bump3(107, cn) case "/user/edit/mfa/disable/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2177,7 +2202,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountEditMFADisableSubmit(w,req,user) - co.RouteViewCounter.Bump3(106, cn) + co.RouteViewCounter.Bump3(108, cn) case "/user/edit/email/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2189,10 +2214,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.AccountEditEmail(w,req,user,h) - co.RouteViewCounter.Bump3(107, cn) + co.RouteViewCounter.Bump3(109, cn) case "/user/edit/token/": err = routes.AccountEditEmailTokenSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(108, cn) + co.RouteViewCounter.Bump3(110, cn) case "/user/edit/logins/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2204,7 +2229,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.AccountLogins(w,req,user,h) - co.RouteViewCounter.Bump3(109, cn) + co.RouteViewCounter.Bump3(111, cn) case "/user/edit/blocked/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2216,7 +2241,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.AccountBlocked(w,req,user,h) - co.RouteViewCounter.Bump3(110, cn) + co.RouteViewCounter.Bump3(112, cn) case "/user/levels/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2228,7 +2253,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.LevelList(w,req,user,h) - co.RouteViewCounter.Bump3(111, cn) + co.RouteViewCounter.Bump3(113, cn) case "/user/convos/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2240,7 +2265,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.Convos(w,req,user,h) - co.RouteViewCounter.Bump3(112, cn) + co.RouteViewCounter.Bump3(114, cn) case "/user/convos/create/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2252,7 +2277,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.ConvosCreate(w,req,user,h) - co.RouteViewCounter.Bump3(113, cn) + co.RouteViewCounter.Bump3(115, cn) case "/user/convo/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2264,7 +2289,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.Convo(w,req,user,h,extraData) - co.RouteViewCounter.Bump3(114, cn) + co.RouteViewCounter.Bump3(116, cn) case "/user/convos/create/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2277,7 +2302,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.ConvosCreateSubmit(w,req,user) - co.RouteViewCounter.Bump3(115, cn) + co.RouteViewCounter.Bump3(117, cn) case "/user/convo/create/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2290,7 +2315,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.ConvosCreateReplySubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(116, cn) + co.RouteViewCounter.Bump3(118, cn) case "/user/convo/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2303,7 +2328,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.ConvosDeleteReplySubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(117, cn) + co.RouteViewCounter.Bump3(119, cn) case "/user/convo/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2316,7 +2341,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.ConvosEditReplySubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(118, cn) + co.RouteViewCounter.Bump3(120, cn) case "/user/block/create/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2328,7 +2353,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.RelationsBlockCreate(w,req,user,h,extraData) - co.RouteViewCounter.Bump3(119, cn) + co.RouteViewCounter.Bump3(121, cn) case "/user/block/create/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2341,7 +2366,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.RelationsBlockCreateSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(120, cn) + co.RouteViewCounter.Bump3(122, cn) case "/user/block/remove/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2353,7 +2378,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.RelationsBlockRemove(w,req,user,h,extraData) - co.RouteViewCounter.Bump3(121, cn) + co.RouteViewCounter.Bump3(123, cn) case "/user/block/remove/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2366,7 +2391,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.RelationsBlockRemoveSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(122, cn) + co.RouteViewCounter.Bump3(124, cn) default: req.URL.Path += extraData h, err := c.UserCheckNano(w,req,user,cn) @@ -2374,7 +2399,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.ViewProfile(w,req,user, h) - co.RouteViewCounter.Bump3(123, cn) + co.RouteViewCounter.Bump3(125, cn) } case "/users": switch(req.URL.Path) { @@ -2390,7 +2415,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.BanUserSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(124, cn) + co.RouteViewCounter.Bump3(126, cn) case "/users/unban/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2403,7 +2428,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.UnbanUser(w,req,user,extraData) - co.RouteViewCounter.Bump3(125, cn) + co.RouteViewCounter.Bump3(127, cn) case "/users/activate/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2416,7 +2441,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.ActivateUser(w,req,user,extraData) - co.RouteViewCounter.Bump3(126, cn) + co.RouteViewCounter.Bump3(128, cn) case "/users/ips/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2428,7 +2453,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.IPSearch(w,req,user,h) - co.RouteViewCounter.Bump3(127, cn) + co.RouteViewCounter.Bump3(129, cn) case "/users/delete-posts/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2441,7 +2466,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.DeletePostsSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(128, cn) + co.RouteViewCounter.Bump3(130, cn) } case "/topic": switch(req.URL.Path) { @@ -2461,7 +2486,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.CreateTopicSubmit(w,req,user) - co.RouteViewCounter.Bump3(129, cn) + co.RouteViewCounter.Bump3(131, cn) case "/topic/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2474,7 +2499,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.EditTopicSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(130, cn) + co.RouteViewCounter.Bump3(132, cn) case "/topic/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2488,7 +2513,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * req.URL.Path += extraData err = routes.DeleteTopicSubmit(w,req,user) - co.RouteViewCounter.Bump3(131, cn) + co.RouteViewCounter.Bump3(133, cn) case "/topic/stick/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2501,7 +2526,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.StickTopicSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(132, cn) + co.RouteViewCounter.Bump3(134, cn) case "/topic/unstick/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2514,7 +2539,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.UnstickTopicSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(133, cn) + co.RouteViewCounter.Bump3(135, cn) case "/topic/lock/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2528,7 +2553,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * req.URL.Path += extraData err = routes.LockTopicSubmit(w,req,user) - co.RouteViewCounter.Bump3(134, cn) + co.RouteViewCounter.Bump3(136, cn) case "/topic/unlock/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2541,7 +2566,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.UnlockTopicSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(135, cn) + co.RouteViewCounter.Bump3(137, cn) case "/topic/move/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2554,7 +2579,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.MoveTopicSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(136, cn) + co.RouteViewCounter.Bump3(138, cn) case "/topic/like/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2567,7 +2592,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.LikeTopicSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(137, cn) + co.RouteViewCounter.Bump3(139, cn) case "/topic/unlike/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2580,7 +2605,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.UnlikeTopicSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(138, cn) + co.RouteViewCounter.Bump3(140, cn) case "/topic/attach/add/submit/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2597,7 +2622,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AddAttachToTopicSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(139, cn) + co.RouteViewCounter.Bump3(141, cn) case "/topic/attach/remove/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2610,14 +2635,14 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.RemoveAttachFromTopicSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(140, cn) + co.RouteViewCounter.Bump3(142, cn) default: h, err := c.UserCheckNano(w,req,user,cn) if err != nil { return err } err = routes.ViewTopic(w,req,user, h, extraData) - co.RouteViewCounter.Bump3(141, cn) + co.RouteViewCounter.Bump3(143, cn) } case "/reply": switch(req.URL.Path) { @@ -2637,7 +2662,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.CreateReplySubmit(w,req,user) - co.RouteViewCounter.Bump3(142, cn) + co.RouteViewCounter.Bump3(144, cn) case "/reply/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2650,7 +2675,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.ReplyEditSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(143, cn) + co.RouteViewCounter.Bump3(145, cn) case "/reply/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2663,7 +2688,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.ReplyDeleteSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(144, cn) + co.RouteViewCounter.Bump3(146, cn) case "/reply/like/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2676,7 +2701,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.ReplyLikeSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(145, cn) + co.RouteViewCounter.Bump3(147, cn) case "/reply/unlike/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2689,7 +2714,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.ReplyUnlikeSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(146, cn) + co.RouteViewCounter.Bump3(148, cn) case "/reply/attach/add/submit/": err = c.MemberOnly(w,req,user) if err != nil { @@ -2706,7 +2731,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AddAttachToReplySubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(147, cn) + co.RouteViewCounter.Bump3(149, cn) case "/reply/attach/remove/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2719,7 +2744,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.RemoveAttachFromReplySubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(148, cn) + co.RouteViewCounter.Bump3(150, cn) } case "/profile": switch(req.URL.Path) { @@ -2735,7 +2760,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.ProfileReplyCreateSubmit(w,req,user) - co.RouteViewCounter.Bump3(149, cn) + co.RouteViewCounter.Bump3(151, cn) case "/profile/reply/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2748,7 +2773,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.ProfileReplyEditSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(150, cn) + co.RouteViewCounter.Bump3(152, cn) case "/profile/reply/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2761,7 +2786,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.ProfileReplyDeleteSubmit(w,req,user,extraData) - co.RouteViewCounter.Bump3(151, cn) + co.RouteViewCounter.Bump3(153, cn) } case "/poll": switch(req.URL.Path) { @@ -2777,10 +2802,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.PollVote(w,req,user,extraData) - co.RouteViewCounter.Bump3(152, cn) + co.RouteViewCounter.Bump3(154, cn) case "/poll/results/": err = routes.PollResults(w,req,user,extraData) - co.RouteViewCounter.Bump3(153, cn) + co.RouteViewCounter.Bump3(155, cn) } case "/accounts": switch(req.URL.Path) { @@ -2790,14 +2815,14 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * return err } err = routes.AccountLogin(w,req,user,h) - co.RouteViewCounter.Bump3(154, cn) + co.RouteViewCounter.Bump3(156, cn) case "/accounts/create/": h, err := c.UserCheckNano(w,req,user,cn) if err != nil { return err } err = routes.AccountRegister(w,req,user,h) - co.RouteViewCounter.Bump3(155, cn) + co.RouteViewCounter.Bump3(157, cn) case "/accounts/logout/": err = c.NoSessionMismatch(w,req,user) if err != nil { @@ -2810,7 +2835,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountLogout(w,req,user) - co.RouteViewCounter.Bump3(156, cn) + co.RouteViewCounter.Bump3(158, cn) case "/accounts/login/submit/": err = c.ParseForm(w,req,user) if err != nil { @@ -2818,14 +2843,14 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountLoginSubmit(w,req,user) - co.RouteViewCounter.Bump3(157, cn) + co.RouteViewCounter.Bump3(159, cn) case "/accounts/mfa_verify/": h, err := c.UserCheckNano(w,req,user,cn) if err != nil { return err } err = routes.AccountLoginMFAVerify(w,req,user,h) - co.RouteViewCounter.Bump3(158, cn) + co.RouteViewCounter.Bump3(160, cn) case "/accounts/mfa_verify/submit/": err = c.ParseForm(w,req,user) if err != nil { @@ -2833,7 +2858,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountLoginMFAVerifySubmit(w,req,user) - co.RouteViewCounter.Bump3(159, cn) + co.RouteViewCounter.Bump3(161, cn) case "/accounts/create/submit/": err = c.ParseForm(w,req,user) if err != nil { @@ -2841,14 +2866,14 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountRegisterSubmit(w,req,user) - co.RouteViewCounter.Bump3(160, cn) + co.RouteViewCounter.Bump3(162, cn) case "/accounts/password-reset/": h, err := c.UserCheckNano(w,req,user,cn) if err != nil { return err } err = routes.AccountPasswordReset(w,req,user,h) - co.RouteViewCounter.Bump3(161, cn) + co.RouteViewCounter.Bump3(163, cn) case "/accounts/password-reset/submit/": err = c.ParseForm(w,req,user) if err != nil { @@ -2856,14 +2881,14 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountPasswordResetSubmit(w,req,user) - co.RouteViewCounter.Bump3(162, cn) + co.RouteViewCounter.Bump3(164, cn) case "/accounts/password-reset/token/": h, err := c.UserCheckNano(w,req,user,cn) if err != nil { return err } err = routes.AccountPasswordResetToken(w,req,user,h) - co.RouteViewCounter.Bump3(163, cn) + co.RouteViewCounter.Bump3(165, cn) case "/accounts/password-reset/token/submit/": err = c.ParseForm(w,req,user) if err != nil { @@ -2871,7 +2896,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } err = routes.AccountPasswordResetTokenSubmit(w,req,user) - co.RouteViewCounter.Bump3(164, cn) + co.RouteViewCounter.Bump3(166, cn) } /*case "/sitemaps": // TODO: Count these views req.URL.Path += extraData @@ -2882,7 +2907,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * http.Redirect(w, req, "/s/"+extraData, http.StatusTemporaryRedirect) case "/uploads": if extraData == "" { - co.RouteViewCounter.Bump3(166, cn) + co.RouteViewCounter.Bump3(168, cn) return c.NotFound(w,req,nil) } /*if bzw, ok := w.(c.BrResponseWriter); ok { @@ -2895,14 +2920,14 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * req.URL.Path += extraData // TODO: Find a way to propagate errors up from this? r.UploadHandler(w,req) // TODO: Count these views - co.RouteViewCounter.Bump3(166, cn) + co.RouteViewCounter.Bump3(168, cn) return nil case "": // Stop the favicons, robots.txt file, etc. resolving to the topics list // TODO: Add support for favicons and robots.txt files switch(extraData) { case "robots.txt": - co.RouteViewCounter.Bump3(168, cn) + co.RouteViewCounter.Bump3(170, cn) return routes.RobotsTxt(w,req) case "favicon.ico": /*if bzw, ok := w.(c.BrResponseWriter); ok { @@ -2914,13 +2939,13 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * } req.URL.Path = "/s/favicon.ico" routes.StaticFile(w,req) - co.RouteViewCounter.Bump3(171, cn) + co.RouteViewCounter.Bump3(173, cn) return nil case "opensearch.xml": - co.RouteViewCounter.Bump3(170, cn) + co.RouteViewCounter.Bump3(172, cn) return routes.OpenSearchXml(w,req) /*case "sitemap.xml": - co.RouteViewCounter.Bump3(169, cn) + co.RouteViewCounter.Bump3(171, cn) return routes.SitemapXml(w,req)*/ } co.RouteViewCounter.Bump(0) @@ -2934,10 +2959,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user * if ok { // TODO: Be more specific about *which* dynamic route it is - co.RouteViewCounter.Bump(165) + co.RouteViewCounter.Bump(167) return h(w,req,user) } - co.RouteViewCounter.Bump3(172, cn) + co.RouteViewCounter.Bump3(174, cn) lp := strings.ToLower(req.URL.Path) if strings.Contains(lp,"admin") || strings.Contains(lp,"sql") || strings.Contains(lp,"manage") || strings.Contains(lp,"//") || strings.Contains(lp,"\\\\") || strings.Contains(lp,"wp") || strings.Contains(lp,"wordpress") || strings.Contains(lp,"config") || strings.Contains(lp,"setup") || strings.Contains(lp,"install") || strings.Contains(lp,"update") || strings.Contains(lp,"php") || strings.Contains(lp,"pl") || strings.Contains(lp,"wget") || strings.Contains(lp,"wp-") || strings.Contains(lp,"include") || strings.Contains(lp,"vendor") || strings.Contains(lp,"bin") || strings.Contains(lp,"system") || strings.Contains(lp,"eval") || strings.Contains(lp,"config") { diff --git a/langs/english.json b/langs/english.json index e8913152..1d8af8f5 100644 --- a/langs/english.json +++ b/langs/english.json @@ -658,6 +658,7 @@ "topic_list.changed_topics":"Click to see %d new or changed topics", "topic_list.most_recent_filter":"Most Recent", "topic_list.most_viewed_filter":"Most Viewed", + "topic_list.week_views_filter":"Week Views", "topic_list.replies_suffix":"replies", "topic_list.likes_suffix":"likes", "topic_list.views_suffix":"views", @@ -806,7 +807,7 @@ "error_head":"An error has occurred", "footer_thingymawhatsit":"Can you please keep the powered by notice? ;)", - "footer_powered_by":"Powered by Gosora", + "footer_powered_by":"Powered by Gosora Forum Software", "footer_made_with_love":"Made with love by Azareal", "footer_theme_selector_aria":"Change the site's appearance", diff --git a/main.go b/main.go index 1c406a2c..178fa681 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,7 @@ import ( "fmt" "io" "log" + "mime" "net/http" "os" "os/signal" @@ -278,6 +279,12 @@ func storeInit() (err error) { return errors.WithStack(err) } + log.Print("Initialising the meta store") + c.Meta, err = meta.NewDefaultMetaStore(acc) + if err != nil { + return errors.WithStack(err) + } + log.Print("Initialising the view counters") if !c.Config.DisableAnalytics { co.GlobalViewCounter, err = co.NewGlobalViewCounter(acc) @@ -332,12 +339,6 @@ func storeInit() (err error) { return errors.WithStack(err) } - log.Print("Initialising the meta store") - c.Meta, err = meta.NewDefaultMetaStore(acc) - if err != nil { - return errors.WithStack(err) - } - return nil } @@ -345,8 +346,7 @@ func storeInit() (err error) { func main() { // TODO: Recover from panics /*defer func() { - r := recover() - if r != nil { + if r := recover(); r != nil { log.Print(r) debug.PrintStack() return @@ -374,6 +374,11 @@ func main() { pprof.StartCPUProfile(f) } + err = mime.AddExtensionType(".avif", "image/avif") + if err != nil { + log.Fatal(err) + } + jsToken, err := c.GenerateSafeString(80) if err != nil { log.Fatal(err) @@ -440,6 +445,7 @@ func main() { defer watcher.Close() go func() { + var ErrFileSkip = errors.New("skip mod file") modifiedFileEvent := func(path string) error { pathBits := strings.Split(path, "\\") if len(pathBits) == 0 { @@ -458,23 +464,27 @@ func main() { } } } - return nil + return ErrFileSkip } // TODO: Expand this to more types of files var err error for { select { - case event := <-watcher.Events: + case ev := <-watcher.Events: // TODO: Handle file deletes (and renames more graciously by removing the old version of it) - if event.Op&fsnotify.Write == fsnotify.Write { - log.Println("modified file:", event.Name) - err = modifiedFileEvent(event.Name) - } else if event.Op&fsnotify.Create == fsnotify.Create { - log.Println("new file:", event.Name) - err = modifiedFileEvent(event.Name) + if ev.Op&fsnotify.Write == fsnotify.Write { + err = modifiedFileEvent(ev.Name) + if err != ErrFileSkip { + log.Println("modified file:", ev.Name) + } else { + err = nil + } + } else if ev.Op&fsnotify.Create == fsnotify.Create { + log.Println("new file:", ev.Name) + err = modifiedFileEvent(ev.Name) } else { - log.Println("unknown event:", event) + log.Println("unknown event:", ev) err = nil } if err != nil { @@ -503,9 +513,12 @@ func main() { } } + /*if err = c.StaticFiles.GenJS(); err != nil { + c.LogError(err) + }*/ + log.Print("Checking for init tasks") - err = sched() - if err != nil { + if err = sched(); err != nil { c.LogError(err) } @@ -519,9 +532,9 @@ func main() { // Resource Management Goroutine go func() { - ucache := c.Users.GetCache() - tcache := c.Topics.GetCache() - if ucache == nil && tcache == nil { + uc := c.Users.GetCache() + tc := c.Topics.GetCache() + if uc == nil && tc == nil { return } @@ -532,13 +545,13 @@ func main() { select { case <-secondTicker.C: // TODO: Add a LastRequested field to cached User structs to avoid evicting the same things which wind up getting loaded again anyway? - if ucache != nil { - ucap := ucache.GetCapacity() - if ucache.Length() <= ucap || c.Users.Count() <= ucap { + if uc != nil { + ucap := uc.GetCapacity() + if uc.Length() <= ucap || c.Users.Count() <= ucap { couldNotDealloc = false continue } - lastEvictedCount = ucache.DeallocOverflow(couldNotDealloc) + lastEvictedCount = uc.DeallocOverflow(couldNotDealloc) couldNotDealloc = (lastEvictedCount == 0) } } diff --git a/patcher/patches.go b/patcher/patches.go index 14becc05..493fb641 100644 --- a/patcher/patches.go +++ b/patcher/patches.go @@ -52,7 +52,7 @@ func init() { addPatch(32, patch32) addPatch(33, patch33) addPatch(34, patch34) - //addPatch(35, patch35) + addPatch(35, patch35) } func bcol(col string, val bool) qgen.DBTableColumn { @@ -937,3 +937,11 @@ func patch34(scanner *bufio.Scanner) error { return nil } + +func patch35(scanner *bufio.Scanner) error { + err := execStmt(qgen.Builder.AddColumn("topics", tC{"weekEvenViews", "int", 0, false, false, "0"}, nil)) + if err != nil { + return err + } + return execStmt(qgen.Builder.AddColumn("topics", tC{"weekOddViews", "int", 0, false, false, "0"}, nil)) +} diff --git a/router_gen/main.go b/router_gen/main.go index 65818884..6a7697da 100644 --- a/router_gen/main.go +++ b/router_gen/main.go @@ -412,7 +412,7 @@ func main() { "Slackbot": "slackbot", "Slack": "slackbot", "Discordbot": "discord", - "TelegramBot": "telegram", + "TelegramBot": "telegram", "Twitterbot": "twitter", "facebookexternalhit": "facebook", "Facebot": "facebook", @@ -431,17 +431,17 @@ func main() { "Cocolyzebot": "cocolyze", "Barkrowler": "babbar", "SurdotlyBot": "surdotly", - "DomCopBot":"domcop", + "DomCopBot": "domcop", "NetcraftSurveyAgent": "netcraft", "BLEXBot": "blexbot", "Burf": "burf", "AspiegelBot": "aspiegel", - "PetalBot": "aspiegel", + "PetalBot": "aspiegel", "RU_Bot": "mail_ru", // Mail.RU_Bot "CCBot": "ccbot", "zgrab": "zgrab", "Nimbostratus": "cloudsystemnetworks", - "MauiBot":"maui", + "MauiBot": "maui", "curl": "curl", "python": "python", "Go": "go", @@ -893,7 +893,11 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { agent = {{.AllAgentMap.internetexplorer}} } case {{.AllAgentMap.zgrab}}: - r.SuspiciousRequest(req,"Vuln Scanner") + w.WriteHeader(200) // 400 + w.Write([]byte("")) + r.DumpRequest(req,"Blocked Scanner") + co.AgentViewCounter.Bump({{.AllAgentMap.zgrab}}) + return } if agent == 0 { diff --git a/router_gen/routes.go b/router_gen/routes.go index a18fa231..ad6f4410 100644 --- a/router_gen/routes.go +++ b/router_gen/routes.go @@ -28,6 +28,7 @@ func routes(r *Router) { topicGroup := newRouteGroup("/topics/", View("routes.TopicList", "/topics/"), View("routes.TopicListMostViewed", "/topics/most-viewed/"), + View("routes.TopicListWeekViews", "/topics/week-views/"), MView("routes.CreateTopic", "/topics/create/", "extraData"), ) r.AddGroup(topicGroup) @@ -276,5 +277,6 @@ func panelRoutes() *RouteGroup { View("panel.LogsMod", "/panel/logs/mod/"), View("panel.LogsAdmin", "/panel/logs/admin/"), View("panel.Debug", "/panel/debug/").Before("AdminOnly"), + View("panel.DebugTasks", "/panel/debug/tasks/").Before("AdminOnly"), ) } diff --git a/routes/panel/common.go b/routes/panel/common.go index a57296a1..3fb090a2 100644 --- a/routes/panel/common.go +++ b/routes/panel/common.go @@ -49,6 +49,7 @@ func buildBasePage(w http.ResponseWriter, r *http.Request, u *c.User, titlePhras return nil, ferr } h.Title = p.GetTitlePhrase("panel_" + titlePhrase) + debugAdmin := true - return &c.BasePanelPage{h, stats, zone, c.ReportForumID}, nil + return &c.BasePanelPage{h, stats, zone, c.ReportForumID, debugAdmin}, nil } diff --git a/routes/panel/dashboard.go b/routes/panel/dashboard.go index c32ef70d..021b2b8a 100644 --- a/routes/panel/dashboard.go +++ b/routes/panel/dashboard.go @@ -29,7 +29,7 @@ type dashStmts struct { // TODO: Stop hard-coding these queries func dashMySQLStmts() (stmts dashStmts, err error) { db := qgen.Builder.GetConn() - prepareStmt := func(table string, ext string, dur string) *sql.Stmt { + prepStmt := func(table, ext, dur string) *sql.Stmt { if err != nil { return nil } @@ -38,11 +38,11 @@ func dashMySQLStmts() (stmts dashStmts, err error) { return stmt } - stmts.todaysPostCount = prepareStmt("replies", "", "day") - stmts.todaysTopicCount = prepareStmt("topics", "", "day") - stmts.todaysNewUserCount = prepareStmt("users", "", "day") - stmts.todaysTopicCountByForum = prepareStmt("topics", " and parentID = ?", "day") - stmts.weeklyTopicCountByForum = prepareStmt("topics", " and parentID = ?", "week") + stmts.todaysPostCount = prepStmt("replies", "", "day") + stmts.todaysTopicCount = prepStmt("topics", "", "day") + stmts.todaysNewUserCount = prepStmt("users", "", "day") + stmts.todaysTopicCountByForum = prepStmt("topics", " and parentID=?", "day") + stmts.weeklyTopicCountByForum = prepStmt("topics", " and parentID=?", "week") return stmts, err } @@ -50,7 +50,7 @@ func dashMySQLStmts() (stmts dashStmts, err error) { // TODO: Stop hard-coding these queries func dashMSSQLStmts() (stmts dashStmts, err error) { db := qgen.Builder.GetConn() - prepareStmt := func(table string, ext string, dur string) *sql.Stmt { + prepStmt := func(table, ext, dur string) *sql.Stmt { if err != nil { return nil } @@ -59,11 +59,11 @@ func dashMSSQLStmts() (stmts dashStmts, err error) { return stmt } - stmts.todaysPostCount = prepareStmt("replies", "", "DAY") - stmts.todaysTopicCount = prepareStmt("topics", "", "DAY") - stmts.todaysNewUserCount = prepareStmt("users", "", "DAY") - stmts.todaysTopicCountByForum = prepareStmt("topics", " and parentID = ?", "DAY") - stmts.weeklyTopicCountByForum = prepareStmt("topics", " and parentID = ?", "WEEK") + stmts.todaysPostCount = prepStmt("replies", "", "DAY") + stmts.todaysTopicCount = prepStmt("topics", "", "DAY") + stmts.todaysNewUserCount = prepStmt("users", "", "DAY") + stmts.todaysTopicCountByForum = prepStmt("topics", " and parentID=?", "DAY") + stmts.weeklyTopicCountByForum = prepStmt("topics", " and parentID=?", "WEEK") return stmts, err } @@ -81,7 +81,7 @@ func Dashboard(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteErro cpustr := unknown var cpuColour string - lessThanSwitch := func(number int, lowerBound int, midBound int) string { + lessThanSwitch := func(number, lowerBound, midBound int) string { switch { case number < lowerBound: return "stat_green" @@ -120,7 +120,7 @@ func Dashboard(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteErro runtime.ReadMemStats(&m) memCount, memUnit := c.ConvertByteUnit(float64(m.Sys)) - greaterThanSwitch := func(number int, lowerBound int, midBound int) string { + greaterThanSwitch := func(number, lowerBound, midBound int) string { switch { case number > midBound: return "stat_green" @@ -174,11 +174,11 @@ func Dashboard(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteErro } grid1 := []GE{} - addElem1 := func(id string, href string, body string, order int, class string, back string, textColour string, tooltip string) { + addElem1 := func(id, href, body string, order int, class, back, textColour, tooltip string) { grid1 = append(grid1, GE{id, href, body, order, class, back, textColour, tooltip}) } gridElements := []GE{} - addElem := func(id string, href string, body string, order int, class string, back string, textColour string, tooltip string) { + addElem := func(id, href, body string, order int, class, back, textColour, tooltip string) { gridElements = append(gridElements, GE{id, href, body, order, class, back, textColour, tooltip}) } diff --git a/routes/panel/debug.go b/routes/panel/debug.go index e51794e2..93b33b78 100644 --- a/routes/panel/debug.go +++ b/routes/panel/debug.go @@ -129,3 +129,15 @@ func Debug(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError { pi := c.PanelDebugPage{basePage, goVersion, dbVersion, uptime, openConnCount, qgen.Builder.GetAdapter().GetName(), goroutines, cpus, debugTasks, memStats, debugCache, debugDatabase, debugDisk} return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_dashboard_right", "debug_page", "panel_debug", pi}) } + +func DebugTasks(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError { + basePage, ferr := buildBasePage(w, r, user, "debug", "debug") + if ferr != nil { + return ferr + } + + var debugTasks []c.PanelDebugTaskTask + + pi := c.PanelDebugTaskPage{basePage, debugTasks} + return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_dashboard_right", "debug_page", "panel_debug_task", pi}) +} diff --git a/routes/panel/plugins.go b/routes/panel/plugins.go index 09f27125..5dc69504 100644 --- a/routes/panel/plugins.go +++ b/routes/panel/plugins.go @@ -17,12 +17,12 @@ func Plugins(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError { return c.NoPermissions(w, r, u) } - var pluginList []interface{} - for _, plugin := range c.Plugins { - pluginList = append(pluginList, plugin) + var plList []interface{} + for _, pl := range c.Plugins { + plList = append(plList, pl) } - return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_plugins", c.PanelPage{basePage, pluginList, nil}}) + return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_plugins", c.PanelPage{basePage, plList, nil}}) } // TODO: Abstract more of the plugin activation / installation / deactivation logic, so we can test all that more reliably and easily diff --git a/routes/topic_list.go b/routes/topic_list.go index 4e641331..bcaa2b82 100644 --- a/routes/topic_list.go +++ b/routes/topic_list.go @@ -54,6 +54,14 @@ func TopicListMostViewed(w http.ResponseWriter, r *http.Request, u *c.User, h *c return TopicListCommon(w, r, u, h, "mostviewed", c.TopicListMostViewed) } +func TopicListWeekViews(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError { + skip, rerr := h.Hooks.VhookSkippable("route_topic_list_weekviews_start", w, r, u, h) + if skip || rerr != nil { + return rerr + } + return TopicListCommon(w, r, u, h, "weekviews", c.TopicListWeekViews) +} + // TODO: Implement search func TopicListCommon(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header, torder string, tsorder int) c.RouteError { h.Title = phrases.GetTitlePhrase("topics") @@ -67,6 +75,7 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user *c.User, h *c. return c.LocalError("Something weird happened", w, r, user) } + var forumList []c.Forum // Get the current page page, _ := strconv.Atoi(r.FormValue("page")) sfids := r.FormValue("fids") @@ -80,19 +89,19 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user *c.User, h *c. fids = append(fids, fid) } if len(fids) == 1 { - forum, err := c.Forums.Get(fids[0]) + f, err := c.Forums.Get(fids[0]) if err != nil { return c.LocalError("Invalid fid forum", w, r, user) } - h.Title = forum.Name - h.ZoneID = forum.ID + h.Title = f.Name + h.ZoneID = f.ID + forumList = append(forumList, *f) } } // TODO: Allow multiple forums in searches // TODO: Simplify this block after initially landing search var topicList []*c.TopicsRow - var forumList []c.Forum var pagi c.Paginator var canDelete, ccanDelete, canLock, ccanLock, canMove, ccanMove bool q := r.FormValue("q") @@ -245,11 +254,14 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user *c.User, h *c. } // TODO: Pass a struct back rather than passing back so many variables + //log.Printf("before forumList: %+v\n", forumList) var fps map[int]c.QuickTools if user.IsSuperAdmin { + //log.Print("user.IsSuperAdmin") topicList, forumList, pagi, err = c.TopicList.GetList(page, tsorder, fids) canLock, canMove = true, true } else { + //log.Print("!user.IsSuperAdmin") topicList, forumList, pagi, err = c.TopicList.GetListByGroup(group, page, tsorder, fids) fps = make(map[int]c.QuickTools) for _, f := range forumList { @@ -283,6 +295,8 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user *c.User, h *c. if err != nil { return c.InternalError(err, w, r) } + //log.Printf("after forumList: %+v\n", forumList) + //log.Printf("after topicList: %+v\n", topicList) // TODO: Reduce the amount of boilerplate here if r.FormValue("js") == "1" { diff --git a/templates/panel_forum_edit.html b/templates/panel_forum_edit.html index d5312499..a933bfc8 100644 --- a/templates/panel_forum_edit.html +++ b/templates/panel_forum_edit.html @@ -2,7 +2,7 @@

{{.Name}}{{lang "panel_forum_head_suffix"}}

-
+
diff --git a/templates/panel_inner_menu.html b/templates/panel_inner_menu.html index 6287d4ff..ea3cf854 100644 --- a/templates/panel_inner_menu.html +++ b/templates/panel_inner_menu.html @@ -97,7 +97,12 @@ {{if .CurrentUser.IsSuperAdmin}}{{end}} - {{if .CurrentUser.IsAdmin}}
+ {{if .CurrentUser.IsAdmin}} + + {{if .DebugAdmin}}{{end}} + {{end}}
\ No newline at end of file diff --git a/templates/panel_word_filters.html b/templates/panel_word_filters.html index 4bd3246b..03b1b34c 100644 --- a/templates/panel_word_filters.html +++ b/templates/panel_word_filters.html @@ -1,16 +1,16 @@

{{lang "panel_word_filters_head"}}

-
+
{{range .Something}} {{else}} @@ -24,14 +24,14 @@

{{lang "panel_word_filters_create_head"}}

- +
diff --git a/templates/topic_alt_quick_reply.html b/templates/topic_alt_quick_reply.html index 1a9f4c39..3e3ad3f4 100644 --- a/templates/topic_alt_quick_reply.html +++ b/templates/topic_alt_quick_reply.html @@ -5,7 +5,7 @@
- {{if .CurrentUser.Tag}}{{else}}{{end}} + {{if .CurrentUser.Tag}}
diff --git a/templates/topic_alt_userinfo.html b/templates/topic_alt_userinfo.html index 09177b71..8a01f9c1 100644 --- a/templates/topic_alt_userinfo.html +++ b/templates/topic_alt_userinfo.html @@ -4,7 +4,7 @@
- {{if .Tag}}{{else}}{{end}} + {{if .Tag}}
diff --git a/templates/topic_inner.html b/templates/topic_inner.html index 7a4c9739..6867adb4 100644 --- a/templates/topic_inner.html +++ b/templates/topic_inner.html @@ -56,7 +56,7 @@ {{if .CurrentUser.Perms.CloseTopic}}{{if .Topic.IsClosed}}{{else}}{{end}}{{end}} {{if .CurrentUser.Perms.PinTopic}}{{if .Topic.Sticky}}{{else}}{{end}}{{end}} - {{if .CurrentUser.Perms.ViewIPs}}{{end}} + {{if .CurrentUser.Perms.ViewIPs}}{{end}} {{end}} diff --git a/templates/topics_inner.html b/templates/topics_inner.html index 438ac08f..706c27cf 100644 --- a/templates/topics_inner.html +++ b/templates/topics_inner.html @@ -8,7 +8,7 @@ {{if .ForumList}}
- - {{if eq .Sort.SortBy "mostviewed"}}{{lang "topic_list.most_viewed_filter"}}{{else}}{{lang "topic_list.most_recent_filter"}}{{end}} + {{if eq .Sort.SortBy "mostviewed"}}{{lang "topic_list.most_viewed_filter"}}{{else if eq .Sort.SortBy "weekviews"}}{{lang "topic_list.week_views_filter"}}{{else}}{{lang "topic_list.most_recent_filter"}}{{end}}
diff --git a/themes/nox/overrides/panel_inner_menu.html b/themes/nox/overrides/panel_inner_menu.html index 6287d4ff..ea3cf854 100644 --- a/themes/nox/overrides/panel_inner_menu.html +++ b/themes/nox/overrides/panel_inner_menu.html @@ -97,7 +97,12 @@ {{if .CurrentUser.IsSuperAdmin}}{{end}} - {{if .CurrentUser.IsAdmin}}
+ {{if .CurrentUser.IsAdmin}} + + {{if .DebugAdmin}}{{end}} + {{end}}
\ No newline at end of file diff --git a/themes/nox/overrides/topics_topic.html b/themes/nox/overrides/topics_topic.html index 3a3f6c8f..1be6fa89 100644 --- a/themes/nox/overrides/topics_topic.html +++ b/themes/nox/overrides/topics_topic.html @@ -1,8 +1,8 @@
@@ -11,11 +11,12 @@ {{.PostCount}} {{lang "topic_list.replies_suffix"}} {{.LikeCount}} {{lang "topic_list.likes_suffix"}} {{.ViewCount}} {{lang "topic_list.views_suffix"}} + {{.WeekViews}} {{lang "topic_list.views_suffix"}}
- + {{.LastUser.Name}}
{{reltime .LastReplyAt}} diff --git a/themes/nox/public/main.css b/themes/nox/public/main.css index 96935ffe..0bf25977 100644 --- a/themes/nox/public/main.css +++ b/themes/nox/public/main.css @@ -618,7 +618,9 @@ h2 { .topic_inner_left br, .topic_right_inside br, .topic_inner_right, +.topic_list:not(.topic_list_weekviews) .topic_middle .weekViewCount, .topic_list:not(.topic_list_mostviewed) .topic_middle .viewCount, +.topic_list_weekviews .topic_middle .likeCount, .topic_list_mostviewed .topic_middle .likeCount { display: none; }