Files
Solo_bot/handlers/start.py
T

267 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
from typing import Any
import aiofiles
from aiogram import F, Router
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.types import (
BufferedInputFile,
CallbackQuery,
InlineKeyboardButton,
Message,
)
from aiogram.utils.keyboard import InlineKeyboardBuilder
from config import (
CAPTCHA_ENABLE,
CHANNEL_EXISTS,
CHANNEL_URL,
CONNECT_ANDROID,
CONNECT_IOS,
DONATIONS_ENABLE,
DOWNLOAD_ANDROID,
DOWNLOAD_IOS,
SUPPORT_CHAT_URL,
)
from database import (
add_connection,
add_referral,
check_connection_exists,
get_coupon_details,
get_referral_by_referred_id,
get_trial,
update_trial,
)
from handlers.buttons.add_subscribe import (
DOWNLOAD_ANDROID_BUTTON,
DOWNLOAD_IOS_BUTTON,
IMPORT_ANDROID,
IMPORT_IOS,
PC_BUTTON,
TV_BUTTON,
)
from handlers.captcha import generate_captcha
from handlers.keys.key_management import create_key
from handlers.keys.trial_key import create_trial_key
from handlers.texts import INSTRUCTIONS_TRIAL, WELCOME_TEXT, get_about_vpn
from logger import logger
router = Router()
@router.callback_query(F.data == "start")
async def handle_start_callback_query(
callback_query: CallbackQuery, state: FSMContext, session: Any, admin: bool, captcha: bool = False
):
await start_command(callback_query.message, state, session, admin, captcha)
@router.message(Command("start"))
async def start_command(message: Message, state: FSMContext, session: Any, admin: bool, captcha: bool = True):
"""Обрабатывает команду /start, включает логику рефералов и подарков."""
logger.info(f"Вызвана функция start_command для пользователя {message.chat.id}")
await state.clear()
# Проверка капчи, если включена
if CAPTCHA_ENABLE and captcha:
captcha = await generate_captcha(message, state)
await message.answer(text=captcha["text"], reply_markup=captcha["markup"])
return
if message.text:
try:
connection_exists = await check_connection_exists(message.chat.id)
logger.info(f"Проверка существования подключения: {connection_exists}")
if not connection_exists:
await add_connection(tg_id=message.chat.id, session=session)
logger.info(f"Пользователь {message.chat.id} успешно добавлен в базу данных.")
if "gift_" in message.text:
logger.info(f"Обнаружена ссылка на подарок: {message.text}")
parts = message.text.split("gift_")[1].split("_")
gift_id = parts[0]
recipient_tg_id = message.chat.id
gift_info = await get_coupon_details(gift_id, session)
if gift_info is None:
logger.warning(f"Подарок с ID {gift_id} уже был использован или не существует.")
await message.answer("Этот подарок уже был использован или не существует.")
return await show_start_menu(message, admin, session)
if gift_info["sender_tg_id"] == recipient_tg_id:
logger.warning(
f"Пользователь {recipient_tg_id} попытался активировать подарок, который был отправлен им самим."
)
await message.answer("❌ Вы не можете получить подарок от самого себя.")
return await show_start_menu(message, admin, session)
await add_connection(tg_id=recipient_tg_id, session=session)
selected_months = gift_info["selected_months"]
expiry_time = gift_info["expiry_time"]
expiry_time_naive = expiry_time.replace(tzinfo=None)
logger.info(f"Подарок с ID {gift_id} успешно найден для пользователя {recipient_tg_id}.")
await create_key(recipient_tg_id, expiry_time_naive, state, session, message)
logger.info(f"Ключ создан для пользователя {recipient_tg_id} на срок {selected_months} месяцев.")
await session.execute(
"UPDATE gifts SET is_used = TRUE, recipient_tg_id = $1 WHERE gift_id = $2",
recipient_tg_id,
gift_id,
)
await message.answer(
f"🎉 Ваш подарок на {selected_months} {'месяц' if selected_months == 1 else 'месяца' if selected_months in [2, 3, 4] else 'месяцев'} активирован!"
)
logger.info(f"Подарок на {selected_months} месяцев активирован для пользователя {recipient_tg_id}.")
return
elif "referral_" in message.text:
try:
referrer_tg_id = int(message.text.split("referral_")[1])
if connection_exists:
logger.info(f"Пользователь {message.chat.id} уже зарегистрирован и не может стать рефералом.")
await message.answer("❌ Вы уже зарегистрированы и не можете использовать реферальную ссылку.")
return await show_start_menu(message, admin, session)
if referrer_tg_id == message.chat.id:
logger.warning(f"Пользователь {message.chat.id} попытался стать рефералом самого себя.")
await message.answer("❌ Вы не можете быть рефералом самого себя.")
return await show_start_menu(message, admin, session)
existing_referral = await get_referral_by_referred_id(message.chat.id, session)
if existing_referral:
logger.info(f"Реферал с ID {message.chat.id} уже существует.")
return await show_start_menu(message, admin, session)
await add_referral(message.chat.id, referrer_tg_id, session)
logger.info(f"Реферал {message.chat.id} использовал ссылку от пользователя {referrer_tg_id}")
return await show_start_menu(message, admin, session)
except (ValueError, IndexError) as e:
logger.error(f"Ошибка при обработке реферальной ссылки: {e}")
return
else:
logger.info(f"Пользователь {message.chat.id} зашел без реферальной ссылки или подарка.")
await show_start_menu(message, admin, session)
except (ValueError, IndexError) as e:
logger.error(f"Ошибка при обработке сообщения пользователя {message.chat.id}: {e}")
await message.answer("❌ Произошла ошибка. Пожалуйста, попробуйте снова.")
else:
await show_start_menu(message, admin, session)
async def show_start_menu(message: Message, admin: bool, session: Any):
"""Функция для отображения стандартного меню"""
logger.info(f"Показываю главное меню для пользователя {message.chat.id}")
trial_status = await get_trial(message.chat.id, session)
image_path = os.path.join("img", "pic.jpg")
builder = InlineKeyboardBuilder()
if trial_status == 0:
builder.row(InlineKeyboardButton(text="🔗 Подключить VPN", callback_data="connect_vpn"))
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
if CHANNEL_EXISTS:
builder.row(
InlineKeyboardButton(text="📞 Поддержка", url=SUPPORT_CHAT_URL),
InlineKeyboardButton(text="📢 Канал", url=CHANNEL_URL),
)
else:
builder.row(InlineKeyboardButton(text="📞 Поддержка", url=SUPPORT_CHAT_URL))
if admin:
builder.row(InlineKeyboardButton(text="🔧 Администратор", callback_data="admin"))
builder.row(InlineKeyboardButton(text="🌐 О VPN", callback_data="about_vpn"))
if os.path.isfile(image_path):
async with aiofiles.open(image_path, "rb") as image_from_buffer:
image_data = await image_from_buffer.read()
await message.answer_photo(
photo=BufferedInputFile(image_data, filename="pic.jpg"),
caption=WELCOME_TEXT,
reply_markup=builder.as_markup(),
)
else:
await message.answer(
text=WELCOME_TEXT,
reply_markup=builder.as_markup(),
)
@router.callback_query(F.data == "connect_vpn")
async def handle_connect_vpn(callback_query: CallbackQuery, session: Any):
user_id = callback_query.message.chat.id
trial_key_info = await create_trial_key(user_id, session)
if "error" in trial_key_info:
await callback_query.message.answer(trial_key_info["error"])
else:
await update_trial(user_id, 1, session)
key_message = (
f"🔑 <b>Ваш персональный ключ доступа:</b>\n"
f"<code>{trial_key_info['key']}</code>\n\n"
f"📋 <b>Быстрая инструкция по подключению:</b>\n{INSTRUCTIONS_TRIAL}"
)
email = trial_key_info["email"]
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text="💬 Поддержка", url=SUPPORT_CHAT_URL))
builder.row(
InlineKeyboardButton(text=DOWNLOAD_IOS_BUTTON, url=DOWNLOAD_IOS),
InlineKeyboardButton(text=DOWNLOAD_ANDROID_BUTTON, url=DOWNLOAD_ANDROID),
)
builder.row(
InlineKeyboardButton(
text=IMPORT_IOS,
url=f"{CONNECT_IOS}{trial_key_info['key']}",
),
InlineKeyboardButton(
text=IMPORT_ANDROID,
url=f"{CONNECT_ANDROID}{trial_key_info['key']}",
),
)
builder.row(
InlineKeyboardButton(text=PC_BUTTON, callback_data=f"connect_pc|{email}"),
InlineKeyboardButton(text=TV_BUTTON, callback_data=f"connect_tv|{email}"),
)
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
await callback_query.message.answer(key_message, reply_markup=builder.as_markup())
@router.callback_query(F.data == "about_vpn")
async def handle_about_vpn(callback_query: CallbackQuery):
builder = InlineKeyboardBuilder()
if DONATIONS_ENABLE:
builder.row(InlineKeyboardButton(text="💰 Поддержать проект", callback_data="donate"))
builder.row(
InlineKeyboardButton(text="📞 Техническая поддержка", url=SUPPORT_CHAT_URL),
)
if CHANNEL_EXISTS:
builder.row(
InlineKeyboardButton(text="📢 Официальный канал", url=CHANNEL_URL),
)
builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="start"))
await callback_query.message.answer(get_about_vpn("3.2.3-minor"), reply_markup=builder.as_markup())