Переделал меню и под роуты адаптировал

This commit is contained in:
Disledg
2024-12-28 21:34:08 +03:00
parent 379da6cbba
commit 9c00529216
4 changed files with 239 additions and 126 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,3 @@
TBot/ TBot/
logs/* logs/*
.code-workspace

View File

@@ -4,6 +4,18 @@ FROM python:3.12-slim
# Устанавливаем рабочую директорию # Устанавливаем рабочую директорию
WORKDIR /app WORKDIR /app
# Устанавливаем необходимые пакеты и локаль
RUN apt-get update && apt-get install -y --no-install-recommends \
locales && \
echo "ru_RU.UTF-8 UTF-8" > /etc/locale.gen && \
locale-gen && \
apt-get clean && rm -rf /var/lib/apt/lists/*
# Устанавливаем переменные окружения для локали
ENV LANG ru_RU.UTF-8
ENV LANGUAGE ru_RU:ru
ENV LC_ALL ru_RU.UTF-8
# Копируем файлы проекта # Копируем файлы проекта
COPY . . COPY . .

View File

@@ -1,17 +1,44 @@
from aiogram import types, Dispatcher from aiogram import types, Dispatcher
from aiogram.filters import Command from aiogram.filters import Command
import aiohttp import aiohttp
import logging
from datetime import datetime
from instences.config import BASE_URL_FASTAPI 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, popup_keyboard, main_keyboard,faq_keyboard, account_keyboard, buy_keyboard,balance_keyboard,guide_keyboard,tarif_Lark_keyboard,tarif_Lark_pro_keyboard,tranhist_keyboard from keyboard.keyboards import subhist_keyboard,confirm_popup_keyboard,tarif_confirm_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): async def call_api(method, endpoint, data=None):
async with aiohttp.ClientSession() as session: """
url = f"{BASE_URL_FASTAPI}{endpoint}" Выполняет HTTP-запрос к FastAPI.
async with session.request(method, url, json=data) as response:
if response.status in {200, 201}: :param method: HTTP метод (GET, POST, и т.д.)
return await response.json() :param endpoint: конечная точка API
return "ERROR" :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"
async def popup_command(message: types.Message): async def popup_command(message: types.Message):
""" """
@@ -53,15 +80,62 @@ async def start_callback_handler(callback: types.CallbackQuery):
) )
async def profile_callback_handler(callback: types.CallbackQuery): async def profile_callback_handler(callback: types.CallbackQuery):
user_data = await call_api("POST", "/user/create", {"telegram_id": callback.from_user.id}) try:
if not user_data: # Создание пользователя
await callback.message.answer("Произошла ошибка, попробуйте позже.") user_data = await call_api("POST", "/user/create", {"telegram_id": callback.from_user.id})
await callback.answer() if user_data == "ERROR" or not isinstance(user_data, dict):
return 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()
text = f"Ваш профиль:\nID: {user_data['username']}\nБаланс: {user_data['balance']}"
await callback.message.edit_text(text, reply_markup=account_keyboard())
await callback.answer()
async def balance_callback_handler(callback: types.CallbackQuery): async def balance_callback_handler(callback: types.CallbackQuery):
user_data = await call_api("GET", f"/user/{callback.from_user.id}") user_data = await call_api("GET", f"/user/{callback.from_user.id}")
@@ -219,7 +293,7 @@ async def popup_confirm_callback_handler(callback: types.CallbackQuery):
""" """
data = callback.data.split(":") data = callback.data.split(":")
popup_info = data[1] popup_info = data[1]
result = await call_api("POST", f"/user/{callback.from_user.id}/balance", {"telegram_id": callback.from_user.id, "amount": popup_info}) result = await call_api("POST", f"/user/{callback.from_user.id}/balance/{float(popup_info)}")
if result == "ERROR": if result == "ERROR":
await callback.message.answer( await callback.message.answer(
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией." "Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
@@ -234,11 +308,19 @@ async def confirm_callback_handler(callback: types.CallbackQuery):
tariff_info = data.split("_") tariff_info = data.split("_")
plan_id = f"{tariff_info[0]}_{tariff_info[1]}_{tariff_info[2]}" 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}) 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 result and result.get("message"): if error_code == "ERROR":
await callback.message.edit_text(f"Подписка успешно оформлена!")
else:
await callback.message.edit_text("Произошла ошибка при оформлении подписки.") 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() await callback.answer()
def register_handlers(dp: Dispatcher): def register_handlers(dp: Dispatcher):

View File

@@ -1,123 +1,141 @@
from aiogram import types, Dispatcher from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery from aiogram.types import InlineKeyboardButton
from aiogram.filters import Command
# Главное меню клавиатура
def main_menu_keyboard():
keyboard = InlineKeyboardMarkup()
keyboard.add(InlineKeyboardButton("Личный кабинет", callback_data="main:personal"))
keyboard.add(InlineKeyboardButton("FAQ", callback_data="main:faq"))
keyboard.add(InlineKeyboardButton("О нас", callback_data="main:about"))
return keyboard
# Личный кабинет клавиатура def main_keyboard():
def personal_menu_keyboard(): """
keyboard = InlineKeyboardMarkup() База
keyboard.add(InlineKeyboardButton("Баланс", callback_data="personal:balance")) """
keyboard.add(InlineKeyboardButton("Приобрести подписку", callback_data="personal:subscribe")) builder = InlineKeyboardBuilder()
keyboard.add(InlineKeyboardButton("Руководство по использованию", callback_data="personal:guide")) builder.row(InlineKeyboardButton(text="Профиль", callback_data="profile"))
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:main")) builder.row(InlineKeyboardButton(text="FAQ", callback_data="faq"))
return keyboard builder.row(InlineKeyboardButton(text="О нас", url="https://www.youtube.com/watch?v=Zirn-CKck-c"))
return builder.as_markup()
# Подписка меню клавиатура def account_keyboard():
def subscribe_menu_keyboard(): """
keyboard = InlineKeyboardMarkup() Аккаунт
keyboard.add(InlineKeyboardButton("Lark", callback_data="subscribe:lark")) """
keyboard.add(InlineKeyboardButton("Lark Pro", callback_data="subscribe:lark_pro")) builder = InlineKeyboardBuilder()
keyboard.add(InlineKeyboardButton("О тарифах", callback_data="subscribe:about_tariffs")) builder.row(InlineKeyboardButton(text="Пополнение баланса", callback_data="popup"))
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:personal")) builder.row(InlineKeyboardButton(text="Приобрести подписку", callback_data="buy_subscription"))
return keyboard builder.row(InlineKeyboardButton(text="Руководство по подключению", callback_data="guide"))
builder.row(InlineKeyboardButton(text="История транзакций", callback_data="tranhist"))
builder.row(InlineKeyboardButton(text="Назад", callback_data="base"))
return builder.as_markup()
# Тарифы Lark клавиатура
def lark_tariffs_keyboard():
keyboard = InlineKeyboardMarkup()
keyboard.add(InlineKeyboardButton("Lark 1 месяц", callback_data="lark:1"))
keyboard.add(InlineKeyboardButton("Lark 6 месяцев", callback_data="lark:6"))
keyboard.add(InlineKeyboardButton("Lark 12 месяцев", callback_data="lark:12"))
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:subscribe"))
return keyboard
# Тарифы Lark Pro клавиатура def buy_keyboard():
def lark_pro_tariffs_keyboard(): """
keyboard = InlineKeyboardMarkup() Приобрести подписку
keyboard.add(InlineKeyboardButton("Lark Pro 1 месяц", callback_data="lark_pro:1")) """
keyboard.add(InlineKeyboardButton("Lark Pro 6 месяцев", callback_data="lark_pro:6")) builder = InlineKeyboardBuilder()
keyboard.add(InlineKeyboardButton("Lark Pro 12 месяцев", callback_data="lark_pro:12")) builder.row(InlineKeyboardButton(text="Тариф Lark", callback_data="subs"))
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:subscribe")) builder.row(InlineKeyboardButton(text="Тариф Lark Pro", callback_data="subs_pro"))
return keyboard builder.row(InlineKeyboardButton(text="О тарифах", url="https://t.me/proxylark/19"))
builder.row(InlineKeyboardButton(text="Назад", callback_data="profile"))
return builder.as_markup()
# Руководство меню клавиатура def subhist_keyboard():
def guide_menu_keyboard(): """
keyboard = InlineKeyboardMarkup() Подписки
keyboard.add(InlineKeyboardButton("iOS, Android", callback_data="guide:ios_android")) """
keyboard.add(InlineKeyboardButton("Windows, Macintosh", callback_data="guide:windows_mac")) builder = InlineKeyboardBuilder()
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:personal")) builder.button(text="Назад", callback_data="profile")
return keyboard return builder.as_markup()
async def start_command(message: types.Message): def popup_keyboard():
"""Обработчик команды /start.""" """
await message.answer("Главное меню", reply_markup=main_menu_keyboard()) Пополнение
"""
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text="200₽", callback_data="popup:200"),InlineKeyboardButton(text="500₽", callback_data="popup:500"))
builder.row(InlineKeyboardButton(text="1000₽", callback_data="popup:1000"),InlineKeyboardButton(text="2000₽", callback_data="popup:2000"))
builder.row(InlineKeyboardButton(text="3000₽", callback_data="popup:3000"),InlineKeyboardButton(text="5000₽", callback_data="popup:5000"))
builder.row(InlineKeyboardButton(text="Назад", callback_data="profile"))
return builder.as_markup()
async def callback_handler(callback: CallbackQuery): def balance_keyboard():
"""Обработчик callback.""" """
data = callback.data.split(":") Баланс
action = data[0] """
sub_action = data[1] if len(data) > 1 else None builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text="Пополнение", callback_data="popup"))
builder.row(InlineKeyboardButton(text="История транзакций", callback_data="tranhist"))
builder.row(InlineKeyboardButton(text="Назад", callback_data="profile"))
return builder.as_markup()
if action == "main": def tarif_Lark_keyboard():
if sub_action == "personal": """
await callback.message.edit_text("Личный кабинет", reply_markup=personal_menu_keyboard()) Тариф Lark
elif sub_action == "faq": """
await callback.message.edit_text("FAQ", reply_markup=InlineKeyboardMarkup().add( builder = InlineKeyboardBuilder()
InlineKeyboardButton("Назад", callback_data="back:main"))) builder.row(InlineKeyboardButton(text="Тариф Lark 1 Месяц", callback_data="Lark:Standart:1"))
elif sub_action == "about": builder.row(InlineKeyboardButton(text="Тариф Lark 6 Месяц", callback_data="Lark:Standart:6"))
await callback.message.edit_text("Наш сайт: {URL}", reply_markup=InlineKeyboardMarkup().add( builder.row(InlineKeyboardButton(text="Тариф Lark 12 Месяц", callback_data="Lark:Standart:12"))
InlineKeyboardButton("Назад", callback_data="back:main"))) builder.row(InlineKeyboardButton(text="Назад", callback_data="buy_subscription"))
return builder.as_markup()
elif action == "personal": def tarif_Lark_pro_keyboard():
if sub_action == "balance": """
await callback.message.edit_text("Баланс:", reply_markup=InlineKeyboardMarkup().add( Тариф Lark Pro
InlineKeyboardButton("Пополнение", callback_data="balance:topup"), """
InlineKeyboardButton("История транзакций", callback_data="balance:history"), builder = InlineKeyboardBuilder()
InlineKeyboardButton("Назад", callback_data="back:personal") builder.row(InlineKeyboardButton(text="Тариф Lark Pro 1 Месяц", callback_data="Lark:Pro:1"))
)) builder.row(InlineKeyboardButton(text="Тариф Lark Pro 6 Месяц", callback_data="Lark:Pro:6"))
elif sub_action == "subscribe": builder.row(InlineKeyboardButton(text="Тариф Lark Pro 12 Месяц", callback_data="Lark:Pro:12"))
await callback.message.edit_text("Выберите подписку:", reply_markup=subscribe_menu_keyboard()) builder.row(InlineKeyboardButton(text="Назад", callback_data="buy_subscription"))
elif sub_action == "guide": return builder.as_markup()
await callback.message.edit_text("Руководство по использованию", reply_markup=guide_menu_keyboard())
elif action == "subscribe": def guide_keyboard():
if sub_action == "lark": """
await callback.message.edit_text("Тарифы Lark", reply_markup=lark_tariffs_keyboard()) Руководство по подключению
elif sub_action == "lark_pro": """
await callback.message.edit_text("Тарифы Lark Pro", reply_markup=lark_pro_tariffs_keyboard()) builder = InlineKeyboardBuilder()
elif sub_action == "about_tariffs": builder.row(InlineKeyboardButton(text="IOS,Android", callback_data="mob"))
await callback.message.edit_text("О тарифах", reply_markup=InlineKeyboardMarkup().add( builder.row(InlineKeyboardButton(text="Windows,MacOS", callback_data="pc"))
InlineKeyboardButton("Назад", callback_data="back:subscribe") builder.row(InlineKeyboardButton(text="Назад", callback_data="profile"))
)) return builder.as_markup()
elif action == "lark":
await callback.message.edit_text(f"Вы выбрали тариф Lark {sub_action} месяцев.", reply_markup=InlineKeyboardMarkup().add(
InlineKeyboardButton("Подтвердить", callback_data=f"confirm:lark:{sub_action}"),
InlineKeyboardButton("Отменить", callback_data="back:subscribe")
))
elif action == "lark_pro": # def about_tarifs_keyboard():
await callback.message.edit_text(f"Вы выбрали тариф Lark Pro {sub_action} месяцев.", reply_markup=InlineKeyboardMarkup().add( # """
InlineKeyboardButton("Подтвердить", callback_data=f"confirm:lark_pro:{sub_action}"), # О тарифах
InlineKeyboardButton("Отменить", callback_data="back:subscribe") # """
)) # builder = InlineKeyboardBuilder()
# builder.row(InlineKeyboardButton(text="Назад", callback_data="buy_subscription"))
# return builder.as_markup()
elif action == "back":
if sub_action == "main":
await callback.message.edit_text("Главное меню", reply_markup=main_menu_keyboard())
elif sub_action == "personal":
await callback.message.edit_text("Личный кабинет", reply_markup=personal_menu_keyboard())
elif sub_action == "subscribe":
await callback.message.edit_text("Выберите подписку:", reply_markup=subscribe_menu_keyboard())
await callback.answer() def faq_keyboard():
"""
FAQ
"""
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text="Назад", callback_data="base"))
return builder.as_markup()
def register_handlers(dp: Dispatcher): def tranhist_keyboard():
dp.message.register(start_command, Command("start")) """
dp.callback_query.register(callback_handler) История транзакций
"""
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text="Назад",callback_data="profile"))
return builder.as_markup()
def tarif_confirm_keyboard(name,amount,classif):
"""
Подтверждение покупки тарифа
"""
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text="Подтвердить", callback_data=f"confirm:{name}_{classif}_{amount}"))
builder.row(InlineKeyboardButton(text="Отменить",callback_data="buy_subscription"))
return builder.as_markup()
def confirm_popup_keyboard():
"""
Подтверждение пополнения
"""
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text="Теперь иди нахуй", callback_data="profile"))
return builder.as_markup()