Files
PenaltyTracker/rules.go
T
2026-05-16 20:39:27 +02:00

116 lines
2.5 KiB
Go

package main
import (
"encoding/csv"
"net/http"
"os"
"path/filepath"
"strings"
"sync"
)
var (
rulesMu sync.RWMutex
rules = map[string]map[string]Rule{}
)
func loadRules(dir string) error {
entries, err := os.ReadDir(dir)
if err != nil {
return err
}
out := map[string]map[string]Rule{}
for _, e := range entries {
if e.IsDir() || !strings.HasSuffix(e.Name(), ".csv") {
continue
}
lang := strings.TrimSuffix(e.Name(), ".csv")
f, err := os.Open(filepath.Join(dir, e.Name()))
if err != nil {
continue
}
r := csv.NewReader(f)
r.FieldsPerRecord = -1
records, err := r.ReadAll()
f.Close()
if err != nil {
continue
}
langMap := map[string]Rule{}
for i, rec := range records {
if len(rec) < 4 {
continue
}
if i == 0 {
lower := strings.ToLower(strings.TrimSpace(rec[0]))
if lower == "number" || lower == "rule_number" || lower == "rule" {
continue
}
}
ru := Rule{
Number: strings.TrimSpace(rec[0]),
Text: strings.TrimSpace(rec[1]),
SuggestedPenalty: strings.TrimSpace(rec[2]),
EscalationMode: strings.TrimSpace(rec[3]),
}
if ru.EscalationMode == "" {
ru.EscalationMode = "same"
}
if strings.HasPrefix(ru.EscalationMode, "escalate:") {
tiers := strings.Split(strings.TrimPrefix(ru.EscalationMode, "escalate:"), "|")
for j, t := range tiers {
tiers[j] = strings.TrimSpace(t)
}
ru.EscalationTiers = tiers
ru.EscalationMode = "escalate"
}
langMap[ru.Number] = ru
}
out[lang] = langMap
}
rulesMu.Lock()
rules = out
rulesMu.Unlock()
return nil
}
func getRules(lang string) []Rule {
rulesMu.RLock()
defer rulesMu.RUnlock()
m, ok := rules[lang]
if !ok {
m = rules["en"]
}
out := make([]Rule, 0, len(m))
for _, r := range m {
out = append(out, r)
}
return out
}
func registerRuleRoutes(mux *http.ServeMux) {
mux.HandleFunc("GET /api/rules", requireAuth(handleListRules))
mux.HandleFunc("POST /api/rules/reload", requireAdmin(handleReloadRules))
}
func handleListRules(w http.ResponseWriter, r *http.Request) {
lang := r.URL.Query().Get("lang")
if lang == "" {
u := userFromCtx(r)
lang = u.Language
}
writeJSON(w, http.StatusOK, getRules(lang))
}
func handleReloadRules(w http.ResponseWriter, r *http.Request) {
dir := os.Getenv("RULES_DIR")
if dir == "" {
dir = "rules"
}
if err := loadRules(dir); err != nil {
writeError(w, http.StatusInternalServerError, "load_error")
return
}
w.WriteHeader(http.StatusNoContent)
}