+17
-2
@@ -7,6 +7,7 @@ from typing import Any
|
||||
from aiogram import BaseMiddleware
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.types import CallbackQuery, Message, TelegramObject, User as TgUser
|
||||
from sqlalchemy.exc import InterfaceError, OperationalError
|
||||
|
||||
from app.config import settings
|
||||
from app.database.crud.user import get_user_by_telegram_id
|
||||
@@ -204,13 +205,27 @@ class AuthMiddleware(BaseMiddleware):
|
||||
data['is_admin'] = settings.is_admin(user.id)
|
||||
|
||||
result = await handler(event, data)
|
||||
await db.commit()
|
||||
try:
|
||||
await db.commit()
|
||||
except (InterfaceError, OperationalError) as conn_err:
|
||||
# Соединение закрылось (таймаут после долгой операции) - просто логируем
|
||||
logger.warning(f'⚠️ Соединение с БД закрыто после обработки, пропускаем commit: {conn_err}')
|
||||
return result
|
||||
|
||||
except (InterfaceError, OperationalError) as conn_err:
|
||||
# Соединение с БД закрылось - не пытаемся rollback
|
||||
logger.error(f'Ошибка соединения с БД в AuthMiddleware: {conn_err}')
|
||||
logger.error(f'Event type: {type(event)}')
|
||||
if hasattr(event, 'data'):
|
||||
logger.error(f'Callback data: {event.data}')
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f'Ошибка в AuthMiddleware: {e}')
|
||||
logger.error(f'Event type: {type(event)}')
|
||||
if hasattr(event, 'data'):
|
||||
logger.error(f'Callback data: {event.data}')
|
||||
await db.rollback()
|
||||
try:
|
||||
await db.rollback()
|
||||
except (InterfaceError, OperationalError):
|
||||
pass # Соединение уже закрыто
|
||||
raise
|
||||
|
||||
@@ -9,6 +9,7 @@ from aiogram import BaseMiddleware, Bot
|
||||
from aiogram.enums import ParseMode
|
||||
from aiogram.exceptions import TelegramBadRequest
|
||||
from aiogram.types import BufferedInputFile, CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, TelegramObject
|
||||
from sqlalchemy.exc import InterfaceError, OperationalError
|
||||
|
||||
from app.config import settings
|
||||
from app.services.startup_notification_service import _get_error_recommendations
|
||||
@@ -67,6 +68,10 @@ class GlobalErrorMiddleware(BaseMiddleware):
|
||||
return await handler(event, data)
|
||||
except TelegramBadRequest as e:
|
||||
return await self._handle_telegram_error(event, e, data)
|
||||
except (InterfaceError, OperationalError) as e:
|
||||
# Ошибки соединения с БД (таймаут после долгих операций) - логируем, но не спамим админам
|
||||
logger.warning('⚠️ Ошибка соединения с БД в GlobalErrorMiddleware: %s', e)
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error('Неожиданная ошибка в GlobalErrorMiddleware: %s', e, exc_info=True)
|
||||
# Отправляем уведомление об ошибке в админский чат
|
||||
@@ -82,13 +87,13 @@ class GlobalErrorMiddleware(BaseMiddleware):
|
||||
if self._is_old_query_error(error_message):
|
||||
return await self._handle_old_query(event, error)
|
||||
if self._is_message_not_modified_error(error_message):
|
||||
return await self._handle_message_not_modified(event, error)
|
||||
return await self._handle_message_not_modified(event, error, data)
|
||||
if self._is_topic_required_error(error_message):
|
||||
# Канал с топиками — просто игнорируем
|
||||
logger.debug('[GlobalErrorMiddleware] Игнорируем ошибку топика: %s', error)
|
||||
return None
|
||||
if self._is_bad_request_error(error_message):
|
||||
return await self._handle_bad_request(event, error)
|
||||
return await self._handle_bad_request(event, error, data)
|
||||
|
||||
# Неизвестная ошибка — логируем и отправляем уведомление
|
||||
logger.error('Неизвестная Telegram API ошибка: %s', error)
|
||||
@@ -117,7 +122,9 @@ class GlobalErrorMiddleware(BaseMiddleware):
|
||||
else:
|
||||
logger.warning('[GlobalErrorMiddleware] Игнорируем устаревший запрос: %s', error)
|
||||
|
||||
async def _handle_message_not_modified(self, event: TelegramObject, error: TelegramBadRequest):
|
||||
async def _handle_message_not_modified(
|
||||
self, event: TelegramObject, error: TelegramBadRequest, data: dict[str, Any]
|
||||
):
|
||||
logger.debug('[GlobalErrorMiddleware] Сообщение не было изменено: %s', error)
|
||||
|
||||
if isinstance(event, CallbackQuery):
|
||||
@@ -127,8 +134,13 @@ class GlobalErrorMiddleware(BaseMiddleware):
|
||||
except TelegramBadRequest as answer_error:
|
||||
if not self._is_old_query_error(str(answer_error).lower()):
|
||||
logger.error('Ошибка при ответе на callback: %s', answer_error)
|
||||
# Отправляем уведомление в админский чат
|
||||
bot = data.get('bot')
|
||||
if bot:
|
||||
user_info = self._get_user_info(event)
|
||||
schedule_error_notification(bot, answer_error, f'Callback answer error: {user_info}')
|
||||
|
||||
async def _handle_bad_request(self, event: TelegramObject, error: TelegramBadRequest):
|
||||
async def _handle_bad_request(self, event: TelegramObject, error: TelegramBadRequest, data: dict[str, Any]):
|
||||
error_message = str(error).lower()
|
||||
|
||||
if BOT_BLOCKED_PHRASE in error_message:
|
||||
@@ -143,6 +155,11 @@ class GlobalErrorMiddleware(BaseMiddleware):
|
||||
logger.warning('[GlobalErrorMiddleware] Чат или сообщение не найдено: %s', error)
|
||||
return
|
||||
logger.error('[GlobalErrorMiddleware] Неизвестная bad request ошибка: %s', error)
|
||||
# Отправляем уведомление перед raise
|
||||
bot = data.get('bot')
|
||||
if bot:
|
||||
user_info = self._get_user_info(event)
|
||||
schedule_error_notification(bot, error, f'Bad request: {user_info}')
|
||||
raise error
|
||||
|
||||
def _get_user_info(self, event: TelegramObject) -> str:
|
||||
|
||||
@@ -30,9 +30,11 @@ from app.database.models import (
|
||||
AdvertisingCampaign,
|
||||
AdvertisingCampaignRegistration,
|
||||
BroadcastHistory,
|
||||
CloudPaymentsPayment,
|
||||
CryptoBotPayment,
|
||||
FreekassaPayment,
|
||||
HeleketPayment,
|
||||
KassaAiPayment,
|
||||
MulenPayPayment,
|
||||
Pal24Payment,
|
||||
PaymentMethod,
|
||||
@@ -957,6 +959,58 @@ class UserService:
|
||||
except Exception as e:
|
||||
logger.error(f'❌ Ошибка удаления Freekassa платежей: {e}')
|
||||
|
||||
# Удаляем Wata платежи (до транзакций, т.к. wata_payments.transaction_id -> transactions.id)
|
||||
try:
|
||||
wata_payments_result = await db.execute(select(WataPayment).where(WataPayment.user_id == user_id))
|
||||
wata_payments = wata_payments_result.scalars().all()
|
||||
|
||||
if wata_payments:
|
||||
logger.info(f'🔄 Удаляем {len(wata_payments)} Wata платежей')
|
||||
await db.execute(
|
||||
update(WataPayment).where(WataPayment.user_id == user_id).values(transaction_id=None)
|
||||
)
|
||||
await db.flush()
|
||||
await db.execute(delete(WataPayment).where(WataPayment.user_id == user_id))
|
||||
await db.flush()
|
||||
except Exception as e:
|
||||
logger.error(f'❌ Ошибка удаления Wata платежей: {e}')
|
||||
|
||||
# Удаляем CloudPayments платежи
|
||||
try:
|
||||
cloudpayments_result = await db.execute(
|
||||
select(CloudPaymentsPayment).where(CloudPaymentsPayment.user_id == user_id)
|
||||
)
|
||||
cloudpayments_payments = cloudpayments_result.scalars().all()
|
||||
|
||||
if cloudpayments_payments:
|
||||
logger.info(f'🔄 Удаляем {len(cloudpayments_payments)} CloudPayments платежей')
|
||||
await db.execute(
|
||||
update(CloudPaymentsPayment)
|
||||
.where(CloudPaymentsPayment.user_id == user_id)
|
||||
.values(transaction_id=None)
|
||||
)
|
||||
await db.flush()
|
||||
await db.execute(delete(CloudPaymentsPayment).where(CloudPaymentsPayment.user_id == user_id))
|
||||
await db.flush()
|
||||
except Exception as e:
|
||||
logger.error(f'❌ Ошибка удаления CloudPayments платежей: {e}')
|
||||
|
||||
# Удаляем KassaAi платежи
|
||||
try:
|
||||
kassa_ai_result = await db.execute(select(KassaAiPayment).where(KassaAiPayment.user_id == user_id))
|
||||
kassa_ai_payments = kassa_ai_result.scalars().all()
|
||||
|
||||
if kassa_ai_payments:
|
||||
logger.info(f'🔄 Удаляем {len(kassa_ai_payments)} KassaAi платежей')
|
||||
await db.execute(
|
||||
update(KassaAiPayment).where(KassaAiPayment.user_id == user_id).values(transaction_id=None)
|
||||
)
|
||||
await db.flush()
|
||||
await db.execute(delete(KassaAiPayment).where(KassaAiPayment.user_id == user_id))
|
||||
await db.flush()
|
||||
except Exception as e:
|
||||
logger.error(f'❌ Ошибка удаления KassaAi платежей: {e}')
|
||||
|
||||
try:
|
||||
transactions_result = await db.execute(select(Transaction).where(Transaction.user_id == user_id))
|
||||
transactions = transactions_result.scalars().all()
|
||||
@@ -1056,17 +1110,6 @@ class UserService:
|
||||
except Exception as e:
|
||||
logger.error(f'❌ Ошибка удаления подписки: {e}')
|
||||
|
||||
try:
|
||||
wata_payments_result = await db.execute(select(WataPayment).where(WataPayment.user_id == user_id))
|
||||
wata_payments = wata_payments_result.scalars().all()
|
||||
|
||||
if wata_payments:
|
||||
logger.info(f'🔄 Удаляем {len(wata_payments)} Wata платежей')
|
||||
await db.execute(delete(WataPayment).where(WataPayment.user_id == user_id))
|
||||
await db.flush()
|
||||
except Exception as e:
|
||||
logger.error(f'❌ Ошибка удаления Wata платежей: {e}')
|
||||
|
||||
try:
|
||||
await db.execute(delete(User).where(User.id == user_id))
|
||||
await db.commit()
|
||||
|
||||
Reference in New Issue
Block a user