Merge pull request #205 from Capybara-z/patch-7
Add tblocker blocking notifications
This commit is contained in:
+3
-3
@@ -1,9 +1,9 @@
|
||||
from aiohttp.web_urldispatcher import UrlDispatcher
|
||||
|
||||
import bot
|
||||
from config import TBLOCKER_WEBHOOK_PATH
|
||||
from .tblocker import tblocker_webhook
|
||||
|
||||
|
||||
async def register_web_routes(router: UrlDispatcher) -> None:
|
||||
dp = bot.dp
|
||||
|
||||
# todo: add your api routes here
|
||||
router.add_post(TBLOCKER_WEBHOOK_PATH, tblocker_webhook)
|
||||
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
import asyncio
|
||||
import datetime
|
||||
from datetime import datetime
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
||||
import aiohttp
|
||||
from aiohttp import web
|
||||
import asyncpg
|
||||
from aiogram.exceptions import TelegramBadRequest, TelegramForbiddenError, TelegramRetryAfter
|
||||
from aiogram.types import InlineKeyboardButton
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from bot import bot
|
||||
from config import BLOCK_DURATION, DATABASE_URL, SERVER_COUNTRIES, TIMESTAMP_TTL
|
||||
from database import get_key_details
|
||||
from logger import logger
|
||||
from handlers.buttons import MAIN_MENU
|
||||
|
||||
|
||||
last_unblock_data = {}
|
||||
|
||||
|
||||
|
||||
def get_country_from_server(server: str) -> str:
|
||||
"""
|
||||
Определяет страну сервера по его имени или домену.
|
||||
Ищет совпадение части домена в полных доменах.
|
||||
"""
|
||||
server_part = server.split('.')[0]
|
||||
|
||||
for full_domain, country in SERVER_COUNTRIES.items():
|
||||
if server_part in full_domain:
|
||||
return country
|
||||
return server
|
||||
|
||||
|
||||
def handle_telegram_errors(func):
|
||||
async def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return await func(*args, **kwargs)
|
||||
except TelegramForbiddenError:
|
||||
tg_id = kwargs.get("tg_id") or args[1]
|
||||
logger.warning(f"🚫 Бот заблокирован пользователем {tg_id}.")
|
||||
return False
|
||||
except TelegramBadRequest:
|
||||
tg_id = kwargs.get("tg_id") or args[1]
|
||||
logger.warning(f"🚫 Чат не найден для пользователя {tg_id}.")
|
||||
return False
|
||||
except Exception as e:
|
||||
tg_id = kwargs.get("tg_id") or args[1]
|
||||
logger.error(f"❌ Ошибка отправки сообщения пользователю {tg_id}: {e}")
|
||||
return False
|
||||
return wrapper
|
||||
|
||||
|
||||
@handle_telegram_errors
|
||||
async def send_notification(tg_id: int, username: str, ip: str, server: str, action: str, timestamp: str):
|
||||
country = get_country_from_server(server)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
|
||||
|
||||
if action == 'block':
|
||||
message = (
|
||||
f"⚠️ <b>Замечено использование торрентов</b> ⚠️\n\n"
|
||||
f"<b>Уважаемый пользователь, мы обнаружили использование торрент-трафика в вашей подписке.</b>\n\n"
|
||||
f"📋 <b>Детали:</b>"
|
||||
f"<blockquote>"
|
||||
f"• Подписка: <code>{username}</code>\n"
|
||||
f"• Сервер: {country}\n"
|
||||
f"• Время блокировки страны: <b>{BLOCK_DURATION} минут</b>"
|
||||
f"</blockquote>\n\n"
|
||||
f"❗️ <b>Важно:</b>\n"
|
||||
f"• Возможно, вы забыли отключить торрент-клиент и сейчас качаете или раздаете торренты через VPN\n"
|
||||
f"• Загрузка и раздача через торренты запрещена согласно правилам использования сервиса\n"
|
||||
f"• Пожалуйста, полностью выключите торрент-клиент\n\n"
|
||||
f"⏳ <b>После истечения времени блокировки доступ будет автоматически восстановлен.</b>\n\n"
|
||||
f"⚠️ <b>Внимание:</b> При повторном использовании торрентов, блокировка будет применена снова."
|
||||
)
|
||||
else:
|
||||
message = (
|
||||
f"✅ <b>Доступ восстановлен</b>\n\n"
|
||||
f"<b>Уважаемый пользователь, временные ограничения для вашей подписки сняты.</b>\n\n"
|
||||
f"📋 <b>Детали:</b>"
|
||||
f"<blockquote>"
|
||||
f"• Подписка: <code>{username}</code>\n"
|
||||
f"• Сервер: {country}"
|
||||
f"</blockquote>\n\n"
|
||||
f"💬 <b>Напоминание:</b>\n"
|
||||
f"• Пожалуйста, воздержитесь от использования торрентов\n"
|
||||
f"• Убедитесь, что торрент-клиент полностью выключен"
|
||||
)
|
||||
|
||||
await bot.send_message(
|
||||
chat_id=tg_id,
|
||||
text=message,
|
||||
parse_mode='HTML',
|
||||
reply_markup=builder.as_markup()
|
||||
)
|
||||
logger.info(f"Отправлено уведомление пользователю {tg_id} о {action} для подписки {username}")
|
||||
return True
|
||||
|
||||
|
||||
async def tblocker_webhook(request):
|
||||
try:
|
||||
data = await request.json()
|
||||
logger.info(f"Получен запрос от tblocker: {data}")
|
||||
|
||||
username = data.get('username')
|
||||
ip = data.get('ip')
|
||||
server = data.get('server')
|
||||
action = data.get('action')
|
||||
timestamp = data.get('timestamp')
|
||||
|
||||
if not all([username, ip, server, action, timestamp]):
|
||||
logger.error("Неполные данные в вебхуке")
|
||||
return web.json_response({"error": "Missing required fields"}, status=400)
|
||||
|
||||
global last_unblock_data
|
||||
current_time = datetime.now().timestamp()
|
||||
|
||||
last_unblock_data = {
|
||||
k: v for k, v in last_unblock_data.items()
|
||||
if current_time - v['received_at'] <= TIMESTAMP_TTL
|
||||
}
|
||||
|
||||
cache_key = f"{username}:{server}"
|
||||
if action == 'unblock' and cache_key in last_unblock_data:
|
||||
if timestamp == last_unblock_data[cache_key]['timestamp']:
|
||||
return web.json_response({"status": "ok", "message": "duplicate unblock skipped"})
|
||||
|
||||
if action == 'unblock':
|
||||
last_unblock_data[cache_key] = {
|
||||
'timestamp': timestamp,
|
||||
'received_at': current_time
|
||||
}
|
||||
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
try:
|
||||
key_info = await get_key_details(username, conn)
|
||||
|
||||
if not key_info:
|
||||
logger.error(f"Ключ не найден для email {username}")
|
||||
return web.json_response({"error": "Key not found"}, status=404)
|
||||
|
||||
success = await send_notification(
|
||||
key_info['tg_id'],
|
||||
username,
|
||||
ip,
|
||||
server,
|
||||
action,
|
||||
timestamp
|
||||
)
|
||||
|
||||
if not success:
|
||||
logger.warning(f"Не удалось отправить уведомление пользователю {key_info['tg_id']}")
|
||||
|
||||
return web.json_response({"status": "ok"})
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при обработке вебхука: {str(e)}")
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
Reference in New Issue
Block a user