mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-20 11:50:27 +00:00
163 lines
5.7 KiB
Python
163 lines
5.7 KiB
Python
import logging
|
||
from aiogram import Dispatcher, types, F, Bot
|
||
from aiogram.fsm.context import FSMContext
|
||
from aiogram.types import InaccessibleMessage
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
||
from app.states import PromoCodeStates
|
||
from app.database.models import User
|
||
from app.keyboards.inline import get_back_keyboard
|
||
from app.localization.texts import get_texts
|
||
from app.services.blacklist_service import blacklist_service
|
||
from app.services.promocode_service import PromoCodeService
|
||
from app.services.admin_notification_service import AdminNotificationService
|
||
from app.utils.decorators import error_handler
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
@error_handler
|
||
async def show_promocode_menu(
|
||
callback: types.CallbackQuery,
|
||
db_user: User,
|
||
state: FSMContext
|
||
):
|
||
texts = get_texts(db_user.language)
|
||
|
||
# Если сообщение недоступно, отправляем новое
|
||
if isinstance(callback.message, InaccessibleMessage):
|
||
await callback.message.answer(
|
||
texts.PROMOCODE_ENTER,
|
||
reply_markup=get_back_keyboard(db_user.language)
|
||
)
|
||
else:
|
||
await callback.message.edit_text(
|
||
texts.PROMOCODE_ENTER,
|
||
reply_markup=get_back_keyboard(db_user.language)
|
||
)
|
||
|
||
await state.set_state(PromoCodeStates.waiting_for_code)
|
||
await callback.answer()
|
||
|
||
|
||
async def activate_promocode_for_registration(
|
||
db: AsyncSession,
|
||
user_id: int,
|
||
code: str,
|
||
bot: Bot = None
|
||
) -> dict:
|
||
"""
|
||
Активирует промокод для пользователя во время регистрации.
|
||
Возвращает результат активации без отправки сообщений.
|
||
"""
|
||
promocode_service = PromoCodeService()
|
||
result = await promocode_service.activate_promocode(db, user_id, code)
|
||
|
||
if result["success"]:
|
||
logger.info(f"✅ Пользователь {user_id} активировал промокод {code} при регистрации")
|
||
|
||
# Отправляем уведомление админу, если бот доступен
|
||
if bot:
|
||
try:
|
||
from app.database.crud.user import get_user_by_id
|
||
user = await get_user_by_id(db, user_id)
|
||
if user:
|
||
notification_service = AdminNotificationService(bot)
|
||
await notification_service.send_promocode_activation_notification(
|
||
db,
|
||
user,
|
||
result.get("promocode", {"code": code}),
|
||
result["description"],
|
||
result.get("balance_before_kopeks"),
|
||
result.get("balance_after_kopeks"),
|
||
)
|
||
except Exception as notify_error:
|
||
logger.error(
|
||
"Ошибка отправки админ уведомления об активации промокода %s: %s",
|
||
code,
|
||
notify_error,
|
||
)
|
||
|
||
return result
|
||
|
||
|
||
@error_handler
|
||
async def process_promocode(
|
||
message: types.Message,
|
||
db_user: User,
|
||
state: FSMContext,
|
||
db: AsyncSession
|
||
):
|
||
# Проверяем, находится ли пользователь в черном списке
|
||
is_blacklisted, blacklist_reason = await blacklist_service.is_user_blacklisted(
|
||
message.from_user.id,
|
||
message.from_user.username
|
||
)
|
||
|
||
if is_blacklisted:
|
||
logger.warning(f"🚫 Пользователь {message.from_user.id} находится в черном списке: {blacklist_reason}")
|
||
try:
|
||
await message.answer(
|
||
f"🚫 Активация промокода невозможна\n\n"
|
||
f"Причина: {blacklist_reason}\n\n"
|
||
f"Если вы считаете, что это ошибка, обратитесь в поддержку."
|
||
)
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при отправке сообщения о блокировке: {e}")
|
||
return
|
||
|
||
texts = get_texts(db_user.language)
|
||
|
||
code = message.text.strip()
|
||
|
||
if not code:
|
||
await message.answer(
|
||
texts.t(
|
||
"PROMOCODE_EMPTY_INPUT",
|
||
"❌ Введите корректный промокод",
|
||
),
|
||
reply_markup=get_back_keyboard(db_user.language)
|
||
)
|
||
return
|
||
|
||
result = await activate_promocode_for_registration(db, db_user.id, code, message.bot)
|
||
|
||
if result["success"]:
|
||
await message.answer(
|
||
texts.PROMOCODE_SUCCESS.format(description=result["description"]),
|
||
reply_markup=get_back_keyboard(db_user.language)
|
||
)
|
||
else:
|
||
error_messages = {
|
||
"not_found": texts.PROMOCODE_INVALID,
|
||
"expired": texts.PROMOCODE_EXPIRED,
|
||
"used": texts.PROMOCODE_USED,
|
||
"already_used_by_user": texts.PROMOCODE_USED,
|
||
"not_first_purchase": texts.t(
|
||
"PROMOCODE_NOT_FIRST_PURCHASE",
|
||
"❌ Этот промокод доступен только для первой покупки"
|
||
),
|
||
"server_error": texts.ERROR
|
||
}
|
||
|
||
error_text = error_messages.get(result["error"], texts.PROMOCODE_INVALID)
|
||
await message.answer(
|
||
error_text,
|
||
reply_markup=get_back_keyboard(db_user.language)
|
||
)
|
||
|
||
await state.clear()
|
||
|
||
|
||
def register_handlers(dp: Dispatcher):
|
||
|
||
dp.callback_query.register(
|
||
show_promocode_menu,
|
||
F.data == "menu_promocode"
|
||
)
|
||
|
||
dp.message.register(
|
||
process_promocode,
|
||
PromoCodeStates.waiting_for_code
|
||
)
|