Merge pull request #165 from izzzzzi/main
Добавление нового middleware и рефакторинг
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
from aiogram import Router
|
||||||
|
|
||||||
|
from .router import router
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["router"]
|
||||||
@@ -3,8 +3,7 @@ from typing import Any
|
|||||||
from aiogram import F, Router
|
from aiogram import F, Router
|
||||||
from aiogram.fsm.context import FSMContext
|
from aiogram.fsm.context import FSMContext
|
||||||
from aiogram.fsm.state import State, StatesGroup
|
from aiogram.fsm.state import State, StatesGroup
|
||||||
from aiogram.types import CallbackQuery, InlineKeyboardButton, Message
|
from aiogram.types import CallbackQuery, Message
|
||||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
|
||||||
|
|
||||||
from database import (
|
from database import (
|
||||||
check_coupon_usage,
|
check_coupon_usage,
|
||||||
@@ -13,8 +12,8 @@ from database import (
|
|||||||
update_balance,
|
update_balance,
|
||||||
update_coupon_usage_count,
|
update_coupon_usage_count,
|
||||||
)
|
)
|
||||||
|
from handlers.utils import edit_or_send_message
|
||||||
from .utils import edit_or_send_message
|
from keyboards.coupons import get_coupon_keyboard
|
||||||
|
|
||||||
|
|
||||||
class CouponActivationState(StatesGroup):
|
class CouponActivationState(StatesGroup):
|
||||||
@@ -26,14 +25,16 @@ router = Router()
|
|||||||
|
|
||||||
@router.callback_query(F.data == "activate_coupon")
|
@router.callback_query(F.data == "activate_coupon")
|
||||||
@router.message(F.text == "/activate_coupon")
|
@router.message(F.text == "/activate_coupon")
|
||||||
async def handle_activate_coupon(callback_query_or_message: Message | CallbackQuery, state: FSMContext):
|
async def handle_activate_coupon(state: FSMContext, target_message: Message):
|
||||||
builder = InlineKeyboardBuilder()
|
"""
|
||||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
Обрабатывает запрос на активацию купона.
|
||||||
|
|
||||||
if isinstance(callback_query_or_message, CallbackQuery):
|
Args:
|
||||||
target_message = callback_query_or_message.message
|
state: Контекст состояния FSM.
|
||||||
else:
|
chat_id: ID чата (добавлено middleware).
|
||||||
target_message = callback_query_or_message
|
target_message: Целевое сообщение для ответа (добавлено middleware).
|
||||||
|
"""
|
||||||
|
builder = get_coupon_keyboard()
|
||||||
|
|
||||||
await edit_or_send_message(
|
await edit_or_send_message(
|
||||||
target_message=target_message,
|
target_message=target_message,
|
||||||
@@ -46,18 +47,37 @@ async def handle_activate_coupon(callback_query_or_message: Message | CallbackQu
|
|||||||
|
|
||||||
|
|
||||||
@router.message(CouponActivationState.waiting_for_coupon_code)
|
@router.message(CouponActivationState.waiting_for_coupon_code)
|
||||||
async def process_coupon_code(message: Message, state: FSMContext, session: Any):
|
async def process_coupon_code(message: Message, state: FSMContext, session: Any, chat_id: int):
|
||||||
coupon_code = message.text.strip()
|
"""
|
||||||
activation_result = await activate_coupon(message.chat.id, coupon_code, session)
|
Обрабатывает введенный код купона.
|
||||||
|
|
||||||
builder = InlineKeyboardBuilder()
|
Args:
|
||||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
message: Сообщение с кодом купона.
|
||||||
|
state: Контекст состояния FSM.
|
||||||
|
session: Сессия базы данных.
|
||||||
|
chat_id: ID чата (добавлено middleware).
|
||||||
|
"""
|
||||||
|
coupon_code = message.text.strip()
|
||||||
|
activation_result = await activate_coupon(chat_id, coupon_code, session)
|
||||||
|
|
||||||
|
builder = get_coupon_keyboard()
|
||||||
|
|
||||||
await message.answer(activation_result, reply_markup=builder.as_markup())
|
await message.answer(activation_result, reply_markup=builder.as_markup())
|
||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
|
|
||||||
async def activate_coupon(user_id: int, coupon_code: str, session: Any):
|
async def activate_coupon(user_id: int, coupon_code: str, session: Any) -> str:
|
||||||
|
"""
|
||||||
|
Активирует купон для пользователя.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id: ID пользователя.
|
||||||
|
coupon_code: Код купона.
|
||||||
|
session: Сессия базы данных.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Сообщение о результате активации.
|
||||||
|
"""
|
||||||
coupon_record = await get_coupon_by_code(coupon_code, session)
|
coupon_record = await get_coupon_by_code(coupon_code, session)
|
||||||
|
|
||||||
if not coupon_record:
|
if not coupon_record:
|
||||||
+4
-4
@@ -20,7 +20,7 @@ router = Router()
|
|||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data == "donate")
|
@router.callback_query(F.data == "donate")
|
||||||
async def process_donate(callback_query: CallbackQuery, state: FSMContext):
|
async def process_donate(callback_query: CallbackQuery, state: FSMContext, target_message: Message):
|
||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
builder = InlineKeyboardBuilder()
|
builder = InlineKeyboardBuilder()
|
||||||
@@ -40,20 +40,20 @@ async def process_donate(callback_query: CallbackQuery, state: FSMContext):
|
|||||||
)
|
)
|
||||||
|
|
||||||
await edit_or_send_message(
|
await edit_or_send_message(
|
||||||
target_message=callback_query.message,
|
target_message=target_message,
|
||||||
text=text,
|
text=text,
|
||||||
reply_markup=builder.as_markup(),
|
reply_markup=builder.as_markup(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data == "enter_custom_donate_amount")
|
@router.callback_query(F.data == "enter_custom_donate_amount")
|
||||||
async def process_enter_donate_amount(callback_query: CallbackQuery, state: FSMContext):
|
async def process_enter_donate_amount(callback_query: CallbackQuery, state: FSMContext, target_message: Message):
|
||||||
builder = InlineKeyboardBuilder()
|
builder = InlineKeyboardBuilder()
|
||||||
builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="donate"))
|
builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="donate"))
|
||||||
text = "💸 Введите сумму доната в рублях:"
|
text = "💸 Введите сумму доната в рублях:"
|
||||||
|
|
||||||
await edit_or_send_message(
|
await edit_or_send_message(
|
||||||
target_message=callback_query.message,
|
target_message=target_message,
|
||||||
text=text,
|
text=text,
|
||||||
reply_markup=builder.as_markup(),
|
reply_markup=builder.as_markup(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ router = Router()
|
|||||||
|
|
||||||
@router.callback_query(F.data == "instructions")
|
@router.callback_query(F.data == "instructions")
|
||||||
@router.message(F.text == "/instructions")
|
@router.message(F.text == "/instructions")
|
||||||
async def send_instructions(callback_query_or_message: CallbackQuery | Message):
|
async def send_instructions(target_message: Message):
|
||||||
instructions_message = INSTRUCTIONS
|
instructions_message = INSTRUCTIONS
|
||||||
image_path = os.path.join("img", "instructions.jpg")
|
image_path = os.path.join("img", "instructions.jpg")
|
||||||
|
|
||||||
@@ -35,11 +35,6 @@ async def send_instructions(callback_query_or_message: CallbackQuery | Message):
|
|||||||
builder.row(InlineKeyboardButton(text="💬 Поддержка", url=SUPPORT_CHAT_URL))
|
builder.row(InlineKeyboardButton(text="💬 Поддержка", url=SUPPORT_CHAT_URL))
|
||||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
||||||
|
|
||||||
if isinstance(callback_query_or_message, CallbackQuery):
|
|
||||||
target_message = callback_query_or_message.message
|
|
||||||
else:
|
|
||||||
target_message = callback_query_or_message
|
|
||||||
|
|
||||||
await edit_or_send_message(
|
await edit_or_send_message(
|
||||||
target_message=target_message,
|
target_message=target_message,
|
||||||
text=instructions_message,
|
text=instructions_message,
|
||||||
@@ -49,14 +44,14 @@ async def send_instructions(callback_query_or_message: CallbackQuery | Message):
|
|||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data.startswith("connect_pc|"))
|
@router.callback_query(F.data.startswith("connect_pc|"))
|
||||||
async def process_connect_pc(callback_query: CallbackQuery, session: Any):
|
async def process_connect_pc(callback_query: CallbackQuery, session: Any, target_message: Message):
|
||||||
key_name = callback_query.data.split("|")[1]
|
key_name = callback_query.data.split("|")[1]
|
||||||
record = await get_key_details(key_name, session)
|
record = await get_key_details(key_name, session)
|
||||||
if not record:
|
if not record:
|
||||||
builder = InlineKeyboardBuilder()
|
builder = InlineKeyboardBuilder()
|
||||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
||||||
await edit_or_send_message(
|
await edit_or_send_message(
|
||||||
target_message=callback_query.message,
|
target_message=target_message,
|
||||||
text="❌ <b>Ключ не найден. Проверьте имя ключа.</b> 🔍",
|
text="❌ <b>Ключ не найден. Проверьте имя ключа.</b> 🔍",
|
||||||
reply_markup=builder.as_markup(),
|
reply_markup=builder.as_markup(),
|
||||||
media_path=None,
|
media_path=None,
|
||||||
@@ -75,7 +70,7 @@ async def process_connect_pc(callback_query: CallbackQuery, session: Any):
|
|||||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
||||||
|
|
||||||
await edit_or_send_message(
|
await edit_or_send_message(
|
||||||
target_message=callback_query.message,
|
target_message=target_message,
|
||||||
text=instruction_message,
|
text=instruction_message,
|
||||||
reply_markup=builder.as_markup(),
|
reply_markup=builder.as_markup(),
|
||||||
media_path=None,
|
media_path=None,
|
||||||
@@ -83,7 +78,7 @@ async def process_connect_pc(callback_query: CallbackQuery, session: Any):
|
|||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data.startswith("connect_tv|"))
|
@router.callback_query(F.data.startswith("connect_tv|"))
|
||||||
async def process_connect_tv(callback_query: CallbackQuery):
|
async def process_connect_tv(callback_query: CallbackQuery, target_message: Message):
|
||||||
key_name = callback_query.data.split("|")[1]
|
key_name = callback_query.data.split("|")[1]
|
||||||
|
|
||||||
builder = InlineKeyboardBuilder()
|
builder = InlineKeyboardBuilder()
|
||||||
@@ -92,7 +87,7 @@ async def process_connect_tv(callback_query: CallbackQuery):
|
|||||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
||||||
|
|
||||||
await edit_or_send_message(
|
await edit_or_send_message(
|
||||||
target_message=callback_query.message,
|
target_message=target_message,
|
||||||
text=CONNECT_TV_TEXT,
|
text=CONNECT_TV_TEXT,
|
||||||
reply_markup=builder.as_markup(),
|
reply_markup=builder.as_markup(),
|
||||||
media_path=None,
|
media_path=None,
|
||||||
@@ -101,7 +96,7 @@ async def process_connect_tv(callback_query: CallbackQuery):
|
|||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data.startswith("continue_tv|"))
|
@router.callback_query(F.data.startswith("continue_tv|"))
|
||||||
async def process_continue_tv(callback_query: CallbackQuery, session: Any):
|
async def process_continue_tv(callback_query: CallbackQuery, session: Any, target_message: Message):
|
||||||
key_name = callback_query.data.split("|")[1]
|
key_name = callback_query.data.split("|")[1]
|
||||||
|
|
||||||
record = await get_key_details(key_name, session)
|
record = await get_key_details(key_name, session)
|
||||||
@@ -114,5 +109,5 @@ async def process_continue_tv(callback_query: CallbackQuery, session: Any):
|
|||||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
||||||
|
|
||||||
await edit_or_send_message(
|
await edit_or_send_message(
|
||||||
target_message=callback_query.message, text=message_text, reply_markup=builder.as_markup(), media_path=None
|
target_message=target_message, text=message_text, reply_markup=builder.as_markup(), media_path=None
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -71,16 +71,18 @@ class Form(FSMContext):
|
|||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data == "create_key")
|
@router.callback_query(F.data == "create_key")
|
||||||
async def confirm_create_new_key(callback_query: CallbackQuery, state: FSMContext, session: Any):
|
async def confirm_create_new_key(
|
||||||
|
callback_query: CallbackQuery, state: FSMContext, session: Any, target_message: Message
|
||||||
|
):
|
||||||
tg_id = callback_query.message.chat.id
|
tg_id = callback_query.message.chat.id
|
||||||
await handle_key_creation(tg_id, state, session, callback_query)
|
await handle_key_creation(tg_id, state, session, target_message)
|
||||||
|
|
||||||
|
|
||||||
async def handle_key_creation(
|
async def handle_key_creation(
|
||||||
tg_id: int,
|
tg_id: int,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
session: Any,
|
session: Any,
|
||||||
message_or_query: Message | CallbackQuery,
|
target_message: Message,
|
||||||
):
|
):
|
||||||
"""Создание ключа с учётом выбора тарифного плана."""
|
"""Создание ключа с учётом выбора тарифного плана."""
|
||||||
current_time = datetime.now(moscow_tz)
|
current_time = datetime.now(moscow_tz)
|
||||||
@@ -94,14 +96,12 @@ async def handle_key_creation(
|
|||||||
updated = await update_trial(tg_id, 1, session)
|
updated = await update_trial(tg_id, 1, session)
|
||||||
if updated:
|
if updated:
|
||||||
await edit_or_send_message(
|
await edit_or_send_message(
|
||||||
target_message=message_or_query
|
target_message=target_message,
|
||||||
if isinstance(message_or_query, Message)
|
|
||||||
else message_or_query.message,
|
|
||||||
text="⏳ Пожалуйста, подождите, создаем вам подключение...",
|
text="⏳ Пожалуйста, подождите, создаем вам подключение...",
|
||||||
reply_markup=None,
|
reply_markup=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
await create_key(tg_id, expiry_time, state, session, message_or_query)
|
await create_key(tg_id, expiry_time, state, session, target_message)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
logger.error(f"Не удалось обновить статус триального периода для пользователя {tg_id}.")
|
logger.error(f"Не удалось обновить статус триального периода для пользователя {tg_id}.")
|
||||||
@@ -122,11 +122,6 @@ async def handle_key_creation(
|
|||||||
)
|
)
|
||||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
||||||
|
|
||||||
if isinstance(message_or_query, CallbackQuery):
|
|
||||||
target_message = message_or_query.message
|
|
||||||
else:
|
|
||||||
target_message = message_or_query
|
|
||||||
|
|
||||||
await edit_or_send_message(
|
await edit_or_send_message(
|
||||||
target_message=target_message,
|
target_message=target_message,
|
||||||
text="💳 Выберите тарифный план для создания нового ключа:",
|
text="💳 Выберите тарифный план для создания нового ключа:",
|
||||||
@@ -195,13 +190,12 @@ async def create_key(
|
|||||||
expiry_time: datetime,
|
expiry_time: datetime,
|
||||||
state: FSMContext | None,
|
state: FSMContext | None,
|
||||||
session: Any,
|
session: Any,
|
||||||
message_or_query: Message | CallbackQuery | None = None,
|
target_message: Message,
|
||||||
old_key_name: str = None,
|
old_key_name: str = None,
|
||||||
plan: int = None,
|
plan: int = None,
|
||||||
):
|
):
|
||||||
"""Создаёт ключ с заданным сроком действия."""
|
"""Создаёт ключ с заданным сроком действия."""
|
||||||
|
|
||||||
target_message = message_or_query.message if isinstance(message_or_query, CallbackQuery) else message_or_query
|
|
||||||
if not await check_connection_exists(tg_id):
|
if not await check_connection_exists(tg_id):
|
||||||
await add_connection(tg_id, balance=0.0, trial=0, session=session)
|
await add_connection(tg_id, balance=0.0, trial=0, session=session)
|
||||||
logger.info(f"[Connection] Подключение создано для пользователя {tg_id}")
|
logger.info(f"[Connection] Подключение создано для пользователя {tg_id}")
|
||||||
|
|||||||
@@ -74,14 +74,9 @@ router = Router()
|
|||||||
|
|
||||||
@router.callback_query(F.data == "view_keys")
|
@router.callback_query(F.data == "view_keys")
|
||||||
@router.message(F.text == "/subs")
|
@router.message(F.text == "/subs")
|
||||||
async def process_callback_or_message_view_keys(callback_query_or_message: Message | CallbackQuery, session: Any):
|
async def process_callback_or_message_view_keys(session: Any, target_message: Message, chat_id: int):
|
||||||
if isinstance(callback_query_or_message, CallbackQuery):
|
|
||||||
target_message = callback_query_or_message.message
|
|
||||||
else:
|
|
||||||
target_message = callback_query_or_message
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
records = await get_keys(target_message.chat.id, session)
|
records = await get_keys(chat_id, session)
|
||||||
inline_keyboard, response_message = build_keys_response(records)
|
inline_keyboard, response_message = build_keys_response(records)
|
||||||
image_path = os.path.join("img", "pic_keys.jpg")
|
image_path = os.path.join("img", "pic_keys.jpg")
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
from aiogram import F, Router
|
from aiogram import F, Router
|
||||||
from aiogram.types import CallbackQuery, InlineKeyboardButton
|
from aiogram.types import CallbackQuery, InlineKeyboardButton, Message
|
||||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||||
from config import (
|
from config import (
|
||||||
CRYPTO_BOT_ENABLE,
|
CRYPTO_BOT_ENABLE,
|
||||||
@@ -17,7 +17,7 @@ router = Router()
|
|||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data == "pay")
|
@router.callback_query(F.data == "pay")
|
||||||
async def handle_pay(callback_query: CallbackQuery):
|
async def handle_pay(callback_query: CallbackQuery, target_message: Message):
|
||||||
builder = InlineKeyboardBuilder()
|
builder = InlineKeyboardBuilder()
|
||||||
|
|
||||||
if YOOKASSA_ENABLE:
|
if YOOKASSA_ENABLE:
|
||||||
@@ -71,7 +71,7 @@ async def handle_pay(callback_query: CallbackQuery):
|
|||||||
)
|
)
|
||||||
|
|
||||||
await edit_or_send_message(
|
await edit_or_send_message(
|
||||||
target_message=callback_query.message,
|
target_message=target_message,
|
||||||
text=payment_text,
|
text=payment_text,
|
||||||
reply_markup=builder.as_markup(),
|
reply_markup=builder.as_markup(),
|
||||||
media_path=None,
|
media_path=None,
|
||||||
|
|||||||
@@ -75,18 +75,18 @@ async def process_callback_pay_robokassa(callback_query: types.CallbackQuery, st
|
|||||||
builder.row(
|
builder.row(
|
||||||
InlineKeyboardButton(
|
InlineKeyboardButton(
|
||||||
text=PAYMENT_OPTIONS[i]["text"],
|
text=PAYMENT_OPTIONS[i]["text"],
|
||||||
callback_data=f'robokassa_amount|{PAYMENT_OPTIONS[i]["callback_data"]}',
|
callback_data=f"robokassa_amount|{PAYMENT_OPTIONS[i]['callback_data']}",
|
||||||
),
|
),
|
||||||
InlineKeyboardButton(
|
InlineKeyboardButton(
|
||||||
text=PAYMENT_OPTIONS[i + 1]["text"],
|
text=PAYMENT_OPTIONS[i + 1]["text"],
|
||||||
callback_data=f'robokassa_amount|{PAYMENT_OPTIONS[i + 1]["callback_data"]}',
|
callback_data=f"robokassa_amount|{PAYMENT_OPTIONS[i + 1]['callback_data']}",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
builder.row(
|
builder.row(
|
||||||
InlineKeyboardButton(
|
InlineKeyboardButton(
|
||||||
text=PAYMENT_OPTIONS[i]["text"],
|
text=PAYMENT_OPTIONS[i]["text"],
|
||||||
callback_data=f'robokassa_amount|{PAYMENT_OPTIONS[i]["callback_data"]}',
|
callback_data=f"robokassa_amount|{PAYMENT_OPTIONS[i]['callback_data']}",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="pay"))
|
builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="pay"))
|
||||||
@@ -100,12 +100,12 @@ async def process_callback_pay_robokassa(callback_query: types.CallbackQuery, st
|
|||||||
logger.info(f"Created new connection for user {tg_id} with balance 0.0.")
|
logger.info(f"Created new connection for user {tg_id} with balance 0.0.")
|
||||||
|
|
||||||
await callback_query.message.delete()
|
await callback_query.message.delete()
|
||||||
|
|
||||||
new_message = await callback_query.message.answer(
|
new_message = await callback_query.message.answer(
|
||||||
text="Выберите сумму пополнения:",
|
text="Выберите сумму пополнения:",
|
||||||
reply_markup=builder.as_markup(),
|
reply_markup=builder.as_markup(),
|
||||||
)
|
)
|
||||||
await state.update_data(message_id=new_message.message_id, chat_id=new_message.chat.id)
|
await state.update_data(message_id=new_message.message_id, chat_id=new_message.chat.id)
|
||||||
await state.set_state(ReplenishBalanceState.choosing_amount_robokassa)
|
await state.set_state(ReplenishBalanceState.choosing_amount_robokassa)
|
||||||
logger.info(f"Displayed amount selection for user {tg_id}.")
|
logger.info(f"Displayed amount selection for user {tg_id}.")
|
||||||
|
|
||||||
|
|||||||
@@ -1,255 +0,0 @@
|
|||||||
import html
|
|
||||||
import os
|
|
||||||
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import asyncpg
|
|
||||||
|
|
||||||
from aiogram import F, Router
|
|
||||||
from aiogram.enums import ParseMode
|
|
||||||
from aiogram.fsm.context import FSMContext
|
|
||||||
from aiogram.types import (
|
|
||||||
CallbackQuery,
|
|
||||||
InlineKeyboardButton,
|
|
||||||
InlineQuery,
|
|
||||||
InlineQueryResultArticle,
|
|
||||||
InputTextMessageContent,
|
|
||||||
Message,
|
|
||||||
)
|
|
||||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
|
||||||
from config import (
|
|
||||||
DATABASE_URL,
|
|
||||||
INLINE_MODE,
|
|
||||||
INSTRUCTIONS_BUTTON,
|
|
||||||
NEWS_MESSAGE,
|
|
||||||
REFERRAL_OFFERS,
|
|
||||||
RENEWAL_PLANS,
|
|
||||||
TRIAL_TIME,
|
|
||||||
USERNAME_BOT,
|
|
||||||
)
|
|
||||||
|
|
||||||
from database import get_balance, get_key_count, get_last_payments, get_referral_stats, get_trial
|
|
||||||
from handlers.buttons.profile import (
|
|
||||||
ADD_SUB,
|
|
||||||
BALANCE,
|
|
||||||
BALANCE_HISTORY,
|
|
||||||
GIFTS,
|
|
||||||
INSTRUCTIONS,
|
|
||||||
INVITE,
|
|
||||||
MAIN_MENU,
|
|
||||||
MY_SUBS,
|
|
||||||
PAYMENT,
|
|
||||||
)
|
|
||||||
from handlers.texts import get_referral_link, invite_message_send, profile_message_send
|
|
||||||
from keyboards.admin.panel_kb import AdminPanelCallback
|
|
||||||
from logger import logger
|
|
||||||
|
|
||||||
from .utils import edit_or_send_message
|
|
||||||
|
|
||||||
|
|
||||||
router = Router()
|
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data == "profile")
|
|
||||||
@router.message(F.text == "/profile")
|
|
||||||
async def process_callback_view_profile(
|
|
||||||
callback_query_or_message: Message | CallbackQuery,
|
|
||||||
state: FSMContext,
|
|
||||||
admin: bool,
|
|
||||||
):
|
|
||||||
if isinstance(callback_query_or_message, CallbackQuery):
|
|
||||||
chat_id = callback_query_or_message.message.chat.id
|
|
||||||
username = html.escape(callback_query_or_message.from_user.full_name)
|
|
||||||
target_message = callback_query_or_message.message
|
|
||||||
else:
|
|
||||||
chat_id = callback_query_or_message.chat.id
|
|
||||||
username = html.escape(callback_query_or_message.from_user.full_name)
|
|
||||||
target_message = callback_query_or_message
|
|
||||||
|
|
||||||
image_path = os.path.join("img", "profile.jpg")
|
|
||||||
logger.info(f"Переход в профиль. Используется изображение: {image_path}")
|
|
||||||
|
|
||||||
key_count = await get_key_count(chat_id)
|
|
||||||
balance = await get_balance(chat_id) or 0
|
|
||||||
|
|
||||||
conn = await asyncpg.connect(DATABASE_URL)
|
|
||||||
try:
|
|
||||||
trial_status = await get_trial(chat_id, conn)
|
|
||||||
|
|
||||||
profile_message = profile_message_send(username, chat_id, int(balance), key_count)
|
|
||||||
if key_count == 0:
|
|
||||||
profile_message += (
|
|
||||||
"\n<blockquote>🔧 <i>Нажмите кнопку ➕ Подписка, чтобы настроить VPN-подключение</i></blockquote>"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
profile_message += f"\n<blockquote> <i>{NEWS_MESSAGE}</i></blockquote>"
|
|
||||||
|
|
||||||
builder = InlineKeyboardBuilder()
|
|
||||||
if trial_status == 0 or key_count == 0:
|
|
||||||
builder.row(InlineKeyboardButton(text=ADD_SUB, callback_data="create_key"))
|
|
||||||
else:
|
|
||||||
builder.row(InlineKeyboardButton(text=MY_SUBS, callback_data="view_keys"))
|
|
||||||
builder.row(InlineKeyboardButton(text=BALANCE, callback_data="balance"))
|
|
||||||
builder.row(
|
|
||||||
InlineKeyboardButton(text=INVITE, callback_data="invite"),
|
|
||||||
InlineKeyboardButton(text=GIFTS, callback_data="gifts"),
|
|
||||||
)
|
|
||||||
if INSTRUCTIONS_BUTTON:
|
|
||||||
builder.row(InlineKeyboardButton(text=INSTRUCTIONS, callback_data="instructions"))
|
|
||||||
if admin:
|
|
||||||
builder.row(
|
|
||||||
InlineKeyboardButton(text="🔧 Администратор", callback_data=AdminPanelCallback(action="admin").pack())
|
|
||||||
)
|
|
||||||
|
|
||||||
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="start"))
|
|
||||||
|
|
||||||
await edit_or_send_message(
|
|
||||||
target_message=target_message,
|
|
||||||
text=profile_message,
|
|
||||||
reply_markup=builder.as_markup(),
|
|
||||||
media_path=image_path,
|
|
||||||
disable_web_page_preview=False,
|
|
||||||
force_text=True,
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
await conn.close()
|
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data == "balance")
|
|
||||||
async def balance_handler(callback_query: CallbackQuery, session: Any):
|
|
||||||
result = await session.fetchrow(
|
|
||||||
"SELECT balance FROM connections WHERE tg_id = $1",
|
|
||||||
callback_query.from_user.id,
|
|
||||||
)
|
|
||||||
balance = result["balance"] if result else 0.0
|
|
||||||
balance = int(balance)
|
|
||||||
|
|
||||||
builder = InlineKeyboardBuilder()
|
|
||||||
builder.row(InlineKeyboardButton(text=PAYMENT, callback_data="pay"))
|
|
||||||
builder.row(InlineKeyboardButton(text=BALANCE_HISTORY, callback_data="balance_history"))
|
|
||||||
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
|
|
||||||
|
|
||||||
text = f"<b>Управление вашим балансом 💰</b>\n\nВаш баланс: {balance}"
|
|
||||||
await edit_or_send_message(
|
|
||||||
target_message=callback_query.message,
|
|
||||||
text=text,
|
|
||||||
reply_markup=builder.as_markup(),
|
|
||||||
media_path=None,
|
|
||||||
disable_web_page_preview=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data == "balance_history")
|
|
||||||
async def balance_history_handler(callback_query: CallbackQuery, session: Any):
|
|
||||||
builder = InlineKeyboardBuilder()
|
|
||||||
builder.row(InlineKeyboardButton(text=PAYMENT, callback_data="pay"))
|
|
||||||
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
|
|
||||||
|
|
||||||
records = await get_last_payments(callback_query.from_user.id, session)
|
|
||||||
|
|
||||||
if records:
|
|
||||||
history_text = "📊 <b>Последние 3 операции с балансом:</b>\n\n"
|
|
||||||
for record in records:
|
|
||||||
amount = record["amount"]
|
|
||||||
payment_system = record["payment_system"]
|
|
||||||
status = record["status"]
|
|
||||||
date = record["created_at"].strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
history_text += (
|
|
||||||
f"<b>Сумма:</b> {amount}₽\n"
|
|
||||||
f"<b>Способ оплаты:</b> {payment_system}\n"
|
|
||||||
f"<b>Статус:</b> {status}\n"
|
|
||||||
f"<b>Дата:</b> {date}\n\n"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
history_text = "❌ У вас пока нет операций с балансом."
|
|
||||||
|
|
||||||
await edit_or_send_message(
|
|
||||||
target_message=callback_query.message,
|
|
||||||
text=history_text,
|
|
||||||
reply_markup=builder.as_markup(),
|
|
||||||
media_path=None,
|
|
||||||
disable_web_page_preview=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.message(F.text == "/tariffs")
|
|
||||||
@router.callback_query(F.data == "view_tariffs")
|
|
||||||
async def view_tariffs_handler(callback_query: CallbackQuery):
|
|
||||||
builder = InlineKeyboardBuilder()
|
|
||||||
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
|
||||||
|
|
||||||
image_path = os.path.join("img", "tariffs.jpg")
|
|
||||||
tariffs_message = "<b>🚀 Доступные тарифы VPN:</b>\n\n" + "\n".join([
|
|
||||||
f"{months} {'месяц' if months == '1' else 'месяца' if int(months) in [2, 3, 4] else 'месяцев'}: "
|
|
||||||
f"{RENEWAL_PLANS[months]['price']} "
|
|
||||||
f"{'💳' if months == '1' else '🌟' if months == '3' else '🔥' if months == '6' else '🚀'} рублей"
|
|
||||||
for months in sorted(RENEWAL_PLANS.keys(), key=int)
|
|
||||||
])
|
|
||||||
|
|
||||||
await edit_or_send_message(
|
|
||||||
target_message=callback_query.message,
|
|
||||||
text=tariffs_message,
|
|
||||||
reply_markup=builder.as_markup(),
|
|
||||||
media_path=image_path,
|
|
||||||
disable_web_page_preview=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data == "invite")
|
|
||||||
@router.message(F.text == "/invite")
|
|
||||||
async def invite_handler(callback_query_or_message: Message | CallbackQuery):
|
|
||||||
chat_id = None
|
|
||||||
if isinstance(callback_query_or_message, CallbackQuery):
|
|
||||||
chat_id = callback_query_or_message.message.chat.id
|
|
||||||
target_message = callback_query_or_message.message
|
|
||||||
else:
|
|
||||||
chat_id = callback_query_or_message.chat.id
|
|
||||||
target_message = callback_query_or_message
|
|
||||||
|
|
||||||
referral_link = get_referral_link(chat_id)
|
|
||||||
referral_stats = await get_referral_stats(chat_id)
|
|
||||||
invite_message = invite_message_send(referral_link, referral_stats)
|
|
||||||
image_path = os.path.join("img", "pic_invite.jpg")
|
|
||||||
|
|
||||||
builder = InlineKeyboardBuilder()
|
|
||||||
if INLINE_MODE:
|
|
||||||
builder.button(text="👥 Пригласить друга", switch_inline_query="invite")
|
|
||||||
else:
|
|
||||||
invite_text = f"\nПриглашаю тебя пользоваться действительно быстрым VPN вместе:\n\n{referral_link}"
|
|
||||||
builder.button(text="👥 Пригласить друга", switch_inline_query=invite_text)
|
|
||||||
builder.button(text="👤 Личный кабинет", callback_data="profile")
|
|
||||||
builder.adjust(1)
|
|
||||||
|
|
||||||
await edit_or_send_message(
|
|
||||||
target_message=target_message,
|
|
||||||
text=invite_message,
|
|
||||||
reply_markup=builder.as_markup(),
|
|
||||||
media_path=image_path,
|
|
||||||
disable_web_page_preview=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.inline_query(F.query.in_(["referral", "ref", "invite"]))
|
|
||||||
async def inline_referral_handler(inline_query: InlineQuery):
|
|
||||||
referral_link = f"https://t.me/{USERNAME_BOT}?start=referral_{inline_query.from_user.id}"
|
|
||||||
|
|
||||||
results: list[InlineQueryResultArticle] = []
|
|
||||||
|
|
||||||
for index, offer in enumerate(REFERRAL_OFFERS):
|
|
||||||
description = offer["description"][:64]
|
|
||||||
message_text = offer["message"].format(trial_time=TRIAL_TIME)[:4096]
|
|
||||||
|
|
||||||
builder = InlineKeyboardBuilder()
|
|
||||||
builder.row(InlineKeyboardButton(text=offer["title"], url=referral_link))
|
|
||||||
|
|
||||||
results.append(
|
|
||||||
InlineQueryResultArticle(
|
|
||||||
id=str(index),
|
|
||||||
title=offer["title"],
|
|
||||||
description=description,
|
|
||||||
input_message_content=InputTextMessageContent(message_text=message_text, parse_mode=ParseMode.HTML),
|
|
||||||
reply_markup=builder.as_markup(),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
await inline_query.answer(results=results, cache_time=86400, is_personal=True)
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
from aiogram import Router
|
||||||
|
|
||||||
|
from .router import router
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["router"]
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
import html
|
||||||
|
import os
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from aiogram import F, Router
|
||||||
|
from aiogram.fsm.context import FSMContext
|
||||||
|
from aiogram.types import CallbackQuery, InlineQuery, InlineQueryResultArticle, InputTextMessageContent, Message
|
||||||
|
from config import INLINE_MODE, REFERRAL_OFFERS, TRIAL_TIME, USERNAME_BOT
|
||||||
|
|
||||||
|
from database import get_balance, get_key_count, get_last_payments, get_referral_stats, get_trial
|
||||||
|
from handlers.texts import get_referral_link, invite_message_send, profile_message_send
|
||||||
|
from handlers.utils import edit_or_send_message
|
||||||
|
from keyboards.profile import get_balance_keyboard, get_invite_keyboard, get_profile_keyboard
|
||||||
|
|
||||||
|
|
||||||
|
router = Router()
|
||||||
|
|
||||||
|
|
||||||
|
@router.callback_query(F.data == "profile")
|
||||||
|
@router.message(F.text == "/profile")
|
||||||
|
async def process_callback_view_profile(
|
||||||
|
state: FSMContext,
|
||||||
|
admin: bool,
|
||||||
|
chat_id: int,
|
||||||
|
target_message: Message,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Обрабатывает запрос на просмотр профиля пользователя.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
state: Контекст состояния FSM.
|
||||||
|
admin: Флаг, указывающий, является ли пользователь администратором.
|
||||||
|
chat_id: ID чата (добавлено middleware).
|
||||||
|
target_message: Целевое сообщение для ответа (добавлено middleware).
|
||||||
|
"""
|
||||||
|
# Получаем информацию о профиле
|
||||||
|
profile_message = await profile_message_send(chat_id)
|
||||||
|
|
||||||
|
# Получаем клавиатуру профиля
|
||||||
|
builder = get_profile_keyboard(admin)
|
||||||
|
|
||||||
|
# Отправляем сообщение с профилем
|
||||||
|
await edit_or_send_message(
|
||||||
|
target_message=target_message,
|
||||||
|
text=profile_message,
|
||||||
|
reply_markup=builder.as_markup(),
|
||||||
|
media_path=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.callback_query(F.data == "balance")
|
||||||
|
async def balance_handler(callback_query: CallbackQuery, session: Any, chat_id: int, target_message: Message):
|
||||||
|
"""
|
||||||
|
Обрабатывает запрос на просмотр баланса.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
callback_query: Колбэк запрос.
|
||||||
|
session: Сессия базы данных.
|
||||||
|
chat_id: ID чата (добавлено middleware).
|
||||||
|
target_message: Целевое сообщение для ответа (добавлено middleware).
|
||||||
|
"""
|
||||||
|
balance = await get_balance(chat_id, session)
|
||||||
|
|
||||||
|
# Получаем клавиатуру баланса
|
||||||
|
builder = get_balance_keyboard()
|
||||||
|
|
||||||
|
# Отправляем сообщение с балансом
|
||||||
|
await edit_or_send_message(
|
||||||
|
target_message=target_message,
|
||||||
|
text=f"<b>💰 Ваш текущий баланс:</b> {balance} руб.\n\n"
|
||||||
|
"Вы можете пополнить баланс через раздел <b>💸 Пополнить баланс</b> в личном кабинете.",
|
||||||
|
reply_markup=builder.as_markup(),
|
||||||
|
media_path=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.callback_query(F.data == "balance_history")
|
||||||
|
async def balance_history_handler(callback_query: CallbackQuery, session: Any, chat_id: int, target_message: Message):
|
||||||
|
"""
|
||||||
|
Обрабатывает запрос на просмотр истории баланса.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
callback_query: Колбэк запрос.
|
||||||
|
session: Сессия базы данных.
|
||||||
|
chat_id: ID чата (добавлено middleware).
|
||||||
|
target_message: Целевое сообщение для ответа (добавлено middleware).
|
||||||
|
"""
|
||||||
|
payments = await get_last_payments(chat_id, session)
|
||||||
|
|
||||||
|
if not payments:
|
||||||
|
history_text = "<b>📊 История операций:</b>\n\nУ вас пока нет операций по балансу."
|
||||||
|
else:
|
||||||
|
history_text = "<b>📊 История операций:</b>\n\n"
|
||||||
|
for payment in payments:
|
||||||
|
amount = payment["amount"]
|
||||||
|
date = payment["created_at"].strftime("%d.%m.%Y %H:%M")
|
||||||
|
description = html.escape(payment["description"] or "")
|
||||||
|
|
||||||
|
if amount > 0:
|
||||||
|
history_text += f"➕ <b>{amount}</b> руб. - {description} ({date})\n"
|
||||||
|
else:
|
||||||
|
history_text += f"➖ <b>{abs(amount)}</b> руб. - {description} ({date})\n"
|
||||||
|
|
||||||
|
# Получаем клавиатуру баланса
|
||||||
|
builder = get_balance_keyboard()
|
||||||
|
|
||||||
|
# Отправляем сообщение с историей баланса
|
||||||
|
await edit_or_send_message(
|
||||||
|
target_message=target_message,
|
||||||
|
text=history_text,
|
||||||
|
reply_markup=builder.as_markup(),
|
||||||
|
media_path=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.callback_query(F.data == "invite")
|
||||||
|
@router.message(F.text == "/invite")
|
||||||
|
async def invite_handler(chat_id: int, target_message: Message):
|
||||||
|
"""
|
||||||
|
Обрабатывает запрос на приглашение друзей.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id: ID чата (добавлено middleware).
|
||||||
|
target_message: Целевое сообщение для ответа (добавлено middleware).
|
||||||
|
"""
|
||||||
|
referral_link = get_referral_link(chat_id)
|
||||||
|
referral_stats = await get_referral_stats(chat_id)
|
||||||
|
invite_message = invite_message_send(referral_link, referral_stats)
|
||||||
|
image_path = os.path.join("img", "pic_invite.jpg")
|
||||||
|
|
||||||
|
# Получаем клавиатуру для приглашений
|
||||||
|
builder = get_invite_keyboard(chat_id, referral_link)
|
||||||
|
|
||||||
|
# Отправляем сообщение с приглашением
|
||||||
|
await edit_or_send_message(
|
||||||
|
target_message=target_message,
|
||||||
|
text=invite_message,
|
||||||
|
reply_markup=builder.as_markup(),
|
||||||
|
media_path=image_path,
|
||||||
|
disable_web_page_preview=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.inline_query(F.query.in_(["referral", "ref", "invite"]))
|
||||||
|
async def inline_referral_handler(inline_query: InlineQuery):
|
||||||
|
"""
|
||||||
|
Обрабатывает инлайн-запрос для реферальной программы.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
inline_query: Инлайн-запрос.
|
||||||
|
"""
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for index, offer in enumerate(REFERRAL_OFFERS):
|
||||||
|
description = offer["description"][:64]
|
||||||
|
message_text = offer["message"].format(trial_time=TRIAL_TIME)[:4096]
|
||||||
|
|
||||||
|
results.append(
|
||||||
|
InlineQueryResultArticle(
|
||||||
|
id=f"ref_{index}",
|
||||||
|
title=offer["title"],
|
||||||
|
description=description,
|
||||||
|
input_message_content=InputTextMessageContent(
|
||||||
|
message_text=message_text,
|
||||||
|
parse_mode="HTML",
|
||||||
|
),
|
||||||
|
thumbnail_url=offer.get("thumbnail_url"),
|
||||||
|
thumbnail_width=100,
|
||||||
|
thumbnail_height=100,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
await inline_query.answer(results=results, cache_time=300)
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
from .keyboards import get_coupon_keyboard
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["get_coupon_keyboard"]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
from aiogram.types import InlineKeyboardButton
|
||||||
|
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||||
|
|
||||||
|
|
||||||
|
def get_coupon_keyboard() -> InlineKeyboardBuilder:
|
||||||
|
"""
|
||||||
|
Создает клавиатуру для работы с купонами.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
InlineKeyboardBuilder: Построитель клавиатуры с кнопками для купонов.
|
||||||
|
"""
|
||||||
|
builder = InlineKeyboardBuilder()
|
||||||
|
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
|
||||||
|
return builder
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
from .keyboards import get_balance_keyboard, get_invite_keyboard, get_profile_keyboard
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["get_profile_keyboard", "get_balance_keyboard", "get_invite_keyboard"]
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
from aiogram.types import InlineKeyboardButton
|
||||||
|
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||||
|
from config import INLINE_MODE
|
||||||
|
|
||||||
|
|
||||||
|
def get_profile_keyboard(admin: bool = False) -> InlineKeyboardBuilder:
|
||||||
|
"""
|
||||||
|
Создает клавиатуру для профиля пользователя.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
admin: Флаг, указывающий, является ли пользователь администратором.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
InlineKeyboardBuilder: Построитель клавиатуры с кнопками профиля.
|
||||||
|
"""
|
||||||
|
builder = InlineKeyboardBuilder()
|
||||||
|
|
||||||
|
# Основные кнопки профиля
|
||||||
|
builder.button(text="💰 Баланс", callback_data="balance")
|
||||||
|
builder.button(text="🔑 Мои подписки", callback_data="my_subs")
|
||||||
|
builder.button(text="💸 Пополнить баланс", callback_data="payment")
|
||||||
|
builder.button(text="🎁 Подарки", callback_data="gifts")
|
||||||
|
builder.button(text="👥 Пригласить друга", callback_data="invite")
|
||||||
|
builder.button(text="📚 Инструкции", callback_data="instructions")
|
||||||
|
builder.button(text="🎫 Активировать купон", callback_data="activate_coupon")
|
||||||
|
|
||||||
|
# Кнопка админ-панели для администраторов
|
||||||
|
if admin:
|
||||||
|
builder.button(text="⚙️ Админ-панель", callback_data="admin_panel")
|
||||||
|
|
||||||
|
# Кнопка главного меню
|
||||||
|
builder.button(text="🏠 Главное меню", callback_data="main_menu")
|
||||||
|
|
||||||
|
# Настройка расположения кнопок (2 кнопки в ряд)
|
||||||
|
builder.adjust(2)
|
||||||
|
|
||||||
|
return builder
|
||||||
|
|
||||||
|
|
||||||
|
def get_balance_keyboard() -> InlineKeyboardBuilder:
|
||||||
|
"""
|
||||||
|
Создает клавиатуру для раздела баланса.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
InlineKeyboardBuilder: Построитель клавиатуры с кнопками для баланса.
|
||||||
|
"""
|
||||||
|
builder = InlineKeyboardBuilder()
|
||||||
|
|
||||||
|
builder.button(text="📊 История баланса", callback_data="balance_history")
|
||||||
|
builder.button(text="👤 Личный кабинет", callback_data="profile")
|
||||||
|
builder.adjust(1)
|
||||||
|
|
||||||
|
return builder
|
||||||
|
|
||||||
|
|
||||||
|
def get_invite_keyboard(chat_id: int, referral_link: str) -> InlineKeyboardBuilder:
|
||||||
|
"""
|
||||||
|
Создает клавиатуру для приглашения друзей.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id: ID чата пользователя.
|
||||||
|
referral_link: Реферальная ссылка.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
InlineKeyboardBuilder: Построитель клавиатуры с кнопками для приглашений.
|
||||||
|
"""
|
||||||
|
builder = InlineKeyboardBuilder()
|
||||||
|
|
||||||
|
if INLINE_MODE:
|
||||||
|
builder.button(text="👥 Пригласить друга", switch_inline_query="invite")
|
||||||
|
else:
|
||||||
|
invite_text = f"\nПриглашаю тебя пользоваться действительно быстрым VPN вместе:\n\n{referral_link}"
|
||||||
|
builder.button(text="👥 Пригласить друга", switch_inline_query=invite_text)
|
||||||
|
|
||||||
|
builder.button(text="👤 Личный кабинет", callback_data="profile")
|
||||||
|
builder.adjust(1)
|
||||||
|
|
||||||
|
return builder
|
||||||
@@ -6,6 +6,7 @@ from aiogram.dispatcher.middlewares.base import BaseMiddleware
|
|||||||
|
|
||||||
from .admin import AdminMiddleware
|
from .admin import AdminMiddleware
|
||||||
from .loggings import LoggingMiddleware
|
from .loggings import LoggingMiddleware
|
||||||
|
from .message_handler import MessageHandlerMiddleware
|
||||||
from .session import SessionMiddleware
|
from .session import SessionMiddleware
|
||||||
from .throttling import ThrottlingMiddleware
|
from .throttling import ThrottlingMiddleware
|
||||||
from .user import UserMiddleware
|
from .user import UserMiddleware
|
||||||
@@ -34,6 +35,7 @@ def register_middleware(
|
|||||||
"logging": LoggingMiddleware(),
|
"logging": LoggingMiddleware(),
|
||||||
"throttling": ThrottlingMiddleware(),
|
"throttling": ThrottlingMiddleware(),
|
||||||
"user": UserMiddleware(),
|
"user": UserMiddleware(),
|
||||||
|
"message_handler": MessageHandlerMiddleware(),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Фильтруем middleware по списку исключений
|
# Фильтруем middleware по списку исключений
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
from collections.abc import Awaitable, Callable
|
||||||
|
from typing import Any, Dict, Union
|
||||||
|
|
||||||
|
from aiogram import BaseMiddleware
|
||||||
|
from aiogram.types import CallbackQuery, Message, TelegramObject
|
||||||
|
|
||||||
|
|
||||||
|
class MessageHandlerMiddleware(BaseMiddleware):
|
||||||
|
"""
|
||||||
|
Middleware для обработки сообщений и callback-запросов.
|
||||||
|
|
||||||
|
Добавляет в контекст обработчика следующие данные:
|
||||||
|
- chat_id: ID чата или пользователя
|
||||||
|
- target_message: Объект сообщения для ответа или редактирования
|
||||||
|
- is_callback: Флаг, указывающий, является ли запрос callback-запросом
|
||||||
|
"""
|
||||||
|
|
||||||
|
async def __call__(
|
||||||
|
self,
|
||||||
|
handler: Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]],
|
||||||
|
event: Message | CallbackQuery,
|
||||||
|
data: dict[str, Any],
|
||||||
|
) -> Any:
|
||||||
|
"""
|
||||||
|
Обрабатывает входящее событие и добавляет в контекст необходимые данные.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
handler: Обработчик события.
|
||||||
|
event: Событие (сообщение или callback-запрос).
|
||||||
|
data: Словарь с данными контекста.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Any: Результат выполнения обработчика.
|
||||||
|
"""
|
||||||
|
# Определяем тип события и извлекаем нужные данные
|
||||||
|
if isinstance(event, CallbackQuery):
|
||||||
|
data["chat_id"] = event.from_user.id
|
||||||
|
data["target_message"] = event.message
|
||||||
|
data["is_callback"] = True
|
||||||
|
else:
|
||||||
|
data["chat_id"] = event.chat.id
|
||||||
|
data["target_message"] = event
|
||||||
|
data["is_callback"] = False
|
||||||
|
|
||||||
|
# Вызываем следующий обработчик
|
||||||
|
return await handler(event, data)
|
||||||
Reference in New Issue
Block a user