feat(training): delete group button (admin only) on Training page
- Backend DELETE /api/groups/<gid> (admin, own-org enforced via _get_owned_group); cascades removal of the group's sessions. GroupStore.delete added. - Training.vue: each group card gets a trash (Trash2 line icon) delete button shown only to admins (auth.isAdmin); confirm dialog; @click.stop so it doesn't navigate. Card restructured so the delete button is not inside the clickable router-link. - test_user_journey: trainee cannot delete (403), admin deletes, group gone (404). All suites pass. Rebuilt dist.
This commit is contained in:
@@ -324,6 +324,28 @@ def update_persona(gid: str, pid: str):
|
||||
return jsonify({"persona": strip_secret_fields(full)})
|
||||
|
||||
|
||||
@groups_bp.delete("/<gid>")
|
||||
@require_auth
|
||||
@require_roles("admin")
|
||||
def delete_group(gid: str):
|
||||
"""Delete a persona group (admin only, own org)."""
|
||||
s = _stores()
|
||||
group = _get_owned_group(s, gid) # also enforces tenant org (super_admin global)
|
||||
s["groups"].delete(gid)
|
||||
# cascade: also remove finished/active sessions for this group's personas
|
||||
try:
|
||||
sess = s.get("session_store")
|
||||
if sess and hasattr(sess, "sessions"):
|
||||
for r in sess.sessions.all():
|
||||
if r.get("group_id") == gid:
|
||||
key = r.get("id") or r.get("sid")
|
||||
if key:
|
||||
sess.sessions.delete(key)
|
||||
except Exception:
|
||||
pass
|
||||
return jsonify({"ok": True, "deleted": gid})
|
||||
|
||||
|
||||
@groups_bp.post("/<gid>/reanalyze")
|
||||
@require_auth
|
||||
@require_roles("admin")
|
||||
|
||||
@@ -95,3 +95,7 @@ class GroupStore:
|
||||
if not found:
|
||||
raise ValueError("persona not found")
|
||||
return self.groups.replace(gid, group)
|
||||
|
||||
def delete(self, gid: str) -> None:
|
||||
"""Hard-delete a group (personas/report included)."""
|
||||
self.groups.delete(gid)
|
||||
|
||||
@@ -93,4 +93,14 @@ after = len(r.get_json()["personas"])
|
||||
assert after > before, f"append should add personas (before={before}, after={after})"
|
||||
print(f"[ok] append adds personas ({before} -> {after}); existing kept")
|
||||
|
||||
# 12. delete group: trainee cannot, admin can
|
||||
r = C.delete(f"/api/groups/{gid}", headers=TH)
|
||||
assert r.status_code == 403, ("trainee must not delete group", r.status_code)
|
||||
print("[ok] trainee cannot delete group (403)")
|
||||
r = C.delete(f"/api/groups/{gid}", headers=AH)
|
||||
assert r.status_code == 200, r.get_json()
|
||||
gone = C.get(f"/api/groups/{gid}", headers=AH)
|
||||
assert gone.status_code == 404, "deleted group should be gone"
|
||||
print("[ok] admin deletes group; group no longer reachable")
|
||||
|
||||
print("ALL USER-JOURNEY FLOW TESTS PASSED")
|
||||
|
||||
Reference in New Issue
Block a user