3 Commits

Author SHA1 Message Date
unknown
ead48389b7 Много чего изменил, надеюсь, запушил правильно 2025-12-06 11:49:36 +03:00
unknown
33414dee65 Исправил много чего в фронте 2025-12-06 11:38:34 +03:00
unknown
709e8f09eb Чет исправил, я забыл 2025-12-02 14:28:03 +03:00
6 changed files with 1091 additions and 1184 deletions

View File

@@ -1,16 +1,16 @@
from .start import router as start_router from .start import router as start_router
from .profile import router as profile_router from .profile import router as profile_router
from .subscriptions import router as subscriptions_router from .subscriptions import router as subscriptions_router
from .support import router as support_router from .support import router as support_router
from .referrals import router as referrals_router from .referrals import router as referrals_router
# Список всех роутеров бота # Список всех роутеров бота
routers = [ routers = [
start_router, start_router,
profile_router, profile_router,
subscriptions_router, subscriptions_router,
support_router, support_router,
referrals_router, referrals_router,
] ]
__all__ = ["routers"] __all__ = ["routers"]

File diff suppressed because it is too large Load Diff

View File

@@ -1,123 +1,63 @@
from aiogram import Router, types from aiogram import Router, types
from aiogram.filters import Command from aiogram.filters import Command
from aiogram.enums.parse_mode import ParseMode from aiogram.enums.parse_mode import ParseMode
import logging import logging
import aiohttp
from .start import call_api # используем уже готовый HTTP-хелпер
from instences.config import BASE_URL_FASTAPI
router = Router()
router = Router() logger = logging.getLogger(__name__)
logger = logging.getLogger(__name__)
async def _build_referral_text(bot, user_id: int) -> str:
async def call_api(method: str, endpoint: str, data=None, base_url: str = BASE_URL_FASTAPI): me = await bot.get_me()
""" bot_username = me.username or "LarkVPN_bot"
Универсальный HTTP-запрос к FastAPI для рефералок.
link = f"https://t.me/{bot_username}?start=ref_{user_id}"
Ожидаем:
GET /user/{telegram_id}/referrals -> { invited_count = ""
"invited_count": int try:
} data = await call_api("GET", f"/user/{user_id}/referrals")
""" if isinstance(data, dict):
url = f"{base_url}{endpoint}" invited_count = str(data.get("invited_count", 0))
logger.info(f"[referrals] Запрос: {method} {url} с данными {data}") except Exception as e:
logger.exception(
try: f"Ошибка при получении количества рефералов для {user_id}: {e}"
async with aiohttp.ClientSession() as session: )
async with session.request(
method, text = (
url, "👥 <b>Реферальная программа</b>\n\n"
json=data, "Зови друзей в Lark VPN и получай бонусы на баланс.\n\n"
headers={"Content-Type": "application/json"}, f"🔗 Твоя ссылка:\n<code>{link}</code>\n\n"
) as response: f"👤 Приглашено: {invited_count}\n\n"
logger.info( )
f"[referrals] Ответ от {url}: статус {response.status}" return text
)
if response.status in {200, 201}: @router.message(Command("referrals"))
result = await response.json() async def referrals_command(message: types.Message):
logger.debug(f"[referrals] Ответ JSON: {result}") logger.info(f"Получена команда /referrals от {message.from_user.id}")
return result try:
if response.status == 404: text = await _build_referral_text(message.bot, message.from_user.id)
logger.debug("[referrals] 404, возвращаю None") await message.answer(text, parse_mode=ParseMode.HTML)
return None except Exception as e:
logger.exception(f"Ошибка в обработчике /referrals: {e}")
logger.error( await message.answer("Произошла ошибка. Попробуй позже.")
f"[referrals] Ошибка в запросе: статус {response.status}, "
f"причина {response.reason}"
) @router.callback_query(lambda callback: callback.data == "referral")
return "ERROR" async def referrals_callback(callback: types.CallbackQuery):
except Exception as e: try:
logger.exception(f"[referrals] Исключение при запросе к {url}: {e}") text = await _build_referral_text(
return "ERROR" callback.message.bot,
callback.from_user.id,
)
async def _build_referral_text(bot, user_id: int) -> str: await callback.message.edit_text(
""" text,
Текст реферальной программы + количество приглашённых. parse_mode=ParseMode.HTML,
""" )
me = await bot.get_me() except Exception as e:
bot_username = me.username or "LarkVPN_bot" logger.exception(f"Ошибка в обработчике callback 'referral': {e}")
await callback.message.answer("Произошла ошибка. Попробуй позже.")
link = f"https://t.me/{bot_username}?start=ref_{user_id}" finally:
await callback.answer()
text = (
"👥 <b>Реферальная программа</b>\n\n"
"Зови друзей в Lark VPN и получай бонусы на баланс.\n\n"
f"🔗 Твоя ссылка:\n<code>{link}</code>\n\n"
)
invited_count = 0
stats = await call_api("GET", f"/user/{user_id}/referrals")
if isinstance(stats, dict):
raw = stats.get("invited_count")
try:
invited_count = int(raw)
except (TypeError, ValueError):
invited_count = 0
elif stats == "ERROR":
logger.warning(
f"[referrals] Ошибка при получении статистики для user_id={user_id}"
)
text += f"👤 Приглашено: {invited_count}\n\n"
text += "Бонусы начисляются, когда приглашённые пополняют баланс."
return text
@router.message(Command("referrals"))
async def referrals_command(message: types.Message):
"""
Команда /referrals — показывает текст реферальной программы.
"""
logger.info(f"[referrals] Команда /referrals от {message.from_user.id}")
try:
text = await _build_referral_text(message.bot, message.from_user.id)
await message.answer(text, parse_mode=ParseMode.HTML)
except Exception as e:
logger.exception(f"[referrals] Ошибка в обработчике /referrals: {e}")
await message.answer("Произошла ошибка. Попробуй позже.")
@router.callback_query(lambda callback: callback.data == "referral")
async def referrals_callback(callback: types.CallbackQuery):
"""
Кнопка «Реферальная программа» (если где-то есть).
"""
try:
text = await _build_referral_text(
callback.message.bot,
callback.from_user.id,
)
await callback.message.edit_text(
text,
parse_mode=ParseMode.HTML,
)
except Exception as e:
logger.exception(
f"[referrals] Ошибка в обработчике callback 'referral': {e}")
await callback.message.answer("Произошла ошибка. Попробуй позже.")
finally:
await callback.answer()

