From 59e491ee0a433fee2fe64bc2713ec0d0e22f7b18 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Else Date: Sun, 9 May 2021 09:08:31 +0200 Subject: [PATCH] Improve blogstats and load table using JS (because it's slow) --- blogroll.go | 7 +++-- blogstats.go | 20 ++++++++++--- database.go | 3 ++ http.go | 7 ++++- markdown.go | 13 +++++++++ render.go | 1 + templates/assets/js/blogstats.js | 27 ++++++++++++------ templates/blogstats.gohtml | 47 +------------------------------ templates/blogstatstable.gohtml | 48 ++++++++++++++++++++++++++++++++ templates/strings/de.yaml | 1 + templates/strings/default.yaml | 1 + 11 files changed, 114 insertions(+), 61 deletions(-) create mode 100644 templates/blogstatstable.gohtml diff --git a/blogroll.go b/blogroll.go index 430dcc7..bb9fde4 100644 --- a/blogroll.go +++ b/blogroll.go @@ -3,6 +3,7 @@ package main import ( "fmt" "io" + "log" "net/http" "sort" "strings" @@ -26,7 +27,8 @@ func serveBlogroll(w http.ResponseWriter, r *http.Request) { return getBlogrollOutlines(c) }) if err != nil { - serveError(w, r, err.Error(), http.StatusInternalServerError) + log.Println("Failed to get outlines:", err.Error()) + serveError(w, r, "", http.StatusInternalServerError) return } if appConfig.Cache != nil && appConfig.Cache.Enable { @@ -54,7 +56,8 @@ func serveBlogrollExport(w http.ResponseWriter, r *http.Request) { return getBlogrollOutlines(c) }) if err != nil { - serveError(w, r, err.Error(), http.StatusInternalServerError) + log.Println("Failed to get outlines:", err.Error()) + serveError(w, r, "", http.StatusInternalServerError) return } if appConfig.Cache != nil && appConfig.Cache.Enable { diff --git a/blogstats.go b/blogstats.go index 6507f37..e610c22 100644 --- a/blogstats.go +++ b/blogstats.go @@ -8,6 +8,18 @@ import ( ) func serveBlogStats(w http.ResponseWriter, r *http.Request) { + blog := r.Context().Value(blogContextKey).(string) + canonical := blogPath(blog) + appConfig.Blogs[blog].BlogStats.Path + render(w, r, templateBlogStats, &renderData{ + BlogString: blog, + Canonical: canonical, + Data: map[string]interface{}{ + "TableUrl": canonical + ".table.html", + }, + }) +} + +func serveBlogStatsTable(w http.ResponseWriter, r *http.Request) { blog := r.Context().Value(blogContextKey).(string) // Start timing t := servertiming.FromContext(r.Context()).NewMetric("sq").Start() @@ -17,6 +29,7 @@ func serveBlogStats(w http.ResponseWriter, r *http.Request) { status: statusPublished, } query, params := buildPostsQuery(prq) + query = "select path, mdtext(content) as content, published, substr(published, 1, 4) as year, substr(published, 6, 2) as month from (" + query + ")" postCount := "coalesce(count(distinct path), 0) as postcount" charCount := "coalesce(sum(coalesce(length(distinct content), 0)), 0)" wordCount := "coalesce(sum(wordcount(distinct content)), 0) as wordcount" @@ -36,7 +49,7 @@ func serveBlogStats(w http.ResponseWriter, r *http.Request) { return } // Count posts per year - rows, err := appDbQuery("select *, "+wordsPerPost+" from (select substr(published, 1, 4) as year, "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published != '' group by year order by year desc)", params...) + rows, err := appDbQuery("select *, "+wordsPerPost+" from (select year, "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published != '' group by year order by year desc)", params...) if err != nil { serveError(w, r, err.Error(), http.StatusInternalServerError) return @@ -66,7 +79,7 @@ func serveBlogStats(w http.ResponseWriter, r *http.Request) { months := map[string][]statsTableType{} month := statsTableType{} for _, year := range years { - rows, err = appDbQuery("select *, "+wordsPerPost+" from (select substr(published, 6, 2) as month, "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published != '' and substr(published, 1, 4) = @year group by month order by month desc)", append(params, sql.Named("year", year.Name))...) + rows, err = appDbQuery("select *, "+wordsPerPost+" from (select month, "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published != '' and year = @year group by month order by month desc)", append(params, sql.Named("year", year.Name))...) if err != nil { serveError(w, r, err.Error(), http.StatusInternalServerError) return @@ -83,9 +96,8 @@ func serveBlogStats(w http.ResponseWriter, r *http.Request) { // Stop timing t.Stop() // Render - render(w, r, templateBlogStats, &renderData{ + render(w, r, templateBlogStatsTable, &renderData{ BlogString: blog, - Canonical: blogPath(blog) + appConfig.Blogs[blog].BlogStats.Path, Data: map[string]interface{}{ "total": total, "years": years, diff --git a/database.go b/database.go index b485474..0a28b89 100644 --- a/database.go +++ b/database.go @@ -25,6 +25,9 @@ func initDatabase() (err error) { if err := c.RegisterFunc("wordcount", wordCount, true); err != nil { return err } + if err := c.RegisterFunc("mdtext", renderText, true); err != nil { + return err + } return nil }, }) diff --git a/http.go b/http.go index 5ebb74d..5071ff5 100644 --- a/http.go +++ b/http.go @@ -478,7 +478,12 @@ func buildDynamicRouter() (*chi.Mux, error) { // Stats if blogConfig.BlogStats != nil && blogConfig.BlogStats.Enabled { statsPath := blogPath + blogConfig.BlogStats.Path - r.With(privateModeHandler...).With(cacheMiddleware, sbm).Get(statsPath, serveBlogStats) + r.Group(func(r chi.Router) { + r.Use(privateModeHandler...) + r.Use(cacheMiddleware, sbm) + r.Get(statsPath, serveBlogStats) + r.Get(statsPath+".table.html", serveBlogStatsTable) + }) } // Date archives diff --git a/markdown.go b/markdown.go index 1af3737..a45eb2c 100644 --- a/markdown.go +++ b/markdown.go @@ -4,6 +4,7 @@ import ( "bytes" "strings" + "github.com/PuerkitoBio/goquery" kemoji "github.com/kyokomi/emoji/v2" "github.com/yuin/goldmark" emoji "github.com/yuin/goldmark-emoji" @@ -54,6 +55,18 @@ func renderMarkdown(source string, absoluteLinks bool) (rendered []byte, err err return buffer.Bytes(), err } +func renderText(s string) string { + h, err := renderMarkdown(s, false) + if err != nil { + return "" + } + d, err := goquery.NewDocumentFromReader(bytes.NewReader(h)) + if err != nil { + return "" + } + return d.Text() +} + // Extensions etc... // All emojis from emoji lib diff --git a/render.go b/render.go index 84409aa..b809dd1 100644 --- a/render.go +++ b/render.go @@ -35,6 +35,7 @@ const ( templateLogin = "login" templateStaticHome = "statichome" templateBlogStats = "blogstats" + templateBlogStatsTable = "blogstatstable" templateComment = "comment" templateCaptcha = "captcha" templateCommentsAdmin = "commentsadmin" diff --git a/templates/assets/js/blogstats.js b/templates/assets/js/blogstats.js index 5f4e37e..40aea99 100644 --- a/templates/assets/js/blogstats.js +++ b/templates/assets/js/blogstats.js @@ -1,11 +1,22 @@ (function () { - Array.from(document.getElementsByClassName('statsyear')).forEach(element => { - element.addEventListener('click', function () { - Array.from(document.getElementsByClassName('statsmonth')).forEach(c => { - if (element.dataset.year == c.dataset.year) { - c.classList.contains('hide') ? c.classList.remove('hide') : c.classList.add('hide') - } + let loadingEl = document.getElementById('loading') + let tableUrl = loadingEl.dataset.table + + let tableReq = new XMLHttpRequest() + tableReq.open('GET', tableUrl) + tableReq.onload = function() { + if (tableReq.status == 200) { + loadingEl.outerHTML = tableReq.responseText + Array.from(document.getElementsByClassName('statsyear')).forEach(element => { + element.addEventListener('click', function () { + Array.from(document.getElementsByClassName('statsmonth')).forEach(c => { + if (element.dataset.year == c.dataset.year) { + c.classList.contains('hide') ? c.classList.remove('hide') : c.classList.add('hide') + } + }) + }) }) - }) - }) + } + } + tableReq.send() })() \ No newline at end of file diff --git a/templates/blogstats.gohtml b/templates/blogstats.gohtml index c94f2da..febbe74 100644 --- a/templates/blogstats.gohtml +++ b/templates/blogstats.gohtml @@ -6,52 +6,7 @@
{{ with .Blog.BlogStats.Title }}

{{ . }}

{{ end }} {{ with .Blog.BlogStats.Description }}{{ md . }}{{ end }} - - - - - - - - - - - - {{ $months := .Data.months }} - {{ range $year := .Data.years }} - - - - - - - - {{ range $month := (index $months $year.Name) }} - - - - - - - - {{ end }} - {{ end }} - - - - - - - - - - - - - - - -
{{ string .Blog.Lang "year" }}{{ string .Blog.Lang "posts" }}~{{ string .Blog.Lang "chars" }}~{{ string .Blog.Lang "words" }}~{{ string .Blog.Lang "wordsperpost" }}
{{ $year.Name }}{{ $year.Posts }}{{ $year.Chars }}{{ $year.Words }}{{ $year.WordsPerPost }}
{{ $year.Name }}-{{ $month.Name }}{{ $month.Posts }}{{ $month.Chars }}{{ $month.Words }}{{ $month.WordsPerPost }}
{{ string .Blog.Lang "withoutdate" }}{{ .Data.withoutdate.Posts }}{{ .Data.withoutdate.Chars }}{{ .Data.withoutdate.Words }}{{ .Data.withoutdate.WordsPerPost }}
{{ string .Blog.Lang "total" }}{{ .Data.total.Posts }}{{ .Data.total.Chars }}{{ .Data.total.Words }}{{ .Data.total.WordsPerPost }}
+

{{ string .Blog.Lang "loading" }}

{{ end }} diff --git a/templates/blogstatstable.gohtml b/templates/blogstatstable.gohtml new file mode 100644 index 0000000..d5755bd --- /dev/null +++ b/templates/blogstatstable.gohtml @@ -0,0 +1,48 @@ +{{ define "blogstatstable" }} + + + + + + + + + + + + {{ $months := .Data.months }} + {{ range $year := .Data.years }} + + + + + + + + {{ range $month := (index $months $year.Name) }} + + + + + + + + {{ end }} + {{ end }} + + + + + + + + + + + + + + + +
{{ string .Blog.Lang "year" }}{{ string .Blog.Lang "posts" }}~{{ string .Blog.Lang "chars" }}~{{ string .Blog.Lang "words" }}~{{ string .Blog.Lang "wordsperpost" }}
{{ $year.Name }}{{ $year.Posts }}{{ $year.Chars }}{{ $year.Words }}{{ $year.WordsPerPost }}
{{ $year.Name }}-{{ $month.Name }}{{ $month.Posts }}{{ $month.Chars }}{{ $month.Words }}{{ $month.WordsPerPost }}
{{ string .Blog.Lang "withoutdate" }}{{ .Data.withoutdate.Posts }}{{ .Data.withoutdate.Chars }}{{ .Data.withoutdate.Words }}{{ .Data.withoutdate.WordsPerPost }}
{{ string .Blog.Lang "total" }}{{ .Data.total.Posts }}{{ .Data.total.Chars }}{{ .Data.total.Words }}{{ .Data.total.WordsPerPost }}
+{{ end }} \ No newline at end of file diff --git a/templates/strings/de.yaml b/templates/strings/de.yaml index bd2cd8e..bdb1be7 100644 --- a/templates/strings/de.yaml +++ b/templates/strings/de.yaml @@ -12,6 +12,7 @@ editor: "Editor" interactions: "Interaktionen & Kommentare" interactionslabel: "Hast du eine Antwort hierzu veröffentlicht? Füge hier die URL ein." likeof: "Gefällt mir von" +loading: "Laden..." next: "Weiter" noposts: "Hier sind keine Posts." oldcontent: "⚠️ Dieser Eintrag ist bereits über ein Jahr alt. Er ist möglicherweise nicht mehr aktuell. Meinungen können sich geändert haben." diff --git a/templates/strings/default.yaml b/templates/strings/default.yaml index 8edc2be..ae8b73a 100644 --- a/templates/strings/default.yaml +++ b/templates/strings/default.yaml @@ -19,6 +19,7 @@ indieauth: "IndieAuth" interactions: "Interactions & Comments" interactionslabel: "Have you published a response to this? Paste the URL here." likeof: "Like of" +loading: "Loading..." login: "Login" logout: "Logout" nameopt: "Name (optional)"