2 Commits

Author SHA1 Message Date
unknown
1db24ace53 fixes 2025-12-06 19:41:13 +03:00
d3e47a662f Временные изменения 2025-12-05 18:45:25 +03:00
6 changed files with 1184 additions and 1091 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,63 +1,123 @@
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()
logger = logging.getLogger(__name__) router = Router()
logger = logging.getLogger(__name__)
async def _build_referral_text(bot, user_id: int) -> str:
me = await bot.get_me() async def call_api(method: str, endpoint: str, data=None, base_url: str = BASE_URL_FASTAPI):
bot_username = me.username or "LarkVPN_bot" """
Универсальный HTTP-запрос к FastAPI для рефералок.
link = f"https://t.me/{bot_username}?start=ref_{user_id}"
Ожидаем:
invited_count = "" GET /user/{telegram_id}/referrals -> {
try: "invited_count": int
data = await call_api("GET", f"/user/{user_id}/referrals") }
if isinstance(data, dict): """
invited_count = str(data.get("invited_count", 0)) url = f"{base_url}{endpoint}"
except Exception as e: logger.info(f"[referrals] Запрос: {method} {url} с данными {data}")
logger.exception(
f"Ошибка при получении количества рефералов для {user_id}: {e}" try:
) async with aiohttp.ClientSession() as session:
async with session.request(
text = ( method,
"👥 <b>Реферальная программа</b>\n\n" url,
"Зови друзей в Lark VPN и получай бонусы на баланс.\n\n" json=data,
f"🔗 Твоя ссылка:\n<code>{link}</code>\n\n" headers={"Content-Type": "application/json"},
f"👤 Приглашено: {invited_count}\n\n" ) as response:
) logger.info(
return text f"[referrals] Ответ от {url}: статус {response.status}"
)
@router.message(Command("referrals")) if response.status in {200, 201}:
async def referrals_command(message: types.Message): result = await response.json()
logger.info(f"Получена команда /referrals от {message.from_user.id}") logger.debug(f"[referrals] Ответ JSON: {result}")
try: return result
text = await _build_referral_text(message.bot, message.from_user.id) if response.status == 404:
await message.answer(text, parse_mode=ParseMode.HTML) logger.debug("[referrals] 404, возвращаю None")
except Exception as e: return None
logger.exception(f"Ошибка в обработчике /referrals: {e}")
await message.answer("Произошла ошибка. Попробуй позже.") logger.error(
f"[referrals] Ошибка в запросе: статус {response.status}, "
f"причина {response.reason}"
@router.callback_query(lambda callback: callback.data == "referral") )
async def referrals_callback(callback: types.CallbackQuery): return "ERROR"
try: except Exception as e:
text = await _build_referral_text( logger.exception(f"[referrals] Исключение при запросе к {url}: {e}")
callback.message.bot, return "ERROR"
callback.from_user.id,
)
await callback.message.edit_text( async def _build_referral_text(bot, user_id: int) -> str:
text, """
parse_mode=ParseMode.HTML, Текст реферальной программы + количество приглашённых.
) """
except Exception as e: me = await bot.get_me()
logger.exception(f"Ошибка в обработчике callback 'referral': {e}") bot_username = me.username or "LarkVPN_bot"
await callback.message.answer("Произошла ошибка. Попробуй позже.")
finally: link = f"https://t.me/{bot_username}?start=ref_{user_id}"
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,11 +1,10 @@
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
@@ -14,39 +13,52 @@ router = Router()
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
async def call_api(method: str, endpoint: str, data: dict | None = None): async def call_api(method: str, endpoint: str, data=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"API {method} {url} data={data}") logger.info(f"[start] Запрос: {method} {url} с данными {data}")
try: try:
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.request(method, url, json=data) as resp: async with session.request(method, url, json=data) as response:
logger.info(f"API response {resp.status} {resp.reason}") logger.info(
if resp.status in {200, 201}: f"[start] Ответ от {url}: статус {response.status}"
return await resp.json() )
if resp.status in {400, 404}:
try: if response.status in {200, 201}:
return await resp.json() result = await response.json()
except Exception: logger.debug(f"[start] Ответ JSON: {result}")
return None return result
if response.status == 404:
logger.debug("[start] Получен 404, возвращаю None")
return None
logger.error( logger.error(
f"Unexpected status {resp.status}: {await resp.text()}" f"[start] Ошибка в запросе: статус {response.status}, "
f"причина {response.reason}"
) )
return "ERROR" return "ERROR"
except Exception as e: except Exception as e:
logger.exception(f"API exception {url}: {e}") logger.exception(f"[start] Исключение при запросе к {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
@@ -72,13 +84,8 @@ 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
@@ -133,24 +140,24 @@ async def start_command(message: Message):
# 3.3. Новый пользователь + чужая рефералка → регистрируем реферал # 3.3. Новый пользователь + чужая рефералка → регистрируем реферал
else: else:
payload = { payload = {
"invited_id": user_id, "referrer_id": referrer_id,
"telegram_id": user_id,
} }
logger.info( logger.info(
f"[start] Фиксирую реферала в бекенде: " f"[start] Фиксирую реферала в бекенде: {payload}"
f"referrer_id={referrer_id}, payload={payload}"
) )
result = await call_api( result = await call_api(
"POST", "POST",
f"/user/{referrer_id}/add_referral", "/user/referrals/track",
payload, payload,
) )
if result == "ERROR": if result == "ERROR":
logger.error( logger.error(
f"[start] Ошибка при фиксации реферала через " f"[start] Ошибка при фиксации реферала: {payload}"
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(
@@ -168,8 +175,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(
@@ -190,7 +197,9 @@ 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_name")) plan_title = _plan_human_title(sub.get("plan"))
end_raw = sub.get("end_date") # Исправил expiry_raw = sub.get("expiry_date")
date_str = "" date_str = ""
days_left = None days_left = None
status_emoji = "🟢" status_emoji = "🟢"
if end_raw: if expiry_raw:
try: try:
dt = datetime.fromisoformat(end_raw) dt = datetime.fromisoformat(expiry_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,22 +272,19 @@ async def cb_sub_cfg(callback: types.CallbackQuery):
await callback.answer() await callback.answer()
return return
uri = None if not isinstance(detail, str) or not detail:
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(
f"Твой конфиг:\n<code>{uri}</code>", text,
parse_mode=ParseMode.HTML, parse_mode=ParseMode.MARKDOWN_V2,
) )
await callback.answer() await callback.answer()
@@ -313,7 +310,7 @@ async def cb_sub_renew(callback: types.CallbackQuery):
await callback.answer() await callback.answer()
return return
plan_id = target.get("plan_name") plan_id = target.get("plan")
if not plan_id: if not plan_id:
await callback.message.answer("Не удалось определить тариф для продления.") await callback.message.answer("Не удалось определить тариф для продления.")
await callback.answer() await callback.answer()
@@ -322,7 +319,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_id": plan_id}, {"telegram_id": str(callback.from_user.id), "plan_name": plan_id},
) )
# Ошибки backend (detail) # Ошибки backend (detail)
@@ -475,7 +472,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_id": plan_id}, {"telegram_id": str(callback.from_user.id), "plan_name": plan_id},
) )
if result == "ERROR" or not isinstance(result, dict): if result == "ERROR" or not isinstance(result, dict):

View File

@@ -1,447 +1,452 @@
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="💵 СБП", text="💵 YooKassa",
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 = []
nav = [] if index > 0:
if index > 0: nav.append(
nav.append( InlineKeyboardButton(
InlineKeyboardButton( text="⬅️",
text="⬅️", callback_data=f"sub_prev:{index-1}",
callback_data=f"sub_prev:{index-1}", )
) )
) if index < total - 1:
if index < total - 1: nav.append(
nav.append( InlineKeyboardButton(
InlineKeyboardButton( text="➡️",
text="➡️", callback_data=f"sub_next:{index+1}",
callback_data=f"sub_next:{index+1}", )
) )
) if nav:
if nav: builder.row(*nav)
builder.row(*nav)
builder.row(
# Конфиг InlineKeyboardButton(
builder.row( text="🔑 Конфиг",
InlineKeyboardButton( callback_data=f"sub_cfg:{sub_id}",
text="🔑 Конфиг", ),
callback_data=f"sub_cfg:{sub_id}", InlineKeyboardButton(
) text="🔁 Продлить",
) callback_data=f"sub_renew:{sub_id}",
),
# Назад в главное меню )
builder.row( builder.row(
InlineKeyboardButton( InlineKeyboardButton(
text="🔙 Назад", text=" Новая",
callback_data="base", # было "profile" изменил callback_data="buy_subscription",
) )
) )
builder.row(
return builder.as_markup() InlineKeyboardButton(
text="🔙 Назад",
callback_data="profile",
def guide_keyboard(): )
""" )
Руководство по подключению return builder.as_markup()
"""
builder = InlineKeyboardBuilder()
builder.row( def guide_keyboard():
InlineKeyboardButton( """
text="📱 iOS / Android", Руководство по подключению
callback_data="mob", """
) builder = InlineKeyboardBuilder()
) builder.row(
builder.row( InlineKeyboardButton(
InlineKeyboardButton( text="📱 iOS / Android",
text="💻 Windows / macOS", callback_data="mob",
callback_data="pc", )
) )
) builder.row(
builder.row( InlineKeyboardButton(
InlineKeyboardButton( text="💻 Windows / macOS",
text="🔙 Назад", callback_data="pc",
callback_data="profile", )
) )
) builder.row(
return builder.as_markup() InlineKeyboardButton(
text="🔙 Назад",
callback_data="profile",
def faq_keyboard(): )
""" )
FAQ return builder.as_markup()
"""
builder = InlineKeyboardBuilder()
builder.row( def faq_keyboard():
InlineKeyboardButton( """
text="🔙 Назад", FAQ
callback_data="base", """
) builder = InlineKeyboardBuilder()
) builder.row(
return builder.as_markup() InlineKeyboardButton(
text="🔙 Назад",
callback_data="base",
def tranhist_keyboard(): )
""" )
История транзакций return builder.as_markup()
"""
builder = InlineKeyboardBuilder()
builder.row( def tranhist_keyboard():
InlineKeyboardButton( """
text="🔙 Назад", История транзакций
callback_data="profile", """
) builder = InlineKeyboardBuilder()
) builder.row(
return builder.as_markup() InlineKeyboardButton(
text="🔙 Назад",
callback_data="profile",
def tarif_confirm_keyboard(name: str, amount: int, classif: str): )
""" )
Подтверждение покупки тарифа return builder.as_markup()
"""
builder = InlineKeyboardBuilder()
builder.row( def tarif_confirm_keyboard(name: str, amount: int, classif: str):
InlineKeyboardButton( """
text=" Подтвердить", Подтверждение покупки тарифа
callback_data=f"confirm:{name}_{classif}_{amount}", """
) builder = InlineKeyboardBuilder()
) builder.row(
builder.row( InlineKeyboardButton(
InlineKeyboardButton( text="✅ Подтвердить",
text="🔙 Отменить", callback_data=f"confirm:{name}_{classif}_{amount}",
callback_data="buy_subscription", )
) )
) builder.row(
return builder.as_markup() InlineKeyboardButton(
text="🔙 Отменить",
callback_data="buy_subscription",
def confirm_popup_keyboard(): )
""" )
Подтверждение пополнения. return builder.as_markup()
"""
builder = InlineKeyboardBuilder()
builder.row( def confirm_popup_keyboard():
InlineKeyboardButton( """
text="✅ Готово, вернуться в профиль", Подтверждение пополнения.
callback_data="profile", """
) builder = InlineKeyboardBuilder()
) builder.row(
return builder.as_markup() InlineKeyboardButton(
text="✅ Готово, вернуться в профиль",
callback_data="profile",
)
)
return builder.as_markup()