diff --git a/database.py b/database.py index 3f4bd37b..565a3157 100644 --- a/database.py +++ b/database.py @@ -35,6 +35,14 @@ async def add_connection(tg_id: int, balance: float = 0.0, trial: int = 0): ''', tg_id, balance, trial) await conn.close() +async def check_connection_exists(tg_id: int): + conn = await asyncpg.connect(DATABASE_URL) + exists = await conn.fetchval(''' + SELECT EXISTS(SELECT 1 FROM connections WHERE tg_id = $1) + ''', tg_id) + await conn.close() + return exists + async def store_key(tg_id: int, client_id: str, email: str, expiry_time: int, key: str): conn = await asyncpg.connect(DATABASE_URL) await conn.execute(''' @@ -85,3 +93,6 @@ async def get_key_count(tg_id: int) -> int: count = await conn.fetchval('SELECT COUNT(*) FROM keys WHERE tg_id = $1', tg_id) await conn.close() 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 diff --git a/handlers/__pycache__/keys.cpython-310.pyc b/handlers/__pycache__/keys.cpython-310.pyc index 0500dff1..bcefdc3a 100644 Binary files a/handlers/__pycache__/keys.cpython-310.pyc and b/handlers/__pycache__/keys.cpython-310.pyc differ diff --git a/handlers/__pycache__/notifications.cpython-310.pyc b/handlers/__pycache__/notifications.cpython-310.pyc index c354ebf2..b4f6a01f 100644 Binary files a/handlers/__pycache__/notifications.cpython-310.pyc and b/handlers/__pycache__/notifications.cpython-310.pyc differ diff --git a/handlers/__pycache__/pay.cpython-310.pyc b/handlers/__pycache__/pay.cpython-310.pyc index 8f4dbf61..ba9e9599 100644 Binary files a/handlers/__pycache__/pay.cpython-310.pyc and b/handlers/__pycache__/pay.cpython-310.pyc differ diff --git a/handlers/keys.py b/handlers/keys.py index ab89bb5e..b244c00d 100644 --- a/handlers/keys.py +++ b/handlers/keys.py @@ -11,6 +11,17 @@ from database import get_balance, update_balance router = Router() +from datetime import datetime, timedelta +import asyncpg +from aiogram import Router, types +from auth import login_with_credentials +from bot import bot +from client import delete_client, extend_client_key +from config import ADMIN_PASSWORD, ADMIN_USERNAME, DATABASE_URL +from database import get_balance, update_balance + +router = Router() + # Обработка запроса на просмотр ключей @router.callback_query(lambda c: c.data == 'view_keys') async def process_callback_view_keys(callback_query: types.CallbackQuery): @@ -30,26 +41,26 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery): key_name = record['email'] client_id = record['client_id'] # Заменяем подчеркивание на вертикальную черту в callback_data - button = types.InlineKeyboardButton(text=key_name, callback_data=f'view_key|{key_name}|{client_id}') + button = types.InlineKeyboardButton(text=f"🔑 {key_name}", callback_data=f'view_key|{key_name}|{client_id}') buttons.append([button]) # Создаем клавиатуру с кнопками inline_keyboard = types.InlineKeyboardMarkup(inline_keyboard=buttons) - response_message = "Выберите ключ для просмотра информации:" + response_message = "Выберите ключ для просмотра информации:" # Редактируем сообщение с клавиатурой - await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=inline_keyboard) + await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=inline_keyboard, parse_mode="HTML") else: # Если нет ключей, добавляем кнопку "Создать ключ" и "Назад" - response_message = "У вас нет ключей." + response_message = "У вас нет ключей." # Кнопка "Создать ключ" - create_key_button = types.InlineKeyboardButton(text='Создать ключ', callback_data='create_key') - back_button = types.InlineKeyboardButton(text='Назад', callback_data='view_profile') # Измените на правильное значение для кнопки "Назад" + create_key_button = types.InlineKeyboardButton(text='➕ Создать ключ', callback_data='create_key') + back_button = types.InlineKeyboardButton(text='🔙 Назад', callback_data='view_profile') # Измените на правильное значение для кнопки "Назад" keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[create_key_button], [back_button]]) - await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=keyboard) + 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() @@ -82,27 +93,27 @@ async def process_callback_view_key(callback_query: types.CallbackQuery): time_left = expiry_date - current_date if time_left.total_seconds() <= 0: - days_left_message = "Ключ истек." + days_left_message = "Ключ истек." elif time_left.days > 0: - days_left_message = f"Осталось дней: {time_left.days}" + days_left_message = f"Осталось дней: {time_left.days}" else: hours_left = time_left.seconds // 3600 - days_left_message = f"Осталось часов: {hours_left}" + days_left_message = f"Осталось часов: {hours_left}" - response_message = (f"Ваш ключ:\n
{key}\n"
- f"Дата окончания: {expiry_date.strftime('%Y-%m-%d %H:%M:%S')}\n"
+ response_message = (f"🔑 Ваш ключ:\n{key}\n"
+ f"📅 Дата окончания: {expiry_date.strftime('%Y-%m-%d %H:%M:%S')}\n"
f"{days_left_message}")
# Кнопки для продления, инструкций и удаления
- renew_button = types.InlineKeyboardButton(text='Продлить ключ', callback_data=f'renew_key|{client_id}')
- instructions_button = types.InlineKeyboardButton(text='Инструкции по использованию', callback_data='instructions')
- delete_button = types.InlineKeyboardButton(text='Удалить ключ', callback_data=f'delete_key|{client_id}')
- back_button = types.InlineKeyboardButton(text='Назад в профиль', callback_data='view_profile')
+ renew_button = types.InlineKeyboardButton(text='⏳ Продлить ключ', callback_data=f'renew_key|{client_id}')
+ instructions_button = types.InlineKeyboardButton(text='📘 Инструкции', callback_data='instructions')
+ delete_button = types.InlineKeyboardButton(text='❌ Удалить ключ', callback_data=f'delete_key|{client_id}')
+ back_button = types.InlineKeyboardButton(text='🔙 Назад в профиль', callback_data='view_profile')
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[renew_button], [instructions_button], [delete_button], [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")
else:
- await bot.edit_message_text("Информация о ключе не найдена.", chat_id=tg_id, message_id=callback_query.message.message_id, parse_mode="HTML")
+ await bot.edit_message_text("Информация о ключе не найдена.", chat_id=tg_id, message_id=callback_query.message.message_id, parse_mode="HTML")
finally:
await conn.close()
@@ -119,13 +130,53 @@ async def process_callback_delete_key(callback_query: types.CallbackQuery):
client_id = callback_query.data.split('|')[1] # Используем разделитель вертикальная черта
confirmation_keyboard = types.InlineKeyboardMarkup(inline_keyboard=[
- [types.InlineKeyboardButton(text='Да, удалить', callback_data=f'confirm_delete|{client_id}')],
- [types.InlineKeyboardButton(text='Нет, отменить', callback_data='view_keys')]
+ [types.InlineKeyboardButton(text='✅ Да, удалить', callback_data=f'confirm_delete|{client_id}')],
+ [types.InlineKeyboardButton(text='❌ Нет, отменить', callback_data='view_keys')]
])
- await bot.edit_message_text("Вы уверены, что хотите удалить ключ?", chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=confirmation_keyboard)
+ await bot.edit_message_text("Вы уверены, что хотите удалить ключ?", chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=confirmation_keyboard, parse_mode="HTML")
await callback_query.answer()
+# Обработка выбора плана продления
+@router.callback_query(lambda c: c.data.startswith('renew_key|'))
+async def process_callback_renew_key(callback_query: types.CallbackQuery):
+ tg_id = callback_query.from_user.id
+ client_id = callback_query.data.split('|')[1] # Используем разделитель вертикальная черта
+
+ try:
+ conn = await asyncpg.connect(DATABASE_URL)
+ try:
+ record = await conn.fetchrow('SELECT email, expiry_time FROM keys WHERE client_id = $1', client_id)
+
+ if record:
+ email = record['email']
+ expiry_time = record['expiry_time']
+ current_time = datetime.utcnow().timestamp() * 1000 # Получаем текущее время в миллисекундах
+
+ # Убираем проверку на истекший ключ
+ keyboard = types.InlineKeyboardMarkup(inline_keyboard=[
+ [types.InlineKeyboardButton(text='📅 1 месяц (100 руб.)', callback_data=f'renew_plan|1|{client_id}')],
+ [types.InlineKeyboardButton(text='📅 3 месяца (250 руб.)', callback_data=f'renew_plan|3|{client_id}')],
+ [types.InlineKeyboardButton(text='🔙 Назад', callback_data='view_profile')]
+ ])
+
+ balance = await get_balance(tg_id)
+ response_message = (f"Выберите план продления:\n"
+ f"💰 Баланс: {balance} руб.\n"
+ f"📅 Текущая дата истечения ключа: {datetime.utcfromtimestamp(expiry_time / 1000).strftime('%Y-%m-%d %H:%M:%S')}")
+
+ 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, parse_mode="HTML")
+
+ await callback_query.answer()
+
+async def handle_error(tg_id, callback_query, message):
+ await bot.edit_message_text(message, chat_id=tg_id, message_id=callback_query.message.message_id)
# Подтверждение удаления
@router.callback_query(lambda c: c.data.startswith('renew_key|'))
diff --git a/handlers/notifications.py b/handlers/notifications.py
index 6ddce0db..b8df99b2 100644
--- a/handlers/notifications.py
+++ b/handlers/notifications.py
@@ -2,12 +2,18 @@ import asyncpg
from datetime import datetime, timedelta
from aiogram import Bot
from aiogram import Router, types
+from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup # Импортируем необходимые классы
from bot import bot
+from config import DATABASE_URL, ADMIN_ID
from aiogram.filters import Command
+from database import get_all_users
+from aiogram.fsm.state import StatesGroup, State
+from aiogram.fsm.context import FSMContext
router = Router()
-from config import DATABASE_URL
+class NotificationStates(StatesGroup):
+ waiting_for_notification_text = State()
async def notify_expiring_keys(bot: Bot):
try:
@@ -25,8 +31,14 @@ async def notify_expiring_keys(bot: Bot):
email = record['email']
expiry_time = record['expiry_time']
expiry_date = datetime.utcfromtimestamp(expiry_time / 1000).strftime('%Y-%m-%d %H:%M:%S')
+
+ # Создаем клавиатуру с кнопкой "Пополнить баланс"
+ keyboard = InlineKeyboardMarkup(inline_keyboard=[
+ [InlineKeyboardButton(text='Пополнить баланс', callback_data='replenish_balance')]
+ ])
+
message = f"Ваш ключ {email} истечет {expiry_date}. Пожалуйста, продлите его."
- await bot.send_message(chat_id=tg_id, text=message, parse_mode='HTML')
+ await bot.send_message(chat_id=tg_id, text=message, parse_mode='HTML', reply_markup=keyboard)
# Получаем все истекшие ключи
expired_records = await conn.fetch('''
@@ -37,31 +49,16 @@ async def notify_expiring_keys(bot: Bot):
for record in expired_records:
tg_id = record['tg_id']
email = record['email']
+
+ # Создаем клавиатуру с кнопкой "Пополнить баланс"
+ keyboard = InlineKeyboardMarkup(inline_keyboard=[
+ [InlineKeyboardButton(text='Пополнить баланс', callback_data='replenish_balance')]
+ ])
+
message = f"Ваш ключ {email} уже истек. Пожалуйста, продлите его."
- await bot.send_message(chat_id=tg_id, text=message, parse_mode='HTML')
+ await bot.send_message(chat_id=tg_id, text=message, parse_mode='HTML', reply_markup=keyboard)
finally:
await conn.close()
except Exception as e:
print(f"Ошибка при отправке уведомлений: {e}")
-
-@router.message(Command(commands=['notify']))
-async def notify_command(message: types.Message):
- # Запрашиваем у администратора ID пользователя и текст уведомления
- await message.answer("Введите ID пользователя и текст уведомления в формате:\n/notify user_id текст", parse_mode="HTML")
-
-# Обработка команды уведомления
-@router.message()
-async def process_notification(message: types.Message):
- if message.text.startswith("/notify"):
- try:
- # Парсим команду
- command, user_id, *text = message.text.split()
- text = ' '.join(text)
-
- # Отправляем сообщение пользователю
- await bot.send_message(chat_id=user_id, text=text)
- await message.answer(f"Уведомление успешно отправлено пользователю {user_id}.")
-
- except Exception as e:
- await message.answer(f"Ошибка при отправке уведомления: {e}")
diff --git a/handlers/pay.py b/handlers/pay.py
index fbad89e2..8cd1a965 100644
--- a/handlers/pay.py
+++ b/handlers/pay.py
@@ -6,7 +6,7 @@ from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from bot import bot
from config import ADMIN_ID, DATABASE_URL
-from database import get_balance, get_key_count, update_balance
+from database import get_balance, get_key_count, update_balance, add_connection, check_connection_exists
from handlers.profile import process_callback_view_profile
router = Router()
@@ -17,9 +17,6 @@ class ReplenishBalanceState(StatesGroup):
waiting_for_admin_confirmation = State()
async def send_message_with_deletion(chat_id, text, reply_markup=None, state=None, message_key='last_message_id'):
- """
- Отправляет новое сообщение и удаляет предыдущее сообщение (если оно существует), сохраненное в состоянии FSM.
- """
if state:
try:
state_data = await state.get_data()
@@ -42,10 +39,20 @@ async def send_message_with_deletion(chat_id, text, reply_markup=None, state=Non
async def process_callback_replenish_balance(callback_query: types.CallbackQuery, state: FSMContext):
tg_id = callback_query.from_user.id
+ # Проверяем, есть ли у пользователя ключи
+ key_count = await get_key_count(tg_id)
+
+ # Если ключей нет, проверяем, существует ли запись с таким tg_id
+ if key_count == 0:
+ exists = await check_connection_exists(tg_id)
+ # Если записи нет, создаем нового клиента в базе данных
+ if not exists:
+ await add_connection(tg_id, balance=0.0, trial=0)
+
await state.set_state(ReplenishBalanceState.choosing_transfer_method)
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='По реквизитам', callback_data='transfer_method_requisites')],
- [InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')] # Кнопка "Назад"
+ [InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')]
])
await callback_query.message.edit_text(
@@ -54,13 +61,10 @@ async def process_callback_replenish_balance(callback_query: types.CallbackQuery
)
await callback_query.answer()
-
@router.callback_query(lambda c: c.data == 'back_to_profile')
async def back_to_profile_handler(callback_query: types.CallbackQuery, state: FSMContext):
await process_callback_view_profile(callback_query, state)
-
-
@router.callback_query(lambda c: c.data.startswith('transfer_method_'))
async def process_transfer_method_selection(callback_query: types.CallbackQuery, state: FSMContext):
data = callback_query.data.split('_', 2)
@@ -76,7 +80,7 @@ async def process_transfer_method_selection(callback_query: types.CallbackQuery,
[InlineKeyboardButton(text='100 RUB', callback_data='amount_100')],
[InlineKeyboardButton(text='300 RUB', callback_data='amount_300')],
[InlineKeyboardButton(text='500 RUB', callback_data='amount_500')],
- [InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')] # Кнопка "Назад"
+ [InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')]
])
await callback_query.message.edit_text(
@@ -90,7 +94,6 @@ async def process_transfer_method_selection(callback_query: types.CallbackQuery,
await send_message_with_deletion(callback_query.from_user.id, "Неверный метод перевода.", state=state, message_key='transfer_method_error_message_id')
return
-
@router.callback_query(lambda c: c.data.startswith('amount_'))
async def process_amount_selection(callback_query: types.CallbackQuery, state: FSMContext):
data = callback_query.data.split('_', 1)
@@ -102,18 +105,15 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
amount_str = data[1]
amount = int(amount_str)
- # Получаем ID сообщения с кнопками выбора суммы
state_data = await state.get_data()
amount_selection_message_id = state_data.get('amount_selection_message_id')
- # Удаляем сообщение с кнопками выбора суммы
if amount_selection_message_id:
try:
await bot.delete_message(chat_id=callback_query.from_user.id, message_id=amount_selection_message_id)
except Exception as e:
print(f"Ошибка при удалении сообщения: {e}")
- # Обновляем состояние и сохраняем выбранную сумму
await state.update_data(amount=amount)
await state.set_state(ReplenishBalanceState.waiting_for_admin_confirmation)
@@ -126,10 +126,9 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
"После перевода отправьте чек и дождитесь подтверждения."
)
- # Редактируем текущее сообщение
await callback_query.message.edit_text(
text=message,
- reply_markup=None # Или добавьте клавиатуру, если нужно
+ reply_markup=None
)
admin_keyboard = InlineKeyboardMarkup(inline_keyboard=[
@@ -147,8 +146,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
await send_message_with_deletion(ADMIN_ID, admin_message, reply_markup=admin_keyboard, state=state, message_key='admin_request_message_id')
await callback_query.answer()
-
-
@router.callback_query(lambda c: c.data.startswith('admin_'))
async def process_admin_confirmation(callback_query: types.CallbackQuery, state: FSMContext):
if callback_query.from_user.id != ADMIN_ID:
@@ -169,35 +166,26 @@ async def process_admin_confirmation(callback_query: types.CallbackQuery, state:
try:
user_id = int(user_id_str)
- # Получаем данные из состояния для удаления сообщения с реквизитами
state_data = await state.get_data()
requisites_message_id = state_data.get('requisites_message_id')
if action == 'confirm':
- # Подключаемся к базе данных PostgreSQL
conn = await asyncpg.connect(DATABASE_URL)
try:
- # Обновляем баланс пользователя
await update_balance(user_id, amount)
-
- # Получаем обновленный баланс
balance = await get_balance(user_id)
- # Создаем клавиатуру с кнопкой "Профиль"
profile_button = InlineKeyboardButton(text='Профиль', callback_data='view_profile')
profile_keyboard = InlineKeyboardMarkup(inline_keyboard=[[profile_button]])
- # Отправляем уведомление с кнопкой "Профиль" администратору
await send_message_with_deletion(callback_query.from_user.id, f"Баланс пользователя успешно пополнен на {amount} RUB.\nТекущий баланс: {balance}", state=state, message_key='admin_confirm_message_id')
- # Отправляем уведомление пользователю с кнопкой "Профиль"
await bot.send_message(
user_id,
f"Ваш баланс был успешно пополнен на {amount} RUB.",
reply_markup=profile_keyboard
)
- # Удаляем сообщение с реквизитами
requisites_message_id = state_data.get('requisites_message_id')
if requisites_message_id:
try:
@@ -218,4 +206,4 @@ async def process_admin_confirmation(callback_query: types.CallbackQuery, state:
finally:
await state.clear()
- await callback_query.answer()
\ No newline at end of file
+ await callback_query.answer()
diff --git a/key_management.py b/key_management.py
index 2336a92e..ef667ddb 100644
--- a/key_management.py
+++ b/key_management.py
@@ -9,7 +9,6 @@ from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import (CallbackQuery, InlineKeyboardButton,
InlineKeyboardMarkup, Message)
-from pytz import timezone
from auth import link, login_with_credentials
from bot import bot, dp
@@ -20,6 +19,7 @@ from database import (add_connection, get_balance, has_active_key, store_key,
update_balance)
from handlers.profile import process_callback_view_profile
from handlers.start import start_command
+from handlers.notifications import send_notification
router = Router()
@@ -46,16 +46,22 @@ async def process_callback_create_key(callback_query: CallbackQuery, state: FSMC
if trial_status == 1:
await callback_query.message.edit_text(
- "У вас уже был пробный ключ. Новый стоит 100 рублей и сразу на месяц. \n\n"
- "Хотите продолжить?",
+ "⚠️ У вас уже был пробный ключ.\n\n"
+ "Новый ключ будет выдан на один месяц и стоит 100 рублей.\n\n"
+ "Хотите продолжить?",
+ parse_mode="HTML", # Добавляем параметр parse_mode
reply_markup=InlineKeyboardMarkup(inline_keyboard=[
- [InlineKeyboardButton(text='Да, создать новый ключ', callback_data='confirm_create_new_key')],
- [InlineKeyboardButton(text='Назад', callback_data='cancel_create_key')]
+ [InlineKeyboardButton(text='✅ Да, создать новый ключ', callback_data='confirm_create_new_key')],
+ [InlineKeyboardButton(text='↩️ Назад', callback_data='cancel_create_key')]
])
)
await state.update_data(creating_new_key=True)
else:
- await callback_query.message.edit_text("Вам будет выдан пробный ключ. Пожалуйста, выберите имя для вашего ключа:")
+ await callback_query.message.edit_text(
+ "🎉 Вам будет выдан пробный ключ на 24 часа!\n\n"
+ "Пожалуйста, введите название для вашего пробного ключа:",
+ parse_mode="HTML"
+ )
await state.set_state(Form.waiting_for_key_name)
await callback_query.answer()
@@ -77,7 +83,7 @@ async def confirm_create_new_key(callback_query: CallbackQuery, state: FSMContex
await state.clear()
return
- await callback_query.message.edit_text("🔑 Пожалуйста, выберите имя для вашего нового ключа:")
+ await callback_query.message.edit_text("🔑 Пожалуйста, введите имя нового ключа:")
await state.set_state(Form.waiting_for_key_name)
await state.update_data(creating_new_key=True)
@@ -113,7 +119,6 @@ async def handle_text(message: Message, state: FSMContext):
async def handle_key_name_input(message: Message, state: FSMContext):
tg_id = message.from_user.id
-
key_name = sanitize_key_name(message.text)
if not key_name:
@@ -140,7 +145,7 @@ async def handle_key_name_input(message: Message, state: FSMContext):
if trial_status == 0:
# Создаем пробный ключ на 1 день
- expiry_time = int((current_time + timedelta(days=1, hours=3)).timestamp() * 1000)
+ expiry_time = current_time + timedelta(days=1, hours=3)
else:
# Проверяем баланс перед созданием нового ключа
balance = await get_balance(tg_id)
@@ -152,26 +157,25 @@ async def handle_key_name_input(message: Message, state: FSMContext):
return
await update_balance(tg_id, -100)
- expiry_time = int((current_time + timedelta(days=30, hours=3)).timestamp() * 1000)
+ expiry_time = current_time + timedelta(days=30, hours=3)
+
+ expiry_timestamp = int(expiry_time.timestamp() * 1000)
try:
# Попробуем добавить клиента
- response = add_client(session, client_id, email, tg_id, limit_ip=1, total_gb=0, expiry_time=expiry_time, enable=True, flow="xtls-rprx-vision")
+ response = add_client(session, client_id, email, tg_id, limit_ip=1, total_gb=0, expiry_time=expiry_timestamp, enable=True, flow="xtls-rprx-vision")
- # Проверяем статус ответа от сервера
if not response.get("success", True):
error_msg = response.get("msg", "Неизвестная ошибка.")
if "Duplicate email" in error_msg:
await message.bot.send_message(tg_id, "❌ Этот email уже используется. Пожалуйста, выберите другое имя для ключа.")
- await state.set_state(Form.waiting_for_key_name) # Возвращаем пользователя к вводу имени ключа
+ await state.set_state(Form.waiting_for_key_name)
return
else:
raise Exception(error_msg)
- # Если добавление клиента прошло успешно, получаем ссылку
connection_link = link(session, client_id, email)
- # Проверка существующей записи
conn = await asyncpg.connect(DATABASE_URL)
try:
existing_connection = await conn.fetchrow('SELECT * FROM connections WHERE tg_id = $1', tg_id)
@@ -180,11 +184,21 @@ async def handle_key_name_input(message: Message, state: FSMContext):
await conn.execute('UPDATE connections SET trial = 1 WHERE tg_id = $1', tg_id)
else:
await add_connection(tg_id, 0, 1)
-
finally:
await conn.close()
- await store_key(tg_id, client_id, email, expiry_time, connection_link)
+ await store_key(tg_id, client_id, email, expiry_timestamp, connection_link)
+
+ # Рассчитываем оставшееся время до окончания действия ключа
+ remaining_time = expiry_time - current_time
+ days = remaining_time.days
+ hours, remainder = divmod(remaining_time.seconds, 3600)
+ minutes, _ = divmod(remainder, 60)
+
+ # Формируем сообщение с информацией о ключе
+ remaining_time_message = (
+ f"Оставшееся время ключа: {days} день"
+ )
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='📖 Инструкции по использованию', callback_data='instructions')],
@@ -193,8 +207,10 @@ async def handle_key_name_input(message: Message, state: FSMContext):
key_message = (
"✅ Ключ успешно создан:\n"
- f"{connection_link}"
+ f"{connection_link}\n\n"
+ f"{remaining_time_message}"
)
+
await message.bot.send_message(tg_id, key_message, parse_mode="HTML", reply_markup=keyboard)
except Exception as e:
@@ -202,9 +218,6 @@ async def handle_key_name_input(message: Message, state: FSMContext):
await state.clear()
-
-
-
@dp.callback_query(F.data == 'instructions')
async def handle_instructions(callback_query: CallbackQuery):
instructions_message = (