Files
deklarix/internal/web/abteilung_handlers_test.go
noroot 22f748d66c feat: Ebene 4 vollständig steuerbar machen — Abteilungen, Werkzeug-Sperrungen, Nutzer-Deaktivierung
Deklarix soll ein buchbarer Service werden — dafür muss jede Entität im
Datenmodell über das Frontend steuerbar sein, nicht nur einsehbar.
Schließt drei konkrete Lücken:

- Abteilungen (GET /verwaltung/abteilungen, anlegen/löschen) — ohne
  diese Seite blieb die Abteilung-Auswahl im Antrag-Fragebogen leer
  und unbenutzbar, das war ein Funktionsdefizit, kein Komfortfehler.
- Eigene Werkzeug-Sperrungen (GET /verwaltung/werkzeuge) — ein Mandant
  kann einen zentralen Katalogeintrag jetzt für sich sperren/entsperren,
  ohne den zentralen Katalog selbst zu verändern.
- Nutzer-Deaktivierung (POST /verwaltung/nutzer/{id}/deaktivieren bzw.
  .../aktivieren, neue Spalte app_user.active, Migration 0012). Nutzer
  werden nicht gelöscht (Fremdschlüssel auf antrag/entscheidung/
  audit_log würden das verhindern und die Historie zerstören) —
  deaktivierte Logins können sich nicht mehr anmelden und verlieren
  eine laufende Sitzung sofort. Ein Admin kann sich nicht selbst
  deaktivieren.

Zusätzlich: store.ListAktiveGenehmigungenForAccount als Grundlage für
die Wiedervorlage (Schritt 7, Web-Layer folgt).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-29 14:07:47 +02:00

97 lines
3.1 KiB
Go

package web_test
import (
"context"
"net/http"
"net/url"
"strings"
"testing"
)
func TestAdminCanCreateAndDeleteAbteilung(t *testing.T) {
fs := newFakeStore()
s := newServer(t, fs)
adminCookie := seedAccountWithRole(t, fs, "Test-Mandant", "admin@example.com", "admin")
resp := postForm(t, s, adminCookie, "/verwaltung/abteilungen", url.Values{"name": {"Vertrieb"}})
if resp.Code != http.StatusSeeOther {
t.Fatalf("create status = %d, body: %s", resp.Code, resp.Body.String())
}
list := getWithCookie(t, s, adminCookie, "/verwaltung/abteilungen")
if !strings.Contains(list.Body.String(), "Vertrieb") {
t.Errorf("expected Vertrieb in the Abteilungsliste, got: %s", list.Body.String())
}
var abtID string
for accID, abts := range fs.abteilungen {
_ = accID
for _, a := range abts {
if a.Name == "Vertrieb" {
abtID = a.ID
}
}
}
if abtID == "" {
t.Fatal("expected Vertrieb to exist in fakeStore")
}
delResp := postForm(t, s, adminCookie, "/verwaltung/abteilungen/"+abtID+"/loeschen", url.Values{})
if delResp.Code != http.StatusSeeOther {
t.Fatalf("delete status = %d, body: %s", delResp.Code, delResp.Body.String())
}
if _, err := fs.GetAbteilung(context.Background(), abtID); err == nil {
t.Error("expected the Abteilung to be deleted")
}
}
func TestNeueAntragFormZeigtAngelegteAbteilung(t *testing.T) {
fs := newFakeStore()
s := newServer(t, fs)
adminCookie := seedAccountWithRole(t, fs, "Test-Mandant", "admin@example.com", "admin")
postForm(t, s, adminCookie, "/verwaltung/abteilungen", url.Values{"name": {"Marketing"}})
resp := getWithCookie(t, s, adminCookie, "/antraege/neu")
if resp.Code != http.StatusOK {
t.Fatalf("status = %d, body: %s", resp.Code, resp.Body.String())
}
if !strings.Contains(resp.Body.String(), "Marketing") {
t.Errorf("expected the newly created Abteilung in the Fragebogen, got: %s", resp.Body.String())
}
}
func TestMitarbeiterCannotAccessAbteilungsverwaltung(t *testing.T) {
fs := newFakeStore()
s := newServer(t, fs)
cookie := seedAccountWithRole(t, fs, "Test-Mandant", "mitarbeiter@example.com", "mitarbeiter")
resp := getWithCookie(t, s, cookie, "/verwaltung/abteilungen")
if resp.Code != http.StatusNotFound {
t.Fatalf("status = %d, want 404 for role mitarbeiter", resp.Code)
}
}
func TestAdminCannotDeleteForeignAbteilung(t *testing.T) {
fs := newFakeStore()
s := newServer(t, fs)
adminA := seedAccountWithRole(t, fs, "Mandant A", "admin-a@example.com", "admin")
postForm(t, s, adminA, "/verwaltung/abteilungen", url.Values{"name": {"Nur A"}})
var abtID string
for _, abts := range fs.abteilungen {
for _, a := range abts {
if a.Name == "Nur A" {
abtID = a.ID
}
}
}
adminB := seedAccountWithRole(t, fs, "Mandant B", "admin-b@example.com", "admin")
resp := postForm(t, s, adminB, "/verwaltung/abteilungen/"+abtID+"/loeschen", url.Values{})
if resp.Code != http.StatusNotFound {
t.Fatalf("status = %d, want 404 for a foreign account's Abteilung", resp.Code)
}
if _, err := fs.GetAbteilung(context.Background(), abtID); err != nil {
t.Error("expected the foreign Abteilung to still exist")
}
}