From af31c551d2f23ef01425bdb2db8f255dbc3047e2 Mon Sep 17 00:00:00 2001 From: Fringg Date: Wed, 18 Feb 2026 11:59:25 +0300 Subject: [PATCH] =?UTF-8?q?fix:=203=20user=20deletion=20bugs=20=E2=80=94?= =?UTF-8?q?=20type=20cast,=20inner=20savepoint,=20lazy=20load?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. connected_squads JSON stores IDs as strings but server_squads.id is integer — cast to int before passing to remove_user_from_servers 2. Wrap remove_user_from_servers in its own db.begin_nested() so its failure doesn't abort the parent savepoint (subscription deletion) 3. Pre-fetch admin.id before delete_user_account to avoid MissingGreenlet when transaction rollback expires the ORM object --- app/cabinet/routes/admin_users.py | 7 +++++-- app/services/user_service.py | 7 ++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/cabinet/routes/admin_users.py b/app/cabinet/routes/admin_users.py index fcf079e3..349b97e2 100644 --- a/app/cabinet/routes/admin_users.py +++ b/app/cabinet/routes/admin_users.py @@ -1771,15 +1771,18 @@ async def full_delete_user( panel_error: str | None = None deleted_from_panel = False + # Pre-fetch admin.id to avoid MissingGreenlet after transaction rollback + admin_id_val = admin.id + # UserService.delete_user_account handles both bot DB and Remnawave panel user_service = UserService() - success = await user_service.delete_user_account(db, user_id, admin.id) + success = await user_service.delete_user_account(db, user_id, admin_id_val) if success: deleted_from_panel = request.delete_from_panel and user.remnawave_uuid is not None reason_text = f' (reason: {request.reason})' if request.reason else '' - logger.info('Admin fully deleted user', admin_id=admin.id, user_id=user_id, reason_text=reason_text) + logger.info('Admin fully deleted user', admin_id=admin_id_val, user_id=user_id, reason_text=reason_text) return FullDeleteUserResponse( success=success, diff --git a/app/services/user_service.py b/app/services/user_service.py index d224ec93..589793a6 100644 --- a/app/services/user_service.py +++ b/app/services/user_service.py @@ -1194,7 +1194,12 @@ class UserService: try: from app.database.crud.server_squad import remove_user_from_servers - await remove_user_from_servers(db, squad_ids) + # JSON may store IDs as strings — cast to int + int_squad_ids = [int(sid) for sid in squad_ids if sid] + if int_squad_ids: + # Own savepoint so failure doesn't abort subscription deletion + async with db.begin_nested(): + await remove_user_from_servers(db, int_squad_ids) except Exception as sq_err: logger.warning('⚠️ Не удалось уменьшить счётчик серверов', error=sq_err)