+59
-1
@@ -29,6 +29,13 @@ async def init_db():
|
|||||||
PRIMARY KEY (tg_id, client_id)
|
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:
|
try:
|
||||||
await conn.execute('''
|
await conn.execute('''
|
||||||
@@ -111,6 +118,10 @@ async def update_balance(tg_id: int, amount: float):
|
|||||||
SET balance = balance + $1
|
SET balance = balance + $1
|
||||||
WHERE tg_id = $2
|
WHERE tg_id = $2
|
||||||
''', amount, tg_id)
|
''', amount, tg_id)
|
||||||
|
|
||||||
|
# Проверка и начисление реферального бонуса
|
||||||
|
await handle_referral_on_balance_update(tg_id, amount)
|
||||||
|
|
||||||
await conn.close()
|
await conn.close()
|
||||||
|
|
||||||
async def get_trial(tg_id: int) -> int:
|
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
|
return count if count is not None else 0
|
||||||
|
|
||||||
async def get_all_users(conn):
|
async def get_all_users(conn):
|
||||||
return await conn.fetch('SELECT tg_id FROM connections')
|
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
|
||||||
|
}
|
||||||
@@ -44,6 +44,10 @@ async def process_callback_create_key(callback_query: CallbackQuery, state: FSMC
|
|||||||
finally:
|
finally:
|
||||||
await conn.close()
|
await conn.close()
|
||||||
|
|
||||||
|
# Добавляем кнопку "Назад"
|
||||||
|
button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='view_profile')
|
||||||
|
server_buttons.append([button_back]) # Кнопка "Назад" внизу списка серверов
|
||||||
|
|
||||||
await callback_query.message.edit_text(
|
await callback_query.message.edit_text(
|
||||||
"<b>⚙️ Выберите сервер для создания ключа:</b>",
|
"<b>⚙️ Выберите сервер для создания ключа:</b>",
|
||||||
parse_mode="HTML",
|
parse_mode="HTML",
|
||||||
@@ -121,7 +125,11 @@ async def cancel_create_key(callback_query: CallbackQuery, state: FSMContext):
|
|||||||
@dp.message()
|
@dp.message()
|
||||||
async def handle_text(message: Message, state: FSMContext):
|
async def handle_text(message: Message, state: FSMContext):
|
||||||
current_state = await state.get_state()
|
current_state = await state.get_state()
|
||||||
|
|
||||||
|
if message.text in ["/start", "/menu"]:
|
||||||
|
await start_command(message)
|
||||||
|
return
|
||||||
|
|
||||||
if message.text == "Мой профиль":
|
if message.text == "Мой профиль":
|
||||||
callback_query = types.CallbackQuery(
|
callback_query = types.CallbackQuery(
|
||||||
id="1",
|
id="1",
|
||||||
@@ -132,10 +140,6 @@ async def handle_text(message: Message, state: FSMContext):
|
|||||||
)
|
)
|
||||||
await process_callback_view_profile(callback_query, state)
|
await process_callback_view_profile(callback_query, state)
|
||||||
return
|
return
|
||||||
|
|
||||||
if message.text in ["/start", "/menu"]:
|
|
||||||
await start_command(message)
|
|
||||||
return
|
|
||||||
|
|
||||||
if message.text in ["/send_to_all"]:
|
if message.text in ["/send_to_all"]:
|
||||||
await send_message_to_all_clients(message)
|
await send_message_to_all_clients(message)
|
||||||
|
|||||||
+4
-3
@@ -320,7 +320,7 @@ async def process_callback_select_server(callback_query: types.CallbackQuery):
|
|||||||
success_delete = delete_client(session, current_server_id, client_id)
|
success_delete = delete_client(session, current_server_id, client_id)
|
||||||
if success_delete:
|
if success_delete:
|
||||||
response_message = ("Ключ успешно перемещен на новый сервер.\n\n"
|
response_message = ("Ключ успешно перемещен на новый сервер.\n\n"
|
||||||
"<b>Не забудьте удалить старый ключ из вашего приложения и установить новый.<b>")
|
"<b>Не забудьте удалить старый ключ из вашего приложения и установить новый.</b>")
|
||||||
else:
|
else:
|
||||||
response_message = "Ошибка при удалении ключа с текущего сервера."
|
response_message = "Ошибка при удалении ключа с текущего сервера."
|
||||||
else:
|
else:
|
||||||
@@ -332,12 +332,13 @@ async def process_callback_select_server(callback_query: types.CallbackQuery):
|
|||||||
back_button = types.InlineKeyboardButton(text='Назад', callback_data='view_keys')
|
back_button = types.InlineKeyboardButton(text='Назад', callback_data='view_keys')
|
||||||
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[back_button]])
|
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:
|
finally:
|
||||||
await conn.close()
|
await conn.close()
|
||||||
|
|
||||||
except Exception as e:
|
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()
|
await callback_query.answer()
|
||||||
|
|||||||
@@ -104,19 +104,22 @@ async def send_message_to_all_clients(message: types.Message):
|
|||||||
await message.answer("У вас нет прав для выполнения этой команды.")
|
await message.answer("У вас нет прав для выполнения этой команды.")
|
||||||
return
|
return
|
||||||
|
|
||||||
text = message.get_args()
|
# Получаем текст сообщения после команды
|
||||||
if not text:
|
text = message.text.split(maxsplit=1) # Разделяем текст сообщения на части
|
||||||
|
if len(text) < 2: # Если нет текста после команды
|
||||||
await message.answer("Пожалуйста, введите текст сообщения после команды.")
|
await message.answer("Пожалуйста, введите текст сообщения после команды.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
text_message = text[1] # Получаем текст сообщения
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn = await asyncpg.connect(DATABASE_URL)
|
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:
|
for record in tg_ids:
|
||||||
tg_id = record['tg_id']
|
tg_id = record['tg_id']
|
||||||
try:
|
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:
|
except Exception as e:
|
||||||
print(f"Ошибка при отправке сообщения пользователю {tg_id}: {e}. Пропускаем этого пользователя.")
|
print(f"Ошибка при отправке сообщения пользователю {tg_id}: {e}. Пропускаем этого пользователя.")
|
||||||
|
|
||||||
|
|||||||
+37
-6
@@ -1,17 +1,18 @@
|
|||||||
from aiogram import Router, types
|
from aiogram import Router, types
|
||||||
from aiogram.fsm.context import FSMContext
|
from aiogram.fsm.context import FSMContext
|
||||||
from aiogram.fsm.state import State, StatesGroup
|
|
||||||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
||||||
|
from aiogram.fsm.state import State, StatesGroup
|
||||||
|
|
||||||
from bot import bot
|
from bot import bot
|
||||||
from database import get_balance, get_key_count
|
from database import get_balance, get_key_count, get_referral_stats
|
||||||
|
|
||||||
router = Router()
|
|
||||||
|
|
||||||
class ReplenishBalanceState(StatesGroup):
|
class ReplenishBalanceState(StatesGroup):
|
||||||
choosing_transfer_method = State()
|
choosing_transfer_method = State()
|
||||||
waiting_for_admin_confirmation = State()
|
waiting_for_admin_confirmation = State()
|
||||||
|
|
||||||
|
router = Router()
|
||||||
|
|
||||||
|
# Хендлер для показа профиля
|
||||||
async def process_callback_view_profile(callback_query: types.CallbackQuery, state: FSMContext):
|
async def process_callback_view_profile(callback_query: types.CallbackQuery, state: FSMContext):
|
||||||
tg_id = callback_query.from_user.id
|
tg_id = callback_query.from_user.id
|
||||||
username = callback_query.from_user.full_name
|
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_create_key = InlineKeyboardButton(text='➕ Устройство', callback_data='create_key')
|
||||||
button_view_keys = InlineKeyboardButton(text='📱 Мои устройства', callback_data='view_keys')
|
button_view_keys = InlineKeyboardButton(text='📱 Мои устройства', callback_data='view_keys')
|
||||||
button_replenish_balance = InlineKeyboardButton(text='💳 Пополнить баланс', callback_data='replenish_balance')
|
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=[
|
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||||
[button_create_key],
|
[button_create_key],
|
||||||
[button_view_keys],
|
[button_view_keys],
|
||||||
[button_replenish_balance],
|
[button_replenish_balance],
|
||||||
|
[button_invite], # Добавили кнопку "Пригласить"
|
||||||
[button_back]
|
[button_back]
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -56,6 +59,34 @@ async def process_callback_view_profile(callback_query: types.CallbackQuery, sta
|
|||||||
|
|
||||||
await callback_query.answer()
|
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"👥 <b>Ваша реферальная ссылка:</b> {referral_link}\n\n"
|
||||||
|
f"🔹 <b>Всего приглашено:</b> {referral_stats['total_referrals']} пользователей\n"
|
||||||
|
f"🔹 <b>Активных рефералов:</b> {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')
|
@router.callback_query(lambda c: c.data == 'view_profile')
|
||||||
async def view_profile_handler(callback_query: types.CallbackQuery, state: FSMContext):
|
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)
|
||||||
+15
-6
@@ -1,5 +1,4 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from aiogram import Router
|
from aiogram import Router
|
||||||
from aiogram.filters import Command
|
from aiogram.filters import Command
|
||||||
from aiogram.fsm.state import State, StatesGroup
|
from aiogram.fsm.state import State, StatesGroup
|
||||||
@@ -7,6 +6,7 @@ from aiogram.types import (BufferedInputFile, CallbackQuery,
|
|||||||
InlineKeyboardButton, InlineKeyboardMarkup, Message)
|
InlineKeyboardButton, InlineKeyboardMarkup, Message)
|
||||||
|
|
||||||
from bot import bot
|
from bot import bot
|
||||||
|
from database import add_referral, check_connection_exists, add_connection
|
||||||
from config import CHANNEL_URL, SUPPORT_CHAT_URL
|
from config import CHANNEL_URL, SUPPORT_CHAT_URL
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
@@ -30,7 +30,7 @@ async def send_welcome_message(chat_id: int):
|
|||||||
inline_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
inline_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||||
[InlineKeyboardButton(text='👤 Мой профиль', callback_data='view_profile')],
|
[InlineKeyboardButton(text='👤 Мой профиль', callback_data='view_profile')],
|
||||||
[InlineKeyboardButton(text='🔒 О VPN', callback_data='about_vpn')],
|
[InlineKeyboardButton(text='🔒 О VPN', callback_data='about_vpn')],
|
||||||
[InlineKeyboardButton(text='📞 Поддержка', url=SUPPORT_CHAT_URL)], # Изменили на кнопку Поддержка
|
[InlineKeyboardButton(text='📞 Поддержка', url=SUPPORT_CHAT_URL)],
|
||||||
[InlineKeyboardButton(text='📢 Наш канал', url=CHANNEL_URL)]
|
[InlineKeyboardButton(text='📢 Наш канал', url=CHANNEL_URL)]
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -45,11 +45,22 @@ async def send_welcome_message(chat_id: int):
|
|||||||
|
|
||||||
@router.message(Command('start'))
|
@router.message(Command('start'))
|
||||||
async def start_command(message: Message):
|
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')
|
@router.callback_query(lambda c: c.data == 'about_vpn')
|
||||||
async def handle_about_vpn(callback_query: CallbackQuery):
|
async def handle_about_vpn(callback_query: CallbackQuery):
|
||||||
|
|
||||||
await callback_query.message.delete()
|
await callback_query.message.delete()
|
||||||
info_message = (
|
info_message = (
|
||||||
"*О VPN*\n\n"
|
"*О VPN*\n\n"
|
||||||
@@ -58,7 +69,6 @@ async def handle_about_vpn(callback_query: CallbackQuery):
|
|||||||
"<b>Ваш ключ — ваша безопасность! Не передавайте своё шифрование сторонним лицам.</b>"
|
"<b>Ваш ключ — ваша безопасность! Не передавайте своё шифрование сторонним лицам.</b>"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_menu')
|
button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_menu')
|
||||||
inline_keyboard_back = InlineKeyboardMarkup(inline_keyboard=[[button_back]])
|
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')
|
@router.callback_query(lambda c: c.data == 'back_to_menu')
|
||||||
async def handle_back_to_menu(callback_query: CallbackQuery):
|
async def handle_back_to_menu(callback_query: CallbackQuery):
|
||||||
|
|
||||||
await callback_query.message.delete()
|
await callback_query.message.delete()
|
||||||
await send_welcome_message(callback_query.from_user.id)
|
await send_welcome_message(callback_query.from_user.id)
|
||||||
await callback_query.answer()
|
await callback_query.answer()
|
||||||
|
|||||||
Reference in New Issue
Block a user