84 lines
2.8 KiB
Go
84 lines
2.8 KiB
Go
package notifyprefs
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"gitea.perlbach24.de/scripte/nexarch/internal/auth"
|
|
)
|
|
|
|
// Handler stellt Benachrichtigungspraeferenzen als HTTP-Endpunkte bereit
|
|
// (CFG-04). Duenner Client von Store — keine eigene Zustelllogik.
|
|
type Handler struct {
|
|
prefs *Store
|
|
}
|
|
|
|
func NewHandler(prefs *Store) *Handler {
|
|
return &Handler{prefs: prefs}
|
|
}
|
|
|
|
type setPreferenceRequest struct {
|
|
EventType string `json:"event_type"`
|
|
Channel string `json:"channel"`
|
|
Enabled bool `json:"enabled"`
|
|
}
|
|
|
|
// SetPreference setzt die eigene Praeferenz des angemeldeten Benutzers
|
|
// (Akzeptanzkriterium 1). Muss hinter auth.RequireAuth haengen.
|
|
func (h *Handler) SetPreference(w http.ResponseWriter, r *http.Request) {
|
|
claims, ok := auth.ClaimsFromContext(r.Context())
|
|
if !ok {
|
|
http.Error(w, "nicht angemeldet", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
var req setPreferenceRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "ungueltige Anfrage", http.StatusBadRequest)
|
|
return
|
|
}
|
|
if err := h.prefs.Set(r.Context(), claims.TenantSlug, claims.UserID, req.EventType, req.Channel, req.Enabled); err != nil {
|
|
http.Error(w, "Einstellung konnte nicht gespeichert werden.", http.StatusBadRequest)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
|
|
// ListMine liefert die eigenen Praeferenzen (Akzeptanzkriterium 1) — nur die
|
|
// EIGENEN, niemals die eines anderen Benutzers (Pruefung 2). claims.UserID
|
|
// kommt ausschliesslich aus dem verifizierten Session-Token, ist also nicht
|
|
// vom Client manipulierbar.
|
|
func (h *Handler) ListMine(w http.ResponseWriter, r *http.Request) {
|
|
claims, ok := auth.ClaimsFromContext(r.Context())
|
|
if !ok {
|
|
http.Error(w, "nicht angemeldet", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
prefs, err := h.prefs.ListForUser(r.Context(), claims.TenantSlug, claims.UserID)
|
|
if err != nil {
|
|
http.Error(w, "Einstellungen konnten nicht geladen werden.", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_ = json.NewEncoder(w).Encode(prefs)
|
|
}
|
|
|
|
// ListTenantOverview liefert die Praeferenzen ALLER Benutzer des eigenen
|
|
// Mandanten (Akzeptanzkriterium 3: Tenant-Admin-Übersicht). Die Zugriffs-
|
|
// beschraenkung "nur Tenant-Admin" ist Aufgabe von RBAC-02 (Policy-
|
|
// Enforcement-Schicht) vor diesem Handler — hier wird bewusst keine eigene
|
|
// Rechtelogik dupliziert (Ticket-Produkt-DNA: duenner Client).
|
|
func (h *Handler) ListTenantOverview(w http.ResponseWriter, r *http.Request) {
|
|
claims, ok := auth.ClaimsFromContext(r.Context())
|
|
if !ok {
|
|
http.Error(w, "nicht angemeldet", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
prefs, err := h.prefs.ListForTenant(r.Context(), claims.TenantSlug)
|
|
if err != nil {
|
|
http.Error(w, "Übersicht konnte nicht geladen werden.", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_ = json.NewEncoder(w).Encode(prefs)
|
|
}
|