Add permanent user deletion endpoint with cascade cleanup and trash icon button in admin panel
Implemented DELETE `/admin/users/{user_id}/permanent` endpoint with safeguards preventing self-deletion and blocking deletion of game hosts. Added cascade deletion of user's game memberships, chips, sheet states, and invite tokens, with winner references nullified. Added trash icon button (🗑) to admin user rows with bilingual confirmation dialog and error handling for game ownership conflicts. Adjusted
This commit is contained in:
@@ -6,7 +6,7 @@ from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
from sqlalchemy.orm import Session
|
||||
from ..db import get_db
|
||||
from ..mailer import send_html_email, send_user_invite
|
||||
from ..models import AppSettings, InviteToken, User, Role
|
||||
from ..models import AppSettings, Game, GameChip, GameMember, InviteToken, SheetState, User, Role
|
||||
from ..security import hash_password, get_session_user_id
|
||||
|
||||
router = APIRouter(prefix="/admin", tags=["admin"])
|
||||
@@ -84,6 +84,28 @@ def create_user(req: Request, data: dict, db: Session = Depends(get_db)):
|
||||
db.commit()
|
||||
return {"ok": True, "id": u.id, "invite_sent": invite_sent}
|
||||
|
||||
@router.delete("/users/{user_id}/permanent")
|
||||
def permanently_delete_user(req: Request, user_id: str, db: Session = Depends(get_db)):
|
||||
admin = require_admin(req, db)
|
||||
if admin.id == user_id:
|
||||
raise HTTPException(400, "cannot delete yourself")
|
||||
|
||||
user = db.query(User).filter(User.id == user_id).first()
|
||||
if not user:
|
||||
raise HTTPException(404, "not found")
|
||||
if db.query(Game).filter(Game.host_user_id == user_id).first():
|
||||
raise HTTPException(409, "cannot delete a user who owns games")
|
||||
|
||||
db.query(Game).filter(Game.winner_user_id == user_id).update({Game.winner_user_id: None}, synchronize_session=False)
|
||||
db.query(GameMember).filter(GameMember.user_id == user_id).delete(synchronize_session=False)
|
||||
db.query(GameChip).filter(GameChip.user_id == user_id).delete(synchronize_session=False)
|
||||
db.query(SheetState).filter(SheetState.owner_user_id == user_id).delete(synchronize_session=False)
|
||||
db.query(InviteToken).filter(InviteToken.user_id == user_id).delete(synchronize_session=False)
|
||||
db.delete(user)
|
||||
db.commit()
|
||||
return {"ok": True, "deleted": True}
|
||||
|
||||
|
||||
@router.delete("/users/{user_id}")
|
||||
def delete_user(req: Request, user_id: str, db: Session = Depends(get_db)):
|
||||
admin = require_admin(req, db)
|
||||
|
||||
Reference in New Issue
Block a user