Files
aura-crm/production/backend/internal/changelog/handler.go
T

88 lines
2.7 KiB
Go

// Package changelog serves the "Обновления" settings tab — a
// human-maintained CHANGELOG.md (repo-root-of-backend, Keep-a-Changelog-
// lite format: `## YYYY-MM-DD` release headers, `### Добавлено/Изменено/
// Исправлено` category subsections) parsed into JSON on every request.
// Deliberately file-based rather than a DB table: entries are meant to be
// written once, by whoever runs deploy.sh for a release, not edited by
// staff through the UI — a file staff can `git log` / review in a PR is a
// better source of truth for "what actually shipped" than a table anyone
// with settings access could silently rewrite.
package changelog
import (
"bufio"
"os"
"strings"
"github.com/gofiber/fiber/v2"
)
const changelogPath = "CHANGELOG.md"
type Entry struct {
Date string `json:"date"`
Categories []EntryCategory `json:"categories"`
}
type EntryCategory struct {
Name string `json:"name"`
Items []string `json:"items"`
}
type Handler struct{}
func NewHandler() *Handler {
return &Handler{}
}
// parse reads the Keep-a-Changelog-lite format described in the package
// doc comment. Deliberately lenient: any line that doesn't match a known
// header shape is treated as a bullet under whatever category/entry is
// currently open, rather than erroring the whole page out over one typo'd
// line in a hand-edited markdown file.
func parse(r *bufio.Scanner) []Entry {
var entries []Entry
var cur *Entry
var curCat *EntryCategory
for r.Scan() {
line := strings.TrimSpace(r.Text())
switch {
case strings.HasPrefix(line, "## "):
entries = append(entries, Entry{Date: strings.TrimSpace(strings.TrimPrefix(line, "## "))})
cur = &entries[len(entries)-1]
curCat = nil
case strings.HasPrefix(line, "### "):
if cur == nil {
continue
}
cur.Categories = append(cur.Categories, EntryCategory{Name: strings.TrimSpace(strings.TrimPrefix(line, "### "))})
curCat = &cur.Categories[len(cur.Categories)-1]
case strings.HasPrefix(line, "- "):
if curCat == nil {
continue
}
curCat.Items = append(curCat.Items, strings.TrimSpace(strings.TrimPrefix(line, "- ")))
}
}
return entries
}
// List is staffAuth-only, no permission gate — "what's new" is useful
// information for every role, same reasoning InterfaceTab.jsx's own
// no-permission-gate comment gives for personal display prefs.
func (h *Handler) List(c *fiber.Ctx) error {
f, err := os.Open(changelogPath)
if err != nil {
// Missing file isn't a server error — just nothing to show yet.
return c.JSON(fiber.Map{"entries": []Entry{}})
}
defer f.Close()
entries := parse(bufio.NewScanner(f))
if entries == nil {
entries = []Entry{}
}
return c.JSON(fiber.Map{"entries": entries})
}