Added a time graph for individual user agents.

We now have an Advanced Forum Permissions Editor providing more granular control over permissions.
Tweaked the button CSS and some other bits and pieces.
Added a details section to the View Count Graph.
Renamed a few template files for the sake of consistency and for an upcoming refactor.
Unknown user agents are now logged in debug mode.
Added GetCopy() to the forum permissions store.
Fixed a crash bug in the forum deletion action.
Refactored the permissions list in the group permissions editor.
This commit is contained in:
Azareal 2018-01-10 03:32:48 +00:00
parent 17b21bb7da
commit 25074b58b2
29 changed files with 583 additions and 240 deletions

View File

@ -100,6 +100,7 @@ var PreRenderHooks = map[string][]func(http.ResponseWriter, *http.Request, *User
"pre_render_panel_analytics_routes": nil,
"pre_render_panel_analytics_agents": nil,
"pre_render_panel_analytics_route_views": nil,
"pre_render_panel_analytics_agent_views": nil,
"pre_render_panel_settings": nil,
"pre_render_panel_setting": nil,
"pre_render_panel_word_filters": nil,

View File

@ -94,13 +94,13 @@ func (forum *Forum) Update(name string, desc string, active bool, preset string)
func (forum *Forum) SetPreset(preset string, gid int) error {
fperms, changed := GroupForumPresetToForumPerms(preset)
if changed {
return forum.setPreset(fperms, preset, gid)
return forum.SetPerms(fperms, preset, gid)
}
return nil
}
// TODO: Refactor this
func (forum *Forum) setPreset(fperms *ForumPerms, preset string, gid int) (err error) {
func (forum *Forum) SetPerms(fperms *ForumPerms, preset string, gid int) (err error) {
err = ReplaceForumPermsForGroup(gid, map[int]string{forum.ID: preset}, map[int]*ForumPerms{forum.ID: fperms})
if err != nil {
LogError(err)

View File

@ -217,6 +217,7 @@ func ReplaceForumPermsForGroupTx(tx *sql.Tx, gid int, presetSets map[int]string,
}
// TODO: Refactor this and write tests for it
// TODO: We really need to improve the thread safety of this
func ForumPermsToGroupForumPreset(fperms *ForumPerms) string {
if !fperms.Overrides {
return "default"

View File

@ -14,6 +14,7 @@ var FPStore ForumPermsStore
type ForumPermsStore interface {
Init() error
Get(fid int, gid int) (fperms *ForumPerms, err error)
GetCopy(fid int, gid int) (fperms ForumPerms, err error)
Reload(id int) error
ReloadGroup(fid int, gid int) error
}
@ -198,6 +199,8 @@ func (fps *MemoryForumPermsStore) cascadePermSetToGroup(forumPerms map[int]map[i
}
// TODO: Add a hook here and have plugin_guilds use it
// TODO: Check if the forum exists?
// TODO: Fix the races
func (fps *MemoryForumPermsStore) Get(fid int, gid int) (fperms *ForumPerms, err error) {
group, err := Groups.Get(gid)
if err != nil {
@ -205,3 +208,13 @@ func (fps *MemoryForumPermsStore) Get(fid int, gid int) (fperms *ForumPerms, err
}
return group.Forums[fid], nil
}
// TODO: Check if the forum exists?
// TODO: Fix the races
func (fps *MemoryForumPermsStore) GetCopy(fid int, gid int) (fperms ForumPerms, err error) {
group, err := Groups.Get(gid)
if err != nil {
return fperms, ErrNoRows
}
return *group.Forums[fid], nil
}

View File

@ -209,6 +209,17 @@ type PanelAnalyticsRoutePage struct {
TimeRange string
}
type PanelAnalyticsAgentPage struct {
Title string
CurrentUser User
Header *HeaderVars
Stats PanelStats
Zone string
Agent string
PrimaryGraph PanelTimeGraph
TimeRange string
}
type PanelThemesPage struct {
Title string
CurrentUser User
@ -281,6 +292,21 @@ type NameLangToggle struct {
Toggle bool
}
type PanelEditForumGroupPage struct {
Title string
CurrentUser User
Header *HeaderVars
Stats PanelStats
Zone string
ForumID int
GroupID int
Name string
Desc string
Active bool
Preset string
Perms []NameLangToggle
}
type PanelEditGroupPermsPage struct {
Title string
CurrentUser User

View File

@ -73,9 +73,9 @@ var Template_profile_handle func(ProfilePage, http.ResponseWriter) error = func(
// nolint
var Template_create_topic_handle func(CreateTopicPage, http.ResponseWriter) error = func(pi CreateTopicPage, w http.ResponseWriter) error {
mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["create-topic"]
mapping, ok := Themes[DefaultThemeBox.Load().(string)].TemplatesMap["create_topic"]
if !ok {
mapping = "create-topic"
mapping = "create_topic"
}
return Templates.ExecuteTemplate(w, mapping+".html", pi)
}

View File

@ -33,6 +33,7 @@ var RouteMap = map[string]interface{}{
"routePanelForumsEditSubmit": routePanelForumsEditSubmit,
"routePanelForumsEditPermsSubmit": routePanelForumsEditPermsSubmit,
"routePanelForumsEditPermsAdvance": routePanelForumsEditPermsAdvance,
"routePanelForumsEditPermsAdvanceSubmit": routePanelForumsEditPermsAdvanceSubmit,
"routePanelSettings": routePanelSettings,
"routePanelSettingEdit": routePanelSettingEdit,
"routePanelSettingEditSubmit": routePanelSettingEditSubmit,
@ -54,6 +55,7 @@ var RouteMap = map[string]interface{}{
"routePanelAnalyticsRoutes": routePanelAnalyticsRoutes,
"routePanelAnalyticsAgents": routePanelAnalyticsAgents,
"routePanelAnalyticsRouteViews": routePanelAnalyticsRouteViews,
"routePanelAnalyticsAgentViews": routePanelAnalyticsAgentViews,
"routePanelGroups": routePanelGroups,
"routePanelGroupsEdit": routePanelGroupsEdit,
"routePanelGroupsEditPerms": routePanelGroupsEditPerms,
@ -101,52 +103,54 @@ var routeMapEnum = map[string]int{
"routePanelForumsEditSubmit": 15,
"routePanelForumsEditPermsSubmit": 16,
"routePanelForumsEditPermsAdvance": 17,
"routePanelSettings": 18,
"routePanelSettingEdit": 19,
"routePanelSettingEditSubmit": 20,
"routePanelWordFilters": 21,
"routePanelWordFiltersCreate": 22,
"routePanelWordFiltersEdit": 23,
"routePanelWordFiltersEditSubmit": 24,
"routePanelWordFiltersDeleteSubmit": 25,
"routePanelThemes": 26,
"routePanelThemesSetDefault": 27,
"routePanelPlugins": 28,
"routePanelPluginsActivate": 29,
"routePanelPluginsDeactivate": 30,
"routePanelPluginsInstall": 31,
"routePanelUsers": 32,
"routePanelUsersEdit": 33,
"routePanelUsersEditSubmit": 34,
"routePanelAnalyticsViews": 35,
"routePanelAnalyticsRoutes": 36,
"routePanelAnalyticsAgents": 37,
"routePanelAnalyticsRouteViews": 38,
"routePanelGroups": 39,
"routePanelGroupsEdit": 40,
"routePanelGroupsEditPerms": 41,
"routePanelGroupsEditSubmit": 42,
"routePanelGroupsEditPermsSubmit": 43,
"routePanelGroupsCreateSubmit": 44,
"routePanelBackups": 45,
"routePanelLogsMod": 46,
"routePanelDebug": 47,
"routePanel": 48,
"routeAccountEditCritical": 49,
"routeAccountEditCriticalSubmit": 50,
"routeAccountEditAvatar": 51,
"routeAccountEditAvatarSubmit": 52,
"routeAccountEditUsername": 53,
"routeAccountEditUsernameSubmit": 54,
"routeAccountEditEmail": 55,
"routeAccountEditEmailTokenSubmit": 56,
"routeProfile": 57,
"routeBanSubmit": 58,
"routeUnban": 59,
"routeActivate": 60,
"routeIps": 61,
"routeDynamic": 62,
"routeUploads": 63,
"routePanelForumsEditPermsAdvanceSubmit": 18,
"routePanelSettings": 19,
"routePanelSettingEdit": 20,
"routePanelSettingEditSubmit": 21,
"routePanelWordFilters": 22,
"routePanelWordFiltersCreate": 23,
"routePanelWordFiltersEdit": 24,
"routePanelWordFiltersEditSubmit": 25,
"routePanelWordFiltersDeleteSubmit": 26,
"routePanelThemes": 27,
"routePanelThemesSetDefault": 28,
"routePanelPlugins": 29,
"routePanelPluginsActivate": 30,
"routePanelPluginsDeactivate": 31,
"routePanelPluginsInstall": 32,
"routePanelUsers": 33,
"routePanelUsersEdit": 34,
"routePanelUsersEditSubmit": 35,
"routePanelAnalyticsViews": 36,
"routePanelAnalyticsRoutes": 37,
"routePanelAnalyticsAgents": 38,
"routePanelAnalyticsRouteViews": 39,
"routePanelAnalyticsAgentViews": 40,
"routePanelGroups": 41,
"routePanelGroupsEdit": 42,
"routePanelGroupsEditPerms": 43,
"routePanelGroupsEditSubmit": 44,
"routePanelGroupsEditPermsSubmit": 45,
"routePanelGroupsCreateSubmit": 46,
"routePanelBackups": 47,
"routePanelLogsMod": 48,
"routePanelDebug": 49,
"routePanel": 50,
"routeAccountEditCritical": 51,
"routeAccountEditCriticalSubmit": 52,
"routeAccountEditAvatar": 53,
"routeAccountEditAvatarSubmit": 54,
"routeAccountEditUsername": 55,
"routeAccountEditUsernameSubmit": 56,
"routeAccountEditEmail": 57,
"routeAccountEditEmailTokenSubmit": 58,
"routeProfile": 59,
"routeBanSubmit": 60,
"routeUnban": 61,
"routeActivate": 62,
"routeIps": 63,
"routeDynamic": 64,
"routeUploads": 65,
}
var reverseRouteMapEnum = map[int]string{
0: "routeAPI",
@ -167,52 +171,54 @@ var reverseRouteMapEnum = map[int]string{
15: "routePanelForumsEditSubmit",
16: "routePanelForumsEditPermsSubmit",
17: "routePanelForumsEditPermsAdvance",
18: "routePanelSettings",
19: "routePanelSettingEdit",
20: "routePanelSettingEditSubmit",
21: "routePanelWordFilters",
22: "routePanelWordFiltersCreate",
23: "routePanelWordFiltersEdit",
24: "routePanelWordFiltersEditSubmit",
25: "routePanelWordFiltersDeleteSubmit",
26: "routePanelThemes",
27: "routePanelThemesSetDefault",
28: "routePanelPlugins",
29: "routePanelPluginsActivate",
30: "routePanelPluginsDeactivate",
31: "routePanelPluginsInstall",
32: "routePanelUsers",
33: "routePanelUsersEdit",
34: "routePanelUsersEditSubmit",
35: "routePanelAnalyticsViews",
36: "routePanelAnalyticsRoutes",
37: "routePanelAnalyticsAgents",
38: "routePanelAnalyticsRouteViews",
39: "routePanelGroups",
40: "routePanelGroupsEdit",
41: "routePanelGroupsEditPerms",
42: "routePanelGroupsEditSubmit",
43: "routePanelGroupsEditPermsSubmit",
44: "routePanelGroupsCreateSubmit",
45: "routePanelBackups",
46: "routePanelLogsMod",
47: "routePanelDebug",
48: "routePanel",
49: "routeAccountEditCritical",
50: "routeAccountEditCriticalSubmit",
51: "routeAccountEditAvatar",
52: "routeAccountEditAvatarSubmit",
53: "routeAccountEditUsername",
54: "routeAccountEditUsernameSubmit",
55: "routeAccountEditEmail",
56: "routeAccountEditEmailTokenSubmit",
57: "routeProfile",
58: "routeBanSubmit",
59: "routeUnban",
60: "routeActivate",
61: "routeIps",
62: "routeDynamic",
63: "routeUploads",
18: "routePanelForumsEditPermsAdvanceSubmit",
19: "routePanelSettings",
20: "routePanelSettingEdit",
21: "routePanelSettingEditSubmit",
22: "routePanelWordFilters",
23: "routePanelWordFiltersCreate",
24: "routePanelWordFiltersEdit",
25: "routePanelWordFiltersEditSubmit",
26: "routePanelWordFiltersDeleteSubmit",
27: "routePanelThemes",
28: "routePanelThemesSetDefault",
29: "routePanelPlugins",
30: "routePanelPluginsActivate",
31: "routePanelPluginsDeactivate",
32: "routePanelPluginsInstall",
33: "routePanelUsers",
34: "routePanelUsersEdit",
35: "routePanelUsersEditSubmit",
36: "routePanelAnalyticsViews",
37: "routePanelAnalyticsRoutes",
38: "routePanelAnalyticsAgents",
39: "routePanelAnalyticsRouteViews",
40: "routePanelAnalyticsAgentViews",
41: "routePanelGroups",
42: "routePanelGroupsEdit",
43: "routePanelGroupsEditPerms",
44: "routePanelGroupsEditSubmit",
45: "routePanelGroupsEditPermsSubmit",
46: "routePanelGroupsCreateSubmit",
47: "routePanelBackups",
48: "routePanelLogsMod",
49: "routePanelDebug",
50: "routePanel",
51: "routeAccountEditCritical",
52: "routeAccountEditCriticalSubmit",
53: "routeAccountEditAvatar",
54: "routeAccountEditAvatarSubmit",
55: "routeAccountEditUsername",
56: "routeAccountEditUsernameSubmit",
57: "routeAccountEditEmail",
58: "routeAccountEditEmailTokenSubmit",
59: "routeProfile",
60: "routeBanSubmit",
61: "routeUnban",
62: "routeActivate",
63: "routeIps",
64: "routeDynamic",
65: "routeUploads",
}
var agentMapEnum = map[string]int{
"unknown": 0,
@ -364,6 +370,9 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
common.AgentViewCounter.Bump(11)
default:
common.AgentViewCounter.Bump(0)
if common.Dev.DebugMode {
log.Print("Unknown UA: ", ua)
}
}
// Deal with the session stuff, etc.
@ -539,11 +548,20 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
case "/panel/forums/edit/perms/":
common.RouteViewCounter.Bump(17)
err = routePanelForumsEditPermsAdvance(w,req,user,extraData)
case "/panel/settings/":
case "/panel/forums/edit/perms/adv/submit/":
err = common.NoSessionMismatch(w,req,user)
if err != nil {
router.handleError(err,w,req,user)
return
}
common.RouteViewCounter.Bump(18)
err = routePanelForumsEditPermsAdvanceSubmit(w,req,user,extraData)
case "/panel/settings/":
common.RouteViewCounter.Bump(19)
err = routePanelSettings(w,req,user)
case "/panel/settings/edit/":
common.RouteViewCounter.Bump(19)
common.RouteViewCounter.Bump(20)
err = routePanelSettingEdit(w,req,user,extraData)
case "/panel/settings/edit/submit/":
err = common.NoSessionMismatch(w,req,user)
@ -552,10 +570,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(20)
common.RouteViewCounter.Bump(21)
err = routePanelSettingEditSubmit(w,req,user,extraData)
case "/panel/settings/word-filters/":
common.RouteViewCounter.Bump(21)
common.RouteViewCounter.Bump(22)
err = routePanelWordFilters(w,req,user)
case "/panel/settings/word-filters/create/":
err = common.NoSessionMismatch(w,req,user)
@ -564,10 +582,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(22)
common.RouteViewCounter.Bump(23)
err = routePanelWordFiltersCreate(w,req,user)
case "/panel/settings/word-filters/edit/":
common.RouteViewCounter.Bump(23)
common.RouteViewCounter.Bump(24)
err = routePanelWordFiltersEdit(w,req,user,extraData)
case "/panel/settings/word-filters/edit/submit/":
err = common.NoSessionMismatch(w,req,user)
@ -576,7 +594,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(24)
common.RouteViewCounter.Bump(25)
err = routePanelWordFiltersEditSubmit(w,req,user,extraData)
case "/panel/settings/word-filters/delete/submit/":
err = common.NoSessionMismatch(w,req,user)
@ -585,10 +603,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(25)
common.RouteViewCounter.Bump(26)
err = routePanelWordFiltersDeleteSubmit(w,req,user,extraData)
case "/panel/themes/":
common.RouteViewCounter.Bump(26)
common.RouteViewCounter.Bump(27)
err = routePanelThemes(w,req,user)
case "/panel/themes/default/":
err = common.NoSessionMismatch(w,req,user)
@ -597,10 +615,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(27)
common.RouteViewCounter.Bump(28)
err = routePanelThemesSetDefault(w,req,user,extraData)
case "/panel/plugins/":
common.RouteViewCounter.Bump(28)
common.RouteViewCounter.Bump(29)
err = routePanelPlugins(w,req,user)
case "/panel/plugins/activate/":
err = common.NoSessionMismatch(w,req,user)
@ -609,7 +627,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(29)
common.RouteViewCounter.Bump(30)
err = routePanelPluginsActivate(w,req,user,extraData)
case "/panel/plugins/deactivate/":
err = common.NoSessionMismatch(w,req,user)
@ -618,7 +636,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(30)
common.RouteViewCounter.Bump(31)
err = routePanelPluginsDeactivate(w,req,user,extraData)
case "/panel/plugins/install/":
err = common.NoSessionMismatch(w,req,user)
@ -627,13 +645,13 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(31)
common.RouteViewCounter.Bump(32)
err = routePanelPluginsInstall(w,req,user,extraData)
case "/panel/users/":
common.RouteViewCounter.Bump(32)
common.RouteViewCounter.Bump(33)
err = routePanelUsers(w,req,user)
case "/panel/users/edit/":
common.RouteViewCounter.Bump(33)
common.RouteViewCounter.Bump(34)
err = routePanelUsersEdit(w,req,user,extraData)
case "/panel/users/edit/submit/":
err = common.NoSessionMismatch(w,req,user)
@ -642,7 +660,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(34)
common.RouteViewCounter.Bump(35)
err = routePanelUsersEditSubmit(w,req,user,extraData)
case "/panel/analytics/views/":
err = common.ParseForm(w,req,user)
@ -651,25 +669,28 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(35)
common.RouteViewCounter.Bump(36)
err = routePanelAnalyticsViews(w,req,user)
case "/panel/analytics/routes/":
common.RouteViewCounter.Bump(36)
common.RouteViewCounter.Bump(37)
err = routePanelAnalyticsRoutes(w,req,user)
case "/panel/analytics/agents/":
common.RouteViewCounter.Bump(37)
common.RouteViewCounter.Bump(38)
err = routePanelAnalyticsAgents(w,req,user)
case "/panel/analytics/route/":
common.RouteViewCounter.Bump(38)
err = routePanelAnalyticsRouteViews(w,req,user,extraData)
case "/panel/groups/":
common.RouteViewCounter.Bump(39)
err = routePanelAnalyticsRouteViews(w,req,user,extraData)
case "/panel/analytics/agent/":
common.RouteViewCounter.Bump(40)
err = routePanelAnalyticsAgentViews(w,req,user,extraData)
case "/panel/groups/":
common.RouteViewCounter.Bump(41)
err = routePanelGroups(w,req,user)
case "/panel/groups/edit/":
common.RouteViewCounter.Bump(40)
common.RouteViewCounter.Bump(42)
err = routePanelGroupsEdit(w,req,user,extraData)
case "/panel/groups/edit/perms/":
common.RouteViewCounter.Bump(41)
common.RouteViewCounter.Bump(43)
err = routePanelGroupsEditPerms(w,req,user,extraData)
case "/panel/groups/edit/submit/":
err = common.NoSessionMismatch(w,req,user)
@ -678,7 +699,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(42)
common.RouteViewCounter.Bump(44)
err = routePanelGroupsEditSubmit(w,req,user,extraData)
case "/panel/groups/edit/perms/submit/":
err = common.NoSessionMismatch(w,req,user)
@ -687,7 +708,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(43)
common.RouteViewCounter.Bump(45)
err = routePanelGroupsEditPermsSubmit(w,req,user,extraData)
case "/panel/groups/create/":
err = common.NoSessionMismatch(w,req,user)
@ -696,7 +717,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(44)
common.RouteViewCounter.Bump(46)
err = routePanelGroupsCreateSubmit(w,req,user)
case "/panel/backups/":
err = common.SuperAdminOnly(w,req,user)
@ -705,10 +726,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(45)
common.RouteViewCounter.Bump(47)
err = routePanelBackups(w,req,user,extraData)
case "/panel/logs/mod/":
common.RouteViewCounter.Bump(46)
common.RouteViewCounter.Bump(48)
err = routePanelLogsMod(w,req,user)
case "/panel/debug/":
err = common.AdminOnly(w,req,user)
@ -717,10 +738,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(47)
common.RouteViewCounter.Bump(49)
err = routePanelDebug(w,req,user)
default:
common.RouteViewCounter.Bump(48)
common.RouteViewCounter.Bump(50)
err = routePanel(w,req,user)
}
if err != nil {
@ -735,7 +756,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(49)
common.RouteViewCounter.Bump(51)
err = routeAccountEditCritical(w,req,user)
case "/user/edit/critical/submit/":
err = common.NoSessionMismatch(w,req,user)
@ -750,7 +771,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(50)
common.RouteViewCounter.Bump(52)
err = routeAccountEditCriticalSubmit(w,req,user)
case "/user/edit/avatar/":
err = common.MemberOnly(w,req,user)
@ -759,7 +780,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(51)
common.RouteViewCounter.Bump(53)
err = routeAccountEditAvatar(w,req,user)
case "/user/edit/avatar/submit/":
err = common.MemberOnly(w,req,user)
@ -768,7 +789,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(52)
common.RouteViewCounter.Bump(54)
err = routeAccountEditAvatarSubmit(w,req,user)
case "/user/edit/username/":
err = common.MemberOnly(w,req,user)
@ -777,7 +798,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(53)
common.RouteViewCounter.Bump(55)
err = routeAccountEditUsername(w,req,user)
case "/user/edit/username/submit/":
err = common.NoSessionMismatch(w,req,user)
@ -792,7 +813,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(54)
common.RouteViewCounter.Bump(56)
err = routeAccountEditUsernameSubmit(w,req,user)
case "/user/edit/email/":
err = common.MemberOnly(w,req,user)
@ -801,7 +822,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(55)
common.RouteViewCounter.Bump(57)
err = routeAccountEditEmail(w,req,user)
case "/user/edit/token/":
err = common.NoSessionMismatch(w,req,user)
@ -816,11 +837,11 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(56)
common.RouteViewCounter.Bump(58)
err = routeAccountEditEmailTokenSubmit(w,req,user,extraData)
default:
req.URL.Path += extraData
common.RouteViewCounter.Bump(57)
common.RouteViewCounter.Bump(59)
err = routeProfile(w,req,user)
}
if err != nil {
@ -841,7 +862,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(58)
common.RouteViewCounter.Bump(60)
err = routeBanSubmit(w,req,user,extraData)
case "/users/unban/":
err = common.NoSessionMismatch(w,req,user)
@ -856,7 +877,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(59)
common.RouteViewCounter.Bump(61)
err = routeUnban(w,req,user,extraData)
case "/users/activate/":
err = common.NoSessionMismatch(w,req,user)
@ -871,7 +892,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(60)
common.RouteViewCounter.Bump(62)
err = routeActivate(w,req,user,extraData)
case "/users/ips/":
err = common.MemberOnly(w,req,user)
@ -880,7 +901,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
common.RouteViewCounter.Bump(61)
common.RouteViewCounter.Bump(63)
err = routeIps(w,req,user)
}
if err != nil {
@ -897,7 +918,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
common.NotFound(w,req)
return
}
common.RouteViewCounter.Bump(63)
common.RouteViewCounter.Bump(65)
req.URL.Path += extraData
// TODO: Find a way to propagate errors up from this?
router.UploadHandler(w,req) // TODO: Count these views
@ -941,7 +962,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
router.RUnlock()
if ok {
common.RouteViewCounter.Bump(62) // TODO: Be more specific about *which* dynamic route it is
common.RouteViewCounter.Bump(64) // TODO: Be more specific about *which* dynamic route it is
req.URL.Path += extraData
err = handle(w,req,user)
if err != nil {

View File

@ -51,12 +51,10 @@ func gloinit() (err error) {
if err != nil {
return err
}
err = common.InitThemes()
if err != nil {
return err
}
common.SwitchToTestDB()
var ok bool
@ -70,12 +68,10 @@ func gloinit() (err error) {
if err != nil {
return err
}
err = InitDatabase()
if err != nil {
return err
}
err = afterDBInit()
if err != nil {
return err

View File

@ -97,7 +97,7 @@ func routeTopicCreate(w http.ResponseWriter, r *http.Request, user common.User,
}
}
err = common.RunThemeTemplate(headerVars.Theme.Name, "create-topic", ctpage, w)
err = common.RunThemeTemplate(headerVars.Theme.Name, "create_topic", ctpage, w)
if err != nil {
return common.InternalError(err, w, r)
}
@ -646,7 +646,7 @@ func routeAccountEditCritical(w http.ResponseWriter, r *http.Request, user commo
return nil
}
}
err := common.Templates.ExecuteTemplate(w, "account-own-edit.html", pi)
err := common.Templates.ExecuteTemplate(w, "account_own_edit.html", pi)
if err != nil {
return common.InternalError(err, w, r)
}
@ -692,7 +692,7 @@ func routeAccountEditCriticalSubmit(w http.ResponseWriter, r *http.Request, user
return nil
}
}
err = common.Templates.ExecuteTemplate(w, "account-own-edit.html", pi)
err = common.Templates.ExecuteTemplate(w, "account_own_edit.html", pi)
if err != nil {
return common.InternalError(err, w, r)
}
@ -711,7 +711,7 @@ func routeAccountEditAvatar(w http.ResponseWriter, r *http.Request, user common.
return nil
}
}
err := common.Templates.ExecuteTemplate(w, "account-own-edit-avatar.html", pi)
err := common.Templates.ExecuteTemplate(w, "account_own_edit_avatar.html", pi)
if err != nil {
return common.InternalError(err, w, r)
}
@ -796,7 +796,7 @@ func routeAccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user c
return nil
}
}
err = common.Templates.ExecuteTemplate(w, "account-own-edit-avatar.html", pi)
err = common.Templates.ExecuteTemplate(w, "account_own_edit_avatar.html", pi)
if err != nil {
return common.InternalError(err, w, r)
}
@ -815,7 +815,7 @@ func routeAccountEditUsername(w http.ResponseWriter, r *http.Request, user commo
return nil
}
}
err := common.Templates.ExecuteTemplate(w, "account-own-edit-username.html", pi)
err := common.Templates.ExecuteTemplate(w, "account_own_edit_username.html", pi)
if err != nil {
return common.InternalError(err, w, r)
}
@ -842,7 +842,7 @@ func routeAccountEditUsernameSubmit(w http.ResponseWriter, r *http.Request, user
return nil
}
}
err = common.Templates.ExecuteTemplate(w, "account-own-edit-username.html", pi)
err = common.Templates.ExecuteTemplate(w, "account_own_edit_username.html", pi)
if err != nil {
return common.InternalError(err, w, r)
}
@ -897,7 +897,7 @@ func routeAccountEditEmail(w http.ResponseWriter, r *http.Request, user common.U
return nil
}
}
err = common.Templates.ExecuteTemplate(w, "account-own-edit-email.html", pi)
err = common.Templates.ExecuteTemplate(w, "account_own_edit_email.html", pi)
if err != nil {
return common.InternalError(err, w, r)
}
@ -969,7 +969,7 @@ func routeAccountEditEmailTokenSubmit(w http.ResponseWriter, r *http.Request, us
return nil
}
}
err = common.Templates.ExecuteTemplate(w, "account-own-edit-email.html", pi)
err = common.Templates.ExecuteTemplate(w, "account_own_edit_email.html", pi)
if err != nil {
return common.InternalError(err, w, r)
}

View File

@ -21,6 +21,30 @@ import (
"github.com/Azareal/gopsutil/mem"
)
// We're trying to reduce the amount of boilerplate in here, so I added these two functions, they might wind up circulating outside this file in the future
func panelSuccessRedirect(dest string, w http.ResponseWriter, r *http.Request, isJs bool) common.RouteError {
if !isJs {
http.Redirect(w, r, dest, http.StatusSeeOther)
} else {
w.Write(successJSONBytes)
}
return nil
}
// TODO: Implement this properly
/*func panelRenderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, user common.User, pi interface{}) common.RouteError {
if common.PreRenderHooks["pre_render_"+tmplName] != nil {
if common.RunPreRenderHook("pre_render_"+tmplName, w, r, &user, &pi) {
return nil
}
}
err = common.Templates.ExecuteTemplate(w, tmplName+".html", pi)
if err != nil {
return common.InternalError(err, w, r)
}
return nil
}*/
func routePanel(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
if ferr != nil {
@ -152,11 +176,12 @@ func routePanel(w http.ResponseWriter, r *http.Request, user common.User) common
return nil
}
}
err = common.Templates.ExecuteTemplate(w, "panel-dashboard.html", pi)
err = common.Templates.ExecuteTemplate(w, "panel_dashboard.html", pi)
if err != nil {
return common.InternalError(err, w, r)
}
return nil
//return panelRenderTemplate("panel_dashboard",w,r,user,pi)
}
func routePanelForums(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
@ -255,7 +280,7 @@ func routePanelForumsDelete(w http.ResponseWriter, r *http.Request, user common.
return nil
}
}
err = common.Templates.ExecuteTemplate(w, "areyousure.html", pi)
err = common.Templates.ExecuteTemplate(w, "are_you_sure.html", pi)
if err != nil {
return common.InternalError(err, w, r)
}
@ -322,6 +347,7 @@ func routePanelForumsEdit(w http.ResponseWriter, r *http.Request, user common.Us
if gid == 0 {
continue
}
// TODO: Don't access the cache on the group directly
gplist = append(gplist, common.GroupForumPermPreset{group, common.ForumPermsToGroupForumPreset(group.Forums[fid])})
}
@ -377,13 +403,7 @@ func routePanelForumsEditSubmit(w http.ResponseWriter, r *http.Request, user com
if err != nil {
return common.InternalErrorJSQ(err, w, r, isJs)
}
if !isJs {
http.Redirect(w, r, "/panel/forums/", http.StatusSeeOther)
} else {
w.Write(successJSONBytes)
}
return nil
return panelSuccessRedirect("/panel/forums/", w, r, isJs)
}
func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError {
@ -419,15 +439,30 @@ func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use
return common.LocalErrorJSQ(err.Error(), w, r, user, isJs)
}
if !isJs {
http.Redirect(w, r, "/panel/forums/edit/"+strconv.Itoa(fid), http.StatusSeeOther)
} else {
w.Write(successJSONBytes)
}
return nil
return panelSuccessRedirect("/panel/forums/edit/"+strconv.Itoa(fid), w, r, isJs)
}
func routePanelForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError {
// A helper function for the Advanced portion of the Forum Perms Editor
func panelForumPermsExtractDash(paramList string) (fid int, gid int, err error) {
params := strings.Split(paramList, "-")
if len(params) != 2 {
return fid, gid, errors.New("Parameter count mismatch")
}
fid, err = strconv.Atoi(params[0])
if err != nil {
return fid, gid, errors.New("The provided Forum ID is not a valid number.")
}
gid, err = strconv.Atoi(params[1])
if err != nil {
err = errors.New("The provided Group ID is not a valid number.")
}
return fid, gid, err
}
func routePanelForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, user common.User, paramList string) common.RouteError {
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
if ferr != nil {
return ferr
@ -436,9 +471,9 @@ func routePanelForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, us
return common.NoPermissions(w, r, user)
}
fid, err := strconv.Atoi(sfid)
fid, gid, err := panelForumPermsExtractDash(paramList)
if err != nil {
return common.LocalError("The provided Forum ID is not a valid number.", w, r, user)
return common.LocalError(err.Error(), w, r, user)
}
forum, err := common.Forums.Get(fid)
@ -452,20 +487,33 @@ func routePanelForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, us
forum.Preset = "custom"
}
glist, err := common.Groups.GetAll()
if err != nil {
forumPerms, err := common.FPStore.Get(fid, gid)
if err == ErrNoRows {
return common.LocalError("The requested group doesn't exist.", w, r, user)
} else if err != nil {
return common.InternalError(err, w, r)
}
var gplist []common.GroupForumPermPreset
for gid, group := range glist {
if gid == 0 {
continue
}
gplist = append(gplist, common.GroupForumPermPreset{group, common.ForumPermsToGroupForumPreset(group.Forums[fid])})
}
var formattedPermList []common.NameLangToggle
pi := common.PanelEditForumPage{common.GetTitlePhrase("panel-edit-forum"), user, headerVars, stats, "forums", forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, gplist}
// TODO: Load the phrases in bulk for efficiency?
// TODO: Reduce the amount of code duplication between this and the group editor. Also, can we grind this down into one line or use a code generator to stay current more easily?
var addNameLangToggle = func(permStr string, perm bool) {
formattedPermList = append(formattedPermList, common.NameLangToggle{permStr, common.GetLocalPermPhrase(permStr), perm})
}
addNameLangToggle("ViewTopic", forumPerms.ViewTopic)
addNameLangToggle("LikeItem", forumPerms.LikeItem)
addNameLangToggle("CreateTopic", forumPerms.CreateTopic)
//<--
addNameLangToggle("EditTopic", forumPerms.EditTopic)
addNameLangToggle("DeleteTopic", forumPerms.DeleteTopic)
addNameLangToggle("CreateReply", forumPerms.CreateReply)
addNameLangToggle("EditReply", forumPerms.EditReply)
addNameLangToggle("DeleteReply", forumPerms.DeleteReply)
addNameLangToggle("PinTopic", forumPerms.PinTopic)
addNameLangToggle("CloseTopic", forumPerms.CloseTopic)
pi := common.PanelEditForumGroupPage{common.GetTitlePhrase("panel-edit-forum"), user, headerVars, stats, "forums", forum.ID, gid, forum.Name, forum.Desc, forum.Active, forum.Preset, formattedPermList}
if common.PreRenderHooks["pre_render_panel_edit_forum"] != nil {
if common.RunPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) {
return nil
@ -479,6 +527,60 @@ func routePanelForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, us
return nil
}
func routePanelForumsEditPermsAdvanceSubmit(w http.ResponseWriter, r *http.Request, user common.User, paramList string) common.RouteError {
_, ferr := common.SimplePanelUserCheck(w, r, &user)
if ferr != nil {
return ferr
}
if !user.Perms.ManageForums {
return common.NoPermissions(w, r, user)
}
isJs := (r.PostFormValue("js") == "1")
fid, gid, err := panelForumPermsExtractDash(paramList)
if err != nil {
return common.LocalError(err.Error(), w, r, user)
}
forum, err := common.Forums.Get(fid)
if err == ErrNoRows {
return common.LocalError("The forum you're trying to edit doesn't exist.", w, r, user)
} else if err != nil {
return common.InternalError(err, w, r)
}
forumPerms, err := common.FPStore.GetCopy(fid, gid)
if err == ErrNoRows {
return common.LocalError("The requested group doesn't exist.", w, r, user)
} else if err != nil {
return common.InternalError(err, w, r)
}
var extractPerm = func(name string) bool {
pvalue := r.PostFormValue("forum-perm-" + name)
return (pvalue == "1")
}
// TODO: Generate this code?
forumPerms.ViewTopic = extractPerm("ViewTopic")
forumPerms.LikeItem = extractPerm("LikeItem")
forumPerms.CreateTopic = extractPerm("CreateTopic")
forumPerms.EditTopic = extractPerm("EditTopic")
forumPerms.DeleteTopic = extractPerm("DeleteTopic")
forumPerms.CreateReply = extractPerm("CreateReply")
forumPerms.EditReply = extractPerm("EditReply")
forumPerms.DeleteReply = extractPerm("DeleteReply")
forumPerms.PinTopic = extractPerm("PinTopic")
forumPerms.CloseTopic = extractPerm("CloseTopic")
err = forum.SetPerms(&forumPerms, "custom", gid)
if err != nil {
return common.LocalErrorJSQ(err.Error(), w, r, user, isJs)
}
return panelSuccessRedirect("/panel/forums/edit/perms/"+strconv.Itoa(fid)+"-"+strconv.Itoa(gid), w, r, isJs)
}
func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
if ferr != nil {
@ -628,6 +730,7 @@ func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user
log.Print("in routePanelAnalyticsRouteViews")
acc := qgen.Builder.Accumulator()
// TODO: Validate the route is valid
rows, err := acc.Select("viewchunks").Columns("count, createdAt").Where("route = ?").DateCutoff("createdAt", timeQuantity, timeUnit).Query(route)
if err != nil && err != ErrNoRows {
return common.InternalError(err, w, r)
@ -677,6 +780,105 @@ func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user
return nil
}
func routePanelAnalyticsAgentViews(w http.ResponseWriter, r *http.Request, user common.User, agent string) common.RouteError {
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
if ferr != nil {
return ferr
}
headerVars.Stylesheets = append(headerVars.Stylesheets, "chartist/chartist.min.css")
headerVars.Scripts = append(headerVars.Scripts, "chartist/chartist.min.js")
var timeQuantity = 6
var timeUnit = "hour"
var timeSlices = 12
var sliceWidth = 60 * 30
var timeRange = "six-hours"
switch r.FormValue("timeRange") {
case "one-day":
timeQuantity = 1
timeUnit = "day"
timeSlices = 24
sliceWidth = 60 * 60
timeRange = "one-day"
case "twelve-hours":
timeQuantity = 12
timeSlices = 24
timeRange = "twelve-hours"
case "six-hours", "":
timeRange = "six-hours"
default:
return common.LocalError("Unknown time range", w, r, user)
}
var revLabelList []int64
var labelList []int64
var viewMap = make(map[int64]int64)
var currentTime = time.Now().Unix()
for i := 1; i <= timeSlices; i++ {
var label = currentTime - int64(i*sliceWidth)
revLabelList = append(revLabelList, label)
viewMap[label] = 0
}
for _, value := range revLabelList {
labelList = append(labelList, value)
}
var viewList []int64
log.Print("in routePanelAnalyticsAgentViews")
acc := qgen.Builder.Accumulator()
// TODO: Verify the agent is valid
rows, err := acc.Select("viewchunks_agents").Columns("count, createdAt").Where("browser = ?").DateCutoff("createdAt", timeQuantity, timeUnit).Query(agent)
if err != nil && err != ErrNoRows {
return common.InternalError(err, w, r)
}
defer rows.Close()
for rows.Next() {
var count int64
var createdAt time.Time
err := rows.Scan(&count, &createdAt)
if err != nil {
return common.InternalError(err, w, r)
}
log.Print("count: ", count)
log.Print("createdAt: ", createdAt)
var unixCreatedAt = createdAt.Unix()
log.Print("unixCreatedAt: ", unixCreatedAt)
for _, value := range labelList {
if unixCreatedAt > value {
viewMap[value] += count
break
}
}
}
err = rows.Err()
if err != nil {
return common.InternalError(err, w, r)
}
for _, value := range revLabelList {
viewList = append(viewList, viewMap[value])
}
graph := common.PanelTimeGraph{Series: viewList, Labels: labelList}
log.Printf("graph: %+v\n", graph)
pi := common.PanelAnalyticsAgentPage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", html.EscapeString(agent), graph, timeRange}
if common.PreRenderHooks["pre_render_panel_analytics_agent_views"] != nil {
if common.RunPreRenderHook("pre_render_panel_analytics_agent_views", w, r, &user, &pi) {
return nil
}
}
err = common.Templates.ExecuteTemplate(w, "panel-analytics-agent-views.html", pi)
if err != nil {
return common.InternalError(err, w, r)
}
return nil
}
func routePanelAnalyticsRoutes(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
if ferr != nil {
@ -951,13 +1153,7 @@ func routePanelWordFiltersCreate(w http.ResponseWriter, r *http.Request, user co
}
common.AddWordFilter(int(lastID), find, replacement)
if !isJs {
http.Redirect(w, r, "/panel/settings/word-filters/", http.StatusSeeOther)
} else {
w.Write(successJSONBytes)
}
return nil
return panelSuccessRedirect("/panel/settings/word-filters/", w, r, isJs)
}
func routePanelWordFiltersEdit(w http.ResponseWriter, r *http.Request, user common.User, wfid string) common.RouteError {
@ -1586,39 +1782,48 @@ func routePanelGroupsEditPerms(w http.ResponseWriter, r *http.Request, user comm
// TODO: Load the phrases in bulk for efficiency?
var localPerms []common.NameLangToggle
localPerms = append(localPerms, common.NameLangToggle{"ViewTopic", common.GetLocalPermPhrase("ViewTopic"), group.Perms.ViewTopic})
localPerms = append(localPerms, common.NameLangToggle{"LikeItem", common.GetLocalPermPhrase("LikeItem"), group.Perms.LikeItem})
localPerms = append(localPerms, common.NameLangToggle{"CreateTopic", common.GetLocalPermPhrase("CreateTopic"), group.Perms.CreateTopic})
var addLocalPerm = func(permStr string, perm bool) {
localPerms = append(localPerms, common.NameLangToggle{permStr, common.GetLocalPermPhrase(permStr), perm})
}
addLocalPerm("ViewTopic", group.Perms.ViewTopic)
addLocalPerm("LikeItem", group.Perms.LikeItem)
addLocalPerm("CreateTopic", group.Perms.CreateTopic)
//<--
localPerms = append(localPerms, common.NameLangToggle{"EditTopic", common.GetLocalPermPhrase("EditTopic"), group.Perms.EditTopic})
localPerms = append(localPerms, common.NameLangToggle{"DeleteTopic", common.GetLocalPermPhrase("DeleteTopic"), group.Perms.DeleteTopic})
localPerms = append(localPerms, common.NameLangToggle{"CreateReply", common.GetLocalPermPhrase("CreateReply"), group.Perms.CreateReply})
localPerms = append(localPerms, common.NameLangToggle{"EditReply", common.GetLocalPermPhrase("EditReply"), group.Perms.EditReply})
localPerms = append(localPerms, common.NameLangToggle{"DeleteReply", common.GetLocalPermPhrase("DeleteReply"), group.Perms.DeleteReply})
localPerms = append(localPerms, common.NameLangToggle{"PinTopic", common.GetLocalPermPhrase("PinTopic"), group.Perms.PinTopic})
localPerms = append(localPerms, common.NameLangToggle{"CloseTopic", common.GetLocalPermPhrase("CloseTopic"), group.Perms.CloseTopic})
addLocalPerm("EditTopic", group.Perms.EditTopic)
addLocalPerm("DeleteTopic", group.Perms.DeleteTopic)
addLocalPerm("CreateReply", group.Perms.CreateReply)
addLocalPerm("EditReply", group.Perms.EditReply)
addLocalPerm("DeleteReply", group.Perms.DeleteReply)
addLocalPerm("PinTopic", group.Perms.PinTopic)
addLocalPerm("CloseTopic", group.Perms.CloseTopic)
var globalPerms []common.NameLangToggle
globalPerms = append(globalPerms, common.NameLangToggle{"BanUsers", common.GetGlobalPermPhrase("BanUsers"), group.Perms.BanUsers})
globalPerms = append(globalPerms, common.NameLangToggle{"ActivateUsers", common.GetGlobalPermPhrase("ActivateUsers"), group.Perms.ActivateUsers})
globalPerms = append(globalPerms, common.NameLangToggle{"EditUser", common.GetGlobalPermPhrase("EditUser"), group.Perms.EditUser})
globalPerms = append(globalPerms, common.NameLangToggle{"EditUserEmail", common.GetGlobalPermPhrase("EditUserEmail"), group.Perms.EditUserEmail})
globalPerms = append(globalPerms, common.NameLangToggle{"EditUserPassword", common.GetGlobalPermPhrase("EditUserPassword"), group.Perms.EditUserPassword})
globalPerms = append(globalPerms, common.NameLangToggle{"EditUserGroup", common.GetGlobalPermPhrase("EditUserGroup"), group.Perms.EditUserGroup})
globalPerms = append(globalPerms, common.NameLangToggle{"EditUserGroupSuperMod", common.GetGlobalPermPhrase("EditUserGroupSuperMod"), group.Perms.EditUserGroupSuperMod})
globalPerms = append(globalPerms, common.NameLangToggle{"EditUserGroupAdmin", common.GetGlobalPermPhrase("EditUserGroupAdmin"), group.Perms.EditUserGroupAdmin})
globalPerms = append(globalPerms, common.NameLangToggle{"EditGroup", common.GetGlobalPermPhrase("EditGroup"), group.Perms.EditGroup})
globalPerms = append(globalPerms, common.NameLangToggle{"EditGroupLocalPerms", common.GetGlobalPermPhrase("EditGroupLocalPerms"), group.Perms.EditGroupLocalPerms})
globalPerms = append(globalPerms, common.NameLangToggle{"EditGroupGlobalPerms", common.GetGlobalPermPhrase("EditGroupGlobalPerms"), group.Perms.EditGroupGlobalPerms})
globalPerms = append(globalPerms, common.NameLangToggle{"EditGroupSuperMod", common.GetGlobalPermPhrase("EditGroupSuperMod"), group.Perms.EditGroupSuperMod})
globalPerms = append(globalPerms, common.NameLangToggle{"EditGroupAdmin", common.GetGlobalPermPhrase("EditGroupAdmin"), group.Perms.EditGroupAdmin})
globalPerms = append(globalPerms, common.NameLangToggle{"ManageForums", common.GetGlobalPermPhrase("ManageForums"), group.Perms.ManageForums})
globalPerms = append(globalPerms, common.NameLangToggle{"EditSettings", common.GetGlobalPermPhrase("EditSettings"), group.Perms.EditSettings})
globalPerms = append(globalPerms, common.NameLangToggle{"ManageThemes", common.GetGlobalPermPhrase("ManageThemes"), group.Perms.ManageThemes})
globalPerms = append(globalPerms, common.NameLangToggle{"ManagePlugins", common.GetGlobalPermPhrase("ManagePlugins"), group.Perms.ManagePlugins})
globalPerms = append(globalPerms, common.NameLangToggle{"ViewAdminLogs", common.GetGlobalPermPhrase("ViewAdminLogs"), group.Perms.ViewAdminLogs})
globalPerms = append(globalPerms, common.NameLangToggle{"ViewIPs", common.GetGlobalPermPhrase("ViewIPs"), group.Perms.ViewIPs})
globalPerms = append(globalPerms, common.NameLangToggle{"UploadFiles", common.GetGlobalPermPhrase("UploadFiles"), group.Perms.UploadFiles})
var addGlobalPerm = func(permStr string, perm bool) {
globalPerms = append(globalPerms, common.NameLangToggle{permStr, common.GetGlobalPermPhrase(permStr), perm})
}
addGlobalPerm("BanUsers", group.Perms.BanUsers)
addGlobalPerm("ActivateUsers", group.Perms.ActivateUsers)
addGlobalPerm("EditUser", group.Perms.EditUser)
addGlobalPerm("EditUserEmail", group.Perms.EditUserEmail)
addGlobalPerm("EditUserPassword", group.Perms.EditUserPassword)
addGlobalPerm("EditUserGroup", group.Perms.EditUserGroup)
addGlobalPerm("EditUserGroupSuperMod", group.Perms.EditUserGroupSuperMod)
addGlobalPerm("EditUserGroupAdmin", group.Perms.EditUserGroupAdmin)
addGlobalPerm("EditGroup", group.Perms.EditGroup)
addGlobalPerm("EditGroupLocalPerms", group.Perms.EditGroupLocalPerms)
addGlobalPerm("EditGroupGlobalPerms", group.Perms.EditGroupGlobalPerms)
addGlobalPerm("EditGroupSuperMod", group.Perms.EditGroupSuperMod)
addGlobalPerm("EditGroupAdmin", group.Perms.EditGroupAdmin)
addGlobalPerm("ManageForums", group.Perms.ManageForums)
addGlobalPerm("EditSettings", group.Perms.EditSettings)
addGlobalPerm("ManageThemes", group.Perms.ManageThemes)
addGlobalPerm("ManagePlugins", group.Perms.ManagePlugins)
addGlobalPerm("ViewAdminLogs", group.Perms.ViewAdminLogs)
addGlobalPerm("ViewIPs", group.Perms.ViewIPs)
addGlobalPerm("UploadFiles", group.Perms.UploadFiles)
pi := common.PanelEditGroupPermsPage{common.GetTitlePhrase("panel-edit-group"), user, headerVars, stats, "groups", group.ID, group.Name, localPerms, globalPerms}
if common.PreRenderHooks["pre_render_panel_edit_group_perms"] != nil {
@ -1768,6 +1973,7 @@ func routePanelGroupsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use
}
}
// TODO: Abstract this
pjson, err := json.Marshal(pmap)
if err != nil {
return common.LocalError("Unable to marshal the data", w, r, user)

View File

@ -546,6 +546,16 @@ $(document).ready(function(){
window.location = this.form.getAttribute("action")+"?timeRange=" + this.options[this.selectedIndex].getAttribute("val"); // Do a redirect as a form submission refuses to work properly
});
$(".unix_to_24_hour_time").each(function(){
let unixTime = this.innerText;
let date = new Date(unixTime*1000);
console.log("date: ", date);
let minutes = "0" + date.getMinutes();
let formattedTime = date.getHours() + ":" + minutes.substr(-2);
console.log("formattedTime:", formattedTime);
this.innerText = formattedTime;
});
this.onkeyup = function(event) {
if(event.which == 37) this.querySelectorAll("#prevFloat a")[0].click();
if(event.which == 39) this.querySelectorAll("#nextFloat a")[0].click();

View File

@ -333,6 +333,9 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
common.AgentViewCounter.Bump({{.AllAgentMap.duckduckgo}})
default:
common.AgentViewCounter.Bump({{.AllAgentMap.unknown}})
if common.Dev.DebugMode {
log.Print("Unknown UA: ", ua)
}
}
// Deal with the session stuff, etc.

View File

@ -67,6 +67,7 @@ func buildPanelRoutes() {
Action("routePanelForumsEditSubmit", "/panel/forums/edit/submit/", "extraData"),
Action("routePanelForumsEditPermsSubmit", "/panel/forums/edit/perms/submit/", "extraData"),
View("routePanelForumsEditPermsAdvance", "/panel/forums/edit/perms/", "extraData"),
Action("routePanelForumsEditPermsAdvanceSubmit", "/panel/forums/edit/perms/adv/submit/", "extraData"),
View("routePanelSettings", "/panel/settings/"),
View("routePanelSettingEdit", "/panel/settings/edit/", "extraData"),
@ -94,6 +95,7 @@ func buildPanelRoutes() {
View("routePanelAnalyticsRoutes", "/panel/analytics/routes/"),
View("routePanelAnalyticsAgents", "/panel/analytics/agents/"),
View("routePanelAnalyticsRouteViews", "/panel/analytics/route/", "extraData"),
View("routePanelAnalyticsAgentViews", "/panel/analytics/agent/", "extraData"),
View("routePanelGroups", "/panel/groups/"),
View("routePanelGroupsEdit", "/panel/groups/edit/", "extraData"),

View File

@ -1,6 +1,6 @@
{{template "header.html" . }}
<div class="colstack account">
{{template "account-menu.html" . }}
{{template "account_menu.html" . }}
<main class="colstack_right">
<div class="colstack_item colstack_head rowhead">
<div class="rowitem"><h1>Edit Password</h1></div>

View File

@ -1,6 +1,6 @@
{{template "header.html" . }}
<div class="colstack account">
{{template "account-menu.html" . }}
{{template "account_menu.html" . }}
<main class="colstack_right">
<div class="colstack_item colstack_head rowhead">
<div class="rowitem"><h1>Edit Avatar</h1></div>

View File

@ -1,6 +1,6 @@
{{template "header.html" . }}
<div class="colstack account account_emails">
{{template "account-menu.html" . }}
{{template "account_menu.html" . }}
<main class="colstack_right">
<div class="colstack_item colstack_head rowhead">
<div class="rowitem"><h1>Emails</h1></div>

View File

@ -1,6 +1,6 @@
{{template "header.html" . }}
<div class="colstack account">
{{template "account-menu.html" . }}
{{template "account_menu.html" . }}
<main class="colstack_right">
<div class="colstack_item colstack_head rowhead">
<div class="rowitem"><h1>Edit Username</h1></div>

View File

@ -0,0 +1,49 @@
{{template "header.html" . }}
<div class="colstack panel_stack">
{{template "panel-menu.html" . }}
<main id="panel_dashboard_right" class="colstack_right">
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/agent/{{.Agent}}" method="get">
<div class="colstack_item colstack_head">
<div class="rowitem">
<a>{{.Agent}} Views</a>
<select class="timeRangeSelector to_right" name="timeRange">
<option val="one-day"{{if eq .TimeRange "one-day"}} selected{{end}}>1 day</option>
<option val="twelve-hours"{{if eq .TimeRange "twelve-hours"}} selected{{end}}>12 hours</option>
<option val="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>6 hours</option>
</select>
</div>
</div>
</form>
<div id="panel_analytics_views" class="colstack_graph_holder">
<div class="ct-chart"></div>
</div>
</main>
</div>
<script>
let labels = [];
let rawLabels = [{{range .PrimaryGraph.Labels}}
{{.}},{{end}}
];
for(const i in rawLabels) {
let date = new Date(rawLabels[i]*1000);
console.log("date: ", date);
let minutes = "0" + date.getMinutes();
let label = date.getHours() + ":" + minutes.substr(-2);
console.log("label:", label);
labels.push(label);
}
labels = labels.reverse()
let seriesData = [{{range .PrimaryGraph.Series}}
{{.}},{{end}}
];
seriesData = seriesData.reverse();
Chartist.Line('.ct-chart', {
labels: labels,
series: [seriesData],
}, {
height: '250px',
});
</script>
{{template "footer.html" . }}

View File

@ -3,7 +3,7 @@
{{template "panel-menu.html" . }}
<main id="panel_dashboard_right" class="colstack_right">
<div class="colstack_item colstack_head">
<div class="rowitem"><a>Agents (24 hours)</a></div>
<div class="rowitem"><a>User Agents (24 hours)</a></div>
</div>
<div id="panel_analytics_agents" class="colstack_item rowlist">
{{range .ItemList}}

View File

@ -15,16 +15,19 @@
</div>
</form>
<div id="panel_analytics_views" class="colstack_graph_holder">
<div class="ct_chart"></div>
<div class="ct_chart" aria-label="View Chart"></div>
</div>
{{/**}}<div id="panel_analytics_views_table" class="colstack_item rowlist">
<div class="colstack_item colstack_head">
<div class="rowitem"><a>Details</a></div>
</div>
<div id="panel_analytics_views_table" class="colstack_item rowlist" aria-label="View Table, this has the same information as the view chart">
{{range .ViewItems}}
<div class="rowitem panel_compactrow editable_parent">
<a class="panel_upshift unix_to_minute_time">{{.Time}}</a>
<a class="panel_upshift unix_to_24_hour_time">{{.Time}}</a>
<span class="panel_compacttext to_right">{{.Count}} views</span>
</div>
{{end}}
</div>{{**/}}
</div>
</main>
</div>
<script>

View File

@ -6,7 +6,7 @@
<div class="colstack_item colstack_head">
<div class="rowitem"><h1>{{.Name}} Forum</h1></div>
</div>
<form action="/panel/groups/edit/perms/submit/{{.ID}}?session={{.CurrentUser.Session}}" method="post">
<form action="/panel/forums/edit/perms/adv/submit/{{.ForumID}}-{{.GroupID}}?session={{.CurrentUser.Session}}" method="post">
<div class="colstack_item rowlist formlist panel_forum_perms">
{{range .Perms}}
<div class="formrow">

View File

@ -59,6 +59,7 @@ var form_vars = {'perm_preset': ['can_moderate','can_post','read_only','no_acces
<div class="panel_floater">
<span data-field="perm_preset" data-type="list" data-value="{{.Preset}}" class="editable_block perm_preset perm_preset_{{.Preset}}"></span>
<a class="panel_right_button" href="/panel/forums/edit/perms/submit/{{$.ID}}"><button class='panel_tag submit_edit show_on_edit' type='submit'>Update</button></a>
<a class="panel_right_button" href="/panel/forums/edit/perms/{{$.ID}}-{{.Group.ID}}"><button class='panel_tag show_on_edit' type='submit'>Full Edit</button></a>
</div>
</div>
</div>

View File

@ -27,7 +27,7 @@
<a class="panel_tag edit_fields hide_on_edit panel_right_button edit_button" aria-label="Edit Forum"></a>
<a class="panel_right_button" href="/panel/forums/edit/submit/{{.ID}}"><button class='panel_tag submit_edit show_on_edit' type='submit'>Update</button></a>
{{if gt .ID 1}}<a href="/panel/forums/delete/{{.ID}}?session={{$.CurrentUser.Session}}" class="panel_tag panel_right_button hide_on_edit delete_button" aria-label="Delete Forum"></a>{{end}}
<a href="/panel/forums/edit/{{.ID}}" class="panel_tag panel_right_button show_on_edit">Full Edit</a>
<a href="/panel/forums/edit/{{.ID}}" class="panel_tag panel_right_button show_on_edit"><button>Full Edit</button></a>
</span>
</div>
{{end}}

View File

@ -431,7 +431,7 @@ input, select {
display: flex;
margin-left: 2px;
}
.quick_button_row button, .quick_button_row label, .ip_search_search, .formbutton {
.quick_button_row button, .quick_button_row label, .ip_search_search, .formbutton, button {
padding-left: 10px;
padding-right: 10px;
padding-top: 6px;
@ -470,10 +470,7 @@ label.uploadItem {
padding-left: 33px;
}
button {
border: 1px solid var(--header-border-color);
}
select, input, textarea, button {
select, input, textarea {
background: var(--element-background-color);
padding: 5px;
color: hsl(0,0%,30%);

View File

@ -171,8 +171,22 @@
stroke: hsl(359,98%,53%) !important;
}
.ct-point {
stroke: hsl(359,98%,33%) !important;
stroke: hsl(359,98%,23%) !important;
}
.ct-point:hover {
stroke: hsl(359,98%,50%) !important;
stroke: hsl(359,98%,20%) !important;
}
.timeRangeSelector {
margin-top: -5px;
}
/* Experimental header tweaks */
.colstack_head a {
font-size: 17px;
}
/*
#panel_analytics_views_table .rowlist .panel_compactrow {
padding: 14px;
font-size: 16px;
}
*/