diff --git a/app/config.py b/app/config.py
index b412f4d3..3e735a76 100644
--- a/app/config.py
+++ b/app/config.py
@@ -509,12 +509,12 @@ class Settings(BaseSettings):
BAN_MSG_PUNISHMENT: str = (
"🚫 АККАУНТ ЗАБЛОКИРОВАН\n"
"━━━━━━━━━━━━━━━━━━━━━\n\n"
- "❌ Причина: Превышен лимит устройств\n\n"
+ "❌ Причина: Превышен лимит устройств\n"
+ "{node_info}\n"
"📊 Детали нарушения:\n"
"├ 📱 Устройств подключено: {ip_count}\n"
"├ 📋 Разрешено по тарифу: {limit}\n"
"└ ⏱ Время блокировки: {ban_minutes} мин\n\n"
- "{node_info}"
"━━━━━━━━━━━━━━━━━━━━━\n"
"💡 Что делать:\n"
"1. Отключите лишние устройства от VPN\n"
@@ -541,11 +541,11 @@ class Settings(BaseSettings):
BAN_MSG_WIFI: str = (
"🚫 АККАУНТ ЗАБЛОКИРОВАН\n"
"━━━━━━━━━━━━━━━━━━━━━\n\n"
- "❌ Причина: Использование WiFi сети\n\n"
+ "❌ Причина: Использование WiFi сети\n"
+ "{node_info}\n"
"📊 Детали:\n"
"├ 📶 Тип подключения: WiFi\n"
"{network_info}"
- "{node_info}"
"└ ⏱ Время блокировки: {ban_minutes} мин\n\n"
"━━━━━━━━━━━━━━━━━━━━━\n"
"💡 Что делать:\n"
@@ -560,11 +560,11 @@ class Settings(BaseSettings):
BAN_MSG_MOBILE: str = (
"🚫 АККАУНТ ЗАБЛОКИРОВАН\n"
"━━━━━━━━━━━━━━━━━━━━━\n\n"
- "❌ Причина: Использование мобильной сети\n\n"
+ "❌ Причина: Использование мобильной сети\n"
+ "{node_info}\n"
"📊 Детали:\n"
"├ 📱 Тип подключения: Мобильная сеть\n"
"{network_info}"
- "{node_info}"
"└ ⏱ Время блокировки: {ban_minutes} мин\n\n"
"━━━━━━━━━━━━━━━━━━━━━\n"
"💡 Что делать:\n"
diff --git a/app/handlers/common.py b/app/handlers/common.py
index 7d389163..4d9bcc70 100644
--- a/app/handlers/common.py
+++ b/app/handlers/common.py
@@ -11,13 +11,25 @@ from app.keyboards.inline import get_back_keyboard
logger = logging.getLogger(__name__)
+async def handle_delete_ban_notification(
+ callback: types.CallbackQuery,
+):
+ """Удаляет уведомление о бане при нажатии на кнопку"""
+ try:
+ await callback.message.delete()
+ await callback.answer("Уведомление удалено")
+ except Exception as e:
+ logger.warning(f"Не удалось удалить уведомление: {e}")
+ await callback.answer("Не удалось удалить", show_alert=False)
+
+
async def handle_unknown_callback(
callback: types.CallbackQuery,
db_user: User
):
-
+
texts = get_texts(db_user.language if db_user else "ru")
-
+
await callback.answer(
texts.t(
"UNKNOWN_CALLBACK_ALERT",
@@ -25,7 +37,7 @@ async def handle_unknown_callback(
),
show_alert=True,
)
-
+
logger.warning(f"Неизвестный callback: {callback.data} от пользователя {callback.from_user.id}")
@@ -99,7 +111,13 @@ async def show_rules(
def register_handlers(dp: Dispatcher):
-
+
+ # Удаление уведомлений о банах
+ dp.callback_query.register(
+ handle_delete_ban_notification,
+ F.data == "ban_notify:delete"
+ )
+
dp.callback_query.register(
show_rules,
F.data == "menu_rules"
diff --git a/app/services/ban_notification_service.py b/app/services/ban_notification_service.py
index a2371b89..c44dbf56 100644
--- a/app/services/ban_notification_service.py
+++ b/app/services/ban_notification_service.py
@@ -7,6 +7,7 @@ from datetime import datetime
from aiogram import Bot
from aiogram.exceptions import TelegramAPIError
+from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
@@ -18,6 +19,13 @@ from app.config import settings
logger = logging.getLogger(__name__)
+def get_delete_keyboard() -> InlineKeyboardMarkup:
+ """Клавиатура с кнопкой удаления уведомления"""
+ return InlineKeyboardMarkup(inline_keyboard=[
+ [InlineKeyboardButton(text="🗑 Удалить", callback_data="ban_notify:delete")]
+ ])
+
+
class BanNotificationService:
"""Сервис для отправки уведомлений о банах пользователям"""
@@ -102,8 +110,8 @@ class BanNotificationService:
logger.warning(f"Пользователь {user_identifier} не найден в базе данных")
return False, f"Пользователь не найден: {user_identifier}", None
- # Формируем информацию о ноде (в формате дерева)
- node_info = f"├ 🖥 Сервер: {node_name}\n" if node_name else ""
+ # Формируем информацию о ноде (заметно выделяем)
+ node_info = f"🖥 Нода: {node_name}" if node_name else ""
# Формируем сообщение из настроек
# Используем безопасное форматирование - если {node_info} отсутствует в шаблоне, не будет ошибки
@@ -126,12 +134,13 @@ class BanNotificationService:
if node_info:
message_text = message_text.rstrip() + f"\n\n{node_info.rstrip()}"
- # Отправляем сообщение
+ # Отправляем сообщение с кнопкой удаления
try:
await self._bot.send_message(
chat_id=user.telegram_id,
text=message_text,
- parse_mode="HTML"
+ parse_mode="HTML",
+ reply_markup=get_delete_keyboard()
)
logger.info(
f"Уведомление о бане отправлено пользователю {username} "
@@ -170,12 +179,13 @@ class BanNotificationService:
# Формируем сообщение из настроек
message_text = settings.BAN_MSG_ENABLED
- # Отправляем сообщение
+ # Отправляем сообщение с кнопкой удаления
try:
await self._bot.send_message(
chat_id=user.telegram_id,
text=message_text,
- parse_mode="HTML"
+ parse_mode="HTML",
+ reply_markup=get_delete_keyboard()
)
logger.info(
f"Уведомление о разбане отправлено пользователю {username} "
@@ -217,12 +227,13 @@ class BanNotificationService:
warning_message=warning_message
)
- # Отправляем сообщение
+ # Отправляем сообщение с кнопкой удаления
try:
await self._bot.send_message(
chat_id=user.telegram_id,
text=message_text,
- parse_mode="HTML"
+ parse_mode="HTML",
+ reply_markup=get_delete_keyboard()
)
logger.info(
f"Предупреждение отправлено пользователю {username} "
@@ -261,9 +272,11 @@ class BanNotificationService:
logger.warning(f"Пользователь {user_identifier} не найден в базе данных")
return False, f"Пользователь не найден: {user_identifier}", None
- # Формируем сообщение из настроек (в формате дерева)
+ # Формируем сообщение из настроек (заметно выделяем)
network_info = f"├ 🌐 Сеть: {network_type}\n" if network_type else ""
- node_info = f"├ 🖥 Сервер: {node_name}\n" if node_name else ""
+ node_info = f"🖥 Нода: {node_name}" if node_name else ""
+
+ logger.info(f"WiFi notification: node_name={node_name!r}, node_info={node_info!r}")
# Безопасное форматирование
format_vars = {
@@ -274,17 +287,19 @@ class BanNotificationService:
try:
message_text = settings.BAN_MSG_WIFI.format(**format_vars)
except KeyError:
+ logger.warning("BAN_MSG_WIFI template missing placeholders, adding node_info to end")
message_text = settings.BAN_MSG_WIFI.format(ban_minutes=ban_minutes)
- extra_info = network_info + node_info
+ extra_info = (network_info + node_info).strip()
if extra_info:
- message_text = message_text.rstrip() + f"\n\n{extra_info.rstrip()}"
+ message_text = message_text.rstrip() + f"\n\n{extra_info}"
- # Отправляем сообщение
+ # Отправляем сообщение с кнопкой удаления
try:
await self._bot.send_message(
chat_id=user.telegram_id,
text=message_text,
- parse_mode="HTML"
+ parse_mode="HTML",
+ reply_markup=get_delete_keyboard()
)
logger.info(
f"Уведомление о WiFi бане отправлено пользователю {username} "
@@ -323,9 +338,9 @@ class BanNotificationService:
logger.warning(f"Пользователь {user_identifier} не найден в базе данных")
return False, f"Пользователь не найден: {user_identifier}", None
- # Формируем сообщение из настроек (в формате дерева)
+ # Формируем сообщение из настроек (заметно выделяем)
network_info = f"├ 🌐 Сеть: {network_type}\n" if network_type else ""
- node_info = f"├ 🖥 Сервер: {node_name}\n" if node_name else ""
+ node_info = f"🖥 Нода: {node_name}" if node_name else ""
# Безопасное форматирование
format_vars = {
@@ -337,16 +352,17 @@ class BanNotificationService:
message_text = settings.BAN_MSG_MOBILE.format(**format_vars)
except KeyError:
message_text = settings.BAN_MSG_MOBILE.format(ban_minutes=ban_minutes)
- extra_info = network_info + node_info
+ extra_info = (network_info + node_info).strip()
if extra_info:
- message_text = message_text.rstrip() + f"\n\n{extra_info.rstrip()}"
+ message_text = message_text.rstrip() + f"\n\n{extra_info}"
- # Отправляем сообщение
+ # Отправляем сообщение с кнопкой удаления
try:
await self._bot.send_message(
chat_id=user.telegram_id,
text=message_text,
- parse_mode="HTML"
+ parse_mode="HTML",
+ reply_markup=get_delete_keyboard()
)
logger.info(
f"Уведомление о Mobile бане отправлено пользователю {username} "
diff --git a/app/webapi/routes/ban_notifications.py b/app/webapi/routes/ban_notifications.py
index 38922f33..20960a58 100644
--- a/app/webapi/routes/ban_notifications.py
+++ b/app/webapi/routes/ban_notifications.py
@@ -46,7 +46,8 @@ async def send_ban_notification(
"""
logger.info(
f"Получен запрос на отправку уведомления типа '{request.notification_type}' "
- f"для пользователя {request.username} ({request.user_identifier})"
+ f"для пользователя {request.username} ({request.user_identifier}), "
+ f"node_name={request.node_name!r}"
)
try: