diff --git a/http.go b/http.go index 66267b1..d9f9318 100644 --- a/http.go +++ b/http.go @@ -2,6 +2,7 @@ package main import ( "compress/flate" + "fmt" "net/http" "strconv" "sync/atomic" @@ -236,6 +237,26 @@ func buildHandler() (http.Handler, error) { r.With(cacheMiddleware, minifier.Middleware).Get(searchResultPath+paginationPath, resultHandler) } + // Year / month archives + months, err := allMonths(blog) + if err != nil { + return nil, err + } + for y, ms := range months { + yearPath := blogPath + "/" + fmt.Sprintf("%0004d", y) + yearHandler := serveYearMonth(blog, yearPath, y, 0) + r.With(cacheMiddleware, minifier.Middleware).Get(yearPath, yearHandler) + r.With(cacheMiddleware, minifier.Middleware).Get(yearPath+feedPath, yearHandler) + r.With(cacheMiddleware, minifier.Middleware).Get(yearPath+paginationPath, yearHandler) + for _, m := range ms { + monthPath := yearPath + "/" + fmt.Sprintf("%02d", m) + monthHandler := serveYearMonth(blog, monthPath, y, m) + r.With(cacheMiddleware, minifier.Middleware).Get(monthPath, monthHandler) + r.With(cacheMiddleware, minifier.Middleware).Get(monthPath+feedPath, monthHandler) + r.With(cacheMiddleware, minifier.Middleware).Get(monthPath+paginationPath, monthHandler) + } + } + // Blog var mw []func(http.Handler) http.Handler if appConfig.ActivityPub.Enabled { diff --git a/posts.go b/posts.go index d5768b0..d558f47 100644 --- a/posts.go +++ b/posts.go @@ -8,8 +8,10 @@ import ( "reflect" "strconv" "strings" + "time" "github.com/go-chi/chi" + "github.com/goodsign/monday" "github.com/vcraescu/go-paginator" ) @@ -132,6 +134,24 @@ func serveSearchResults(blog string, path string) func(w http.ResponseWriter, r }) } +func serveYearMonth(blog string, path string, year, month int) func(w http.ResponseWriter, r *http.Request) { + var title string + if month == 0 { + title = fmt.Sprintf("%0004d", year) + } else { + ml := monday.Locale(appConfig.Blogs[blog].TimeLang) + date := time.Date(0, 0, 10, 0, 0, 0, 0, time.Local).AddDate(year, month, 0) + title = monday.Format(date, "January 2006", ml) + } + return serveIndex(&indexConfig{ + blog: blog, + path: path, + year: year, + month: month, + title: title, + }) +} + type indexConfig struct { blog string path string @@ -139,6 +159,8 @@ type indexConfig struct { tax *taxonomy taxValue string parameter string + year int + month int title string description string summaryTemplate string @@ -161,12 +183,14 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) { } } p := paginator.New(&postPaginationAdapter{config: &postsRequestConfig{ - blog: ic.blog, - sections: sections, - taxonomy: ic.tax, - taxonomyValue: ic.taxValue, - parameter: ic.parameter, - search: search, + blog: ic.blog, + sections: sections, + taxonomy: ic.tax, + taxonomyValue: ic.taxValue, + parameter: ic.parameter, + search: search, + publishedYear: ic.year, + publishedMonth: ic.month, }}, appConfig.Blogs[ic.blog].Pagination) p.SetPage(pageNo) var posts []*post diff --git a/postsDb.go b/postsDb.go index cacef44..758f8de 100644 --- a/postsDb.go +++ b/postsDb.go @@ -230,6 +230,8 @@ type postsRequestConfig struct { taxonomyValue string parameter string parameterValue string + publishedYear int + publishedMonth int } func buildQuery(config *postsRequestConfig) (query string, args []interface{}) { @@ -270,6 +272,14 @@ func buildQuery(config *postsRequestConfig) (query string, args []interface{}) { } postsTable += ")" } + if config.publishedYear != 0 { + postsTable = "(select * from " + postsTable + " p where substr(p.published, 1, 4) = @publishedyear)" + args = append(args, sql.Named("publishedyear", fmt.Sprintf("%0004d", config.publishedYear))) + } + if config.publishedMonth != 0 { + postsTable = "(select * from " + postsTable + " p where substr(p.published, 6, 2) = @publishedmonth)" + args = append(args, sql.Named("publishedmonth", fmt.Sprintf("%02d", config.publishedMonth))) + } defaultTables := " from " + postsTable + " p left outer join post_parameters pp on p.path = pp.path " defaultSorting := " order by p.published desc " if config.path != "" { @@ -352,3 +362,20 @@ func allTaxonomyValues(blog string, taxonomy string) ([]string, error) { } return values, nil } + +func allMonths(blog string) (months map[int][]int, err error) { + rows, err := appDbQuery("select distinct substr(published, 1, 4) as year, substr(published, 6, 2) as month from posts where blog = @blog and year != '' and month != ''", sql.Named("blog", blog)) + if err != nil { + return nil, err + } + months = map[int][]int{} + for rows.Next() { + var year, month int + err = rows.Scan(&year, &month) + if err != nil { + return nil, err + } + months[year] = append(months[year], month) + } + return +}