243 lines
9.4 KiB
Python
243 lines
9.4 KiB
Python
from aiogram import Router, types
|
||
from aiogram.types import CallbackQuery
|
||
import logging
|
||
from datetime import datetime
|
||
from aiogram.enums.parse_mode import ParseMode
|
||
import locale
|
||
from instences.config import BASE_URL_FASTAPI
|
||
import aiohttp
|
||
from keyboard.keyboards import (
|
||
account_keyboard,
|
||
popup_keyboard,
|
||
tranhist_keyboard,
|
||
confirm_popup_keyboard,
|
||
guide_keyboard,
|
||
balance_keyboard,
|
||
)
|
||
|
||
locale.setlocale(locale.LC_TIME, "ru_RU.UTF-8")
|
||
|
||
router = Router()
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
async def call_api(method, endpoint, data=None):
|
||
"""
|
||
Выполняет HTTP-запрос к FastAPI.
|
||
"""
|
||
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
|
||
if response.status == 404:
|
||
logger.debug(f"Код {response.status}, возвращаю ничего")
|
||
return None
|
||
logger.error(
|
||
f"Ошибка в запросе: статус {response.status}, причина {response.reason}"
|
||
)
|
||
return "ERROR"
|
||
except Exception as e:
|
||
logger.exception(f"Исключение при выполнении запроса к {url}: {e}")
|
||
return "ERROR"
|
||
|
||
|
||
@router.callback_query(lambda callback: callback.data == "profile")
|
||
async def profile_callback_handler(callback: CallbackQuery):
|
||
"""
|
||
Профиль пользователя.
|
||
Логика работы с API сохранена, переписан только текст/визуал.
|
||
"""
|
||
try:
|
||
user_data = await call_api("GET", f"/user/{callback.from_user.id}")
|
||
if not user_data:
|
||
await callback.message.answer(
|
||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
||
)
|
||
await callback.answer()
|
||
return
|
||
|
||
sub_data = await call_api("GET", f"/subscription/{user_data['telegram_id']}/last")
|
||
if sub_data == "ERROR" or not isinstance(sub_data, dict):
|
||
sub_data = None
|
||
|
||
balance_text = f"💰 Баланс: {user_data['balance']} ₽"
|
||
|
||
username = callback.from_user.username or "пользователь"
|
||
|
||
# Нет подписки
|
||
if not sub_data:
|
||
text = (
|
||
f"📜 Профиль {username}\n\n"
|
||
f"{balance_text}\n\n"
|
||
"У тебя пока нет активной подписки.\n"
|
||
"Пополняй баланс и подключай тариф Lark, чтобы получить статус 🐣 или 🦅."
|
||
)
|
||
else:
|
||
expiry_date = sub_data.get("end_date")
|
||
formatted_date = (
|
||
datetime.fromisoformat(expiry_date).strftime("%d %B %Y г.")
|
||
if expiry_date
|
||
else None
|
||
)
|
||
is_expired = (
|
||
datetime.fromisoformat(expiry_date) < datetime.now()
|
||
if expiry_date
|
||
else True
|
||
)
|
||
status_icon = "✖️" if is_expired else "☑️"
|
||
profile_status = "🦅" if "Pro" in sub_data.get("plan", "") else "🐣"
|
||
|
||
if not is_expired and formatted_date:
|
||
sub_text = (
|
||
f"Подписка активна до {formatted_date} {status_icon}\n"
|
||
f"Текущий статус: {profile_status}"
|
||
)
|
||
else:
|
||
sub_text = (
|
||
f"Подписка неактивна {status_icon}\n"
|
||
"Ты можешь продлить её в разделе подписок."
|
||
)
|
||
|
||
text = (
|
||
f"📜 Профиль {username} {profile_status}\n\n"
|
||
f"{sub_text}\n\n"
|
||
f"{balance_text}"
|
||
)
|
||
|
||
await callback.message.edit_text(text, reply_markup=account_keyboard())
|
||
except Exception as e:
|
||
logger.exception(f"Ошибка в обработчике профиля: {e}")
|
||
await callback.message.answer("Произошла ошибка. Попробуйте позже.")
|
||
finally:
|
||
await callback.answer()
|
||
|
||
|
||
@router.callback_query(lambda callback: callback.data == "balance")
|
||
async def balance_callback_handler(callback: CallbackQuery):
|
||
"""
|
||
Обработчик callback_query для баланса.
|
||
"""
|
||
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']} ₽\n\n"
|
||
"Выбери сумму, на которую хочешь пополнить счёт.",
|
||
reply_markup=balance_keyboard(),
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
@router.callback_query(lambda callback: callback.data == "popup")
|
||
async def popup_callback_handler(callback: CallbackQuery):
|
||
"""
|
||
Обработчик callback_query для выбора суммы пополнения.
|
||
"""
|
||
user = await call_api("GET", f"/user/{callback.from_user.id}")
|
||
if not user:
|
||
await callback.message.answer(
|
||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
||
)
|
||
await callback.answer()
|
||
return
|
||
|
||
await callback.message.edit_text(
|
||
"Выбери сумму для пополнения баланса.",
|
||
reply_markup=popup_keyboard(),
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
@router.callback_query(lambda callback: callback.data == "tranhist")
|
||
async def tranhist_callback_handler(callback: CallbackQuery):
|
||
"""
|
||
Обработчик callback_query для истории транзакций.
|
||
(Логику и формат Markdown_V2 не трогаем, чтобы не поймать новые баги)
|
||
"""
|
||
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
|
||
|
||
try:
|
||
transactions = await call_api("GET", f"/user/{user_data['telegram_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):
|
||
dt = datetime.fromisoformat(tran["created_at"]).strftime(
|
||
"%d.%m.%Y %H:%M:%S"
|
||
)
|
||
result += f"{count}. Сумма: {tran['amount']}, Дата: {dt}\n"
|
||
if len(result) > 4000:
|
||
result += "...\nСлишком много транзакций для отображения."
|
||
break
|
||
result += "```"
|
||
await callback.message.edit_text(
|
||
result,
|
||
parse_mode=ParseMode.MARKDOWN_V2,
|
||
reply_markup=tranhist_keyboard(),
|
||
)
|
||
except Exception as e:
|
||
logger.error(f"Ошибка обработки транзакций: {e}")
|
||
await callback.message.edit_text("Произошла ошибка. Попробуйте позже.")
|
||
finally:
|
||
await callback.answer()
|
||
|
||
|
||
@router.callback_query(lambda callback: callback.data.startswith("popup:"))
|
||
async def popup_confirm_callback_handler(callback: 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} ₽. Спасибо, что остаёшься с Lark."
|
||
await callback.message.edit_text(
|
||
text=text, reply_markup=confirm_popup_keyboard()
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
@router.callback_query(lambda callback: callback.data == "guide")
|
||
async def guide_callback_handler(callback: CallbackQuery):
|
||
"""
|
||
Обработчик callback_query для руководства.
|
||
"""
|
||
await callback.message.edit_text(
|
||
"Выбери платформу, для которой нужно руководство по подключению:",
|
||
reply_markup=guide_keyboard(),
|
||
)
|
||
await callback.answer()
|