Files
Telegram-bot-old/handlers/handlers.py

417 lines
19 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.

from aiogram import types, Dispatcher
from aiogram.filters import Command
import aiohttp
import logging
from datetime import datetime
from instences.config import BASE_URL_FASTAPI
import locale
locale.setlocale(locale.LC_TIME, "ru_RU.UTF-8")
from keyboard.keyboards import subhist_keyboard,confirm_popup_keyboard,tarif_confirm_keyboard,ticket_keyboard, popup_keyboard, main_keyboard,faq_keyboard, account_keyboard, buy_keyboard,balance_keyboard,guide_keyboard,tarif_Lark_keyboard,tarif_Lark_pro_keyboard,tranhist_keyboard
logger = logging.getLogger(__name__)
# Инициализируем менеджер базы данных
async def call_api(method, endpoint, data=None):
"""
Выполняет HTTP-запрос к FastAPI.
:param method: HTTP метод (GET, POST, и т.д.)
:param endpoint: конечная точка API
:param data: тело запроса (если необходимо)
:return: JSON-ответ или "ERROR" при неуспехе
"""
url = f"{BASE_URL_FASTAPI}{endpoint}"
logger.info(f"Инициализация запроса: {method} {url} с данными {data}")
try:
async with aiohttp.ClientSession() as session:
async with session.request(method, url, json=data) as response:
logger.info(f"Получен ответ от {url}: статус {response.status}")
if response.status in {200, 201}:
result = await response.json()
logger.debug(f"Ответ JSON: {result}")
return result
logger.error(f"Ошибка в запросе: статус {response.status}, причина {response.reason}")
return "ERROR"
except Exception as e:
logger.exception(f"Исключение при выполнении запроса к {url}: {e}")
return "ERROR"
user_state = {}
async def start_ticket_creation(message: types.Message):
"""
Начинает процесс создания тикета.
"""
await message.answer(
"Введите тему тикета (или нажмите 'Отмена', чтобы выйти):",
reply_markup=ticket_keyboard()
)
user_state[message.from_user.id] = {"step": "subject"}
async def handle_ticket_input(message: types.Message):
"""
Обрабатывает ввод данных для тикета.
"""
user_id = message.from_user.id
text = message.text.lower()
if text == "отмена":
await message.answer("Создание тикета отменено.", reply_markup=types.ReplyKeyboardRemove())
user_state.pop(user_id, None)
return
state = user_state.get(user_id)
if not state:
await message.answer("Нет активного процесса создания тикета. Введите /support для начала.")
return
if state["step"] == "subject":
state["subject"] = message.text
state["step"] = "message"
await message.answer("Введите описание проблемы:")
elif state["step"] == "message":
state["message"] = message.text
await create_ticket(message, state)
user_state.pop(user_id, None)
async def create_ticket(message: types.Message, state):
"""
Отправляет запрос на создание тикета через FastAPI.
"""
user_id = message.from_user.id
subject = state["subject"]
ticket_message = state["message"]
try:
logger.info(f"Создание тикета для пользователя {user_id}: Тема - {subject}, Сообщение - {ticket_message}")
user_data = await call_api("GET", f"/user/{message.from_user.id}")
if not user_data:
await message.edit_text("Вы еще не зарегистрированы.")
await message.answer()
return
# Отправляем запрос через call_api
ticket_data = await call_api(
"POST",
f"/support/tickets?user_id={user_data['id']}", # Передаём user_id как query-параметр
data={"subject": subject, "message": ticket_message}
)
if ticket_data != "ERROR":
await message.answer(
f"✅ Тикет успешно создан!\n"
f"📌 Тема: {ticket_data['subject']}\n"
f"📊 Статус: {ticket_data['status']}\n"
f"📅 Дата создания: {ticket_data['created_at']}"
)
else:
await message.answer("❌ Ошибка создания тикета. Попробуйте позже.")
except Exception as e:
logger.exception(f"Ошибка при создании тикета для пользователя {user_id}: {e}")
await message.answer("❌ Произошла ошибка при создании тикета.")
async def subhist_command(message: types.Message):
"""
Обработчик команды для отправки истории подписок.
"""
user_data = await call_api("GET", f"/user/{message.from_user.id}")
if not user_data:
await message.edit_text("Вы еще не зарегистрированы.")
await message.answer()
return
subscriptions = await call_api("GET", f"/subscriptions/{user_data['id']}")
if not subscriptions:
await message.edit_text("У вас нет активных подписок.", reply_markup=account_keyboard())
await message.answer()
return
result = "Ваши подписки:\n"
for count, sub in enumerate(subscriptions, start=1):
result += f"{count}. Тариф: {sub['plan']}, Истекает: {sub['expiry_date']}\n"
await message.edit_text(result, reply_markup=account_keyboard())
await message.answer()
await message.answer("subhist", reply_markup=subhist_keyboard())
async def start_command(message: types.Message):
"""
Обработчик команды /start.
"""
await message.answer(f"""Приветствуем в рядах птенец {message.from_user.username}🐣
\nСкорее пополни баланс, приобрети подписку и получай доступ к TikTok, YouTube, Discord, Instagram на всех устройствах без ограничений ❕❕❕
\nОзнакомься с руководством по пользованию и выбери подходящий тариф 🦅
\nСледи за акциями, спец-предложениями, а также розыгрышами по ссылке ниже
\n👇👇👇
\nhttps://t.me/+0z5xqn3F1m02OTJi
\nС любовью ваши пернатые разработчики 🤍🤍🤍""", reply_markup=main_keyboard())
async def start_callback_handler(callback: types.CallbackQuery):
"""
Обработчик callback_query с data="base".
"""
await callback.message.edit_text(
f"""Приветствуем в рядах птенец {callback.from_user.username}🐣
\nСкорее пополни баланс, приобрети подписку и получай доступ к TikTok, YouTube, Discord, Instagram на всех устройствах без ограничений ❕❕❕
\nОзнакомься с руководством по пользованию и выбери подходящий тариф 🦅
\nСледи за акциями, спец-предложениями, а также розыгрышами по ссылке ниже
\n👇👇👇
\nhttps://t.me/+0z5xqn3F1m02OTJi
\nС любовью ваши пернатые разработчики 🤍🤍🤍""",
reply_markup=main_keyboard()
)
async def profile_callback_handler(callback: types.CallbackQuery):
try:
# Создание пользователя
user_data = await call_api("POST", "/user/create", {"telegram_id": callback.from_user.id})
if user_data == "ERROR" or not isinstance(user_data, dict):
raise ValueError("Не удалось создать пользователя.")
# Получение подписки
sub_data = await call_api("GET", f"/subscription/{user_data['id']}/last")
if sub_data == "ERROR" or not isinstance(sub_data, dict):
sub_data = None
# Формирование текста баланса
balance_text = f"Баланс: {user_data['balance']}"
# Если подписки нет
if not sub_data:
text = f"Профиль {callback.from_user.username}\n{balance_text}\nПополните баланс и приобретите подписку чтобы получить активный статус (🐣,🦅)"
else:
# Получение даты окончания подписки
expiry_date = sub_data.get("expiry_date")
formatted_date = None
# Преобразование времени в презентабельный формат
if expiry_date:
expiry_datetime = datetime.fromisoformat(expiry_date)
formatted_date = expiry_datetime.strftime("%d %B %Y г.")
# Проверка на истечение подписки
is_expired = datetime.fromisoformat(expiry_date) < datetime.now() if expiry_date else True
plan_type = sub_data.get("plan", "")
status_icon = "✖️" if is_expired else "☑️"
# Определение статуса
if "Pro" in plan_type:
profile_status = "🦅"
else:
profile_status = "🐣"
# Формирование текста профиля
sub_text = (
f"Ваша подписка действует до {formatted_date} {status_icon}"
if not is_expired else f"Статус подписки: {status_icon}"
)
text = f"Профиль {callback.from_user.username} {profile_status}:\n{sub_text}\n{balance_text}"
# Отправка текста пользователю
await callback.message.edit_text(text, reply_markup=account_keyboard())
except ValueError as e:
await callback.message.answer(f"Ошибка: {e}")
except Exception as e:
logger.exception(f"Ошибка в обработчике профиля: {e}")
await callback.message.answer("Произошла ошибка. Попробуйте позже.")
finally:
await callback.answer()
async def balance_callback_handler(callback: types.CallbackQuery):
user_data = await call_api("GET", f"/user/{callback.from_user.id}")
if not user_data:
await callback.message.answer("Вы еще не зарегистрированы.")
await callback.answer()
return
await callback.message.edit_text(
f"Ваш баланс: {user_data['balance']} ₽. Выберите сумму для пополнения 🐥",
reply_markup=balance_keyboard()
)
await callback.answer()
async def popup_callback_handler(callback: types.CallbackQuery):
"""
Обработчик callback_query с data="popup".
"""
user = await call_api("POST", "/user/create", {"telegram_id": callback.from_user.id})
if user == "ERROR":
await callback.message.answer(
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
)
await callback.answer()
return
if user:
await callback.message.edit_text(
f"Работает в режиме теста!!!",
reply_markup=popup_keyboard()
)
else:
await callback.message.edit_text("Вы еще не зарегистрированы.")
await callback.answer()
async def tranhist_callback_handler(callback: types.CallbackQuery):
user_data = await call_api("GET", f"/user/{callback.from_user.id}")
if not user_data:
await callback.message.edit_text("Вы еще не зарегистрированы.")
await callback.answer()
return
transactions = await call_api("GET", f"/user/{user_data['id']}/transactions")
if not transactions:
await callback.message.edit_text("У вас нет транзакций.", reply_markup=tranhist_keyboard())
await callback.answer()
return
result = "Ваши транзакции:\n"
for count, tran in enumerate(transactions, start=1):
result += f"{count}. Сумма: {tran['amount']}, Дата: {tran['created_at']}\n"
await callback.message.edit_text(result, reply_markup=tranhist_keyboard())
await callback.answer()
async def buy_subscription_callback_handler(callback: types.CallbackQuery):
"""
Обработчик callback_query с data="buy_subscription".
"""
await callback.message.edit_text(
f"Ознакомься с условиями в вкладке \"О тарифах\" и выбери подходящий 🦅",
reply_markup=buy_keyboard()
)
async def guide_callback_handler(callback:types.CallbackQuery):
"""
Обработчик callback_query с data="guide".
"""
await callback.message.edit_text(
f"Руководство по использованию продкута что мы высрали;)",
reply_markup=guide_keyboard()
)
async def subs_callback_handler(callback: types.CallbackQuery):
"""
Обработчик callback_query с data="subs".
"""
await callback.message.edit_text(
f"Подписки птенчик",
reply_markup=tarif_Lark_keyboard()
)
async def subs_pro_callback_handler(callback: types.CallbackQuery):
"""
Обработчик callback_query с data="subs_pro".
"""
await callback.message.edit_text(
f"Подписки птенчик ПРО",
reply_markup=tarif_Lark_pro_keyboard()
)
# async def about_tarifs_callback_handler(callback: types.CallbackQuery):
# """
# Обработчик callback_query с data="about_tarifs".
# """
# await callback.message.edit_text(
# f"Бла бла бла, хуйня на хуйне",
# reply_markup=about_tarifs_keyboard()
# )
async def faq_callback_handler(callback:types.CallbackQuery):
"""
Обработчик callback_query с data="faq".
"""
await callback.message.edit_text(
f"FAQ YOU",
reply_markup=faq_keyboard()
)
async def lark_tariff_callback_handler(callback: types.CallbackQuery):
"""
Обработчик для выбора тарифа Lark.
"""
data = callback.data.split(":")
tariff_name = data[0]
tariff_class = data[1]
tariff_time = int(data[2])
# Определение окончания для месяцев
if tariff_time == 1:
months = f"{tariff_time} месяц"
elif 2 <= tariff_time <= 4:
months = f"{tariff_time} месяца"
else:
months = f"{tariff_time} месяцев"
text = f"Тариф {tariff_name} на {months}. Продолжите покупку..."
# Рендеринг клавиатуры
keyboard = tarif_confirm_keyboard(tariff_name, tariff_time, tariff_class)
await callback.message.edit_text(text=text, reply_markup=keyboard)
async def popup_confirm_callback_handler(callback: types.CallbackQuery):
"""
Обработчик подтверждения пополнения баланса.
"""
data = callback.data.split(":")
popup_info = data[1]
result = await call_api("POST", f"/user/{callback.from_user.id}/balance/{float(popup_info)}")
if result == "ERROR":
await callback.message.answer(
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
)
await callback.answer()
return
text = f"Вы пополнили свой баланс на {popup_info}. P.S. Мы завтра закрываемся"
await callback.message.edit_text(text=text, reply_markup=confirm_popup_keyboard())
async def confirm_callback_handler(callback: types.CallbackQuery):
data = callback.data.split(":")[1]
tariff_info = data.split("_")
plan_id = f"{tariff_info[0]}_{tariff_info[1]}_{tariff_info[2]}"
result = await call_api("POST", "/subscription/buy", {"telegram_id": callback.from_user.id, "plan_id": plan_id})
error_detail = result.get("detail",{})
error_code = error_detail.get("code", "")
if error_code == "ERROR":
await callback.message.edit_text("Произошла ошибка при оформлении подписки.")
if error_code == "INSUFFICIENT_FUNDS":
await callback.message.edit_text("Денег на вашем балансе не достаточно.")
if error_code == "TARIFF_NOT_FOUND":
await callback.message.edit_text("Ваш тариф не найден.")
if error_code == "ACTIVE_SUBSCRIPTION_EXISTS":
await callback.message.edit_text("Вы уже имеете активную подписку.")
else:
await callback.message.edit_text(f"Подписка успешно оформлена!")
await callback.answer()
def register_handlers(dp: Dispatcher):
"""
Регистрация хэндлеров в диспетчере.
"""
dp.callback_query.register(popup_callback_handler, lambda c: c.data == "popup")
dp.callback_query.register(start_callback_handler, lambda c: c.data == "base")
dp.callback_query.register(subs_callback_handler, lambda c: c.data == "subs")
dp.callback_query.register(subs_pro_callback_handler, lambda c: c.data == "subs_pro")
dp.callback_query.register(faq_callback_handler, lambda c: c.data == "faq")
dp.callback_query.register(profile_callback_handler, lambda c: c.data == "profile")
dp.callback_query.register(tranhist_callback_handler, lambda c: c.data == "tranhist")
dp.callback_query.register(buy_subscription_callback_handler, lambda c: c.data == "buy_subscription")
dp.message.register(start_command, Command("start"))
dp.message.register(start_command, Command("subscriptions"))
dp.message.register(start_ticket_creation, Command("support"))
dp.message.register(handle_ticket_input) # Для любых сообщений
dp.callback_query.register(balance_callback_handler, lambda c: c.data == "balance")
dp.callback_query.register(guide_callback_handler, lambda c: c.data == "guide")
# dp.callback_query.register(about_tarifs_callback_handler, lambda c: c.data == "about_tarifs")
dp.callback_query.register(lark_tariff_callback_handler, lambda c: c.data.startswith("Lark:"))
dp.callback_query.register(confirm_callback_handler, lambda c: c.data.startswith("confirm:"))
dp.callback_query.register(popup_confirm_callback_handler, lambda c: c.data.startswith("popup:"))