package handlers // blog implementation concept import ( "bytes" "fmt" "os" "path/filepath" "time" "git.tijl.dev/tijl/tijl.dev-core/internal/i18n" log "git.tijl.dev/tijl/tijl.dev-core/modules/logger" "git.tijl.dev/tijl/tijl.dev-core/modules/web" "github.com/gofiber/fiber/v2" "github.com/yuin/goldmark" "github.com/yuin/goldmark-meta" "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/parser" ) type Post struct { Meta PostMeta Content string } type PostMeta struct { Title string Slug string Description string Author string Language string PublishDate time.Time UpdatedDate time.Time Tags []string } var posts []Post func LoadPosts() { posts = []Post{} md := goldmark.New( goldmark.WithExtensions(extension.Table, extension.Strikethrough, extension.Linkify, extension.TaskList, extension.GFM, extension.DefinitionList, extension.Footnote, extension.Typographer, meta.Meta), goldmark.WithParserOptions( parser.WithAutoHeadingID(), ), ) files, err := filepath.Glob("blog/*.md") if err != nil { log.Error().Err(err).Msg("handlers.LoadPosts(): error reading folder") } for _, file := range files { content, err := os.ReadFile(file) if err != nil { log.Error().Err(err).Msg("handlers.LoadPosts(): error reading file") continue } var buf bytes.Buffer context := parser.NewContext() if err := md.Convert(content, &buf, parser.WithContext(context)); err != nil { log.Fatal().Err(err) } metaData := meta.Get(context) postMeta, err := MapToPostMeta(metaData) posts = append(posts, Post{ Content: buf.String(), Meta: postMeta, }) } log.Debug().Msg("loaded blog posts") } func blogIndexHandler(c *fiber.Ctx) error { data := *web.Common(c) data["Title"] = i18n.Translate(c, "blog") data["Posts"] = posts return c.Render("blog", data, "layouts/base") } func MapToPostMeta(m map[string]interface{}) (PostMeta, error) { var post PostMeta var ok bool var err error if post.Title, ok = m["title"].(string); !ok { return post, fmt.Errorf("missing or invalid type for Title") } if post.Slug, ok = m["slug"].(string); !ok { return post, fmt.Errorf("missing or invalid type for Title") } if post.Description, ok = m["description"].(string); !ok { return post, fmt.Errorf("missing or invalid type for Description") } if post.Author, ok = m["author"].(string); !ok { return post, fmt.Errorf("missing or invalid type for Author") } if post.Language, ok = m["language"].(string); !ok { return post, fmt.Errorf("missing or invalid type for Language") } if publishDate, ok := m["publish_date"].(string); ok { post.PublishDate, err = time.Parse("02 Jan 2006", publishDate) if err != nil { return post, fmt.Errorf("invalid format for PublishDate: %v", err) } } else { return post, fmt.Errorf("missing or invalid type for PublishDate") } if updatedDate, ok := m["updated_date"].(string); ok { post.UpdatedDate, err = time.Parse("02 Jan 2006", updatedDate) if err != nil { return post, fmt.Errorf("invalid format for PublishDate: %v", err) } } else { return post, fmt.Errorf("missing or invalid type for PublishDate") } if tags, ok := m["tags"].([]interface{}); ok { for _, tag := range tags { if strTag, ok := tag.(string); ok { post.Tags = append(post.Tags, strTag) } else { return post, fmt.Errorf("invalid type in Tags slice") } } } else { return post, fmt.Errorf("missing or invalid type for Tags") } return post, nil }