summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/api/admin.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/api/admin.py')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/admin.py33
1 files changed, 32 insertions, 1 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/admin.py b/packages/meshbay-hub/src/meshbay_hub/api/admin.py
index 164885d..efebb75 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/admin.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/admin.py
@@ -14,7 +14,7 @@ from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from meshbay_hub.auth import decrypt_email
-from meshbay_hub.api.deps import require_moderator
+from meshbay_hub.api.deps import require_admin, require_moderator
from meshbay_hub.api.revocation import get_connected_node_count
from meshbay_hub.db.engine import get_db
from meshbay_hub.db.models import Group, GroupMember, IPLog, Node, User
@@ -181,6 +181,37 @@ async def admin_patch_user(
# ── Groups ───────────────────────────────────────────────────────────────────
+@router.delete("/users/{user_id}")
+async def admin_delete_user(
+ user_id: str,
+ current_user: User = Depends(require_admin),
+ db: AsyncSession = Depends(get_db),
+):
+ """
+ Erase an account. Same erasure a user performs on themselves.
+
+ Admin rather than moderator: suspension is reversible and is the moderation
+ tool; this is not. Refused for one's own account — an administrator locking
+ themselves out is a support incident, and there is `DELETE /v1/users/me` for
+ someone who means it.
+ """
+ from meshbay_hub.api.users import erase_account
+
+ user = await db.get(User, user_id)
+ if not user:
+ raise HTTPException(status_code=404, detail="User not found")
+ if user.id == current_user.id:
+ raise HTTPException(
+ status_code=400,
+ detail="Use your own account settings to delete your account")
+ if user.status == "deleted":
+ raise HTTPException(status_code=410, detail="Account already deleted")
+
+ result = await erase_account(db, user)
+ log.info("Account %s erased by admin %s", result["username"], current_user.username)
+ return result
+
+
@router.get("/groups")
async def admin_list_groups(
current_user: User = Depends(require_moderator),