2021-01-04 19:29:49 +00:00
package main
import (
2021-04-28 18:03:20 +00:00
"database/sql"
2021-05-10 15:37:34 +00:00
"encoding/json"
"log"
2021-01-04 19:29:49 +00:00
"net/http"
)
2021-06-06 12:39:42 +00:00
func ( a * goBlog ) initBlogStats ( ) {
2021-05-10 15:37:34 +00:00
f := func ( p * post ) {
2021-06-06 12:39:42 +00:00
a . db . resetBlogStats ( p . Blog )
2021-05-10 15:37:34 +00:00
}
2021-06-06 12:39:42 +00:00
a . pPostHooks = append ( a . pPostHooks , f )
a . pUpdateHooks = append ( a . pUpdateHooks , f )
a . pDeleteHooks = append ( a . pDeleteHooks , f )
2021-05-10 15:37:34 +00:00
}
2021-06-06 12:39:42 +00:00
func ( a * goBlog ) serveBlogStats ( w http . ResponseWriter , r * http . Request ) {
2021-05-09 07:08:31 +00:00
blog := r . Context ( ) . Value ( blogContextKey ) . ( string )
2021-06-10 20:09:50 +00:00
bc := a . cfg . Blogs [ blog ]
canonical := bc . getRelativePath ( bc . BlogStats . Path )
2021-06-06 12:39:42 +00:00
a . render ( w , r , templateBlogStats , & renderData {
2021-05-09 07:08:31 +00:00
BlogString : blog ,
2021-06-10 20:09:50 +00:00
Canonical : a . getFullAddress ( canonical ) ,
2021-05-09 07:08:31 +00:00
Data : map [ string ] interface { } {
"TableUrl" : canonical + ".table.html" ,
} ,
} )
}
2021-06-06 12:39:42 +00:00
func ( a * goBlog ) serveBlogStatsTable ( w http . ResponseWriter , r * http . Request ) {
2021-03-22 07:20:56 +00:00
blog := r . Context ( ) . Value ( blogContextKey ) . ( string )
2021-06-18 12:32:03 +00:00
data , err , _ := a . blogStatsCacheGroup . Do ( blog , func ( ) ( interface { } , error ) {
2021-06-06 12:39:42 +00:00
return a . db . getBlogStats ( blog )
2021-05-09 07:35:37 +00:00
} )
if err != nil {
2021-06-06 12:39:42 +00:00
a . serveError ( w , r , err . Error ( ) , http . StatusInternalServerError )
2021-05-09 07:35:37 +00:00
return
}
// Render
2021-06-06 12:39:42 +00:00
a . render ( w , r , templateBlogStatsTable , & renderData {
2021-05-09 07:35:37 +00:00
BlogString : blog ,
Data : data ,
} )
}
2021-06-06 12:39:42 +00:00
func ( db * database ) getBlogStats ( blog string ) ( data map [ string ] interface { } , err error ) {
if stats := db . loadBlogStatsCache ( blog ) ; stats != nil {
2021-05-10 15:37:34 +00:00
return stats , nil
2021-05-09 07:35:37 +00:00
}
2021-03-22 07:20:56 +00:00
// Build query
2021-04-23 18:52:12 +00:00
prq := & postsRequestConfig {
2021-03-22 07:20:56 +00:00
blog : blog ,
status : statusPublished ,
2021-04-23 18:52:12 +00:00
}
query , params := buildPostsQuery ( prq )
2021-05-09 07:08:31 +00:00
query = "select path, mdtext(content) as content, published, substr(published, 1, 4) as year, substr(published, 6, 2) as month from (" + query + ")"
2021-04-30 16:42:10 +00:00
postCount := "coalesce(count(distinct path), 0) as postcount"
2021-06-15 15:36:41 +00:00
charCount := "coalesce(sum(coalesce(charcount(distinct content), 0)), 0)"
2021-04-30 16:42:10 +00:00
wordCount := "coalesce(sum(wordcount(distinct content)), 0) as wordcount"
wordsPerPost := "coalesce(round(wordcount/postcount,0), 0)"
2021-04-28 18:03:20 +00:00
type statsTableType struct {
Name , Posts , Chars , Words , WordsPerPost string
}
2021-03-22 07:20:56 +00:00
// Count total posts
2021-06-06 12:39:42 +00:00
row , err := db . queryRow ( "select *, " + wordsPerPost + " from (select " + postCount + ", " + charCount + ", " + wordCount + " from (" + query + "))" , params ... )
2021-03-22 07:20:56 +00:00
if err != nil {
2021-05-09 07:35:37 +00:00
return nil , err
2021-03-22 07:20:56 +00:00
}
2021-04-28 18:03:20 +00:00
total := statsTableType { }
if err = row . Scan ( & total . Posts , & total . Chars , & total . Words , & total . WordsPerPost ) ; err != nil {
2021-05-09 07:35:37 +00:00
return nil , err
2021-03-22 07:20:56 +00:00
}
// Count posts per year
2021-06-06 12:39:42 +00:00
rows , err := db . query ( "select *, " + wordsPerPost + " from (select year, " + postCount + ", " + charCount + ", " + wordCount + " from (" + query + ") where published != '' group by year order by year desc)" , params ... )
2021-03-22 07:20:56 +00:00
if err != nil {
2021-05-09 07:35:37 +00:00
return nil , err
2021-03-22 07:20:56 +00:00
}
2021-04-28 18:03:20 +00:00
var years [ ] statsTableType
year := statsTableType { }
2021-03-22 07:20:56 +00:00
for rows . Next ( ) {
2021-04-28 18:03:20 +00:00
if err = rows . Scan ( & year . Name , & year . Posts , & year . Chars , & year . Words , & year . WordsPerPost ) ; err == nil {
years = append ( years , year )
2021-04-23 18:52:12 +00:00
} else {
2021-05-09 07:35:37 +00:00
return nil , err
2021-04-23 18:52:12 +00:00
}
}
// Count posts without date
2021-06-06 12:39:42 +00:00
row , err = db . queryRow ( "select *, " + wordsPerPost + " from (select " + postCount + ", " + charCount + ", " + wordCount + " from (" + query + ") where published = '')" , params ... )
2021-04-23 18:52:12 +00:00
if err != nil {
2021-05-09 07:35:37 +00:00
return nil , err
2021-04-23 18:52:12 +00:00
}
2021-04-28 18:03:20 +00:00
noDate := statsTableType { }
if err = row . Scan ( & noDate . Posts , & noDate . Chars , & noDate . Words , & noDate . WordsPerPost ) ; err != nil {
2021-05-09 07:35:37 +00:00
return nil , err
2021-04-23 18:52:12 +00:00
}
// Count posts per month per year
2021-04-28 18:03:20 +00:00
months := map [ string ] [ ] statsTableType { }
month := statsTableType { }
2021-04-23 18:52:12 +00:00
for _ , year := range years {
2021-06-06 12:39:42 +00:00
rows , err = db . query ( "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 ) ) ... )
2021-04-23 18:52:12 +00:00
if err != nil {
2021-05-09 07:35:37 +00:00
return nil , err
2021-04-23 18:52:12 +00:00
}
for rows . Next ( ) {
2021-04-28 18:03:20 +00:00
if err = rows . Scan ( & month . Name , & month . Posts , & month . Chars , & month . Words , & month . WordsPerPost ) ; err == nil {
months [ year . Name ] = append ( months [ year . Name ] , month )
2021-04-23 18:52:12 +00:00
} else {
2021-05-09 07:35:37 +00:00
return nil , err
2021-04-23 18:52:12 +00:00
}
2021-01-04 19:29:49 +00:00
}
}
2021-05-10 15:37:34 +00:00
data = map [ string ] interface { } {
2021-05-09 07:35:37 +00:00
"total" : total ,
"years" : years ,
"withoutdate" : noDate ,
"months" : months ,
}
2021-06-06 12:39:42 +00:00
db . cacheBlogStats ( blog , data )
2021-05-09 07:35:37 +00:00
return data , nil
}
2021-06-06 12:39:42 +00:00
func ( db * database ) cacheBlogStats ( blog string , stats map [ string ] interface { } ) {
2021-05-10 15:37:34 +00:00
jb , _ := json . Marshal ( stats )
2021-06-06 12:39:42 +00:00
_ = db . cachePersistently ( "blogstats_" + blog , jb )
2021-05-10 15:37:34 +00:00
}
2021-06-06 12:39:42 +00:00
func ( db * database ) loadBlogStatsCache ( blog string ) ( stats map [ string ] interface { } ) {
data , err := db . retrievePersistentCache ( "blogstats_" + blog )
2021-05-10 15:37:34 +00:00
if err != nil || data == nil {
return nil
}
err = json . Unmarshal ( data , & stats )
if err != nil {
log . Println ( err )
}
return stats
}
2021-06-06 12:39:42 +00:00
func ( db * database ) resetBlogStats ( blog string ) {
_ = db . clearPersistentCache ( "blogstats_" + blog )
2021-01-04 19:29:49 +00:00
}