Merge pull request #28 from Vladless/youkassa

Youkassa
This commit is contained in:
Vladislav Lisitsyn
2024-10-04 02:13:12 +03:00
committed by GitHub
6 changed files with 131 additions and 25 deletions
+59 -1
View File
@@ -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
}
+9 -5
View File
@@ -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
View File
@@ -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()
+7 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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()