diff --git a/bot.py b/bot.py index b22f25db..622fc347 100644 --- a/bot.py +++ b/bot.py @@ -9,7 +9,7 @@ storage = MemoryStorage() dp = Dispatcher(bot=bot, storage=storage) router = Router() -from handlers import balance, keys, pay, profile, start +from handlers import balance, keys, pay, profile, start, notifications from key_management import router as key_management_router # Регистрация обработчиков @@ -19,6 +19,7 @@ dp.include_router(keys.router) dp.include_router(balance.router) dp.include_router(key_management_router) dp.include_router(pay.router) +dp.include_router(notifications.router) diff --git a/client.py b/client.py index 87587bab..19fb12b3 100644 --- a/client.py +++ b/client.py @@ -40,6 +40,7 @@ def add_client(session, client_id: str, email: str, tg_id: str, limit_ip: int, t if response.status_code == 200: print(f"Клиент добавлен: email={email}") + return response.json() else: print(f"Ошибка при добавлении клиента: {response.status_code}, {response.text}") diff --git a/handlers/__pycache__/keys.cpython-310.pyc b/handlers/__pycache__/keys.cpython-310.pyc index 028d3eb0..0500dff1 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 80b1e136..c354ebf2 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 65cf0116..97a39129 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 064d3517..ab89bb5e 100644 --- a/handlers/keys.py +++ b/handlers/keys.py @@ -79,9 +79,16 @@ async def process_callback_view_key(callback_query: types.CallbackQuery): expiry_time = record['expiry_time'] expiry_date = datetime.utcfromtimestamp(expiry_time / 1000) current_date = datetime.utcnow() - days_left = (expiry_date - current_date).days + time_left = expiry_date - current_date + + if time_left.total_seconds() <= 0: + days_left_message = "Ключ истек." + elif time_left.days > 0: + days_left_message = f"Осталось дней: {time_left.days}" + else: + hours_left = time_left.seconds // 3600 + days_left_message = f"Осталось часов: {hours_left}" - days_left_message = f"Осталось дней: {days_left}" if days_left > 0 else "Ключ истек." response_message = (f"Ваш ключ:\n
{key}\n"
f"Дата окончания: {expiry_date.strftime('%Y-%m-%d %H:%M:%S')}\n"
f"{days_left_message}")
diff --git a/handlers/notifications.py b/handlers/notifications.py
index 42c57a76..6ddce0db 100644
--- a/handlers/notifications.py
+++ b/handlers/notifications.py
@@ -1,6 +1,11 @@
import asyncpg
from datetime import datetime, timedelta
from aiogram import Bot
+from aiogram import Router, types
+from bot import bot
+from aiogram.filters import Command
+
+router = Router()
from config import DATABASE_URL
@@ -39,3 +44,24 @@ async def notify_expiring_keys(bot: Bot):
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 1828e21f..826f3d6f 100644
--- a/handlers/pay.py
+++ b/handlers/pay.py
@@ -232,4 +232,4 @@ async def process_admin_confirmation(callback_query: types.CallbackQuery, state:
finally:
await state.clear()
- await callback_query.answer()
+ await callback_query.answer()
\ No newline at end of file
diff --git a/key_management.py b/key_management.py
index 9cd058ec..2336a92e 100644
--- a/key_management.py
+++ b/key_management.py
@@ -9,6 +9,7 @@ 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
@@ -139,7 +140,7 @@ async def handle_key_name_input(message: Message, state: FSMContext):
if trial_status == 0:
# Создаем пробный ключ на 1 день
- expiry_time = int((current_time + timedelta(days=1)).timestamp() * 1000)
+ expiry_time = int((current_time + timedelta(days=1, hours=3)).timestamp() * 1000)
else:
# Проверяем баланс перед созданием нового ключа
balance = await get_balance(tg_id)
@@ -151,10 +152,23 @@ 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)).timestamp() * 1000)
+ expiry_time = int((current_time + timedelta(days=30, hours=3)).timestamp() * 1000)
try:
- 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_time, 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) # Возвращаем пользователя к вводу имени ключа
+ return
+ else:
+ raise Exception(error_msg)
+
+ # Если добавление клиента прошло успешно, получаем ссылку
connection_link = link(session, client_id, email)
# Проверка существующей записи
@@ -182,6 +196,7 @@ async def handle_key_name_input(message: Message, state: FSMContext):
f"{connection_link}"
)
await message.bot.send_message(tg_id, key_message, parse_mode="HTML", reply_markup=keyboard)
+
except Exception as e:
await message.bot.send_message(tg_id, f"❌ Ошибка при создании ключа: {e}")
@@ -189,6 +204,7 @@ async def handle_key_name_input(message: Message, state: FSMContext):
+
@dp.callback_query(F.data == 'instructions')
async def handle_instructions(callback_query: CallbackQuery):
instructions_message = (