summaryrefslogtreecommitdiffci
path: root/internal/router/handlers/lang-blog.go
blob: 9f7947b8a5fcced749a758566579e912fe3bcb6f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package handlers

import (
	"fmt"
	"log/slog"
	"net/url"
	"regexp"
	"slices"
	"strings"
	"time"

	"github.com/SayaAndy/saya-today-web/internal/blog"
	"github.com/SayaAndy/saya-today-web/internal/router"
	"github.com/gofiber/fiber/v2"
)

func init() {
	router.Routes = append(router.Routes, &CatalogueHandler{getTagsQuery: regexp.MustCompile(`tags\[\]=([\w]+)`)})
}

type CatalogueHandler struct {
	router.BasicHandler
	getTagsQuery *regexp.Regexp
}

func (r *CatalogueHandler) Filter() (method string, path string) {
	return "GET", "/:lang/blog"
}

func (r *CatalogueHandler) IsTemplated() bool {
	return true
}

func (r *CatalogueHandler) TemplatesToInject() []string {
	return []string{"views/pages/blog-catalogue.html"}
}

func (r *CatalogueHandler) ToCache() router.CacheSetting {
	return router.ByUrlAndQuery
}

func (r *CatalogueHandler) CacheDuration() time.Duration {
	return 5 * time.Minute
}

func (r *CatalogueHandler) ToValidateLang() router.LangSetting {
	return router.InPath
}

func (r *CatalogueHandler) SitemapInfo(supplements *router.Supplements) []router.SitemapInfo {
	sitemapInfo := []router.SitemapInfo{}
	for _, lang := range supplements.AvailableLanguages {
		sitemapInfo = append(sitemapInfo, router.SitemapInfo{Loc: "/" + lang.Name + "/blog", Priority: 0.3})
	}
	return sitemapInfo
}

func (r *CatalogueHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta []router.MetaField, err error) {
	return []router.MetaField{
		{Property: "og:title", Content: supplements.Localization[lang].BlogSearch.Header},
		{Property: "og:description", Content: supplements.Localization[lang].BlogSearch.Description},
		{Property: "og:url", Content: fmt.Sprintf("%s/%s/blog", templateMap["CanonicalEndpoint"], lang)},
		{Property: "og:type", Content: "website"},
	}, nil
}

func (r *CatalogueHandler) RenderBody(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) {
	querySort := c.Query("sort", "publicationDateDesc")
	previousBlogPage := c.Query("codename")

	encodedQuery := c.Request().URI().QueryString()
	decodedQuery, _ := url.QueryUnescape(string(encodedQuery))
	matches := r.getTagsQuery.FindAllStringSubmatch(decodedQuery, -1)

	queryTags := make([]string, 0, len(matches))
	for _, match := range matches {
		queryTags = append(queryTags, string(match[1]))
	}

	tagsArray, err := getTags(supplements.BlogClient, lang)
	if err != nil {
		return fiber.StatusInternalServerError, fmt.Errorf("failed to get the available tags")
	}

	templateMap["Tags"] = tagsArray
	templateMap["QuerySort"] = querySort
	templateMap["QueryTags"] = strings.Join(queryTags, ",")
	templateMap["Title"] = supplements.Localization[lang].BlogSearch.Header
	templateMap["PreviousBlogPage"] = previousBlogPage

	return fiber.StatusOK, nil
}

func (r *CatalogueHandler) RenderHeader(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) {
	templateMap["Title"] = supplements.Localization[lang].BlogSearch.Header
	return fiber.StatusOK, nil
}

type Tag struct {
	Name  string `json:"Name" yaml:"name"`
	Count int    `json:"Count" yaml:"count"`
}

func getTags(blogClient blog.Client, lang string) (tags []Tag, err error) {
	pages, err := blogClient.Scan(lang + "/")
	if err != nil {
		slog.Warn("failed to scan pages via b2", slog.String("error", err.Error()))
		return nil, fmt.Errorf("failed to scan pages via b2: %w", err)
	}

	tagsMap := make(map[string]int)
	for _, page := range pages {
		for _, tag := range page.Metadata.Tags {
			tagsMap[tag]++
		}
	}
	slog.Debug("enlist pages for catalogue", slog.Int("tag_count", len(tagsMap)), slog.Int("page_count", len(pages)), slog.String("lang", lang))

	tagsArray := make([]Tag, 0, len(tagsMap))
	for tag, count := range tagsMap {
		tagsArray = append(tagsArray, Tag{tag, count})
	}
	slices.SortFunc(tagsArray, func(a Tag, b Tag) int {
		return strings.Compare(a.Name, b.Name)
	})

	return tagsArray, nil
}