mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2026-02-04 10:35:30 +00:00
211 lines
5.5 KiB
Go
211 lines
5.5 KiB
Go
package controllers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/Theodor-Springmann-Stiftung/musenalm/app"
|
|
"github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels"
|
|
"github.com/Theodor-Springmann-Stiftung/musenalm/middleware"
|
|
"github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels"
|
|
"github.com/Theodor-Springmann-Stiftung/musenalm/templating"
|
|
"github.com/pocketbase/pocketbase/core"
|
|
"github.com/pocketbase/pocketbase/tools/router"
|
|
"golang.org/x/text/collate"
|
|
"golang.org/x/text/language"
|
|
)
|
|
|
|
const (
|
|
URL_ABKUERZUNGEN = "/abkuerzungen/"
|
|
TEMPLATE_ABKUERZUNGEN = "/abkuerzungen/"
|
|
)
|
|
|
|
func init() {
|
|
ap := &AbkuerzungenPage{
|
|
StaticPage: pagemodels.StaticPage{
|
|
Name: pagemodels.P_ABKUERZUNGEN_NAME,
|
|
URL: URL_ABKUERZUNGEN,
|
|
Template: TEMPLATE_ABKUERZUNGEN,
|
|
Layout: templating.DEFAULT_LAYOUT_NAME,
|
|
},
|
|
}
|
|
app.Register(ap)
|
|
}
|
|
|
|
type AbkuerzungenPage struct {
|
|
pagemodels.StaticPage
|
|
}
|
|
|
|
type AbkEntry struct {
|
|
Key string
|
|
Value string
|
|
}
|
|
|
|
type AbkuerzungenResult struct {
|
|
Entries []AbkEntry
|
|
}
|
|
|
|
func (p *AbkuerzungenPage) Setup(router *router.Router[*core.RequestEvent], app core.App, engine *templating.Engine) error {
|
|
router.GET(URL_ABKUERZUNGEN, p.GET(engine, app))
|
|
|
|
rg := router.Group(URL_ABKUERZUNGEN)
|
|
rg.BindFunc(middleware.IsAdminOrEditor())
|
|
rg.POST("", p.POST(engine, app))
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *AbkuerzungenPage) GET(engine *templating.Engine, app core.App) HandleFunc {
|
|
return func(e *core.RequestEvent) error {
|
|
// Read abbreviations from data table
|
|
dataRecord, err := dbmodels.Data_Key(app, "abkuerzungen")
|
|
if err != nil {
|
|
return engine.Response500(e, err, nil)
|
|
}
|
|
|
|
// Parse JSON value into map
|
|
abkMap := make(map[string]string)
|
|
rawValue := dataRecord.Value()
|
|
|
|
// Convert via JSON marshal/unmarshal to handle types.JSONRaw
|
|
jsonBytes, err := json.Marshal(rawValue)
|
|
if err != nil {
|
|
app.Logger().Error("Failed to marshal abkürzungen", "error", err)
|
|
return engine.Response500(e, err, nil)
|
|
}
|
|
|
|
if err := json.Unmarshal(jsonBytes, &abkMap); err != nil {
|
|
app.Logger().Error("Failed to unmarshal abkürzungen", "error", err)
|
|
return engine.Response500(e, err, nil)
|
|
}
|
|
|
|
// Convert to sorted array
|
|
entries := []AbkEntry{}
|
|
for k, v := range abkMap {
|
|
entries = append(entries, AbkEntry{Key: k, Value: v})
|
|
}
|
|
|
|
// Sort by key (German collation)
|
|
collator := collate.New(language.German)
|
|
slices.SortFunc(entries, func(a, b AbkEntry) int {
|
|
return collator.CompareString(a.Key, b.Key)
|
|
})
|
|
|
|
data := map[string]any{
|
|
"result": &AbkuerzungenResult{Entries: entries},
|
|
}
|
|
|
|
req := templating.NewRequest(e)
|
|
if req.Session() != nil {
|
|
data["csrf_token"] = req.Session().Token
|
|
} else {
|
|
data["csrf_token"] = ""
|
|
}
|
|
|
|
if msg := e.Request.URL.Query().Get("success"); msg != "" {
|
|
data["success"] = msg
|
|
}
|
|
if msg := e.Request.URL.Query().Get("error"); msg != "" {
|
|
data["error"] = msg
|
|
}
|
|
|
|
return engine.Response200(e, p.Template, data, p.Layout)
|
|
}
|
|
}
|
|
|
|
type abkFormEntry struct {
|
|
Key string `form:"key"`
|
|
Value string `form:"value"`
|
|
Delete string `form:"_delete"`
|
|
}
|
|
|
|
func (p *AbkuerzungenPage) POST(engine *templating.Engine, app core.App) HandleFunc {
|
|
return func(e *core.RequestEvent) error {
|
|
req := templating.NewRequest(e)
|
|
|
|
// Parse form manually to handle array syntax
|
|
if err := e.Request.ParseForm(); err != nil {
|
|
return p.redirectError(e, "Formulardaten ungültig.")
|
|
}
|
|
|
|
csrfToken := e.Request.FormValue("csrf_token")
|
|
|
|
// Validate CSRF
|
|
if err := req.CheckCSRF(csrfToken); err != nil {
|
|
return p.redirectError(e, err.Error())
|
|
}
|
|
|
|
// Build new map from form data
|
|
newMap := make(map[string]string)
|
|
|
|
// Parse array fields manually
|
|
form := e.Request.Form
|
|
i := 0
|
|
for {
|
|
keyField := fmt.Sprintf("abkuerzungen[%d][key]", i)
|
|
valueField := fmt.Sprintf("abkuerzungen[%d][value]", i)
|
|
deleteField := fmt.Sprintf("abkuerzungen[%d][_delete]", i)
|
|
|
|
key := form.Get(keyField)
|
|
value := form.Get(valueField)
|
|
delete := form.Get(deleteField)
|
|
|
|
// No more entries
|
|
if key == "" && value == "" {
|
|
break
|
|
}
|
|
|
|
app.Logger().Info("Form entry", "i", i, "key", key, "value", value, "delete", delete)
|
|
i++
|
|
|
|
// Skip deleted or empty entries
|
|
if delete == "true" || strings.TrimSpace(key) == "" {
|
|
continue
|
|
}
|
|
|
|
key = strings.TrimSpace(key)
|
|
value = strings.TrimSpace(value)
|
|
|
|
// Validate required value
|
|
if value == "" {
|
|
return p.redirectError(e, fmt.Sprintf("Abkürzung '%s' benötigt eine Beschreibung.", key))
|
|
}
|
|
|
|
// Check for duplicates
|
|
if _, exists := newMap[key]; exists {
|
|
return p.redirectError(e, fmt.Sprintf("Doppelter Schlüssel: '%s'", key))
|
|
}
|
|
|
|
newMap[key] = value
|
|
}
|
|
|
|
app.Logger().Info("Saving abkürzungen", "count", len(newMap))
|
|
|
|
// Update data record
|
|
dataRecord, err := dbmodels.Data_Key(app, "abkuerzungen")
|
|
if err != nil {
|
|
app.Logger().Error("Failed to load abkuerzungen record", "error", err)
|
|
return p.redirectError(e, "Laden der Daten fehlgeschlagen.")
|
|
}
|
|
|
|
dataRecord.Set(dbmodels.VALUE_FIELD, newMap)
|
|
if err := app.Save(dataRecord); err != nil {
|
|
app.Logger().Error("Failed to save abkuerzungen", "error", err)
|
|
return p.redirectError(e, "Speichern fehlgeschlagen.")
|
|
}
|
|
|
|
// Redirect with success message
|
|
redirect := fmt.Sprintf("%s?success=%s", URL_ABKUERZUNGEN, url.QueryEscape("Änderungen gespeichert."))
|
|
return e.Redirect(http.StatusSeeOther, redirect)
|
|
}
|
|
}
|
|
|
|
func (p *AbkuerzungenPage) redirectError(e *core.RequestEvent, message string) error {
|
|
redirect := fmt.Sprintf("%s?error=%s", URL_ABKUERZUNGEN, url.QueryEscape(message))
|
|
return e.Redirect(http.StatusSeeOther, redirect)
|
|
}
|