You can now filter analytics graphs by a day, twelve hours and six hours.
Added a X-XSS-Protection header. Fixed some Group Editor CSS for Cosora.
This commit is contained in:
parent
d0b6559df9
commit
c7aec90612
|
@ -0,0 +1,33 @@
|
|||
We're not accepting contributions right now, although you're welcome to poke me about things. I'd like to put a process together at some point.
|
||||
|
||||
# Coding Standards
|
||||
|
||||
All code must be unit tested where ever possible with the exception of JavaScript which is untestable with our current technologies, tread with caution there.
|
||||
|
||||
# Golang
|
||||
|
||||
Use the standard linter and listen to what it tells you to do.
|
||||
|
||||
The route assignments in main.go are *legacy code*, add new routes to `router_gen/routes.go` instead.
|
||||
|
||||
Try to use the single responsibility principle where ever possible, with the exception for if doing so will cause a large performance drop. In other words, don't give your interfaces / structs too many responsibilities, keep them simple.
|
||||
|
||||
Avoid hand-rolling queries. Use the builders, a ready built statement or a datastore structure instead. Preferably a datastore.
|
||||
|
||||
More coming up.
|
||||
|
||||
# JavaScript
|
||||
|
||||
Use semicolons at the end of statements. If you don't, you might wind up breaking a minifier or two.
|
||||
|
||||
Always use strict mode.
|
||||
|
||||
Don't worry about ES5, we're targetting modern browsers. If we decide to backport code to older browsers, then we'll transpile the files.
|
||||
|
||||
Don't use await until Edge gets around to implementing it.
|
||||
|
||||
To keep consistency with Go code, variables must be camelCase.
|
||||
|
||||
# JSON
|
||||
|
||||
To keep consistency with Go code, map keys must be camelCase.
|
|
@ -154,6 +154,11 @@ type PanelTimeGraph struct {
|
|||
Labels []int64 // unixtimes for the bottom, gets converted into 1:00, 2:00, etc. with JS
|
||||
}
|
||||
|
||||
type PanelAnalyticsItem struct {
|
||||
Time int64
|
||||
Count int64
|
||||
}
|
||||
|
||||
type PanelAnalyticsPage struct {
|
||||
Title string
|
||||
CurrentUser User
|
||||
|
@ -161,6 +166,8 @@ type PanelAnalyticsPage struct {
|
|||
Stats PanelStats
|
||||
Zone string
|
||||
PrimaryGraph PanelTimeGraph
|
||||
ViewItems []PanelAnalyticsItem
|
||||
TimeRange string
|
||||
}
|
||||
|
||||
type PanelAnalyticsRoutesItem struct {
|
||||
|
@ -185,6 +192,7 @@ type PanelAnalyticsRoutePage struct {
|
|||
Zone string
|
||||
Route string
|
||||
PrimaryGraph PanelTimeGraph
|
||||
TimeRange string
|
||||
}
|
||||
|
||||
type PanelThemesPage struct {
|
||||
|
|
|
@ -278,7 +278,7 @@ func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) {
|
|||
|
||||
h := w.Header()
|
||||
h.Set("X-Frame-Options", "deny")
|
||||
//h.Set("X-XSS-Protection", "1")
|
||||
h.Set("X-XSS-Protection", "1; mode=block") // TODO: Remove when we add a CSP? CSP's are horrendously glitchy things, tread with caution before removing
|
||||
// TODO: Set the content policy header
|
||||
|
||||
return *usercpy, true
|
||||
|
|
|
@ -45,6 +45,7 @@ type User struct {
|
|||
Perms Perms
|
||||
PluginPerms map[string]bool
|
||||
Session string
|
||||
//AuthToken string
|
||||
Loggedin bool
|
||||
Avatar string
|
||||
Message string
|
||||
|
|
282
gen_router.go
282
gen_router.go
|
@ -32,6 +32,7 @@ var RouteMap = map[string]interface{}{
|
|||
"routePanelForumsEdit": routePanelForumsEdit,
|
||||
"routePanelForumsEditSubmit": routePanelForumsEditSubmit,
|
||||
"routePanelForumsEditPermsSubmit": routePanelForumsEditPermsSubmit,
|
||||
"routePanelForumsEditPermsAdvance": routePanelForumsEditPermsAdvance,
|
||||
"routePanelSettings": routePanelSettings,
|
||||
"routePanelSettingEdit": routePanelSettingEdit,
|
||||
"routePanelSettingEditSubmit": routePanelSettingEditSubmit,
|
||||
|
@ -98,51 +99,52 @@ var routeMapEnum = map[string]int{
|
|||
"routePanelForumsEdit": 14,
|
||||
"routePanelForumsEditSubmit": 15,
|
||||
"routePanelForumsEditPermsSubmit": 16,
|
||||
"routePanelSettings": 17,
|
||||
"routePanelSettingEdit": 18,
|
||||
"routePanelSettingEditSubmit": 19,
|
||||
"routePanelWordFilters": 20,
|
||||
"routePanelWordFiltersCreate": 21,
|
||||
"routePanelWordFiltersEdit": 22,
|
||||
"routePanelWordFiltersEditSubmit": 23,
|
||||
"routePanelWordFiltersDeleteSubmit": 24,
|
||||
"routePanelThemes": 25,
|
||||
"routePanelThemesSetDefault": 26,
|
||||
"routePanelPlugins": 27,
|
||||
"routePanelPluginsActivate": 28,
|
||||
"routePanelPluginsDeactivate": 29,
|
||||
"routePanelPluginsInstall": 30,
|
||||
"routePanelUsers": 31,
|
||||
"routePanelUsersEdit": 32,
|
||||
"routePanelUsersEditSubmit": 33,
|
||||
"routePanelAnalyticsViews": 34,
|
||||
"routePanelAnalyticsRoutes": 35,
|
||||
"routePanelAnalyticsRouteViews": 36,
|
||||
"routePanelGroups": 37,
|
||||
"routePanelGroupsEdit": 38,
|
||||
"routePanelGroupsEditPerms": 39,
|
||||
"routePanelGroupsEditSubmit": 40,
|
||||
"routePanelGroupsEditPermsSubmit": 41,
|
||||
"routePanelGroupsCreateSubmit": 42,
|
||||
"routePanelBackups": 43,
|
||||
"routePanelLogsMod": 44,
|
||||
"routePanelDebug": 45,
|
||||
"routePanel": 46,
|
||||
"routeAccountEditCritical": 47,
|
||||
"routeAccountEditCriticalSubmit": 48,
|
||||
"routeAccountEditAvatar": 49,
|
||||
"routeAccountEditAvatarSubmit": 50,
|
||||
"routeAccountEditUsername": 51,
|
||||
"routeAccountEditUsernameSubmit": 52,
|
||||
"routeAccountEditEmail": 53,
|
||||
"routeAccountEditEmailTokenSubmit": 54,
|
||||
"routeProfile": 55,
|
||||
"routeBanSubmit": 56,
|
||||
"routeUnban": 57,
|
||||
"routeActivate": 58,
|
||||
"routeIps": 59,
|
||||
"routeDynamic": 60,
|
||||
"routeUploads": 61,
|
||||
"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,
|
||||
"routePanelAnalyticsRouteViews": 37,
|
||||
"routePanelGroups": 38,
|
||||
"routePanelGroupsEdit": 39,
|
||||
"routePanelGroupsEditPerms": 40,
|
||||
"routePanelGroupsEditSubmit": 41,
|
||||
"routePanelGroupsEditPermsSubmit": 42,
|
||||
"routePanelGroupsCreateSubmit": 43,
|
||||
"routePanelBackups": 44,
|
||||
"routePanelLogsMod": 45,
|
||||
"routePanelDebug": 46,
|
||||
"routePanel": 47,
|
||||
"routeAccountEditCritical": 48,
|
||||
"routeAccountEditCriticalSubmit": 49,
|
||||
"routeAccountEditAvatar": 50,
|
||||
"routeAccountEditAvatarSubmit": 51,
|
||||
"routeAccountEditUsername": 52,
|
||||
"routeAccountEditUsernameSubmit": 53,
|
||||
"routeAccountEditEmail": 54,
|
||||
"routeAccountEditEmailTokenSubmit": 55,
|
||||
"routeProfile": 56,
|
||||
"routeBanSubmit": 57,
|
||||
"routeUnban": 58,
|
||||
"routeActivate": 59,
|
||||
"routeIps": 60,
|
||||
"routeDynamic": 61,
|
||||
"routeUploads": 62,
|
||||
}
|
||||
var reverseRouteMapEnum = map[int]string{
|
||||
0: "routeAPI",
|
||||
|
@ -162,51 +164,52 @@ var reverseRouteMapEnum = map[int]string{
|
|||
14: "routePanelForumsEdit",
|
||||
15: "routePanelForumsEditSubmit",
|
||||
16: "routePanelForumsEditPermsSubmit",
|
||||
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: "routePanelAnalyticsRouteViews",
|
||||
37: "routePanelGroups",
|
||||
38: "routePanelGroupsEdit",
|
||||
39: "routePanelGroupsEditPerms",
|
||||
40: "routePanelGroupsEditSubmit",
|
||||
41: "routePanelGroupsEditPermsSubmit",
|
||||
42: "routePanelGroupsCreateSubmit",
|
||||
43: "routePanelBackups",
|
||||
44: "routePanelLogsMod",
|
||||
45: "routePanelDebug",
|
||||
46: "routePanel",
|
||||
47: "routeAccountEditCritical",
|
||||
48: "routeAccountEditCriticalSubmit",
|
||||
49: "routeAccountEditAvatar",
|
||||
50: "routeAccountEditAvatarSubmit",
|
||||
51: "routeAccountEditUsername",
|
||||
52: "routeAccountEditUsernameSubmit",
|
||||
53: "routeAccountEditEmail",
|
||||
54: "routeAccountEditEmailTokenSubmit",
|
||||
55: "routeProfile",
|
||||
56: "routeBanSubmit",
|
||||
57: "routeUnban",
|
||||
58: "routeActivate",
|
||||
59: "routeIps",
|
||||
60: "routeDynamic",
|
||||
61: "routeUploads",
|
||||
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: "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",
|
||||
}
|
||||
|
||||
// TODO: Stop spilling these into the package scope?
|
||||
|
@ -469,11 +472,14 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
|
||||
common.RouteViewCounter.Bump(16)
|
||||
err = routePanelForumsEditPermsSubmit(w,req,user,extraData)
|
||||
case "/panel/settings/":
|
||||
case "/panel/forums/edit/perms/":
|
||||
common.RouteViewCounter.Bump(17)
|
||||
err = routePanelForumsEditPermsAdvance(w,req,user,extraData)
|
||||
case "/panel/settings/":
|
||||
common.RouteViewCounter.Bump(18)
|
||||
err = routePanelSettings(w,req,user)
|
||||
case "/panel/settings/edit/":
|
||||
common.RouteViewCounter.Bump(18)
|
||||
common.RouteViewCounter.Bump(19)
|
||||
err = routePanelSettingEdit(w,req,user,extraData)
|
||||
case "/panel/settings/edit/submit/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -482,10 +488,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(19)
|
||||
common.RouteViewCounter.Bump(20)
|
||||
err = routePanelSettingEditSubmit(w,req,user,extraData)
|
||||
case "/panel/settings/word-filters/":
|
||||
common.RouteViewCounter.Bump(20)
|
||||
common.RouteViewCounter.Bump(21)
|
||||
err = routePanelWordFilters(w,req,user)
|
||||
case "/panel/settings/word-filters/create/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -494,10 +500,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(21)
|
||||
common.RouteViewCounter.Bump(22)
|
||||
err = routePanelWordFiltersCreate(w,req,user)
|
||||
case "/panel/settings/word-filters/edit/":
|
||||
common.RouteViewCounter.Bump(22)
|
||||
common.RouteViewCounter.Bump(23)
|
||||
err = routePanelWordFiltersEdit(w,req,user,extraData)
|
||||
case "/panel/settings/word-filters/edit/submit/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -506,7 +512,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(23)
|
||||
common.RouteViewCounter.Bump(24)
|
||||
err = routePanelWordFiltersEditSubmit(w,req,user,extraData)
|
||||
case "/panel/settings/word-filters/delete/submit/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -515,10 +521,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(24)
|
||||
common.RouteViewCounter.Bump(25)
|
||||
err = routePanelWordFiltersDeleteSubmit(w,req,user,extraData)
|
||||
case "/panel/themes/":
|
||||
common.RouteViewCounter.Bump(25)
|
||||
common.RouteViewCounter.Bump(26)
|
||||
err = routePanelThemes(w,req,user)
|
||||
case "/panel/themes/default/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -527,10 +533,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(26)
|
||||
common.RouteViewCounter.Bump(27)
|
||||
err = routePanelThemesSetDefault(w,req,user,extraData)
|
||||
case "/panel/plugins/":
|
||||
common.RouteViewCounter.Bump(27)
|
||||
common.RouteViewCounter.Bump(28)
|
||||
err = routePanelPlugins(w,req,user)
|
||||
case "/panel/plugins/activate/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -539,7 +545,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(28)
|
||||
common.RouteViewCounter.Bump(29)
|
||||
err = routePanelPluginsActivate(w,req,user,extraData)
|
||||
case "/panel/plugins/deactivate/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -548,7 +554,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(29)
|
||||
common.RouteViewCounter.Bump(30)
|
||||
err = routePanelPluginsDeactivate(w,req,user,extraData)
|
||||
case "/panel/plugins/install/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -557,13 +563,13 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(30)
|
||||
common.RouteViewCounter.Bump(31)
|
||||
err = routePanelPluginsInstall(w,req,user,extraData)
|
||||
case "/panel/users/":
|
||||
common.RouteViewCounter.Bump(31)
|
||||
common.RouteViewCounter.Bump(32)
|
||||
err = routePanelUsers(w,req,user)
|
||||
case "/panel/users/edit/":
|
||||
common.RouteViewCounter.Bump(32)
|
||||
common.RouteViewCounter.Bump(33)
|
||||
err = routePanelUsersEdit(w,req,user,extraData)
|
||||
case "/panel/users/edit/submit/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -572,25 +578,31 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(33)
|
||||
common.RouteViewCounter.Bump(34)
|
||||
err = routePanelUsersEditSubmit(w,req,user,extraData)
|
||||
case "/panel/analytics/views/":
|
||||
common.RouteViewCounter.Bump(34)
|
||||
err = common.ParseForm(w,req,user)
|
||||
if err != nil {
|
||||
router.handleError(err,w,req,user)
|
||||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(35)
|
||||
err = routePanelAnalyticsViews(w,req,user)
|
||||
case "/panel/analytics/routes/":
|
||||
common.RouteViewCounter.Bump(35)
|
||||
common.RouteViewCounter.Bump(36)
|
||||
err = routePanelAnalyticsRoutes(w,req,user)
|
||||
case "/panel/analytics/route/":
|
||||
common.RouteViewCounter.Bump(36)
|
||||
common.RouteViewCounter.Bump(37)
|
||||
err = routePanelAnalyticsRouteViews(w,req,user,extraData)
|
||||
case "/panel/groups/":
|
||||
common.RouteViewCounter.Bump(37)
|
||||
common.RouteViewCounter.Bump(38)
|
||||
err = routePanelGroups(w,req,user)
|
||||
case "/panel/groups/edit/":
|
||||
common.RouteViewCounter.Bump(38)
|
||||
common.RouteViewCounter.Bump(39)
|
||||
err = routePanelGroupsEdit(w,req,user,extraData)
|
||||
case "/panel/groups/edit/perms/":
|
||||
common.RouteViewCounter.Bump(39)
|
||||
common.RouteViewCounter.Bump(40)
|
||||
err = routePanelGroupsEditPerms(w,req,user,extraData)
|
||||
case "/panel/groups/edit/submit/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -599,7 +611,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(40)
|
||||
common.RouteViewCounter.Bump(41)
|
||||
err = routePanelGroupsEditSubmit(w,req,user,extraData)
|
||||
case "/panel/groups/edit/perms/submit/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -608,7 +620,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(41)
|
||||
common.RouteViewCounter.Bump(42)
|
||||
err = routePanelGroupsEditPermsSubmit(w,req,user,extraData)
|
||||
case "/panel/groups/create/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -617,7 +629,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(42)
|
||||
common.RouteViewCounter.Bump(43)
|
||||
err = routePanelGroupsCreateSubmit(w,req,user)
|
||||
case "/panel/backups/":
|
||||
err = common.SuperAdminOnly(w,req,user)
|
||||
|
@ -626,10 +638,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(43)
|
||||
common.RouteViewCounter.Bump(44)
|
||||
err = routePanelBackups(w,req,user,extraData)
|
||||
case "/panel/logs/mod/":
|
||||
common.RouteViewCounter.Bump(44)
|
||||
common.RouteViewCounter.Bump(45)
|
||||
err = routePanelLogsMod(w,req,user)
|
||||
case "/panel/debug/":
|
||||
err = common.AdminOnly(w,req,user)
|
||||
|
@ -638,10 +650,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(45)
|
||||
common.RouteViewCounter.Bump(46)
|
||||
err = routePanelDebug(w,req,user)
|
||||
default:
|
||||
common.RouteViewCounter.Bump(46)
|
||||
common.RouteViewCounter.Bump(47)
|
||||
err = routePanel(w,req,user)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -656,7 +668,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(47)
|
||||
common.RouteViewCounter.Bump(48)
|
||||
err = routeAccountEditCritical(w,req,user)
|
||||
case "/user/edit/critical/submit/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -671,7 +683,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(48)
|
||||
common.RouteViewCounter.Bump(49)
|
||||
err = routeAccountEditCriticalSubmit(w,req,user)
|
||||
case "/user/edit/avatar/":
|
||||
err = common.MemberOnly(w,req,user)
|
||||
|
@ -680,7 +692,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(49)
|
||||
common.RouteViewCounter.Bump(50)
|
||||
err = routeAccountEditAvatar(w,req,user)
|
||||
case "/user/edit/avatar/submit/":
|
||||
err = common.MemberOnly(w,req,user)
|
||||
|
@ -689,7 +701,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(50)
|
||||
common.RouteViewCounter.Bump(51)
|
||||
err = routeAccountEditAvatarSubmit(w,req,user)
|
||||
case "/user/edit/username/":
|
||||
err = common.MemberOnly(w,req,user)
|
||||
|
@ -698,7 +710,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(51)
|
||||
common.RouteViewCounter.Bump(52)
|
||||
err = routeAccountEditUsername(w,req,user)
|
||||
case "/user/edit/username/submit/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -713,7 +725,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(52)
|
||||
common.RouteViewCounter.Bump(53)
|
||||
err = routeAccountEditUsernameSubmit(w,req,user)
|
||||
case "/user/edit/email/":
|
||||
err = common.MemberOnly(w,req,user)
|
||||
|
@ -722,7 +734,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(53)
|
||||
common.RouteViewCounter.Bump(54)
|
||||
err = routeAccountEditEmail(w,req,user)
|
||||
case "/user/edit/token/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -737,11 +749,11 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(54)
|
||||
common.RouteViewCounter.Bump(55)
|
||||
err = routeAccountEditEmailTokenSubmit(w,req,user,extraData)
|
||||
default:
|
||||
req.URL.Path += extraData
|
||||
common.RouteViewCounter.Bump(55)
|
||||
common.RouteViewCounter.Bump(56)
|
||||
err = routeProfile(w,req,user)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -762,7 +774,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(56)
|
||||
common.RouteViewCounter.Bump(57)
|
||||
err = routeBanSubmit(w,req,user,extraData)
|
||||
case "/users/unban/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -777,7 +789,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(57)
|
||||
common.RouteViewCounter.Bump(58)
|
||||
err = routeUnban(w,req,user,extraData)
|
||||
case "/users/activate/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
|
@ -792,7 +804,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(58)
|
||||
common.RouteViewCounter.Bump(59)
|
||||
err = routeActivate(w,req,user,extraData)
|
||||
case "/users/ips/":
|
||||
err = common.MemberOnly(w,req,user)
|
||||
|
@ -801,7 +813,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
common.RouteViewCounter.Bump(59)
|
||||
common.RouteViewCounter.Bump(60)
|
||||
err = routeIps(w,req,user)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -818,7 +830,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
common.NotFound(w,req)
|
||||
return
|
||||
}
|
||||
common.RouteViewCounter.Bump(61)
|
||||
common.RouteViewCounter.Bump(62)
|
||||
req.URL.Path += extraData
|
||||
// TODO: Find a way to propagate errors up from this?
|
||||
router.UploadHandler(w,req) // TODO: Count these views
|
||||
|
@ -862,7 +874,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
router.RUnlock()
|
||||
|
||||
if ok {
|
||||
common.RouteViewCounter.Bump(60) // TODO: Be more specific about *which* dynamic route it is
|
||||
common.RouteViewCounter.Bump(61) // TODO: Be more specific about *which* dynamic route it is
|
||||
req.URL.Path += extraData
|
||||
err = handle(w,req,user)
|
||||
if err != nil {
|
||||
|
|
116
panel_routes.go
116
panel_routes.go
|
@ -427,6 +427,58 @@ func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use
|
|||
return nil
|
||||
}
|
||||
|
||||
func routePanelForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError {
|
||||
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageForums {
|
||||
return common.NoPermissions(w, r, user)
|
||||
}
|
||||
|
||||
fid, err := strconv.Atoi(sfid)
|
||||
if err != nil {
|
||||
return common.LocalError("The provided Forum ID is not a valid number.", 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)
|
||||
}
|
||||
|
||||
if forum.Preset == "" {
|
||||
forum.Preset = "custom"
|
||||
}
|
||||
|
||||
glist, err := common.Groups.GetAll()
|
||||
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])})
|
||||
}
|
||||
|
||||
pi := common.PanelEditForumPage{common.GetTitlePhrase("panel-edit-forum"), user, headerVars, stats, "forums", forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, gplist}
|
||||
if common.PreRenderHooks["pre_render_panel_edit_forum"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = common.Templates.ExecuteTemplate(w, "panel-forum-edit-perms.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
|
||||
if ferr != nil {
|
||||
|
@ -435,13 +487,36 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo
|
|||
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 <= 12; i++ {
|
||||
var label = currentTime - int64(i*60*30)
|
||||
for i := 1; i <= timeSlices; i++ {
|
||||
var label = currentTime - int64(i*sliceWidth)
|
||||
revLabelList = append(revLabelList, label)
|
||||
viewMap[label] = 0
|
||||
}
|
||||
|
@ -453,7 +528,7 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo
|
|||
log.Print("in routePanelAnalyticsViews")
|
||||
|
||||
acc := qgen.Builder.Accumulator()
|
||||
rows, err := acc.Select("viewchunks").Columns("count, createdAt").Where("route = ''").DateCutoff("createdAt", 6, "hour").Query()
|
||||
rows, err := acc.Select("viewchunks").Columns("count, createdAt").Where("route = ''").DateCutoff("createdAt", timeQuantity, timeUnit).Query()
|
||||
if err != nil && err != ErrNoRows {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -483,13 +558,15 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo
|
|||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
var viewItems []common.PanelAnalyticsItem
|
||||
for _, value := range revLabelList {
|
||||
viewList = append(viewList, viewMap[value])
|
||||
viewItems = append(viewItems, common.PanelAnalyticsItem{Time: value, Count: viewMap[value]})
|
||||
}
|
||||
graph := common.PanelTimeGraph{Series: viewList, Labels: labelList}
|
||||
log.Printf("graph: %+v\n", graph)
|
||||
|
||||
pi := common.PanelAnalyticsPage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", graph}
|
||||
pi := common.PanelAnalyticsPage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", graph, viewItems, timeRange}
|
||||
if common.PreRenderHooks["pre_render_panel_analytics"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_analytics", w, r, &user, &pi) {
|
||||
return nil
|
||||
|
@ -563,13 +640,36 @@ func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user
|
|||
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 <= 12; i++ {
|
||||
var label = currentTime - int64(i*60*30)
|
||||
for i := 1; i <= timeSlices; i++ {
|
||||
var label = currentTime - int64(i*sliceWidth)
|
||||
revLabelList = append(revLabelList, label)
|
||||
viewMap[label] = 0
|
||||
}
|
||||
|
@ -581,7 +681,7 @@ func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user
|
|||
log.Print("in routePanelAnalyticsRouteViews")
|
||||
|
||||
acc := qgen.Builder.Accumulator()
|
||||
rows, err := acc.Select("viewchunks").Columns("count, createdAt").Where("route = ?").DateCutoff("createdAt", 6, "hour").Query(route)
|
||||
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)
|
||||
}
|
||||
|
@ -617,7 +717,7 @@ func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user
|
|||
graph := common.PanelTimeGraph{Series: viewList, Labels: labelList}
|
||||
log.Printf("graph: %+v\n", graph)
|
||||
|
||||
pi := common.PanelAnalyticsRoutePage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", html.EscapeString(route), graph}
|
||||
pi := common.PanelAnalyticsRoutePage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", html.EscapeString(route), graph, timeRange}
|
||||
if common.PreRenderHooks["pre_render_panel_analytics_route_views"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_analytics_route_views", w, r, &user, &pi) {
|
||||
return nil
|
||||
|
|
|
@ -248,15 +248,13 @@ $(document).ready(function(){
|
|||
$(this).closest('.deletable_block').remove();
|
||||
});
|
||||
|
||||
$(".edit_item").click(function(event)
|
||||
{
|
||||
$(".edit_item").click(function(event){
|
||||
event.preventDefault();
|
||||
let blockParent = $(this).closest('.editable_parent');
|
||||
let block = blockParent.find('.editable_block').eq(0);
|
||||
block.html("<textarea style='width: 99%;' name='edit_item'>" + block.html() + "</textarea><br /><a href='" + $(this).closest('a').attr("href") + "'><button class='submit_edit' type='submit'>Update</button></a>");
|
||||
|
||||
$(".submit_edit").click(function(event)
|
||||
{
|
||||
$(".submit_edit").click(function(event){
|
||||
event.preventDefault();
|
||||
let blockParent = $(this).closest('.editable_parent');
|
||||
let block = blockParent.find('.editable_block').eq(0);
|
||||
|
@ -270,6 +268,12 @@ $(document).ready(function(){
|
|||
});
|
||||
});
|
||||
|
||||
$("#forum_quick_perms").click(function(){
|
||||
$(".submit_edit").click(function(event){
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
$(".edit_field").click(function(event)
|
||||
{
|
||||
event.preventDefault();
|
||||
|
@ -536,8 +540,16 @@ $(document).ready(function(){
|
|||
});
|
||||
});
|
||||
|
||||
// The time range selector for the time graphs in the Control Panel
|
||||
$(".timeRangeSelector").change(function(){
|
||||
console.log("Changed the time range to " + this.options[this.selectedIndex].getAttribute("val"));
|
||||
window.location = this.form.getAttribute("action")+"?timeRange=" + this.options[this.selectedIndex].getAttribute("val"); // Do a redirect as a form submission refuses to work properly
|
||||
});
|
||||
|
||||
this.onkeyup = function(event) {
|
||||
if(event.which == 37) this.querySelectorAll("#prevFloat a")[0].click();
|
||||
if(event.which == 39) this.querySelectorAll("#nextFloat a")[0].click();
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
|
@ -17,6 +17,7 @@ func createTables(adapter qgen.Adapter) error {
|
|||
qgen.DBTableColumn{"createdAt", "createdAt", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"lastActiveAt", "datetime", 0, false, false, ""},
|
||||
qgen.DBTableColumn{"session", "varchar", 200, false, false, "''"},
|
||||
//qgen.DBTableColumn{"authToken", "varchar", 200, false, false, "''"},
|
||||
qgen.DBTableColumn{"last_ip", "varchar", 200, false, false, "0.0.0.0.0"},
|
||||
qgen.DBTableColumn{"email", "varchar", 200, false, false, "''"},
|
||||
qgen.DBTableColumn{"avatar", "varchar", 100, false, false, "''"},
|
||||
|
|
|
@ -66,6 +66,7 @@ func buildPanelRoutes() {
|
|||
View("routePanelForumsEdit", "/panel/forums/edit/", "extraData"),
|
||||
Action("routePanelForumsEditSubmit", "/panel/forums/edit/submit/", "extraData"),
|
||||
Action("routePanelForumsEditPermsSubmit", "/panel/forums/edit/perms/submit/", "extraData"),
|
||||
View("routePanelForumsEditPermsAdvance", "/panel/forums/edit/perms/", "extraData"),
|
||||
|
||||
View("routePanelSettings", "/panel/settings/"),
|
||||
View("routePanelSettingEdit", "/panel/settings/edit/", "extraData"),
|
||||
|
@ -89,7 +90,7 @@ func buildPanelRoutes() {
|
|||
View("routePanelUsersEdit", "/panel/users/edit/", "extraData"),
|
||||
Action("routePanelUsersEditSubmit", "/panel/users/edit/submit/", "extraData"),
|
||||
|
||||
View("routePanelAnalyticsViews", "/panel/analytics/views/"),
|
||||
View("routePanelAnalyticsViews", "/panel/analytics/views/").Before("ParseForm"),
|
||||
View("routePanelAnalyticsRoutes", "/panel/analytics/routes/"),
|
||||
View("routePanelAnalyticsRouteViews", "/panel/analytics/route/", "extraData"),
|
||||
|
||||
|
|
|
@ -2,9 +2,18 @@
|
|||
<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/route/{{.Route}}" method="get">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><a>{{.Route}} Views</a></div>
|
||||
<div class="rowitem">
|
||||
<a>{{.Route}} 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>
|
||||
|
|
|
@ -2,12 +2,29 @@
|
|||
<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/views/" method="get">
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><a>Views</a></div>
|
||||
<div class="rowitem">
|
||||
<a>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 class="ct_chart"></div>
|
||||
</div>
|
||||
{{/**}}<div id="panel_analytics_views_table" class="colstack_item rowlist">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_to_minute_time">{{.Time}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}} views</span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>{{**/}}
|
||||
</main>
|
||||
</div>
|
||||
<script>
|
||||
|
@ -30,7 +47,7 @@ let seriesData = [{{range .PrimaryGraph.Series}}
|
|||
];
|
||||
seriesData = seriesData.reverse();
|
||||
|
||||
Chartist.Line('.ct-chart', {
|
||||
Chartist.Line('.ct_chart', {
|
||||
labels: labels,
|
||||
series: [seriesData],
|
||||
}, {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
{{template "header.html" . }}
|
||||
<div class="colstack panel_stack">
|
||||
{{template "panel-menu.html" . }}
|
||||
|
||||
<main class="colstack_right">
|
||||
<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">
|
||||
<div class="colstack_item rowlist formlist panel_forum_perms">
|
||||
{{range .Perms}}
|
||||
<div class="formrow">
|
||||
<div class="formitem">
|
||||
<a>{{.LangStr}}</a>
|
||||
<div class="to_right">
|
||||
<select name="forum-perm-{{.Name}}">
|
||||
<option{{if .Toggle}} selected{{end}} value=1>Yes</option>
|
||||
<option{{if not .Toggle}} selected{{end}} value=0>No</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="formrow">
|
||||
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">Update Forum</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
</div>
|
||||
{{template "footer.html" . }}
|
|
@ -16,13 +16,13 @@
|
|||
<div class="rowitem"><h1>{{.Name}} Group</h1></div>
|
||||
</div>
|
||||
<form action="/panel/groups/edit/perms/submit/{{.ID}}?session={{.CurrentUser.Session}}" method="post">
|
||||
<div id="panel_group" class="colstack_item rowlist formlist">
|
||||
{{if .CurrentUser.Perms.EditGroupLocalPerms}}
|
||||
<div class="colstack_item rowlist formlist panel_group_perms">
|
||||
{{range .LocalPerms}}
|
||||
<div class="formrow">
|
||||
<div class="formitem">
|
||||
<a>{{.LangStr}}</a>
|
||||
<div style="float: right;">
|
||||
<div class="to_right">
|
||||
<select name="group-perm-{{.Name}}">
|
||||
<option{{if .Toggle}} selected{{end}} value=1>Yes</option>
|
||||
<option{{if not .Toggle}} selected{{end}} value=0>No</option>
|
||||
|
@ -31,21 +31,21 @@
|
|||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<div class="formrow">
|
||||
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">Update Group</button></div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .CurrentUser.Perms.EditGroupGlobalPerms}}
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><h1>Extended Permissions</h1></div>
|
||||
</div>
|
||||
<div class="colstack_item rowlist formlist">
|
||||
{{if .CurrentUser.Perms.EditGroupGlobalPerms}}
|
||||
<div class="colstack_item rowlist formlist panel_group_perms">
|
||||
{{range .GlobalPerms}}
|
||||
<div class="formrow">
|
||||
<div class="formitem">
|
||||
<a>{{.LangStr}}</a>
|
||||
<div style="float: right;">
|
||||
<div class="to_right">
|
||||
<select name="group-perm-{{.Name}}">
|
||||
<option{{if .Toggle}} selected{{end}} value=1>Yes</option>
|
||||
<option{{if not .Toggle}} selected{{end}} value=0>No</option>
|
||||
|
@ -54,11 +54,11 @@
|
|||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<div class="formrow">
|
||||
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">Update Group</button></div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</form>
|
||||
</main>
|
||||
</div>
|
||||
|
|
|
@ -92,6 +92,10 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.panel_group_perms .formitem a {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#panel_word_filters .itemSeparator:before {
|
||||
content: "|";
|
||||
padding-left: 5px;
|
||||
|
@ -164,8 +168,11 @@
|
|||
padding-top: 16px;
|
||||
}
|
||||
.ct-series-a .ct-bar, .ct-series-a .ct-line, .ct-series-a .ct-point, .ct-series-a .ct-slice-donut {
|
||||
stroke: hsl(359,98%,53%) !important;
|
||||
}
|
||||
.ct-point {
|
||||
stroke: hsl(359,98%,33%) !important;
|
||||
}
|
||||
.ct-point {
|
||||
stroke: hsl(359,98%,53%) !important;
|
||||
}
|
||||
.ct-point:hover {
|
||||
stroke: hsl(359,98%,50%) !important;
|
||||
}
|
Loading…
Reference in New Issue