diff --git a/database.py b/database.py
index 603089de..339edc47 100644
--- a/database.py
+++ b/database.py
@@ -29,6 +29,13 @@ async def init_db():
PRIMARY KEY (tg_id, client_id)
)
''')
+ await conn.execute('''
+ CREATE TABLE IF NOT EXISTS referrals (
+ referred_tg_id BIGINT PRIMARY KEY NOT NULL, -- ID приглашенного пользователя
+ referrer_tg_id BIGINT NOT NULL, -- ID пригласившего пользователя
+ reward_issued BOOLEAN DEFAULT FALSE -- Был ли начислен бонус
+ )
+ ''')
try:
await conn.execute('''
@@ -111,6 +118,10 @@ async def update_balance(tg_id: int, amount: float):
SET balance = balance + $1
WHERE tg_id = $2
''', amount, tg_id)
+
+ # Проверка и начисление реферального бонуса
+ await handle_referral_on_balance_update(tg_id, amount)
+
await conn.close()
async def get_trial(tg_id: int) -> int:
@@ -126,4 +137,51 @@ async def get_key_count(tg_id: int) -> int:
return count if count is not None else 0
async def get_all_users(conn):
- return await conn.fetch('SELECT tg_id FROM connections')
\ No newline at end of file
+ return await conn.fetch('SELECT tg_id FROM connections')
+
+async def add_referral(referred_tg_id: int, referrer_tg_id: int):
+ conn = await asyncpg.connect(DATABASE_URL)
+ await conn.execute('''
+ INSERT INTO referrals (referred_tg_id, referrer_tg_id)
+ VALUES ($1, $2)
+ ''', referred_tg_id, referrer_tg_id)
+ await conn.close()
+
+async def handle_referral_on_balance_update(tg_id: int, amount: float):
+ conn = await asyncpg.connect(DATABASE_URL)
+
+ # Проверяем, есть ли реферал в таблице
+ referral = await conn.fetchrow('''
+ SELECT referrer_tg_id, reward_issued FROM referrals WHERE referred_tg_id = $1
+ ''', tg_id)
+
+ if referral and not referral['reward_issued'] and amount > 0:
+ referrer_tg_id = referral['referrer_tg_id']
+
+ # Начисляем бонус (25% от платежа) пригласившему
+ bonus = amount * 0.25 # 25% от платежа
+ await update_balance(referrer_tg_id, bonus)
+
+ # Обновляем статус бонуса как выданный
+ await conn.execute('''
+ UPDATE referrals SET reward_issued = TRUE WHERE referred_tg_id = $1
+ ''', tg_id)
+
+ await conn.close()
+
+async def get_referral_stats(referrer_tg_id: int):
+ conn = await asyncpg.connect(DATABASE_URL)
+ total_referrals = await conn.fetchval('''
+ SELECT COUNT(*) FROM referrals WHERE referrer_tg_id = $1
+ ''', referrer_tg_id)
+
+ active_referrals = await conn.fetchval('''
+ SELECT COUNT(*) FROM referrals WHERE referrer_tg_id = $1 AND reward_issued = TRUE
+ ''', referrer_tg_id)
+
+ await conn.close()
+
+ return {
+ 'total_referrals': total_referrals,
+ 'active_referrals': active_referrals
+ }
\ No newline at end of file
diff --git a/handlers/key_management.py b/handlers/key_management.py
index 40679b3f..b7e5fbdc 100644
--- a/handlers/key_management.py
+++ b/handlers/key_management.py
@@ -44,6 +44,10 @@ async def process_callback_create_key(callback_query: CallbackQuery, state: FSMC
finally:
await conn.close()
+ # Добавляем кнопку "Назад"
+ button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='view_profile')
+ server_buttons.append([button_back]) # Кнопка "Назад" внизу списка серверов
+
await callback_query.message.edit_text(
"⚙️ Выберите сервер для создания ключа:",
parse_mode="HTML",
@@ -121,7 +125,11 @@ async def cancel_create_key(callback_query: CallbackQuery, state: FSMContext):
@dp.message()
async def handle_text(message: Message, state: FSMContext):
current_state = await state.get_state()
-
+
+ if message.text in ["/start", "/menu"]:
+ await start_command(message)
+ return
+
if message.text == "Мой профиль":
callback_query = types.CallbackQuery(
id="1",
@@ -132,10 +140,6 @@ async def handle_text(message: Message, state: FSMContext):
)
await process_callback_view_profile(callback_query, state)
return
-
- if message.text in ["/start", "/menu"]:
- await start_command(message)
- return
if message.text in ["/send_to_all"]:
await send_message_to_all_clients(message)
diff --git a/handlers/keys.py b/handlers/keys.py
index 586cdcbe..b17f8289 100644
--- a/handlers/keys.py
+++ b/handlers/keys.py
@@ -320,7 +320,7 @@ async def process_callback_select_server(callback_query: types.CallbackQuery):
success_delete = delete_client(session, current_server_id, client_id)
if success_delete:
response_message = ("Ключ успешно перемещен на новый сервер.\n\n"
- "Не забудьте удалить старый ключ из вашего приложения и установить новый.")
+ "Не забудьте удалить старый ключ из вашего приложения и установить новый.")
else:
response_message = "Ошибка при удалении ключа с текущего сервера."
else:
@@ -332,12 +332,13 @@ async def process_callback_select_server(callback_query: types.CallbackQuery):
back_button = types.InlineKeyboardButton(text='Назад', callback_data='view_keys')
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[back_button]])
- await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=keyboard)
+ # Указываем parse_mode='HTML' для форматирования
+ await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=keyboard, parse_mode='HTML')
finally:
await conn.close()
except Exception as e:
- await bot.edit_message_text(f"Ошибка при смене локации: {e}", chat_id=tg_id, message_id=callback_query.message.message_id)
+ await bot.edit_message_text(f"Ошибка при смене локации: {e}", chat_id=tg_id, message_id=callback_query.message.message_id, parse_mode='HTML')
await callback_query.answer()
diff --git a/handlers/notifications.py b/handlers/notifications.py
index 776d4e67..e74a121e 100644
--- a/handlers/notifications.py
+++ b/handlers/notifications.py
@@ -104,19 +104,22 @@ async def send_message_to_all_clients(message: types.Message):
await message.answer("У вас нет прав для выполнения этой команды.")
return
- text = message.get_args()
- if not text:
+ # Получаем текст сообщения после команды
+ text = message.text.split(maxsplit=1) # Разделяем текст сообщения на части
+ if len(text) < 2: # Если нет текста после команды
await message.answer("Пожалуйста, введите текст сообщения после команды.")
return
+ text_message = text[1] # Получаем текст сообщения
+
try:
conn = await asyncpg.connect(DATABASE_URL)
- tg_ids = await conn.fetch('SELECT tg_id FROM keys')
+ tg_ids = await conn.fetch('SELECT tg_id FROM connections')
for record in tg_ids:
tg_id = record['tg_id']
try:
- await bot.send_message(chat_id=tg_id, text=text)
+ await bot.send_message(chat_id=tg_id, text=text_message)
except Exception as e:
print(f"Ошибка при отправке сообщения пользователю {tg_id}: {e}. Пропускаем этого пользователя.")
diff --git a/handlers/profile.py b/handlers/profile.py
index 5641c6ea..78b7e6bb 100644
--- a/handlers/profile.py
+++ b/handlers/profile.py
@@ -1,17 +1,18 @@
from aiogram import Router, types
from aiogram.fsm.context import FSMContext
-from aiogram.fsm.state import State, StatesGroup
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
+from aiogram.fsm.state import State, StatesGroup
from bot import bot
-from database import get_balance, get_key_count
-
-router = Router()
+from database import get_balance, get_key_count, get_referral_stats
class ReplenishBalanceState(StatesGroup):
choosing_transfer_method = State()
waiting_for_admin_confirmation = State()
+router = Router()
+
+# Хендлер для показа профиля
async def process_callback_view_profile(callback_query: types.CallbackQuery, state: FSMContext):
tg_id = callback_query.from_user.id
username = callback_query.from_user.full_name
@@ -32,12 +33,14 @@ async def process_callback_view_profile(callback_query: types.CallbackQuery, sta
button_create_key = InlineKeyboardButton(text='➕ Устройство', callback_data='create_key')
button_view_keys = InlineKeyboardButton(text='📱 Мои устройства', callback_data='view_keys')
button_replenish_balance = InlineKeyboardButton(text='💳 Пополнить баланс', callback_data='replenish_balance')
- button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_menu') # Добавляем кнопку "Назад"
+ button_invite = InlineKeyboardButton(text='👥 Пригласить', callback_data='invite')
+ button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_menu')
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[button_create_key],
[button_view_keys],
[button_replenish_balance],
+ [button_invite], # Добавили кнопку "Пригласить"
[button_back]
])
@@ -56,6 +59,34 @@ async def process_callback_view_profile(callback_query: types.CallbackQuery, sta
await callback_query.answer()
+# Хендлер для кнопки "Пригласить"
+@router.callback_query(lambda c: c.data == 'invite')
+async def invite_handler(callback_query: types.CallbackQuery):
+ tg_id = callback_query.from_user.id
+ referral_link = f"https://t.me/SoloNetVPN_bot?start=referral_{tg_id}"
+
+ referral_stats = await get_referral_stats(tg_id)
+
+ invite_message = (
+ f"👥 Ваша реферальная ссылка: {referral_link}\n\n"
+ f"🔹 Всего приглашено: {referral_stats['total_referrals']} пользователей\n"
+ f"🔹 Активных рефералов: {referral_stats['active_referrals']}"
+ )
+
+ button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='view_profile')
+ keyboard = InlineKeyboardMarkup(inline_keyboard=[[button_back]])
+
+ await callback_query.message.delete()
+
+ await bot.send_message(
+ chat_id=tg_id,
+ text=invite_message,
+ parse_mode='HTML',
+ reply_markup=keyboard
+ )
+
+ await callback_query.answer()
+
@router.callback_query(lambda c: c.data == 'view_profile')
async def view_profile_handler(callback_query: types.CallbackQuery, state: FSMContext):
- await process_callback_view_profile(callback_query, state)
+ await process_callback_view_profile(callback_query, state)
\ No newline at end of file
diff --git a/handlers/start.py b/handlers/start.py
index 87f002e4..1faa3e92 100644
--- a/handlers/start.py
+++ b/handlers/start.py
@@ -1,5 +1,4 @@
import os
-
from aiogram import Router
from aiogram.filters import Command
from aiogram.fsm.state import State, StatesGroup
@@ -7,6 +6,7 @@ from aiogram.types import (BufferedInputFile, CallbackQuery,
InlineKeyboardButton, InlineKeyboardMarkup, Message)
from bot import bot
+from database import add_referral, check_connection_exists, add_connection
from config import CHANNEL_URL, SUPPORT_CHAT_URL
router = Router()
@@ -30,7 +30,7 @@ async def send_welcome_message(chat_id: int):
inline_keyboard = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='👤 Мой профиль', callback_data='view_profile')],
[InlineKeyboardButton(text='🔒 О VPN', callback_data='about_vpn')],
- [InlineKeyboardButton(text='📞 Поддержка', url=SUPPORT_CHAT_URL)], # Изменили на кнопку Поддержка
+ [InlineKeyboardButton(text='📞 Поддержка', url=SUPPORT_CHAT_URL)],
[InlineKeyboardButton(text='📢 Наш канал', url=CHANNEL_URL)]
])
@@ -45,11 +45,22 @@ async def send_welcome_message(chat_id: int):
@router.message(Command('start'))
async def start_command(message: Message):
- await send_welcome_message(message.chat.id)
+ if 'referral_' in message.text:
+ referrer_tg_id = int(message.text.split('referral_')[1])
+
+ if not await check_connection_exists(message.from_user.id):
+ await add_connection(message.from_user.id)
+
+ await add_referral(message.from_user.id, referrer_tg_id)
+
+ await message.answer("Вас пригласил друг, добро пожаловать!")
+ else:
+ await message.answer("Вы уже зарегистрированы в системе!")
+ else:
+ await send_welcome_message(message.chat.id)
@router.callback_query(lambda c: c.data == 'about_vpn')
async def handle_about_vpn(callback_query: CallbackQuery):
-
await callback_query.message.delete()
info_message = (
"*О VPN*\n\n"
@@ -58,7 +69,6 @@ async def handle_about_vpn(callback_query: CallbackQuery):
"Ваш ключ — ваша безопасность! Не передавайте своё шифрование сторонним лицам."
)
-
button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_menu')
inline_keyboard_back = InlineKeyboardMarkup(inline_keyboard=[[button_back]])
@@ -71,7 +81,6 @@ async def handle_about_vpn(callback_query: CallbackQuery):
@router.callback_query(lambda c: c.data == 'back_to_menu')
async def handle_back_to_menu(callback_query: CallbackQuery):
-
await callback_query.message.delete()
await send_welcome_message(callback_query.from_user.id)
await callback_query.answer()