TV/Send_message/custom_refferal_level/buttons

This commit is contained in:
Vladless
2024-12-28 22:22:56 +03:00
parent 79602d593b
commit d2fc1eb256
13 changed files with 3293 additions and 2279 deletions
+14 -13
View File
@@ -594,14 +594,11 @@ async def handle_referral_on_balance_update(tg_id: int, amount: float):
Обработка многоуровневой реферальной системы при обновлении баланса пользователя.
Метод анализирует цепочку рефералов для указанного пользователя и начисляет
бонусы рефереерам на разных уровнях согласно настроенным процентам.
бонусы реферерам на разных уровнях согласно настроенным процентам.
Args:
tg_id (int): Идентификатор Telegram пользователя, пополнившего баланс
amount (float): Сумма пополнения баланса
Raises:
Exception: В случае ошибки при работе с базой данных
"""
conn = None
try:
@@ -609,8 +606,11 @@ async def handle_referral_on_balance_update(tg_id: int, amount: float):
logger.info(f"Начало обработки реферальной системы для пользователя {tg_id}")
MAX_REFERRAL_LEVELS = len(REFERRAL_BONUS_PERCENTAGES.keys())
visited_tg_ids = set()
if MAX_REFERRAL_LEVELS == 0:
logger.warning("Реферальные бонусы отключены.")
return
visited_tg_ids = set()
current_tg_id = tg_id
referral_chain = []
@@ -695,8 +695,10 @@ async def get_referral_stats(referrer_tg_id: int):
)
logger.debug(f"Получено количество активных рефералов: {active_referrals}")
MAX_REFERRAL_LEVELS = len(REFERRAL_BONUS_PERCENTAGES.keys())
referrals_by_level_records = await conn.fetch(
"""
f"""
WITH RECURSIVE referral_levels AS (
SELECT referred_tg_id, referrer_tg_id, 1 AS level
FROM referrals
@@ -707,7 +709,7 @@ async def get_referral_stats(referrer_tg_id: int):
SELECT r.referred_tg_id, r.referrer_tg_id, rl.level + 1
FROM referrals r
JOIN referral_levels rl ON r.referrer_tg_id = rl.referred_tg_id
WHERE rl.level < 5
WHERE rl.level < {MAX_REFERRAL_LEVELS}
)
SELECT level,
COUNT(*) AS level_count,
@@ -730,7 +732,7 @@ async def get_referral_stats(referrer_tg_id: int):
logger.debug(f"Получена статистика рефералов по уровням: {referrals_by_level}")
total_referral_bonus = await conn.fetchval(
"""
f"""
WITH RECURSIVE referral_levels AS (
SELECT
referred_tg_id,
@@ -747,13 +749,11 @@ async def get_referral_stats(referrer_tg_id: int):
rl.level + 1
FROM referrals r
JOIN referral_levels rl ON r.referrer_tg_id = rl.referred_tg_id
WHERE rl.level < 5
WHERE rl.level < {MAX_REFERRAL_LEVELS}
)
SELECT
SUM(p.amount * CASE
WHEN rl.level = 1 THEN 0.25
WHEN rl.level = 2 THEN 0.10
WHEN rl.level = 3 THEN 0.05
{" ".join([f"WHEN rl.level = {level} THEN {REFERRAL_BONUS_PERCENTAGES[level]}" for level in REFERRAL_BONUS_PERCENTAGES])}
ELSE 0
END) AS total_bonus
FROM referral_levels rl
@@ -762,6 +762,8 @@ async def get_referral_stats(referrer_tg_id: int):
""",
referrer_tg_id,
)
total_referral_bonus = total_referral_bonus or 0
logger.debug(
f"Получена общая сумма бонусов от рефералов: {total_referral_bonus}"
)
@@ -784,7 +786,6 @@ async def get_referral_stats(referrer_tg_id: int):
logger.info("Закрытие подключения к базе данных")
async def update_key_expiry(client_id: str, new_expiry_time: int):
"""
Обновление времени истечения ключа для указанного клиента.
+28 -3
View File
@@ -34,6 +34,8 @@ async def handle_admin_callback_query(callback_query: CallbackQuery, state: FSMC
async def handle_admin_message(message: types.Message, state: FSMContext):
await state.clear()
BOT_VERSION = "3.2.3-beta" # Укажите текущую версию бота
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(
@@ -58,14 +60,37 @@ async def handle_admin_message(message: types.Message, state: FSMContext):
builder.row(
InlineKeyboardButton(text="📢 Массовая рассылка", callback_data="send_to_alls")
)
builder.row(
InlineKeyboardButton(
text="🤖 Управление Ботом", callback_data="bot_management"
)
)
builder.row(
InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile")
)
await message.answer(
f"🤖 Панель администратора\n\nВерсия бота: <b>{BOT_VERSION}</b>",
reply_markup=builder.as_markup(),
parse_mode="HTML"
)
@router.callback_query(F.data == "bot_management")
async def handle_bot_management(callback_query: types.CallbackQuery):
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text="💾 Создать резервную копию", callback_data="backups")
)
builder.row(
InlineKeyboardButton(text="🔄 Перезагрузить бота", callback_data="restart_bot")
)
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
await message.answer("🤖 Панель администратора", reply_markup=builder.as_markup())
builder.row(
InlineKeyboardButton(text="⬅️ Назад", callback_data="admin")
)
await callback_query.message.answer(
"🤖 Управление ботом",
reply_markup=builder.as_markup(),
)
@router.callback_query(F.data == "user_stats", IsAdminFilter())
@@ -163,7 +188,7 @@ async def export_users_csv(callback_query: CallbackQuery, session: Any):
)
return
csv_data = "tg_id,username,first_name,last_name,language_code,is_bot,balance,trial\n" # Заголовки CSV
csv_data = "tg_id,username,first_name,last_name,language_code,is_bot,balance,trial\n"
for user in users:
csv_data += f"{user['tg_id']},{user['username']},{user['first_name']},{user['last_name']},{user['language_code']},{user['is_bot']},{user['balance']},{user['trial']}\n"
+43 -1
View File
@@ -2,7 +2,7 @@ import asyncio
from datetime import datetime
from typing import Any
from aiogram import F, Router, types
from aiogram import Bot, F, Router, types
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup
@@ -29,6 +29,7 @@ class UserEditorState(StatesGroup):
waiting_for_new_balance = State()
waiting_for_key_name = State()
waiting_for_expiry_time = State()
waiting_for_message_text = State()
@router.callback_query(F.data == "search_by_tg_id", IsAdminFilter())
@@ -114,6 +115,12 @@ async def handle_username_input(
)
)
builder.row(InlineKeyboardButton(text="❌ Удалить клиента", callback_data=f"confirm_delete_user_{tg_id}"))
builder.row(
InlineKeyboardButton(
text="✉️ Отправить сообщение",
callback_data=f"send_message_{tg_id}"
)
)
builder.row(InlineKeyboardButton(text="🔙 Назад", callback_data="user_editor"))
user_info = (
@@ -128,6 +135,35 @@ async def handle_username_input(
await state.set_state(UserEditorState.displaying_user_info)
@router.callback_query(F.data.startswith("send_message_"))
async def handle_send_message(callback_query: types.CallbackQuery, state: FSMContext):
tg_id = callback_query.data.split("_")[2]
await state.update_data(target_tg_id=tg_id)
await callback_query.message.answer(
"✉️ Введите текст сообщения, которое вы хотите отправить пользователю."
)
await state.set_state(UserEditorState.waiting_for_message_text)
@router.message(UserEditorState.waiting_for_message_text, IsAdminFilter())
async def process_send_message(message: types.Message, state: FSMContext, bot: Bot):
data = await state.get_data()
target_tg_id = data.get("target_tg_id")
if not target_tg_id:
await message.answer("🚫 Ошибка: ID пользователя не найден.")
await state.clear()
return
try:
await bot.send_message(chat_id=target_tg_id, text=message.text)
await message.answer("✅ Сообщение успешно отправлено.")
except Exception as e:
await message.answer(f"❌ Не удалось отправить сообщение: {e}")
await state.clear()
@router.message(UserEditorState.waiting_for_tg_id, F.text.isdigit(), IsAdminFilter())
async def handle_tg_id_input(message: types.Message, state: FSMContext, session: Any):
tg_id = int(message.text)
@@ -172,6 +208,12 @@ async def handle_tg_id_input(message: types.Message, state: FSMContext, session:
callback_data=f"restore_trial_{tg_id}",
)
)
builder.row(
InlineKeyboardButton(
text="✉️ Отправить сообщение",
callback_data=f"send_message_{tg_id}"
)
)
builder.row(InlineKeyboardButton(text="🔙 Назад", callback_data="user_editor"))
+1 -1
View File
@@ -2,4 +2,4 @@ GIFT = "🎁 Подарить подписку"
MY_GIFTS = "🎁 Мои подарки"
PROFILE = "👤 Личный кабинет"
BACK = "🔙 Назад"
GIFTS_ABOUT = "<b>Дарите подарки и следите, чтобы они дошли до адресата! 🎄</b>"
GIFTS_ABOUT = "<b>Дарите подарки и следите, чтобы они дошли до адресата! 🎄</b>"
+8
View File
@@ -0,0 +1,8 @@
ADD_SUB = " Устройство"
MY_SUBS = "📱 Мои устройства"
PAYMENT = "💳 Пополнить баланс"
INVITE = "👥 Пригласить"
GIFTS = "🎁 Подарить"
TARRIFS = "💡 Тарифы"
INSTRUCTIONS = "📘 Инструкции"
MAIN_MENU = "⬅️ Главное меню"
+1 -1
View File
@@ -1,3 +1,3 @@
PAY = "Пополнить"
BACK = "⬅️ Назад"
CUSTOM_SUM = "💰 Ввести свою сумму"
CUSTOM_SUM = "💰 Ввести свою сумму"
+69 -2
View File
@@ -1,12 +1,13 @@
import os
from typing import Any
import asyncpg
from aiogram import F, Router, types
from aiogram.types import BufferedInputFile, InlineKeyboardButton
from aiogram.utils.keyboard import InlineKeyboardBuilder
from config import CONNECT_MACOS, CONNECT_WINDOWS, SUPPORT_CHAT_URL
from handlers.texts import INSTRUCTION_PC, INSTRUCTIONS, KEY_MESSAGE
from config import CONNECT_MACOS, CONNECT_WINDOWS, DATABASE_URL, SUPPORT_CHAT_URL
from handlers.texts import CONNECT_TV_TEXT, INSTRUCTION_PC, INSTRUCTIONS, KEY_MESSAGE, SUBSCRIPTION_DETAILS_TEXT
router = Router()
@@ -87,3 +88,69 @@ async def process_connect_pc(callback_query: types.CallbackQuery, session: Any):
parse_mode="HTML",
disable_web_page_preview=True,
)
@router.callback_query(F.data.startswith("connect_tv|"))
async def process_connect_tv(callback_query: types.CallbackQuery):
key_name = callback_query.data.split("|")[1]
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(
text="▶ Продолжить", callback_data=f"continue_tv|{key_name}"
)
)
builder.row(
InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile")
)
await callback_query.message.answer(
text=CONNECT_TV_TEXT,
reply_markup=builder.as_markup(),
parse_mode="HTML"
)
@router.callback_query(F.data.startswith("continue_tv|"))
async def process_continue_tv(callback_query: types.CallbackQuery):
key_name = callback_query.data.split("|")[1]
tg_id = callback_query.from_user.id
print(f"tg_id: {tg_id}, key_name: {key_name}") # Отладочный вывод
conn = await asyncpg.connect(DATABASE_URL)
try:
record = await conn.fetchrow(
"""
SELECT k.key
FROM keys k
WHERE k.tg_id = $1 AND k.email = $2
""",
tg_id,
key_name,
)
print(f"Query result: {record}") # Отладочный вывод результата
finally:
await conn.close()
subscription_link = record['key']
message_text = SUBSCRIPTION_DETAILS_TEXT.format(subscription_link=subscription_link)
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(
text="📖 Полная инструкция", url="https://vpn4tv.com/quick-guide.html"
)
)
builder.row(
InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile")
)
await callback_query.message.answer(
text=message_text,
reply_markup=builder.as_markup(),
parse_mode="HTML"
)
+4 -1
View File
@@ -208,7 +208,10 @@ async def process_callback_view_key(callback_query: types.CallbackQuery, session
builder.row(
InlineKeyboardButton(
text="💻 Windows/Linux", callback_data=f"connect_pc|{key_name}"
text="💻 Компьютеры", callback_data=f"connect_pc|{key_name}"
),
InlineKeyboardButton(
text="📺 Андроид TV", callback_data=f"connect_tv|{key_name}"
)
)
File diff suppressed because it is too large Load Diff
+2295 -1478
View File
File diff suppressed because it is too large Load Diff
+9 -8
View File
@@ -7,6 +7,7 @@ from aiogram.utils.keyboard import InlineKeyboardBuilder
from config import NEWS_MESSAGE, RENEWAL_PLANS
from database import get_balance, get_key_count, get_referral_stats
from handlers.buttons.profile import ADD_SUB, GIFTS, INSTRUCTIONS, INVITE, MAIN_MENU, MY_SUBS, PAYMENT, TARRIFS
from handlers.texts import get_referral_link, invite_message_send, profile_message_send
router = Router()
@@ -41,29 +42,29 @@ async def process_callback_view_profile(
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text=" Устройство", callback_data="create_key"),
InlineKeyboardButton(text="📱 Мои устройства", callback_data="view_keys"),
InlineKeyboardButton(text=ADD_SUB, callback_data="create_key"),
InlineKeyboardButton(text=MY_SUBS, callback_data="view_keys"),
)
builder.row(
InlineKeyboardButton(
text="💳 Пополнить баланс",
text=PAYMENT,
callback_data="pay",
)
)
builder.row()
builder.row(
InlineKeyboardButton(text="👥 Пригласить", callback_data="invite"),
InlineKeyboardButton(text="🎁 Подарить", callback_data="gifts"),
InlineKeyboardButton(text=INVITE, callback_data="invite"),
InlineKeyboardButton(text=GIFTS, callback_data="gifts"),
)
builder.row(
InlineKeyboardButton(text="💡 Тарифы", callback_data="view_tariffs"),
InlineKeyboardButton(text="📘 Инструкции", callback_data="instructions"),
InlineKeyboardButton(text=TARRIFS, callback_data="view_tariffs"),
InlineKeyboardButton(text=INSTRUCTIONS, callback_data="instructions"),
)
if admin:
builder.row(
InlineKeyboardButton(text="🔧 Администратор", callback_data="admin")
)
builder.row(InlineKeyboardButton(text="⬅️ Главное меню", callback_data="start"))
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="start"))
if os.path.isfile(image_path):
with open(image_path, "rb") as image_file: