Browse Source

Blogstats with months (on click)

master
Jan-Lukas Else 3 weeks ago
parent
commit
47ddcc4028
  1. 54
      blogstats.go
  2. 12
      check.go
  3. 11
      templates/assets/js/blogstats.js
  4. 23
      templates/blogstats.gohtml
  5. 1
      templates/strings/de.yaml
  6. 1
      templates/strings/default.yaml
  7. 2
      utils.go

54
blogstats.go

@ -2,15 +2,17 @@ package main
import (
"net/http"
"strconv"
)
func serveBlogStats(w http.ResponseWriter, r *http.Request) {
blog := r.Context().Value(blogContextKey).(string)
// Build query
query, params := buildPostsQuery(&postsRequestConfig{
prq := &postsRequestConfig{
blog: blog,
status: statusPublished,
})
}
query, params := buildPostsQuery(prq)
// Count total posts
row, err := appDbQueryRow("select count(distinct path) from ("+query+")", params...)
if err != nil {
@ -28,21 +30,55 @@ func serveBlogStats(w http.ResponseWriter, r *http.Request) {
serveError(w, r, err.Error(), http.StatusInternalServerError)
return
}
var years, counts []int
var years []stringPair
for rows.Next() {
var year, count int
var year, count string
if err = rows.Scan(&year, &count); err == nil {
years = append(years, year)
counts = append(counts, count)
years = append(years, stringPair{year, count})
} else {
serveError(w, r, err.Error(), http.StatusInternalServerError)
return
}
}
// Count posts without date
row, err = appDbQueryRow("select count(distinct path) from ("+query+") where published = ''", params...)
if err != nil {
serveError(w, r, err.Error(), http.StatusInternalServerError)
return
}
var noDateCount int
if err = row.Scan(&noDateCount); err != nil {
serveError(w, r, err.Error(), http.StatusInternalServerError)
return
}
// Count posts per month per year
months := map[string][]stringPair{}
for _, year := range years {
prq.publishedYear, _ = strconv.Atoi(year.First)
query, params = buildPostsQuery(prq)
rows, err = appDbQuery("select substr(published, 6, 2) as month, count(distinct path) as count from ("+query+") where published != '' group by month order by month desc", params...)
if err != nil {
serveError(w, r, err.Error(), http.StatusInternalServerError)
return
}
for rows.Next() {
var month, count string
if err = rows.Scan(&month, &count); err == nil {
months[year.First] = append(months[year.First], stringPair{month, count})
} else {
serveError(w, r, err.Error(), http.StatusInternalServerError)
return
}
}
}
render(w, r, templateBlogStats, &renderData{
BlogString: blog,
Canonical: blogPath(blog) + appConfig.Blogs[blog].BlogStats.Path,
Data: map[string]interface{}{
"total": totalCount,
"years": years,
"counts": counts,
"total": totalCount,
"years": years,
"withoutdate": noDateCount,
"months": months,
},
})
}

12
check.go

@ -36,10 +36,10 @@ func checkAllExternalLinks() {
wg.Add(1)
for postLinkPair := range linkChan {
rm.RLock()
_, ok := responses[postLinkPair.second]
_, ok := responses[postLinkPair.Second]
rm.RUnlock()
if !ok {
req, err := http.NewRequest(http.MethodGet, postLinkPair.second, nil)
req, err := http.NewRequest(http.MethodGet, postLinkPair.Second, nil)
if err != nil {
fmt.Println(err.Error())
continue
@ -50,19 +50,19 @@ func checkAllExternalLinks() {
req.Header.Set("Accept-Language", "en-US,en;q=0.5")
resp, err := client.Do(req)
if err != nil {
fmt.Println(postLinkPair.second+" ("+postLinkPair.first+"):", err.Error())
fmt.Println(postLinkPair.Second+" ("+postLinkPair.First+"):", err.Error())
continue
}
status := resp.StatusCode
_, _ = io.Copy(io.Discard, resp.Body)
resp.Body.Close()
rm.Lock()
responses[postLinkPair.second] = status
responses[postLinkPair.Second] = status
rm.Unlock()
}
rm.RLock()
if response, ok := responses[postLinkPair.second]; ok && !checkSuccessStatus(response) {
fmt.Println(postLinkPair.second+" ("+postLinkPair.first+"):", response)
if response, ok := responses[postLinkPair.Second]; ok && !checkSuccessStatus(response) {
fmt.Println(postLinkPair.Second+" ("+postLinkPair.First+"):", response)
}
rm.RUnlock()
}

11
templates/assets/js/blogstats.js

@ -0,0 +1,11 @@
(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')
}
})
})
})
})()

23
templates/blogstats.gohtml

@ -14,19 +14,30 @@
</tr>
</thead>
<tbody>
{{ $counts := .Data.counts }}
{{ range $i, $year := .Data.years }}
<tr>
<td class="tal">{{ $year }}</td>
<td class="tar">{{ index $counts $i }}</td>
{{ $months := .Data.months }}
{{ range $year := .Data.years }}
<tr class="statsyear" data-year="{{ $year.First }}">
<td class="tal"><b>{{ $year.First }}</b></td>
<td class="tar">{{ $year.Second }}</td>
</tr>
{{ range $month := (index $months $year.First) }}
<tr class="statsmonth hide" data-year="{{ $year.First }}">
<td class="tal">{{ $month.First }}</td>
<td class="tar">{{ $month.Second }}</td>
</tr>
{{ end }}
{{ end }}
<tr>
<td class="tal"><b>{{ string .Blog.Lang "total" }}</b></td>
<td class="tal"><b>{{ string .Blog.Lang "withoutdate" }}</b></td>
<td class="tar">{{ .Data.withoutdate }}</td>
</tr>
<tr>
<td class="tal"><u><b>{{ string .Blog.Lang "total" }}</b></u></td>
<td class="tar">{{ .Data.total }}</td>
</tr>
</tbody>
</table>
<script defer src="{{ asset "js/blogstats.js" }}"></script>
</main>
{{ end }}

1
templates/strings/de.yaml

@ -29,4 +29,5 @@ update: "Aktualisieren"
updatedon: "Aktualisiert am"
upload: "Hochladen"
view: "Anschauen"
withoutdate: "Ohne Datum"
year: "Jahr"

1
templates/strings/default.yaml

@ -47,4 +47,5 @@ verified: "Verified"
view: "View"
webmentions: "Webmentions"
websiteopt: "Website (optional)"
withoutdate: "Without date"
year: "Year"

2
utils.go

@ -162,5 +162,5 @@ func dateFormat(date string, format string) string {
}
type stringPair struct {
first, second string
First, Second string
}
Loading…
Cancel
Save