mirror of https://github.com/jlelse/GoBlog
Add blog stats with posts per year
This commit is contained in:
parent
7979fc3ef3
commit
37f36678b2
|
@ -0,0 +1,43 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func serveBlogStats(blog, statsPath string) func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var totalCount int
|
||||||
|
row, err := appDbQueryRow("select count(path) as count from posts where blog = @blog", sql.Named("blog", blog))
|
||||||
|
if err != nil {
|
||||||
|
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = row.Scan(&totalCount)
|
||||||
|
if err != nil {
|
||||||
|
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var years, counts []int
|
||||||
|
rows, err := appDbQuery("select substr(published, 1, 4) as year, count(path) as count from posts where blog = @blog and coalesce(published, '') != '' group by year order by year desc", sql.Named("blog", blog))
|
||||||
|
if err != nil {
|
||||||
|
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for rows.Next() {
|
||||||
|
var year, count int
|
||||||
|
rows.Scan(&year, &count)
|
||||||
|
years = append(years, year)
|
||||||
|
counts = append(counts, count)
|
||||||
|
}
|
||||||
|
render(w, templateBlogStats, &renderData{
|
||||||
|
blogString: blog,
|
||||||
|
Canonical: statsPath,
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"total": totalCount,
|
||||||
|
"years": years,
|
||||||
|
"counts": counts,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,6 +59,7 @@ type configBlog struct {
|
||||||
Menus map[string]*menu `mapstructure:"menus"`
|
Menus map[string]*menu `mapstructure:"menus"`
|
||||||
Photos *photos `mapstructure:"photos"`
|
Photos *photos `mapstructure:"photos"`
|
||||||
Search *search `mapstructure:"search"`
|
Search *search `mapstructure:"search"`
|
||||||
|
BlogStats *blogStats `mapstructure:"blogStats"`
|
||||||
CustomPages []*customPage `mapstructure:"custompages"`
|
CustomPages []*customPage `mapstructure:"custompages"`
|
||||||
Telegram *configTelegram `mapstructure:"telegram"`
|
Telegram *configTelegram `mapstructure:"telegram"`
|
||||||
PostAsHome bool `mapstructure:"postAsHome"`
|
PostAsHome bool `mapstructure:"postAsHome"`
|
||||||
|
@ -102,6 +103,13 @@ type search struct {
|
||||||
Placeholder string `mapstructure:"placeholder"`
|
Placeholder string `mapstructure:"placeholder"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type blogStats struct {
|
||||||
|
Enabled bool `mapstructure:"enabled"`
|
||||||
|
Path string `mapstructure:"path"`
|
||||||
|
Title string `mapstructure:"title"`
|
||||||
|
Description string `mapstructure:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
type customPage struct {
|
type customPage struct {
|
||||||
Path string `mapstructure:"path"`
|
Path string `mapstructure:"path"`
|
||||||
Template string `mapstructure:"template"`
|
Template string `mapstructure:"template"`
|
||||||
|
|
10
http.go
10
http.go
|
@ -226,7 +226,7 @@ func buildHandler() (http.Handler, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Photos
|
// Photos
|
||||||
if blogConfig.Photos.Enabled {
|
if blogConfig.Photos != nil && blogConfig.Photos.Enabled {
|
||||||
photoPath := blogPath + blogConfig.Photos.Path
|
photoPath := blogPath + blogConfig.Photos.Path
|
||||||
handler := servePhotos(blog, photoPath)
|
handler := servePhotos(blog, photoPath)
|
||||||
r.With(cacheMiddleware, minifier.Middleware).Get(photoPath, handler)
|
r.With(cacheMiddleware, minifier.Middleware).Get(photoPath, handler)
|
||||||
|
@ -234,7 +234,7 @@ func buildHandler() (http.Handler, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search
|
// Search
|
||||||
if blogConfig.Search.Enabled {
|
if blogConfig.Search != nil && blogConfig.Search.Enabled {
|
||||||
searchPath := blogPath + blogConfig.Search.Path
|
searchPath := blogPath + blogConfig.Search.Path
|
||||||
handler := serveSearch(blog, searchPath)
|
handler := serveSearch(blog, searchPath)
|
||||||
r.With(cacheMiddleware, minifier.Middleware).Get(searchPath, handler)
|
r.With(cacheMiddleware, minifier.Middleware).Get(searchPath, handler)
|
||||||
|
@ -246,6 +246,12 @@ func buildHandler() (http.Handler, error) {
|
||||||
r.With(cacheMiddleware, minifier.Middleware).Get(searchResultPath+paginationPath, resultHandler)
|
r.With(cacheMiddleware, minifier.Middleware).Get(searchResultPath+paginationPath, resultHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stats
|
||||||
|
if blogConfig.BlogStats != nil && blogConfig.BlogStats.Enabled {
|
||||||
|
statsPath := blogPath + blogConfig.BlogStats.Path
|
||||||
|
r.With(cacheMiddleware, minifier.Middleware).Get(statsPath, serveBlogStats(blog, statsPath))
|
||||||
|
}
|
||||||
|
|
||||||
// Year / month archives
|
// Year / month archives
|
||||||
dates, err := allPublishedDates(blog)
|
dates, err := allPublishedDates(blog)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -33,6 +33,7 @@ const templatePhotosSummary = "photosummary"
|
||||||
const templateEditor = "editor"
|
const templateEditor = "editor"
|
||||||
const templateLogin = "login"
|
const templateLogin = "login"
|
||||||
const templateStaticHome = "statichome"
|
const templateStaticHome = "statichome"
|
||||||
|
const templateBlogStats = "blogstats"
|
||||||
|
|
||||||
var templates map[string]*template.Template
|
var templates map[string]*template.Template
|
||||||
var templateFunctions template.FuncMap
|
var templateFunctions template.FuncMap
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
{{ define "title" }}
|
||||||
|
<title>{{ with .Blog.BlogStats.Title }}{{ . }} - {{ end }}{{ .Blog.Title }}</title>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "main" }}
|
||||||
|
<main>
|
||||||
|
{{ with .Blog.BlogStats.Title }}<h1>{{ . }}</h1>{{ end }}
|
||||||
|
{{ with .Blog.BlogStats.Description }}{{ md . }}{{ end }}
|
||||||
|
<table class="p">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="text-align:left">{{ string .Blog.Lang "year" }}</th>
|
||||||
|
<th style="text-align:right">{{ string .Blog.Lang "count" }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{ $counts := .Data.counts }}
|
||||||
|
{{ range $i, $year := .Data.years }}
|
||||||
|
<tr>
|
||||||
|
<td style="text-align:left">{{ $year }}</td>
|
||||||
|
<td style="text-align:right">{{ index $counts $i }}</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
<tr>
|
||||||
|
<td style="text-align:left"><b>{{ string .Blog.Lang "total" }}</b></td>
|
||||||
|
<td style="text-align:right">{{ .Data.total }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</main>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "blogstats" }}
|
||||||
|
{{ template "base" . }}
|
||||||
|
{{ end }}
|
|
@ -12,3 +12,6 @@ stopspeak: "Hör auf zu sprechen!"
|
||||||
oldcontent: "⚠️ Dieser Eintrag ist bereits über ein Jahr alt. Er ist möglicherweise nicht mehr aktuell. Meinungen können sich geändert haben."
|
oldcontent: "⚠️ Dieser Eintrag ist bereits über ein Jahr alt. Er ist möglicherweise nicht mehr aktuell. Meinungen können sich geändert haben."
|
||||||
search: "Suchen"
|
search: "Suchen"
|
||||||
shorturl: "Kurz-URL:"
|
shorturl: "Kurz-URL:"
|
||||||
|
year: "Jahr"
|
||||||
|
count: "Anzahl"
|
||||||
|
total: "Gesamt"
|
|
@ -31,3 +31,6 @@ login: "Login"
|
||||||
username: "Username"
|
username: "Username"
|
||||||
password: "Password"
|
password: "Password"
|
||||||
shorturl: "Short URL:"
|
shorturl: "Short URL:"
|
||||||
|
year: "Year"
|
||||||
|
count: "Count"
|
||||||
|
total: "Total"
|
Loading…
Reference in New Issue