Localised the analytics panes.

Tweaked the analytics phrases to make them a little more compact so they don't overlap as badly.
Added support for Facebook to the analytics panel.
Fixed a bug where language ISO codes weren't tracked properly.
Fixed a bug with settings overflowing their containers on Cosora.
The panel elements can now take up more room on Nox.
Added some information on per-theme overrides to docs/templates.md

Added the analytics.now phrase.
Added the analytics.today phrase.
Added the analytics.days phrase.
Added the analytics.days_short phrase.
Added the analytics.months phrase.
Added the analytics.months_short phrase.
This commit is contained in:
Azareal 2019-03-03 12:28:17 +10:00
parent ec313253ac
commit ce04b6001e
9 changed files with 75 additions and 53 deletions

View File

@ -4,6 +4,8 @@ Gosora uses a subset of [Go Templates](https://golang.org/pkg/text/template/) wh
The base templates are stored in `/templates/` and you can shadow them by placing modified duplicates in `/templates/overrides/`. The default themes all share the same set of templates present there. The base templates are stored in `/templates/` and you can shadow them by placing modified duplicates in `/templates/overrides/`. The default themes all share the same set of templates present there.
You can also override templates on a per-theme basis by navigating to `/themes/themeName/overrides` (replace themeName with the name of the theme) and placing the modified duplicates there.
# Non-standard Extensions # Non-standard Extensions
We also have a few non-standard extensions only available on certain pages or areas, but these shouldn't be relied on in favour of more general mechanisms. We also have a few non-standard extensions only available on certain pages or areas, but these shouldn't be relied on in favour of more general mechanisms.

View File

@ -478,17 +478,18 @@ var agentMapEnum = map[string]int{
"seznambot": 17, "seznambot": 17,
"discord": 18, "discord": 18,
"twitter": 19, "twitter": 19,
"cloudflare": 20, "facebook": 20,
"uptimebot": 21, "cloudflare": 21,
"slackbot": 22, "uptimebot": 22,
"discourse": 23, "slackbot": 23,
"lynx": 24, "discourse": 24,
"blank": 25, "lynx": 25,
"malformed": 26, "blank": 26,
"suspicious": 27, "malformed": 27,
"semrush": 28, "suspicious": 28,
"dotbot": 29, "semrush": 29,
"zgrab": 30, "dotbot": 30,
"zgrab": 31,
} }
var reverseAgentMapEnum = map[int]string{ var reverseAgentMapEnum = map[int]string{
0: "unknown", 0: "unknown",
@ -511,17 +512,18 @@ var reverseAgentMapEnum = map[int]string{
17: "seznambot", 17: "seznambot",
18: "discord", 18: "discord",
19: "twitter", 19: "twitter",
20: "cloudflare", 20: "facebook",
21: "uptimebot", 21: "cloudflare",
22: "slackbot", 22: "uptimebot",
23: "discourse", 23: "slackbot",
24: "lynx", 24: "discourse",
25: "blank", 25: "lynx",
26: "malformed", 26: "blank",
27: "suspicious", 27: "malformed",
28: "semrush", 28: "suspicious",
29: "dotbot", 29: "semrush",
30: "zgrab", 30: "dotbot",
31: "zgrab",
} }
var markToAgent = map[string]string{ var markToAgent = map[string]string{
"OPR": "opera", "OPR": "opera",
@ -546,6 +548,8 @@ var markToAgent = map[string]string{
"Slackbot": "slackbot", "Slackbot": "slackbot",
"Discordbot": "discord", "Discordbot": "discord",
"Twitterbot": "twitter", "Twitterbot": "twitter",
"facebookexternalhit": "facebook",
"Facebot": "facebook",
"Discourse": "discourse", "Discourse": "discourse",
"SemrushBot": "semrush", "SemrushBot": "semrush",
"DotBot": "dotbot", "DotBot": "dotbot",
@ -663,7 +667,7 @@ func (r *GenRouter) SuspiciousRequest(req *http.Request, prepend string) {
prepend += "\n" prepend += "\n"
} }
r.DumpRequest(req,prepend+"Suspicious Request") r.DumpRequest(req,prepend+"Suspicious Request")
counters.AgentViewCounter.Bump(27) counters.AgentViewCounter.Bump(28)
} }
// TODO: Pass the default path or config struct to the router rather than accessing it via a package global // TODO: Pass the default path or config struct to the router rather than accessing it via a package global
@ -690,7 +694,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(200) // 400 w.WriteHeader(200) // 400
w.Write([]byte("")) w.Write([]byte(""))
r.DumpRequest(req,"Malformed Request") r.DumpRequest(req,"Malformed Request")
counters.AgentViewCounter.Bump(26) counters.AgentViewCounter.Bump(27)
return return
} }
@ -752,7 +756,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// TODO: Use a more efficient detector instead of smashing every possible combination in // TODO: Use a more efficient detector instead of smashing every possible combination in
ua := strings.TrimSpace(strings.Replace(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36","",-1)) // Noise, no one's going to be running this and it would require some sort of agent ranking system to determine which identifier should be prioritised over another ua := strings.TrimSpace(strings.Replace(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36","",-1)) // Noise, no one's going to be running this and it would require some sort of agent ranking system to determine which identifier should be prioritised over another
if ua == "" { if ua == "" {
counters.AgentViewCounter.Bump(25) counters.AgentViewCounter.Bump(26)
if common.Dev.DebugMode { if common.Dev.DebugMode {
var prepend string var prepend string
for _, char := range req.UserAgent() { for _, char := range req.UserAgent() {
@ -870,7 +874,9 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
continue continue
} }
llLang = seg llLang = seg
break
} }
common.DebugDetail("llLang:", llLang)
if llLang == "" { if llLang == "" {
counters.LangViewCounter.Bump("none") counters.LangViewCounter.Bump("none")
} else { } else {

View File

@ -386,6 +386,13 @@
"topic.copy_button_text":"Copy", "topic.copy_button_text":"Copy",
"topic.upload_button_text":"Upload", "topic.upload_button_text":"Upload",
"analytics.now": "now",
"analytics.today": "today",
"analytics.days": " days",
"analytics.days_short": "d",
"analytics.months": " months",
"analytics.months_short": "m",
"panel_rank_admins":"Admins", "panel_rank_admins":"Admins",
"panel_rank_mods":"Mods", "panel_rank_mods":"Mods",
"panel_rank_banned":"Banned", "panel_rank_banned":"Banned",

View File

@ -6,32 +6,30 @@
// TODO: Load rawLabels and seriesData dynamically rather than potentially fiddling with nonces for the CSP? // TODO: Load rawLabels and seriesData dynamically rather than potentially fiddling with nonces for the CSP?
function buildStatsChart(rawLabels, seriesData, timeRange, legendNames) { function buildStatsChart(rawLabels, seriesData, timeRange, legendNames) {
let labels = []; let labels = [];
let aphrases = phraseBox["analytics"];
if(timeRange=="one-year") { if(timeRange=="one-year") {
labels = ["today","01 months"]; labels = [aphrases["analytics.now"],"1" + aphrases["analytics.months_short"]];
for(let i = 2; i < 12; i++) { for(let i = 2; i < 12; i++) {
let label = "0" + i + " months"; let label = i + aphrases["analytics.months_short"];
if(label.length > "01 months".length) label = label.substr(1);
labels.push(label); labels.push(label);
} }
} else if(timeRange=="three-months") { } else if(timeRange=="three-months") {
labels = ["today","01 days"]; labels = [aphrases["analytics.now"],"3" + aphrases["analytics.days_short"]]
for(let i = 2; i < 90; i = i + 3) { for(let i = 6; i < 90; i = i + 3) {
let label = "0" + i + " days"; let label = i + aphrases["analytics.days_short"];
if(label.length > "01 days".length) label = label.substr(1);
labels.push(label); labels.push(label);
} }
} else if(timeRange=="one-month") { } else if(timeRange=="one-month") {
labels = ["today","01 days"]; labels = [aphrases["analytics.now"],"1" + aphrases["analytics.days_short"]];
for(let i = 2; i < 30; i++) { for(let i = 2; i < 30; i++) {
let label = "0" + i + " days"; let label = i + aphrases["analytics.days_short"];
if(label.length > "01 days".length) label = label.substr(1);
labels.push(label); labels.push(label);
} }
} else if(timeRange=="one-week") { } else if(timeRange=="one-week") {
labels = ["today"]; labels = [aphrases["analytics.now"]];
for(let i = 2; i < 14; i++) { for(let i = 2; i < 14; i++) {
if (i%2==0) labels.push(""); if (i%2==0) labels.push("");
else labels.push(Math.floor(i/2) + " days"); else labels.push(Math.floor(i/2) + aphrases["analytics.days"]);
} }
} else { } else {
for(const i in rawLabels) { for(const i in rawLabels) {

View File

@ -167,7 +167,7 @@ function RelativeTime(date) {
function initPhrases() { function initPhrases() {
console.log("in initPhrases") console.log("in initPhrases")
fetchPhrases("status,topic_list,alerts,paginator") fetchPhrases("status,topic_list,alerts,paginator,analytics")
} }
function fetchPhrases(plist) { function fetchPhrases(plist) {

View File

@ -213,6 +213,7 @@ func main() {
"seznambot", "seznambot",
"discord", "discord",
"twitter", "twitter",
"facebook",
"cloudflare", "cloudflare",
"uptimebot", "uptimebot",
"slackbot", "slackbot",
@ -255,6 +256,8 @@ func main() {
"Slackbot", "Slackbot",
"Discordbot", "Discordbot",
"Twitterbot", "Twitterbot",
"facebookexternalhit",
"Facebot",
"Discourse", "Discourse",
"SemrushBot", "SemrushBot",
@ -273,20 +276,22 @@ func main() {
"SamsungBrowser": "samsung", "SamsungBrowser": "samsung",
"UCBrowser": "ucbrowser", "UCBrowser": "ucbrowser",
"Google": "googlebot", "Google": "googlebot",
"Googlebot": "googlebot", "Googlebot": "googlebot",
"yandex": "yandex", // from the URL "yandex": "yandex", // from the URL
"DuckDuckBot": "duckduckgo", "DuckDuckBot": "duckduckgo",
"Baiduspider": "baidu", "Baiduspider": "baidu",
"bingbot": "bing", "bingbot": "bing",
"BingPreview": "bing", "BingPreview": "bing",
"SeznamBot": "seznambot", "SeznamBot": "seznambot",
"CloudFlare": "cloudflare", // Track alwayson specifically in case there are other bots? "CloudFlare": "cloudflare", // Track alwayson specifically in case there are other bots?
"Uptimebot": "uptimebot", "Uptimebot": "uptimebot",
"Slackbot": "slackbot", "Slackbot": "slackbot",
"Discordbot": "discord", "Discordbot": "discord",
"Twitterbot": "twitter", "Twitterbot": "twitter",
"Discourse": "discourse", "facebookexternalhit": "facebook",
"Facebot": "facebook",
"Discourse": "discourse",
"SemrushBot": "semrush", "SemrushBot": "semrush",
"DotBot": "dotbot", "DotBot": "dotbot",
@ -662,7 +667,9 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
continue continue
} }
llLang = seg llLang = seg
break
} }
common.DebugDetail("llLang:", llLang)
if llLang == "" { if llLang == "" {
counters.LangViewCounter.Bump("none") counters.LangViewCounter.Bump("none")
} else { } else {

View File

@ -143,6 +143,7 @@ var phraseWhitelist = []string{
"status", "status",
"alerts", "alerts",
"paginator", "paginator",
"analytics",
} }
func routeAPIPhrases(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { func routeAPIPhrases(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {

View File

@ -198,6 +198,7 @@
float: none; float: none;
margin-top: auto; margin-top: auto;
padding-top: 14px; padding-top: 14px;
word-break: break-all;
} }
#panel_page_list textarea, #panel_page_edit textarea { #panel_page_list textarea, #panel_page_edit textarea {
margin-top: 8px; margin-top: 8px;

View File

@ -27,7 +27,7 @@
.colstack_right { .colstack_right {
background-color: #333333; background-color: #333333;
width: 75%; width: 90%;
padding-top: 12px; padding-top: 12px;
padding-right: 24px; padding-right: 24px;
padding-bottom: 24px; padding-bottom: 24px;