fix: resolve sync 404 errors, user deletion FK constraint, and device limit not sent to RemnaWave

1. Remove pointless HWID reset during auto-sync deactivation — user
   doesn't exist in panel, API returns 404, UUID is cleaned up below.

2. Clean up RESTRICT FK references (AdminAuditLog, WithdrawalRequest,
   AdminRole, UserRole, AccessPolicy) before deleting user to prevent
   IntegrityError on admin_audit_log_user_id_fkey.

3. Fix device limit not being sent to RemnaWave when
   DEVICES_SELECTION_DISABLED_AMOUNT=0: treat 0 as "no forced override"
   instead of sending hwidDeviceLimit:0 (which Remnawave interprets as
   unlimited). Now falls through to subscription.device_limit from tariff.

4. Add info-level logging to POST /api/users (was debug) to match
   existing PATCH logging for device limit diagnostics.
This commit is contained in:
Fringg
2026-02-25 11:53:49 +03:00
parent 731eb24364
commit 1ce91749aa
5 changed files with 33 additions and 18 deletions

View File

@@ -1525,8 +1525,8 @@ class Settings(BaseSettings):
logger.warning('Некорректное значение DEVICES_SELECTION_DISABLED_AMOUNT', raw_value=raw_value)
return None
if value < 0:
return 0
if value <= 0:
return None
return value

View File

@@ -461,9 +461,19 @@ class RemnaWaveAPI:
if active_internal_squads:
data['activeInternalSquads'] = active_internal_squads
logger.debug('Создание пользователя в панели', data=data)
logger.info(
'POST /api/users payload',
username=data.get('username'),
hwidDeviceLimit=data.get('hwidDeviceLimit'),
status=data.get('status'),
)
response = await self._make_request('POST', '/api/users', data)
user = self._parse_user(response['response'])
logger.info(
'POST /api/users response',
uuid=user.uuid,
response_hwidDeviceLimit=user.hwid_device_limit,
)
return await self.enrich_user_with_happ_link(user)
async def get_user_by_uuid(self, uuid: str) -> RemnaWaveUser | None:

View File

@@ -1499,19 +1499,8 @@ class RemnaWaveService:
logger.info('🗑️ Деактивация подписки пользователя (нет в панели)', telegram_id=telegram_id)
if db_user.remnawave_uuid and hwid_api_client:
try:
devices_reset = await hwid_api_client.reset_user_devices(db_user.remnawave_uuid)
if devices_reset:
logger.info(
'🔧 Сброшены HWID устройства для пользователя', telegram_id=telegram_id
)
except Exception as hwid_error:
logger.error(
'❌ Ошибка сброса HWID устройств для',
telegram_id=telegram_id,
hwid_error=hwid_error,
)
# NOTE: Не сбрасываем HWID здесь — пользователь уже удалён из панели,
# API вернёт 404, UUID очищается ниже (cleanup_mutation)
try:
from sqlalchemy import delete

View File

@@ -1203,6 +1203,22 @@ class UserService:
logger.error('❌ Ошибка удаления подписки', error=e)
try:
from app.database.models import (
AccessPolicy,
AdminAuditLog,
AdminRole,
UserRole,
WithdrawalRequest,
)
await db.execute(delete(AdminAuditLog).where(AdminAuditLog.user_id == user_id))
await db.execute(delete(WithdrawalRequest).where(WithdrawalRequest.user_id == user_id))
await db.execute(
update(WithdrawalRequest).where(WithdrawalRequest.processed_by == user_id).values(processed_by=None)
)
await db.execute(update(AdminRole).where(AdminRole.created_by == user_id).values(created_by=None))
await db.execute(update(UserRole).where(UserRole.assigned_by == user_id).values(assigned_by=None))
await db.execute(update(AccessPolicy).where(AccessPolicy.created_by == user_id).values(created_by=None))
await db.execute(delete(User).where(User.id == user_id))
await db.commit()
logger.info('✅ Пользователь окончательно удален из базы', user_id=user_id)

View File

@@ -181,7 +181,7 @@ def resolve_hwid_device_limit(subscription: Subscription | None) -> int | None:
if not settings.is_devices_selection_enabled():
forced_limit = settings.get_disabled_mode_device_limit()
if forced_limit is not None:
if forced_limit is not None and forced_limit > 0:
_logger.info(
'DEVICES_SELECTION disabled, using forced limit',
forced_limit=forced_limit,
@@ -189,7 +189,7 @@ def resolve_hwid_device_limit(subscription: Subscription | None) -> int | None:
subscription_id=getattr(subscription, 'id', None),
)
return forced_limit
# Если forced_limit не задан, используем device_limit из подписки
# forced_limit не задан или равен 0 — используем device_limit из подписки,
# чтобы при смене тарифа лимит устройств обновлялся в панели
limit = getattr(subscription, 'device_limit', None)