diff --git a/handlers/admin/stats/stats_handler.py b/handlers/admin/stats/stats_handler.py
index 5ee43ab4..b2efe1df 100644
--- a/handlers/admin/stats/stats_handler.py
+++ b/handlers/admin/stats/stats_handler.py
@@ -121,7 +121,7 @@ async def handle_stats(callback_query: CallbackQuery, session: Any):
f"├ 📆 За неделю: {total_payments_week} ₽\n"
f"├ 📆 За месяц: {total_payments_month} ₽\n"
f"└ 🏦 Всего: {total_payments_all_time} ₽\n\n"
- f"🔥 Горящие лиды: {hot_leads_count} (платили, но не активировали ключи)\n\n"
+ f"🔥 Горящие лиды: {hot_leads_count} (платили, но не продлили)\n\n"
f"⏱️ Последнее обновление: {update_time}"
)
diff --git a/handlers/buttons.py b/handlers/buttons.py
index c0032a80..7bd83484 100644
--- a/handlers/buttons.py
+++ b/handlers/buttons.py
@@ -45,14 +45,16 @@ CANCEL = "❌ Отмена"
DOWNLOAD_IOS_BUTTON = "🍏 Скачать iOS"
DOWNLOAD_ANDROID_BUTTON = "🤖 Скачать Android"
+DOWNLOAD_MACOS_BUTTON = "🍏 Скачать macOS"
+DOWNLOAD_PC_BUTTON = "💻 Скачать Windows"
IMPORT_IOS = "🍏 Подключить"
IMPORT_ANDROID = "🤖 Подключить"
PC_BUTTON = "💻 Компьютеры"
TV_BUTTON = "📺 Андроид TV"
CONNECT_PHONE = "📱 Подключить телефон"
CONNECT_DEVICE = "📲 Подключить устройство"
-CONNECT_WINDOWS_BUTTON = "💻 Подключить Windows"
-CONNECT_MACOS_BUTTON = "💻 Подключить MacOS"
+CONNECT_WINDOWS_BUTTON = "💻 Подключить"
+CONNECT_MACOS_BUTTON = "🍏 Подключить"
ALIAS = "✏️"
UNFREEZE = "🟢 Разморозить подписку"
FREEZE = "🛑 Заморозить подписку"
@@ -64,6 +66,8 @@ QR = "📷 Показать QR-код"
IPHONE = "🍏 Айфон"
ANDROID = "🤖 Андроид"
PC = "💻 Компьютер"
+PC_PC = "💻 Windows"
+PC_MACOS = "🍏 macOS"
TV = "📺 Телевизор"
ROUTER = "📶 Роутер"
MANUAL_INSTRUCTIONS = "📖 Ручная установка"
diff --git a/handlers/instructions/instructions.py b/handlers/instructions/instructions.py
index f436d7fc..22545e69 100644
--- a/handlers/instructions/instructions.py
+++ b/handlers/instructions/instructions.py
@@ -1,5 +1,4 @@
import os
-
from typing import Any
from aiogram import F, Router
@@ -10,20 +9,32 @@ from aiogram.types import (
)
from aiogram.utils.keyboard import InlineKeyboardBuilder
-from config import CONNECT_MACOS, CONNECT_WINDOWS, SUPPORT_CHAT_URL
+from config import (
+ CONNECT_MACOS,
+ CONNECT_WINDOWS,
+ DOWNLOAD_MACOS,
+ DOWNLOAD_PC,
+ SUPPORT_CHAT_URL,
+)
from database import get_key_details
from handlers.buttons import (
BACK,
CONNECT_MACOS_BUTTON,
CONNECT_WINDOWS_BUTTON,
+ DOWNLOAD_MACOS_BUTTON,
+ DOWNLOAD_PC_BUTTON,
MAIN_MENU,
+ PC_MACOS,
+ PC_PC,
SUPPORT,
TV_CONTINUE,
TV_INSTRUCTIONS,
)
from handlers.texts import (
+ CHOOSE_DEVICE_TEXT,
CONNECT_TV_TEXT,
INSTRUCTIONS,
+ INSTRUCTION_MACOS,
INSTRUCTION_PC,
KEY_MESSAGE,
SUBSCRIPTION_DETAILS_TEXT,
@@ -72,16 +83,54 @@ async def process_connect_pc(callback_query: CallbackQuery, session: Any):
)
return
+ builder = InlineKeyboardBuilder()
+ builder.row(InlineKeyboardButton(text=PC_PC, callback_data=f"windows_menu|{key_name}"))
+ builder.row(InlineKeyboardButton(text=PC_MACOS, callback_data=f"macos_menu|{key_name}"))
+ builder.row(InlineKeyboardButton(text=BACK, callback_data=f"view_key|{key_name}"))
+
+ await edit_or_send_message(
+ target_message=callback_query.message,
+ text=CHOOSE_DEVICE_TEXT,
+ reply_markup=builder.as_markup(),
+ media_path=None,
+ )
+
+
+@router.callback_query(F.data.startswith("windows_menu|"))
+async def process_windows_menu(callback_query: CallbackQuery, session: Any):
+ key_name = callback_query.data.split("|")[1]
+ record = await get_key_details(key_name, session)
key = record["key"]
key_message_text = KEY_MESSAGE.format(key)
instruction_message = f"{key_message_text}{INSTRUCTION_PC}"
builder = InlineKeyboardBuilder()
+ builder.row(InlineKeyboardButton(text=DOWNLOAD_PC_BUTTON, url=DOWNLOAD_PC))
builder.row(InlineKeyboardButton(text=CONNECT_WINDOWS_BUTTON, url=f"{CONNECT_WINDOWS}{key}"))
+ builder.row(InlineKeyboardButton(text=SUPPORT, url=SUPPORT_CHAT_URL))
+ builder.row(InlineKeyboardButton(text=BACK, callback_data=f"connect_pc|{key_name}"))
+
+ await edit_or_send_message(
+ target_message=callback_query.message,
+ text=instruction_message,
+ reply_markup=builder.as_markup(),
+ media_path=None,
+ )
+
+
+@router.callback_query(F.data.startswith("macos_menu|"))
+async def process_macos_menu(callback_query: CallbackQuery, session: Any):
+ key_name = callback_query.data.split("|")[1]
+ record = await get_key_details(key_name, session)
+ key = record["key"]
+ key_message_text = KEY_MESSAGE.format(key)
+ instruction_message = f"{key_message_text}{INSTRUCTION_MACOS}"
+
+ builder = InlineKeyboardBuilder()
+ builder.row(InlineKeyboardButton(text=DOWNLOAD_MACOS_BUTTON, url=DOWNLOAD_MACOS))
builder.row(InlineKeyboardButton(text=CONNECT_MACOS_BUTTON, url=f"{CONNECT_MACOS}{key}"))
builder.row(InlineKeyboardButton(text=SUPPORT, url=SUPPORT_CHAT_URL))
- builder.row(InlineKeyboardButton(text=BACK, callback_data=f"view_key|{key_name}"))
- builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
+ builder.row(InlineKeyboardButton(text=BACK, callback_data=f"connect_pc|{key_name}"))
await edit_or_send_message(
target_message=callback_query.message,
@@ -123,5 +172,8 @@ async def process_continue_tv(callback_query: CallbackQuery, session: Any):
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
await edit_or_send_message(
- target_message=callback_query.message, text=message_text, reply_markup=builder.as_markup(), media_path=None
+ target_message=callback_query.message,
+ text=message_text,
+ reply_markup=builder.as_markup(),
+ media_path=None,
)
diff --git a/handlers/keys/keys.py b/handlers/keys/keys.py
index f9d804de..2e85766f 100644
--- a/handlers/keys/keys.py
+++ b/handlers/keys/keys.py
@@ -87,6 +87,7 @@ from handlers.payments.robokassa_pay import handle_custom_amount_input
from handlers.payments.yookassa_pay import process_custom_amount_input
from handlers.texts import (
ANDROID_DESCRIPTION_TEMPLATE,
+ CHOOSE_DEVICE_TEXT,
DELETE_KEY_CONFIRM_MSG,
DISCOUNTS,
FREEZE_SUBSCRIPTION_CONFIRM_MSG,
@@ -420,7 +421,7 @@ async def handle_connect_device(callback_query: CallbackQuery):
await edit_or_send_message(
target_message=callback_query.message,
- text="📲 Выберите устройство, которое хотите подключить:",
+ text=CHOOSE_DEVICE_TEXT,
reply_markup=builder.as_markup(),
media_path=None,
)
diff --git a/handlers/profile.py b/handlers/profile.py
index 85b1458d..82fe9ea3 100644
--- a/handlers/profile.py
+++ b/handlers/profile.py
@@ -294,6 +294,28 @@ async def inline_referral_handler(inline_query: InlineQuery):
async def top_referrals_handler(callback_query: CallbackQuery):
conn = await asyncpg.connect(DATABASE_URL)
try:
+ user_referral_count = await conn.fetchval(
+ "SELECT COUNT(*) FROM referrals WHERE referrer_tg_id = $1",
+ callback_query.from_user.id
+ ) or 0
+
+ personal_block = "Твоё место в рейтинге:\n"
+ if user_referral_count > 0:
+ user_position = await conn.fetchval(
+ """
+ SELECT COUNT(*) + 1 FROM (
+ SELECT COUNT(*) as cnt
+ FROM referrals
+ GROUP BY referrer_tg_id
+ HAVING COUNT(*) > $1
+ ) AS better_users
+ """,
+ user_referral_count
+ )
+ personal_block += f"{user_position}. {callback_query.from_user.id} - {user_referral_count} чел."
+ else:
+ personal_block += "Ты еще не приглашал пользователей в проект."
+
top_referrals = await conn.fetch(
"""
SELECT referrer_tg_id, COUNT(*) as referral_count
@@ -306,14 +328,13 @@ async def top_referrals_handler(callback_query: CallbackQuery):
is_admin = callback_query.from_user.id in ADMIN_ID
rows = ""
-
for i, row in enumerate(top_referrals, 1):
tg_id = str(row["referrer_tg_id"])
count = row["referral_count"]
display_id = tg_id if is_admin else f"{tg_id[:5]}*****"
rows += f"{i}. {display_id} - {count} чел.\n"
- text = TOP_REFERRALS_TEXT.format(rows=rows)
+ text = TOP_REFERRALS_TEXT.format(personal_block=personal_block, rows=rows)
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text=BACK, callback_data="invite"))