Three rename leftovers from t-paliad-025 fixed in one shot: 1. TSX/TS element ID mismatches — every page that worked via getElementById was broken because the client TS was renamed (e.g. project-title) but the TSX still used the German id (akte-title), so $() / getElementById would throw "missing element". Renamed `akte-*` → `project-*`, `termin-akte-*` → `termin-project-*`, `frist-akte-*` → `frist-project-*`, `new-instance-akte` → `new-instance-project`, `frist-filter-akte` → `frist-filter-project`, `termin-filter-akte` → `termin-filter-project` across all affected TSX. 2. Migration 020 idempotency — every ALTER TABLE/FUNCTION/COLUMN now lives in a DO $$…EXCEPTION WHEN undefined_table/column/function THEN NULL block. Production already has English names (manually patched), and the rewritten migration 018 creates English names directly on a fresh DB; the old non-defensive 020 would have failed in both scenarios. Down migration wrapped the same way for symmetry. 3. PostgREST endpoint names — `checklists_feedback` and `courts_feedback` referenced tables that don't exist; migration 020 renames the source tables to `checklist_feedback` / `court_feedback` (singular, matching `link_feedback`). Handlers now point at those. `glossary_suggestions` reverts to `glossar_suggestions` — that table lives in the shared public schema (pre-paliad era) and is not under our migration control. Verified: go build / go vet / go test / bun run build all clean. Migration 020 dry-runs clean against current production state inside a transaction.
125 lines
3.6 KiB
Go
125 lines
3.6 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"mgit.msbls.de/m/patholo/internal/auth"
|
|
"mgit.msbls.de/m/patholo/internal/checklists"
|
|
)
|
|
|
|
type ChecklistFeedback struct {
|
|
FeedbackType string `json:"feedback_type"`
|
|
Checklist string `json:"checklist"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
func handleChecklistsPage(w http.ResponseWriter, r *http.Request) {
|
|
http.ServeFile(w, r, "dist/checklists.html")
|
|
}
|
|
|
|
func handleChecklistDetailPage(w http.ResponseWriter, r *http.Request) {
|
|
slug := r.PathValue("slug")
|
|
if _, ok := checklists.Find(slug); !ok {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
http.ServeFile(w, r, "dist/checklists-detail.html")
|
|
}
|
|
|
|
func handleChecklistInstancePage(w http.ResponseWriter, r *http.Request) {
|
|
http.ServeFile(w, r, "dist/checklists-instance.html")
|
|
}
|
|
|
|
func handleChecklistsAPI(w http.ResponseWriter, r *http.Request) {
|
|
writeJSON(w, http.StatusOK, checklists.Summaries())
|
|
}
|
|
|
|
func handleChecklistAPI(w http.ResponseWriter, r *http.Request) {
|
|
slug := r.PathValue("slug")
|
|
c, ok := checklists.Find(slug)
|
|
if !ok {
|
|
writeJSON(w, http.StatusNotFound, map[string]string{"error": "Checkliste nicht gefunden."})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, c)
|
|
}
|
|
|
|
func handleChecklistsFeedback(w http.ResponseWriter, r *http.Request) {
|
|
var feedback ChecklistFeedback
|
|
if err := json.NewDecoder(r.Body).Decode(&feedback); err != nil {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Ungültige Anfrage."})
|
|
return
|
|
}
|
|
|
|
feedback.FeedbackType = strings.TrimSpace(feedback.FeedbackType)
|
|
feedback.Checklist = strings.TrimSpace(feedback.Checklist)
|
|
feedback.Message = strings.TrimSpace(feedback.Message)
|
|
|
|
if feedback.Message == "" || feedback.FeedbackType == "" {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Nachricht und Art sind erforderlich."})
|
|
return
|
|
}
|
|
|
|
accessToken := ""
|
|
email := ""
|
|
if cookie, err := r.Cookie(auth.SessionCookieName); err == nil {
|
|
accessToken = cookie.Value
|
|
email = extractEmailFromJWT(cookie.Value)
|
|
}
|
|
|
|
payload := map[string]string{
|
|
"feedback_type": feedback.FeedbackType,
|
|
"checklist": feedback.Checklist,
|
|
"message": feedback.Message,
|
|
"submitted_by": email,
|
|
}
|
|
|
|
jsonBody, err := json.Marshal(payload)
|
|
if err != nil {
|
|
log.Printf("checklists feedback marshal error: %v", err)
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "Interner Fehler."})
|
|
return
|
|
}
|
|
|
|
endpoint := fmt.Sprintf("%s/rest/v1/checklist_feedback", authClient.URL)
|
|
req2, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsonBody))
|
|
if err != nil {
|
|
log.Printf("checklists feedback request error: %v", err)
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "Interner Fehler."})
|
|
return
|
|
}
|
|
req2.Header.Set("Content-Type", "application/json")
|
|
req2.Header.Set("apikey", authClient.AnonKey)
|
|
if accessToken != "" {
|
|
req2.Header.Set("Authorization", "Bearer "+accessToken)
|
|
} else {
|
|
req2.Header.Set("Authorization", "Bearer "+authClient.AnonKey)
|
|
}
|
|
req2.Header.Set("Prefer", "return=minimal")
|
|
|
|
client := &http.Client{Timeout: 5 * time.Second}
|
|
resp, err := client.Do(req2)
|
|
if err != nil {
|
|
log.Printf("checklists feedback supabase error: %v", err)
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "Fehler beim Speichern."})
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode >= 300 {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
log.Printf("checklists feedback supabase status %d: %s", resp.StatusCode, string(body))
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "Fehler beim Speichern."})
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusCreated, map[string]string{"ok": "true"})
|
|
}
|