summaryrefslogtreecommitdiff
path: root/internal/router/handlers
diff options
from:
to:
context:
space:
mode:
authorGravatar Saya Andy <145215889+SayaAndy@users.noreply.github.com> 2026-05-02 23:49:00 +0700
committerGravatar GitHub <noreply@github.com> 2026-05-02 23:49:00 +0700
commitd8de4ede8c6a0cc02b9c8c30d68155b1f838254c (patch)
tree449701dcf7ac0aafc7f21116b77203d0cc51fc98 /internal/router/handlers
parent4c05d4c66827d6e5a131c657ee08293bcde497d1 (diff)
parentcca3ff72b5e29b31122c0a0496be741e7bc0162b (diff)
downloadweb-0.14.0.tar.gz
web-0.14.0.zip
v0.14.0 (#27)v0.14.0
* [feat: migrate to uz.saya.casa](https://github.com/SayaAndy/saya-today-web/commit/d3a63ca8a84bf4583bac8f5fd09bd52774bc4158) * [feat: overhaul the design of blog catalog](https://github.com/SayaAndy/saya-today-web/commit/99294b260661a8d3f6992404de7881945eab837b) * [feat: replace font-andika with M PLUS and Gentium Plus](https://github.com/SayaAndy/saya-today-web/commit/b1355436e96f2dfa777e843b53896d0bb71628e3) * [feat: use yandexcloud.kz for photos & static](https://github.com/SayaAndy/saya-today-web/commit/3898baa47faf268864ecac3699f7e98c6cac01a4) * [feat: move from b2 to s3 for blog pages & facts](https://github.com/SayaAndy/saya-today-web/commit/3efa6ed24713658af855c0ca9504f3e089342182) * [feat: support s3 for blog pages](https://github.com/SayaAndy/saya-today-web/commit/66b2a96fcca113105043be3cb9c49f8ee7fe240c) * [feat: use accent colors for glightbox tooltip](https://github.com/SayaAndy/saya-today-web/commit/81a9147c5406e3b2f2441373b935d7c5de2780da) * [fix: set sidecar onclick attribute correctly in update](https://github.com/SayaAndy/saya-today-web/commit/941bd3b3f3e26ca62757a34a20bc9b323be02a74) * [fix: set cache-control for non-cacheable pages](https://github.com/SayaAndy/saya-today-web/commit/78d6b00cd973e4254ea13cbb17bb35a30fef51b9) * [feat: update font-awesome 6.7.2 to 7.2.0](https://github.com/SayaAndy/saya-today-web/commit/5e64aa9db2796e8aa6267d2ed9179ea01dc6561b) * [fix: remove leading slash in path with going up](https://github.com/SayaAndy/saya-today-web/commit/13428b467f752d9b53b39a3c8122998f1896ed1e) * [feat: implement rate limiting](https://github.com/SayaAndy/saya-today-web/commit/ca1f36376865cb2a20923aa62fdff3ee217abde3) * [feat: integrate unix sockets into stage & prod](https://github.com/SayaAndy/saya-today-web/commit/507bcbac6b1bf9f1a731afbe82bec10700f4028c) * [feat: compact & move new fonts into yandexcloud.kz](https://github.com/SayaAndy/saya-today-web/pull/27/commits/cca3ff72b5e29b31122c0a0496be741e7bc0162b) * [feat: update all github actions, golang dependencies, golang to 1.26, alpine to 3.23](https://github.com/SayaAndy/saya-today-web/commit/a3aa1dd07abfbbb27a7dfeeb536a6fcc51709256) * [refactor: simpler frontmatter parser (replace regexp with bytes pkg)](https://github.com/SayaAndy/saya-today-web/commit/42bf9d8e7f459f9021fb6fb389d3b51fed5edc35) * [feat: allow some api methods + disallow user pages for bots](https://github.com/SayaAndy/saya-today-web/commit/e3c80a07514a052adafd5c0f51daf69b664530e0)
Diffstat (limited to 'internal/router/handlers')
-rw-r--r--internal/router/handlers/api-v1-blog-search.go12
-rw-r--r--internal/router/handlers/api-v1-email-send-verification-code.go4
-rw-r--r--internal/router/handlers/api-v1-email-verify.go4
-rw-r--r--internal/router/handlers/api-v1-like-get.go2
-rw-r--r--internal/router/handlers/api-v1-like-put.go6
-rw-r--r--internal/router/handlers/api-v1-subs-put.go4
-rw-r--r--internal/router/handlers/lang-blog-title.go18
-rw-r--r--internal/router/handlers/lang-blog.go8
-rw-r--r--internal/router/handlers/lang-map.go8
-rw-r--r--internal/router/handlers/lang-user.go2
-rw-r--r--internal/router/handlers/lang.go10
11 files changed, 53 insertions, 25 deletions
diff --git a/internal/router/handlers/api-v1-blog-search.go b/internal/router/handlers/api-v1-blog-search.go
index a0316e2..38004a1 100644
--- a/internal/router/handlers/api-v1-blog-search.go
+++ b/internal/router/handlers/api-v1-blog-search.go
@@ -10,7 +10,7 @@ import (
"strings"
"time"
- "github.com/SayaAndy/saya-today-web/internal/b2"
+ "github.com/SayaAndy/saya-today-web/internal/blog"
"github.com/SayaAndy/saya-today-web/internal/router"
"github.com/gofiber/fiber/v2"
)
@@ -44,6 +44,10 @@ func (r *BlogSearchHandler) ToValidateLang() router.LangSetting {
return router.InForm
}
+func (r *BlogSearchHandler) RateLimiter() *fiber.Handler {
+ return &router.RateLimiterLoose
+}
+
func (r *BlogSearchHandler) Render(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) {
sort := c.Query("sort")
tz := c.Query("tz")
@@ -56,11 +60,11 @@ func (r *BlogSearchHandler) Render(c *fiber.Ctx, supplements *router.Supplements
cacheKey := "blog-search." + lang + ".pages-list"
- var pages []*b2.BlogPage
+ var pages []*blog.Page
if pagesBytes, ok := supplements.PageCache.Get(cacheKey); pagesBytes != nil || ok {
json.Unmarshal(pagesBytes, &pages)
} else {
- pages, err = supplements.B2Client.Scan(lang + "/")
+ pages, err = supplements.BlogClient.Scan(lang + "/")
if err != nil {
return fiber.StatusInternalServerError, fmt.Errorf("failed to scan pages for '%s' lang: %w", lang, err)
}
@@ -91,7 +95,9 @@ func (r *BlogSearchHandler) Render(c *fiber.Ctx, supplements *router.Supplements
"Thumbnail": page.Metadata.Thumbnail,
"Tags": page.Metadata.Tags,
"LikeCount": supplements.ClientCache.GetLikeCount(page.FileName),
+ "Liked": supplements.ClientCache.GetLikeStatus(c.IP(), page.FileName),
"ViewCount": supplements.ClientCache.GetViewCount(page.FileName),
+ "Viewed": supplements.ClientCache.GetViewStatus(c.IP(), page.FileName),
})
break
}
diff --git a/internal/router/handlers/api-v1-email-send-verification-code.go b/internal/router/handlers/api-v1-email-send-verification-code.go
index 20c5fb6..0b53efa 100644
--- a/internal/router/handlers/api-v1-email-send-verification-code.go
+++ b/internal/router/handlers/api-v1-email-send-verification-code.go
@@ -38,6 +38,10 @@ func (r *SendVerificationCodeHandler) ToValidateLang() router.LangSetting {
return router.InReferer
}
+func (r *SendVerificationCodeHandler) RateLimiter() *fiber.Handler {
+ return &router.RateLimiterStrict
+}
+
func (r *SendVerificationCodeHandler) Render(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) {
id := c.IP()
templateMap["StatusId"] = "email-message"
diff --git a/internal/router/handlers/api-v1-email-verify.go b/internal/router/handlers/api-v1-email-verify.go
index c9ec969..ace1870 100644
--- a/internal/router/handlers/api-v1-email-verify.go
+++ b/internal/router/handlers/api-v1-email-verify.go
@@ -36,6 +36,10 @@ func (r *VerifyCodeHandler) ToValidateLang() router.LangSetting {
return router.InReferer
}
+func (r *VerifyCodeHandler) RateLimiter() *fiber.Handler {
+ return &router.RateLimiterStrict
+}
+
func (r *VerifyCodeHandler) Render(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) {
verificationCode := c.FormValue("email_code")
templateMap["StatusId"] = "verification-message"
diff --git a/internal/router/handlers/api-v1-like-get.go b/internal/router/handlers/api-v1-like-get.go
index e9c176e..0eaf5f6 100644
--- a/internal/router/handlers/api-v1-like-get.go
+++ b/internal/router/handlers/api-v1-like-get.go
@@ -48,7 +48,7 @@ func (r *GetLikeHandler) Render(c *fiber.Ctx, supplements *router.Supplements, l
page := pathParts[2]
pageLink := lang + "/" + page + ".md"
- if pages, _ := supplements.B2Client.Scan(pageLink); len(pages) == 0 {
+ if pages, _ := supplements.BlogClient.Scan(pageLink); len(pages) == 0 {
return fiber.StatusNotFound, fmt.Errorf("server did not find '%s' article", pageLink)
}
diff --git a/internal/router/handlers/api-v1-like-put.go b/internal/router/handlers/api-v1-like-put.go
index ea4ef4b..8305d2b 100644
--- a/internal/router/handlers/api-v1-like-put.go
+++ b/internal/router/handlers/api-v1-like-put.go
@@ -37,6 +37,10 @@ func (r *PutLikeHandler) ToValidateLang() router.LangSetting {
return router.InReferer
}
+func (r *PutLikeHandler) RateLimiter() *fiber.Handler {
+ return &router.RateLimiterMedium
+}
+
func (r *PutLikeHandler) Render(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) {
path, pathParts, _, err := router.GetPathFromReferer(c)
if err != nil {
@@ -49,7 +53,7 @@ func (r *PutLikeHandler) Render(c *fiber.Ctx, supplements *router.Supplements, l
page := pathParts[2]
pageLink := lang + "/" + page + ".md"
- if pages, _ := supplements.B2Client.Scan(pageLink); len(pages) == 0 {
+ if pages, _ := supplements.BlogClient.Scan(pageLink); len(pages) == 0 {
return fiber.StatusNotFound, fmt.Errorf("server did not find '%s' article", pageLink)
}
diff --git a/internal/router/handlers/api-v1-subs-put.go b/internal/router/handlers/api-v1-subs-put.go
index 144abe5..32fba7e 100644
--- a/internal/router/handlers/api-v1-subs-put.go
+++ b/internal/router/handlers/api-v1-subs-put.go
@@ -34,6 +34,10 @@ func (r *PutSubsHandler) ToValidateLang() router.LangSetting {
return router.InReferer
}
+func (r *PutSubsHandler) RateLimiter() *fiber.Handler {
+ return &router.RateLimiterMedium
+}
+
func (r *PutSubsHandler) Render(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) {
templateMap["StatusId"] = "subs-message"
diff --git a/internal/router/handlers/lang-blog-title.go b/internal/router/handlers/lang-blog-title.go
index 5bfc6e7..49744c1 100644
--- a/internal/router/handlers/lang-blog-title.go
+++ b/internal/router/handlers/lang-blog-title.go
@@ -7,7 +7,7 @@ import (
"strings"
"time"
- "github.com/SayaAndy/saya-today-web/internal/b2"
+ "github.com/SayaAndy/saya-today-web/internal/blog"
"github.com/SayaAndy/saya-today-web/internal/frontmatter"
"github.com/SayaAndy/saya-today-web/internal/router"
"github.com/gofiber/fiber/v2"
@@ -49,7 +49,7 @@ func (r *BlogPageHandler) ToValidateLang() router.LangSetting {
func (r *BlogPageHandler) SitemapInfo(supplements *router.Supplements) []router.SitemapInfo {
sitemapInfo := []router.SitemapInfo{}
- pages, err := supplements.B2Client.Scan("")
+ pages, err := supplements.BlogClient.Scan("")
if err != nil {
return sitemapInfo
}
@@ -66,7 +66,7 @@ func (r *BlogPageHandler) SitemapInfo(supplements *router.Supplements) []router.
}
func (r *BlogPageHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (meta []router.MetaField, err error) {
- metadata, _, err := supplements.B2Client.ReadFrontmatter(lang + "/" + c.Params("title") + ".md")
+ metadata, _, err := supplements.BlogClient.ReadFrontmatter(lang + "/" + c.Params("title") + ".md")
if err != nil {
return nil, fmt.Errorf("failed to read frontmatter of the desired blog post: %w", err)
}
@@ -74,7 +74,7 @@ func (r *BlogPageHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements,
return []router.MetaField{
{Property: "og:title", Content: metadata.Title},
{Property: "og:description", Content: fmt.Sprintf("%s [%s]", metadata.ShortDescription, metadata.ActionDate)},
- {Property: "og:image", Content: fmt.Sprintf("https://f003.backblazeb2.com/file/sayana-photos/webp-320p/%s.webp", metadata.Thumbnail)},
+ {Property: "og:image", Content: fmt.Sprintf(supplements.PhotoStorage.Thumbnail320p.BaseUrl, metadata.Thumbnail)},
{Property: "og:url", Content: fmt.Sprintf("%s/%s/blog/%s", templateMap["CanonicalEndpoint"], lang, c.Params("title"))},
{Property: "og:type", Content: "website"},
{Name: "twitter:card", Content: "summary_large_image"},
@@ -82,7 +82,7 @@ func (r *BlogPageHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements,
}
func (r *BlogPageHandler) AddLinkedData(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (ld map[string]any, err error) {
- metadata, _, err := supplements.B2Client.ReadFrontmatter(lang + "/" + c.Params("title") + ".md")
+ metadata, _, err := supplements.BlogClient.ReadFrontmatter(lang + "/" + c.Params("title") + ".md")
if err != nil {
return nil, fmt.Errorf("failed to read frontmatter of the desired blog post: %w", err)
}
@@ -103,7 +103,7 @@ func (r *BlogPageHandler) RenderBody(c *fiber.Ctx, supplements *router.Supplemen
return fiber.StatusBadRequest, fmt.Errorf("failed to get path from referer: %w", err)
}
- metadata, parsedMarkdown, err := readBlogPost(supplements.MarkdownRenderer, supplements.B2Client, lang+"/"+pathParts[2])
+ metadata, parsedMarkdown, err := readBlogPost(supplements.MarkdownRenderer, supplements.BlogClient, lang+"/"+pathParts[2])
if err != nil {
return fiber.StatusNotFound, fmt.Errorf("failed to find '%s' post: %w", pathParts[2], err)
}
@@ -138,7 +138,7 @@ func (r *BlogPageHandler) RenderHeader(c *fiber.Ctx, supplements *router.Supplem
return fiber.StatusBadRequest, fmt.Errorf("failed to get path from referer: %w", err)
}
- metadata, _, err := supplements.B2Client.ReadFrontmatter(lang + "/" + pathParts[2] + ".md")
+ metadata, _, err := supplements.BlogClient.ReadFrontmatter(lang + "/" + pathParts[2] + ".md")
if err != nil {
return fiber.StatusNotFound, fmt.Errorf("could not read '%s' for metadata: %w", path, err)
}
@@ -148,8 +148,8 @@ func (r *BlogPageHandler) RenderHeader(c *fiber.Ctx, supplements *router.Supplem
return fiber.StatusOK, nil
}
-func readBlogPost(md goldmark.Markdown, b2Client *b2.B2Client, sourceName string) (metadata *frontmatter.Metadata, html string, err error) {
- metadata, markdown, err := b2Client.ReadFrontmatter(sourceName + ".md")
+func readBlogPost(md goldmark.Markdown, blogClient blog.Client, sourceName string) (metadata *frontmatter.Metadata, html string, err error) {
+ metadata, markdown, err := blogClient.ReadFrontmatter(sourceName + ".md")
if err != nil {
return nil, "", fmt.Errorf("failed to read a frontmatter file: %w", err)
}
diff --git a/internal/router/handlers/lang-blog.go b/internal/router/handlers/lang-blog.go
index 709d3dc..79ec9f3 100644
--- a/internal/router/handlers/lang-blog.go
+++ b/internal/router/handlers/lang-blog.go
@@ -9,7 +9,7 @@ import (
"strings"
"time"
- "github.com/SayaAndy/saya-today-web/internal/b2"
+ "github.com/SayaAndy/saya-today-web/internal/blog"
"github.com/SayaAndy/saya-today-web/internal/router"
"github.com/gofiber/fiber/v2"
)
@@ -79,7 +79,7 @@ func (r *CatalogueHandler) RenderBody(c *fiber.Ctx, supplements *router.Suppleme
queryTags = append(queryTags, string(match[1]))
}
- tagsArray, err := getTags(supplements.B2Client, lang)
+ tagsArray, err := getTags(supplements.BlogClient, lang)
if err != nil {
return fiber.StatusInternalServerError, fmt.Errorf("failed to get the available tags")
}
@@ -102,8 +102,8 @@ type Tag struct {
Count int `json:"Count" yaml:"count"`
}
-func getTags(b2Client *b2.B2Client, lang string) (tags []Tag, err error) {
- pages, err := b2Client.Scan(lang + "/")
+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)
diff --git a/internal/router/handlers/lang-map.go b/internal/router/handlers/lang-map.go
index 551b485..d452bc7 100644
--- a/internal/router/handlers/lang-map.go
+++ b/internal/router/handlers/lang-map.go
@@ -7,7 +7,7 @@ import (
"strconv"
"strings"
- "github.com/SayaAndy/saya-today-web/internal/b2"
+ "github.com/SayaAndy/saya-today-web/internal/blog"
"github.com/SayaAndy/saya-today-web/internal/router"
"github.com/gofiber/fiber/v2"
)
@@ -49,8 +49,8 @@ func (r *MapHandler) SitemapInfo(supplements *router.Supplements) []router.Sitem
}
func (r *MapHandler) Render(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) {
- pages, err := supplements.B2Client.Scan(lang + "/")
- slices.SortFunc(pages, func(a *b2.BlogPage, b *b2.BlogPage) int {
+ pages, err := supplements.BlogClient.Scan(lang + "/")
+ slices.SortFunc(pages, func(a *blog.Page, b *blog.Page) int {
return a.Metadata.PublishedTime.Compare(b.Metadata.PublishedTime)
})
status := fiber.StatusOK
@@ -60,7 +60,7 @@ func (r *MapHandler) Render(c *fiber.Ctx, supplements *router.Supplements, lang
slog.String("lang", lang),
)
status = fiber.StatusPartialContent
- pages = []*b2.BlogPage{}
+ pages = []*blog.Page{}
}
type MapMarker struct {
diff --git a/internal/router/handlers/lang-user.go b/internal/router/handlers/lang-user.go
index eae1685..0dda529 100644
--- a/internal/router/handlers/lang-user.go
+++ b/internal/router/handlers/lang-user.go
@@ -55,7 +55,7 @@ func (r *UserHandler) RenderBody(c *fiber.Ctx, supplements *router.Supplements,
slog.Error("get info from mailer about a client", slog.String("error", err.Error()))
}
- tagsArray, err := getTags(supplements.B2Client, lang)
+ tagsArray, err := getTags(supplements.BlogClient, lang)
if err != nil {
return fiber.ErrInternalServerError.Code, fmt.Errorf("failed to get the available tags")
}
diff --git a/internal/router/handlers/lang.go b/internal/router/handlers/lang.go
index c618353..25b5036 100644
--- a/internal/router/handlers/lang.go
+++ b/internal/router/handlers/lang.go
@@ -53,7 +53,10 @@ func (r *HomeHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lan
return []router.MetaField{
{Property: "og:title", Content: supplements.Localization[lang].HomePage.Header},
{Property: "og:description", Content: supplements.Localization[lang].HomePage.HomePageDescription},
- {Property: "og:image", Content: fmt.Sprintf("https://f003.backblazeb2.com/file/sayana-static/home-page-gifs/otter-%d.gif", rand.Int()%3+1)},
+ {Property: "og:image", Content: fmt.Sprintf(
+ supplements.PhotoStorage.HomePageGifs.BaseUrl,
+ supplements.PhotoStorage.HomePageGifs.Indexes[rand.Int()%len(supplements.PhotoStorage.HomePageGifs.Indexes)],
+ )},
{Property: "og:url", Content: fmt.Sprintf("%s/%s", templateMap["CanonicalEndpoint"], lang)},
{Property: "og:type", Content: "website"},
}, nil
@@ -63,7 +66,10 @@ func (r *HomeHandler) RenderBody(c *fiber.Ctx, supplements *router.Supplements,
templateMap["Title"] = supplements.Localization[lang].HomePage.Header
templateMap["FilledHeartCount"] = uint(40)
templateMap["OutlineHeartCount"] = uint(40)
- templateMap["GifName"] = fmt.Sprintf("otter-%d.gif", rand.Int()%3+1)
+ templateMap["GifUrl"] = fmt.Sprintf(
+ supplements.PhotoStorage.HomePageGifs.BaseUrl,
+ supplements.PhotoStorage.HomePageGifs.Indexes[rand.Int()%len(supplements.PhotoStorage.HomePageGifs.Indexes)],
+ )
templateMap["FunFacts"] = supplements.FactGiver.Give(lang)
return fiber.StatusOK, nil
}