feat(registratie): WP-36 — admin cases page + admin delete
Admin-only overview of all cases across owners + an admin delete, gated by a new
`cases:manage` capability (Authz role→cap + CanManageCases + CasesAdmin gate;
FE capability + guard + nav + role.interceptor prefix — the org-template/stamdata
recipe). Backend adds ApplicationStore.ListAll()/DeleteAny() and GET /admin/cases +
DELETE /admin/cases/{id}; admin delete removes ANY case incl. submitted. Page lives
in registratie/ui (owns the Aanvraag aggregate; reuses aanvraag-view + parse),
routed /beheer/zaken; delete guarded by a native confirm, optimistic with rollback.
Typed client regenerated (documents the new endpoints + owner field).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -80,6 +80,19 @@ public static class ApplicationStore
|
||||
}
|
||||
}
|
||||
|
||||
/// Admin: every case across all owners (WP-36). The per-owner List is the norm; this
|
||||
/// is the deliberate cross-owner read behind the admin-only /admin/cases endpoint.
|
||||
public static IReadOnlyList<Aanvraag> ListAll()
|
||||
{
|
||||
lock (_gate)
|
||||
{
|
||||
using var db = Db.Create();
|
||||
// Order client-side: SQLite can't ORDER BY a DateTimeOffset (same constraint the
|
||||
// rest of the store sidesteps by never sorting in the query).
|
||||
return db.Applications.ToList().OrderByDescending(a => a.UpdatedAt).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// Draft sync: idempotent upsert of the wizard snapshot. Only a Concept is mutable.
|
||||
public static bool SyncDraft(string id, string owner, JsonElement draft, int stepIndex, int stepCount, IReadOnlyList<string>? documentIds)
|
||||
{
|
||||
@@ -116,6 +129,28 @@ public static class ApplicationStore
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Admin: delete ANY case regardless of owner or submitted state (WP-36). The
|
||||
/// user-facing Delete refuses a submitted aanvraag and is owner-scoped; an admin
|
||||
/// managing the register may remove any case. Cascades to the case's documents
|
||||
/// using its own owner. Returns false only when the id doesn't exist.
|
||||
public static bool DeleteAny(string id)
|
||||
{
|
||||
string owner;
|
||||
List<string> docs;
|
||||
lock (_gate)
|
||||
{
|
||||
using var db = Db.Create();
|
||||
var a = db.Applications.Find(id);
|
||||
if (a is null) return false;
|
||||
owner = a.Owner;
|
||||
docs = a.DocumentIds.ToList();
|
||||
db.Applications.Remove(a);
|
||||
db.SaveChanges();
|
||||
}
|
||||
foreach (var d in docs) DocumentStore.DeleteOwned(d, owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Submit transition. reject != null → Afgewezen; else accepted (In behandeling,
|
||||
/// auto-advancing to Goedgekeurd after the window when autoApprovable). Returns null
|
||||
/// if the aanvraag is gone or already submitted (idempotency guard).
|
||||
|
||||
Reference in New Issue
Block a user