View File

@@ -1,10 +1,11 @@
from aiogram import Router, types from aiogram import Router, types
from aiogram.filters import Command from aiogram.filters import Command
from aiogram.types import Message, CallbackQuery
from aiogram.enums.parse_mode import ParseMode from aiogram.enums.parse_mode import ParseMode
import logging import logging
import aiohttp import aiohttp
from aiogram.types import Message, CallbackQuery
from instences.config import BASE_URL_FASTAPI from instences.config import BASE_URL_FASTAPI
from keyboard.keyboards import main_keyboard from keyboard.keyboards import main_keyboard
from .referrals import _build_referral_text from .referrals import _build_referral_text
@@ -13,52 +14,39 @@ router = Router()
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
async def call_api(method: str, endpoint: str, data=None): async def call_api(method: str, endpoint: str, data: dict | None = None):
""" """Мини-обёртка для запросов к backend API."""
Выполняет HTTP-запрос к FastAPI.
Возвращает:
- dict при 200/201
- None при 404
- "ERROR" при остальных ошибках
"""
url = f"{BASE_URL_FASTAPI}{endpoint}" url = f"{BASE_URL_FASTAPI}{endpoint}"
logger.info(f"[start] Запрос: {method} {url} с данными {data}") logger.info(f"API {method} {url} data={data}")
try: try:
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.request(method, url, json=data) as response: async with session.request(method, url, json=data) as resp:
logger.info( logger.info(f"API response {resp.status} {resp.reason}")
f"[start] Ответ от {url}: статус {response.status}" if resp.status in {200, 201}:
) return await resp.json()
if resp.status in {400, 404}:
if response.status in {200, 201}: try:
result = await response.json() return await resp.json()
logger.debug(f"[start] Ответ JSON: {result}") except Exception:
return result return None
if response.status == 404:
logger.debug("[start] Получен 404, возвращаю None")
return None
logger.error( logger.error(
f"[start] Ошибка в запросе: статус {response.status}, " f"Unexpected status {resp.status}: {await resp.text()}"
f"причина {response.reason}"
) )
return "ERROR" return "ERROR"
except Exception as e: except Exception as e:
logger.exception(f"[start] Исключение при запросе к {url}: {e}") logger.exception(f"API exception {url}: {e}")
return "ERROR" return "ERROR"
def _welcome_text(username: str | None) -> str: def _welcome_text(username: str | None) -> str:
""" """Текст приветствия в /start и в главном меню."""
Текст приветствия в /start и в главном меню.
"""
return "🥚 Lark Security\n\nВыберите действие из меню ниже." return "🥚 Lark Security\n\nВыберите действие из меню ниже."
def _parse_referrer_id(message: Message) -> int | None: def _parse_referrer_id(message: Message) -> int | None:
""" """Достаём ref_<telegram_id> из /start.
Достаём ref_<telegram_id> из /start.
Примеры: Примеры:
/start /start
/start ref_123456789 /start ref_123456789
@@ -84,8 +72,13 @@ def _parse_referrer_id(message: Message) -> int | None:
@router.message(Command("start")) @router.message(Command("start"))
async def start_command(message: Message): async def start_command(message: Message):
""" """/start с обработкой реферального параметра.
/start c обработкой реферального параметра.
Логика:
- проверяем, есть ли пользователь в БД по telegram_id;
- если нет — создаём через /user/create;
- если есть корректный ref_ и пользователь новый — вызываем
/user/{referrer_id}/add_referral с invited_id = telegram_id.
""" """
user_id = message.from_user.id user_id = message.from_user.id
username = message.from_user.username username = message.from_user.username
@@ -140,24 +133,24 @@ async def start_command(message: Message):
# 3.3. Новый пользователь + чужая рефералка → регистрируем реферал # 3.3. Новый пользователь + чужая рефералка → регистрируем реферал
else: else:
payload = { payload = {
"referrer_id": referrer_id, "invited_id": user_id,
"telegram_id": user_id,
} }
logger.info( logger.info(
f"[start] Фиксирую реферала в бекенде: {payload}" f"[start] Фиксирую реферала в бекенде: "
f"referrer_id={referrer_id}, payload={payload}"
) )
result = await call_api( result = await call_api(
"POST", "POST",
"/user/referrals/track", f"/user/{referrer_id}/add_referral",
payload, payload,
) )
if result == "ERROR": if result == "ERROR":
logger.error( logger.error(
f"[start] Ошибка при фиксации реферала: {payload}" f"[start] Ошибка при фиксации реферала через "
f"/user/{referrer_id}/add_referral: referrer={referrer_id}, "
f"invited={user_id}"
) )
await message.answer( await message.answer("Вы вошли по реферальной ссылке.")
"Вы вошли по реферальной ссылке."
)
# 4. В любом случае показываем главное меню # 4. В любом случае показываем главное меню
await message.answer( await message.answer(
@@ -175,8 +168,8 @@ async def start_command(message: Message):
@router.message(Command("referrals")) @router.message(Command("referrals"))
async def referrals_menu_command(message: Message): async def referrals_menu_command(message: Message):
""" """Команда /referrals из бокового меню Telegram.
Команда /referrals из бокового меню Telegram.
Показывает текст реферальной программы. Показывает текст реферальной программы.
""" """
logger.info( logger.info(
@@ -197,9 +190,7 @@ async def referrals_menu_command(message: Message):
@router.callback_query(lambda callback: callback.data == "base") @router.callback_query(lambda callback: callback.data == "base")
async def start_callback_handler(callback: CallbackQuery): async def start_callback_handler(callback: CallbackQuery):
""" """Callback с data="base" — возврат в главное меню."""
Callback с data="base" — возврат в главное меню.
"""
try: try:
user_id = callback.from_user.id user_id = callback.from_user.id
username = callback.from_user.username username = callback.from_user.username

View File

@@ -129,15 +129,15 @@ async def _show_subscriptions_view(
index = max(0, min(index, len(subs) - 1)) index = max(0, min(index, len(subs) - 1))
sub = subs[index] sub = subs[index]
plan_title = _plan_human_title(sub.get("plan")) plan_title = _plan_human_title(sub.get("plan_name"))
expiry_raw = sub.get("expiry_date") end_raw = sub.get("end_date") # Исправил
date_str = "" date_str = ""
days_left = None days_left = None
status_emoji = "🟢" status_emoji = "🟢"
if expiry_raw: if end_raw:
try: try:
dt = datetime.fromisoformat(expiry_raw) dt = datetime.fromisoformat(end_raw)
date_str = dt.strftime("%d.%m.%Y") date_str = dt.strftime("%d.%m.%Y")
now = datetime.now(dt.tzinfo) if dt.tzinfo else datetime.now() now = datetime.now(dt.tzinfo) if dt.tzinfo else datetime.now()
days_left = (dt.date() - now.date()).days days_left = (dt.date() - now.date()).days
@@ -272,19 +272,22 @@ async def cb_sub_cfg(callback: types.CallbackQuery):
await callback.answer() await callback.answer()
return return
if not isinstance(detail, str) or not detail: uri = None
if isinstance(detail, str):
uri = detail.strip()
elif isinstance(detail, list) and detail:
uri = str(detail[0]).strip()
if not uri:
await callback.message.answer( await callback.message.answer(
"Что-то пошло не так при выдаче конфига." "Что-то пошло не так при выдаче конфига."
) )
await callback.answer() await callback.answer()
return return
escaped = escape_markdown_v2(detail)
text = f"Твой конфиг:\n```{escaped}```"
await callback.message.answer( await callback.message.answer(
text, f"Твой конфиг:\n<code>{uri}</code>",
parse_mode=ParseMode.MARKDOWN_V2, parse_mode=ParseMode.HTML,
) )
await callback.answer() await callback.answer()
@@ -310,7 +313,7 @@ async def cb_sub_renew(callback: types.CallbackQuery):
await callback.answer() await callback.answer()
return return
plan_id = target.get("plan") plan_id = target.get("plan_name")
if not plan_id: if not plan_id:
await callback.message.answer("Не удалось определить тариф для продления.") await callback.message.answer("Не удалось определить тариф для продления.")
await callback.answer() await callback.answer()
@@ -319,7 +322,7 @@ async def cb_sub_renew(callback: types.CallbackQuery):
result = await call_api( result = await call_api(
"POST", "POST",
"/subscription/buy", "/subscription/buy",
{"telegram_id": str(callback.from_user.id), "plan_name": plan_id}, {"telegram_id": str(callback.from_user.id), "plan_id": plan_id},
) )
# Ошибки backend (detail) # Ошибки backend (detail)
@@ -472,7 +475,7 @@ async def confirm_callback_handler(callback: types.CallbackQuery):
result = await call_api( result = await call_api(
"POST", "POST",
"/subscription/buy", "/subscription/buy",
{"telegram_id": str(callback.from_user.id), "plan_name": plan_id}, {"telegram_id": str(callback.from_user.id), "plan_id": plan_id},
) )
if result == "ERROR" or not isinstance(result, dict): if result == "ERROR" or not isinstance(result, dict):

View File

@@ -1,452 +1,447 @@
from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder
from aiogram.types import InlineKeyboardButton, KeyboardButton from aiogram.types import InlineKeyboardButton, KeyboardButton
def main_keyboard(): def main_keyboard():
""" """
Главное меню Главное меню
""" """
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="📜 Профиль", text="📜 Профиль",
callback_data="profile", callback_data="profile",
) )
) )
# ------ # ------
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="❔ FAQ ❔", text="❔ FAQ ❔",
callback_data="faq", callback_data="faq",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text=" О нас", text=" О нас",
url="https://www.youtube.com/watch?v=Zirn-CKck-c", url="https://www.youtube.com/watch?v=Zirn-CKck-c",
) )
) )
return builder.as_markup() return builder.as_markup()
def account_keyboard(): def account_keyboard():
""" """
Клавиатура профиля: Клавиатура профиля:
пополнить баланс, история транзакций, назад в главное меню. пополнить баланс, история транзакций, назад в главное меню.
""" """
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🪙 Пополнить баланс", text="🪙 Пополнить баланс",
callback_data="balance", callback_data="balance",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🧾 История транзакций", text="🧾 История транзакций",
callback_data="tranhist", callback_data="tranhist",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🔙 Назад", text="🔙 Назад",
callback_data="base", callback_data="base",
) )
) )
return builder.as_markup() return builder.as_markup()
def balance_keyboard(): def balance_keyboard():
""" """
Экран баланса Экран баланса
""" """
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🪙 Пополнить баланс", text="🪙 Пополнить баланс",
callback_data="popup", callback_data="popup",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🧾 История транзакций", text="🧾 История транзакций",
callback_data="tranhist", callback_data="tranhist",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🔙 Назад", text="🔙 Назад",
callback_data="profile", callback_data="profile",
) )
) )
return builder.as_markup() return builder.as_markup()
def popup_keyboard(): def popup_keyboard():
""" """
Суммы пополнения: 200, 300, 600, 1000 ₽. Суммы пополнения: 200, 300, 600, 1000 ₽.
""" """
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
builder.row( builder.row(
InlineKeyboardButton(text="200 ₽", callback_data="popup:200"), InlineKeyboardButton(text="200 ₽", callback_data="popup:200"),
) )
builder.row( builder.row(
InlineKeyboardButton(text="300 ₽", callback_data="popup:300"), InlineKeyboardButton(text="300 ₽", callback_data="popup:300"),
) )
builder.row( builder.row(
InlineKeyboardButton(text="600 ₽", callback_data="popup:600"), InlineKeyboardButton(text="600 ₽", callback_data="popup:600"),
) )
builder.row( builder.row(
InlineKeyboardButton(text="1000 ₽", callback_data="popup:1000"), InlineKeyboardButton(text="1000 ₽", callback_data="popup:1000"),
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🔙 Назад", text="🔙 Назад",
callback_data="profile", # назад в профиль callback_data="profile", # назад в профиль
) )
) )
return builder.as_markup() return builder.as_markup()
def payment_methods_keyboard(amount: int): def payment_methods_keyboard(amount: int):
""" """
Способы оплаты для выбранной суммы. Способы оплаты для выбранной суммы.
""" """
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="⭐ Telegram Stars", text="⭐ Telegram Stars",
callback_data=f"method_stars_{amount}", callback_data=f"method_stars_{amount}",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="💵 YooKassa", text="💵 СБП",
callback_data=f"method_ykassa_{amount}", callback_data=f"method_ykassa_{amount}",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🪙 CryptoBot", text="🪙 CryptoBot",
callback_data=f"method_crypto_{amount}", callback_data=f"method_crypto_{amount}",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🔙 Назад", text="🔙 Назад",
callback_data="popup", callback_data="popup",
) )
) )
return builder.as_markup() return builder.as_markup()
def ticket_list_keyboard(tickets): def ticket_list_keyboard(tickets):
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
for ticket in tickets: for ticket in tickets:
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text=f"Тикет: {ticket['subject']}", text=f"Тикет: {ticket['subject']}",
callback_data=f"ticket_{ticket['id']}", callback_data=f"ticket_{ticket['id']}",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🔙 Назад", text="🔙 Назад",
callback_data="main_sup", callback_data="main_sup",
) )
) )
return builder.as_markup() return builder.as_markup()
def sup_keyboard(): def sup_keyboard():
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="📝 Создать запрос", text="📝 Создать запрос",
callback_data="make_ticket", callback_data="make_ticket",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="📂 Мои запросы", text="📂 Мои запросы",
callback_data="my_tickets", callback_data="my_tickets",
) )
) )
return builder.as_markup() return builder.as_markup()
def ticket_keyboard(): def ticket_keyboard():
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🔙 Отмена", text="🔙 Отмена",
callback_data="cancel", callback_data="cancel",
) )
) )
return builder.as_markup() return builder.as_markup()
def buy_keyboard(): def buy_keyboard():
""" """
Меню выбора тарифа. Меню выбора тарифа.
""" """
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🐣 Lark Basic", text="🐣 Lark Basic",
callback_data="subs", callback_data="subs",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🦅 Lark Pro", text="🦅 Lark Pro",
callback_data="subs_pro", callback_data="subs_pro",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="👨‍👩‍👧 Lark Family", text="👨‍👩‍👧 Lark Family",
callback_data="subs_family", callback_data="subs_family",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🔙 Назад", text="🔙 Назад",
callback_data="profile", callback_data="profile",
) )
) )
return builder.as_markup() return builder.as_markup()
def tarif_Lark_keyboard(): def tarif_Lark_keyboard():
""" """
Тариф Lark Basic (Standart) Тариф Lark Basic (Standart)
""" """
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🐣 Lark 1 месяц", text="🐣 Lark 1 месяц",
callback_data="Lark:Standart:1", callback_data="Lark:Standart:1",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🐣 Lark 6 месяцев", text="🐣 Lark 6 месяцев",
callback_data="Lark:Standart:6", callback_data="Lark:Standart:6",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🐣 Lark 12 месяцев", text="🐣 Lark 12 месяцев",
callback_data="Lark:Standart:12", callback_data="Lark:Standart:12",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🔙 Назад", text="🔙 Назад",
callback_data="buy_subscription", callback_data="buy_subscription",
) )
) )
return builder.as_markup() return builder.as_markup()
def tarif_Lark_pro_keyboard(): def tarif_Lark_pro_keyboard():
""" """
Тариф Lark Pro Тариф Lark Pro
""" """
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🦅 Lark Pro 1 месяц", text="🦅 Lark Pro 1 месяц",
callback_data="Lark:Pro:1", callback_data="Lark:Pro:1",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🦅 Lark Pro 6 месяцев", text="🦅 Lark Pro 6 месяцев",
callback_data="Lark:Pro:6", callback_data="Lark:Pro:6",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🦅 Lark Pro 12 месяцев", text="🦅 Lark Pro 12 месяцев",
callback_data="Lark:Pro:12", callback_data="Lark:Pro:12",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🔙 Назад", text="🔙 Назад",
callback_data="buy_subscription", callback_data="buy_subscription",
) )
) )
return builder.as_markup() return builder.as_markup()
def tarif_Lark_family_keyboard(): def tarif_Lark_family_keyboard():
""" """
Тариф Lark Family. Тариф Lark Family.
""" """
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="👨‍👩‍👧 Lark Family 1 месяц", text="👨‍👩‍👧 Lark Family 1 месяц",
callback_data="Lark:Family:1", callback_data="Lark:Family:1",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="👨‍👩‍👧 Lark Family 6 месяцев", text="👨‍👩‍👧 Lark Family 6 месяцев",
callback_data="Lark:Family:6", callback_data="Lark:Family:6",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="👨‍👩‍👧 Lark Family 12 месяцев", text="👨‍👩‍👧 Lark Family 12 месяцев",
callback_data="Lark:Family:12", callback_data="Lark:Family:12",
) )
) )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🔙 Назад", text="🔙 Назад",
callback_data="buy_subscription", callback_data="buy_subscription",
) )
) )
return builder.as_markup() return builder.as_markup()
def subscriptions_card_keyboard(sub_id: str, index: int, total: int): def subscriptions_card_keyboard(sub_id: str, index: int, total: int):
""" """
Карточка подписки: Карточка подписки:
навигация, конфиг, продление, новая, назад. навигация, конфиг, назад в главное меню.
""" """
builder = InlineKeyboardBuilder() builder = InlineKeyboardBuilder()
nav = [] # Навигация по подпискам
if index > 0: nav = []
nav.append( if index > 0:
InlineKeyboardButton( nav.append(
text="⬅️", InlineKeyboardButton(
callback_data=f"sub_prev:{index-1}", text="⬅️",
) callback_data=f"sub_prev:{index-1}",
) )
if index < total - 1: )
nav.append( if index < total - 1:
InlineKeyboardButton( nav.append(
text="➡️", InlineKeyboardButton(
callback_data=f"sub_next:{index+1}", text="➡️",
) callback_data=f"sub_next:{index+1}",
) )
if nav: )
builder.row(*nav) if nav:
builder.row(*nav)
builder.row(
InlineKeyboardButton( # Конфиг
text="🔑 Конфиг", builder.row(
callback_data=f"sub_cfg:{sub_id}", InlineKeyboardButton(
), text="🔑 Конфиг",
InlineKeyboardButton( callback_data=f"sub_cfg:{sub_id}",
text="🔁 Продлить", )
callback_data=f"sub_renew:{sub_id}", )
),
) # Назад в главное меню
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text=" Новая", text="🔙 Назад",
callback_data="buy_subscription", callback_data="base", # было "profile" изменил
) )
) )
builder.row(
InlineKeyboardButton( return builder.as_markup()
text="🔙 Назад",
callback_data="profile",
) def guide_keyboard():
) """
return builder.as_markup() Руководство по подключению
"""
builder = InlineKeyboardBuilder()
def guide_keyboard(): builder.row(
""" InlineKeyboardButton(
Руководство по подключению text="📱 iOS / Android",
""" callback_data="mob",
builder = InlineKeyboardBuilder() )
builder.row( )
InlineKeyboardButton( builder.row(
text="📱 iOS / Android", InlineKeyboardButton(
callback_data="mob", text="💻 Windows / macOS",
) callback_data="pc",
) )
builder.row( )
InlineKeyboardButton( builder.row(
text="💻 Windows / macOS", InlineKeyboardButton(
callback_data="pc", text="🔙 Назад",
) callback_data="profile",
) )
builder.row( )
InlineKeyboardButton( return builder.as_markup()
text="🔙 Назад",
callback_data="profile",
) def faq_keyboard():
) """
return builder.as_markup() FAQ
"""
builder = InlineKeyboardBuilder()
def faq_keyboard(): builder.row(
""" InlineKeyboardButton(
FAQ text="🔙 Назад",
""" callback_data="base",
builder = InlineKeyboardBuilder() )
builder.row( )
InlineKeyboardButton( return builder.as_markup()
text="🔙 Назад",
callback_data="base",
) def tranhist_keyboard():
) """
return builder.as_markup() История транзакций
"""
builder = InlineKeyboardBuilder()
def tranhist_keyboard(): builder.row(
""" InlineKeyboardButton(
История транзакций text="🔙 Назад",
""" callback_data="profile",
builder = InlineKeyboardBuilder() )
builder.row( )
InlineKeyboardButton( return builder.as_markup()
text="🔙 Назад",
callback_data="profile",
) def tarif_confirm_keyboard(name: str, amount: int, classif: str):
) """
return builder.as_markup() Подтверждение покупки тарифа
"""
builder = InlineKeyboardBuilder()
def tarif_confirm_keyboard(name: str, amount: int, classif: str): builder.row(
""" InlineKeyboardButton(
Подтверждение покупки тарифа text=" Подтвердить",
""" callback_data=f"confirm:{name}_{classif}_{amount}",
builder = InlineKeyboardBuilder() )
builder.row( )
InlineKeyboardButton( builder.row(
text="✅ Подтвердить", InlineKeyboardButton(
callback_data=f"confirm:{name}_{classif}_{amount}", text="🔙 Отменить",
) callback_data="buy_subscription",
) )
builder.row( )
InlineKeyboardButton( return builder.as_markup()
text="🔙 Отменить",
callback_data="buy_subscription",
) def confirm_popup_keyboard():
) """
return builder.as_markup() Подтверждение пополнения.
"""
builder = InlineKeyboardBuilder()
def confirm_popup_keyboard(): builder.row(
""" InlineKeyboardButton(
Подтверждение пополнения. text="✅ Готово, вернуться в профиль",
""" callback_data="profile",
builder = InlineKeyboardBuilder() )
builder.row( )
InlineKeyboardButton( return builder.as_markup()
text="✅ Готово, вернуться в профиль",
callback_data="profile",
)
)
return builder.as_markup()