package handlers
import (
"bytes"
"fmt"
"html/template"
"strings"
"time"
"github.com/SayaAndy/saya-today-web/internal/b2"
"github.com/SayaAndy/saya-today-web/internal/frontmatter"
"github.com/SayaAndy/saya-today-web/internal/router"
"github.com/gofiber/fiber/v2"
"github.com/yuin/goldmark"
)
func init() {
router.Routes = append(router.Routes, &BlogPageHandler{})
}
type BlogPageHandler struct {
router.BasicHandler
}
func (r *BlogPageHandler) Filter() (method string, path string) {
return "GET", "/:lang/blog/:title"
}
func (r *BlogPageHandler) IsTemplated() bool {
return true
}
func (r *BlogPageHandler) TemplatesToInject() []string {
return []string{"views/pages/blog-page.html"}
}
func (r *BlogPageHandler) ToCache() router.CacheSetting {
return router.ByUrlOnly
}
func (r *BlogPageHandler) CacheDuration() time.Duration {
return 15 * time.Minute
}
func (r *BlogPageHandler) ToValidateLang() router.LangSetting {
return router.InPath
}
func (r *BlogPageHandler) RenderBody(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) {
_, pathParts, _, err := router.GetPathFromReferer(c)
if err != nil {
return fiber.StatusBadRequest, fmt.Errorf("failed to get path from referer: %w", err)
}
metadata, parsedMarkdown, err := readBlogPost(supplements.MarkdownRenderer, supplements.B2Client, lang+"/"+pathParts[2])
if err != nil {
return fiber.StatusNotFound, fmt.Errorf("failed to find '%s' post: %w", pathParts[2], err)
}
geolocationParts := strings.Split(metadata.Geolocation, " ")
var x, y, areaError string
if len(geolocationParts) >= 2 {
x = geolocationParts[0]
y = geolocationParts[1]
}
if len(geolocationParts) >= 3 {
areaError = geolocationParts[2]
}
templateMap["MapLocationX"] = x
templateMap["MapLocationY"] = y
templateMap["MapLocationAreaMeters"] = areaError
templateMap["Title"] = metadata.Title
templateMap["ParsedMarkdown"] = template.HTML(parsedMarkdown)
templateMap["PublishedDate"] = metadata.PublishedTime.Format("2006-01-02 15:04:05 -07:00")
templateMap["ActionDate"] = metadata.ActionDate
go supplements.ClientCache.View(c.IP(), pathParts[2])
return fiber.StatusOK, nil
}
func (r *BlogPageHandler) RenderHeader(c *fiber.Ctx, supplements *router.Supplements, lang string, templateMap fiber.Map) (statusCode int, err error) {
path, pathParts, _, err := router.GetPathFromReferer(c)
if err != nil {
return fiber.StatusBadRequest, fmt.Errorf("failed to get path from referer: %w", err)
}
metadata, _, err := supplements.B2Client.ReadFrontmatter(lang + "/" + pathParts[2] + ".md")
if err != nil {
return fiber.StatusNotFound, fmt.Errorf("could not read '%s' for metadata: %w", path, err)
}
templateMap["Title"] = metadata.Title
templateMap["PublishedDate"] = metadata.PublishedTime.Format("2006-01-02 15:04:05 -07:00")
templateMap["ActionDate"] = metadata.ActionDate
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")
if err != nil {
return nil, "", fmt.Errorf("failed to read a frontmatter file: %w", err)
}
var buf bytes.Buffer
if err := md.Convert(markdown, &buf); err != nil {
return nil, "", fmt.Errorf("convert source context from md to html: %w", err)
}
return metadata, buf.String(), nil
}