diff --git a/bot.py b/bot.py index cdc9dc8b..3a8f1b84 100644 --- a/bot.py +++ b/bot.py @@ -8,7 +8,7 @@ storage = MemoryStorage() dp = Dispatcher(bot=bot, storage=storage) router = Router() -from handlers import start, profile, keys, stats, expiry, balance, pay +from handlers import start, profile, keys, balance, pay from key_management import router as key_management_router @@ -16,8 +16,6 @@ from key_management import router as key_management_router dp.include_router(start.router) dp.include_router(profile.router) dp.include_router(keys.router) -dp.include_router(stats.router) -dp.include_router(expiry.router) dp.include_router(balance.router) dp.include_router(key_management_router) dp.include_router(pay.router) diff --git a/client.py b/client.py index 7b699364..a6ae8247 100644 --- a/client.py +++ b/client.py @@ -9,10 +9,8 @@ import aiosqlite def add_client(session, client_id: str, email: str, tg_id: str, limit_ip: int, total_gb: int, expiry_time: int, enable: bool, flow: str): url = 'https://solonet.pocomacho.ru:62553/solonet/panel/api/inbounds/addClient' - # Преобразуем email в нижний регистр email = email.lower() - # Формируем данные клиента client_data = { "id": client_id, "alterId": 0, @@ -26,22 +24,19 @@ def add_client(session, client_id: str, email: str, tg_id: str, limit_ip: int, t "flow": flow, } - # Преобразуем данные клиента в строку JSON settings = json.dumps({"clients": [client_data]}) - # Формируем тело запроса data = { - "id": 1, # Если id динамически изменяется, замените это значение + "id": 1, "settings": settings } headers = { - 'Content-Type': 'application/json', # Если требуется токен авторизации + 'Content-Type': 'application/json', } response = session.post(url, json=data, headers=headers) - # Выводим информацию о запросе и ответе print(f"Запрос на добавление клиента: {data}") print(f"Статус ответа: {response.status_code}") print(f"Ответ от сервера: {response.text}") @@ -51,10 +46,7 @@ def add_client(session, client_id: str, email: str, tg_id: str, limit_ip: int, t else: print(f"Ошибка при добавлении клиента: {response.status_code}, {response.text}") -import json - def extend_client_key(session, tg_id, client_id, email: str, new_expiry_time: int) -> bool: - # Получаем текущие данные клиента response = session.get(f"https://solonet.pocomacho.ru:62553/solonet/panel/api/inbounds/getClientTraffics/{email}") print(f"GET {response.url} Status: {response.status_code}") print(f"GET Response: {response.text}") @@ -70,25 +62,21 @@ def extend_client_key(session, tg_id, client_id, email: str, new_expiry_time: in print("Не удалось получить данные клиента.") return False - # Получаем текущий срок действия current_expiry_time = client_data.get('expiryTime', 0) - # Если нет текущего срока, используем новый срок if current_expiry_time == 0: current_expiry_time = new_expiry_time - # Определяем новый срок окончания updated_expiry_time = max(current_expiry_time, new_expiry_time) - # Формируем данные для обновления payload = { - "id": 1, # Если id динамически изменяется, замените это значение + "id": 1, "settings": json.dumps({ "clients": [ { "id": client_id, "alterId": 0, - "email": email.lower(), # Приведение email к нижнему регистру + "email": email.lower(), "limitIp": 2, "totalGB": 429496729600000, "expiryTime": updated_expiry_time, @@ -117,6 +105,22 @@ def extend_client_key(session, tg_id, client_id, email: str, new_expiry_time: in else: print(f"Ошибка при продлении ключа: {response.status_code} - {response.text}") return False + except Exception as e: + print(f"Ошибка запроса: {e}") + return False + +def delete_client(session, client_id: str) -> bool: + url = f"https://solonet.pocomacho.ru:62553/solonet/panel/api/inbounds/1/delClient/{client_id}" + headers = { + 'Accept': 'application/json' + } + try: + response = session.post(url, headers=headers) + if response.status_code == 200: + return True + else: + print(f"Ошибка при удалении клиента: {response.status_code} - {response.text}") + return False except Exception as e: print(f"Ошибка запроса: {e}") return False \ No newline at end of file diff --git a/database.py b/database.py index 4c9ea929..4497275a 100644 --- a/database.py +++ b/database.py @@ -1,48 +1,46 @@ import aiosqlite from datetime import datetime from config import DATABASE_PATH -import aiosqlite async def init_db(): async with aiosqlite.connect(DATABASE_PATH) as db: await db.execute(''' CREATE TABLE IF NOT EXISTS connections ( - tg_id INTEGER NOT NULL, - client_id TEXT NOT NULL, - email TEXT NOT NULL, - expiry_time INTEGER NOT NULL, + tg_id INTEGER PRIMARY KEY NOT NULL, balance REAL NOT NULL DEFAULT 0.0, - PRIMARY KEY (tg_id, client_id) + trial INTEGER NOT NULL DEFAULT 0 ) ''') await db.execute(''' CREATE TABLE IF NOT EXISTS keys ( - tg_id INTEGER NOT NULL, -- Добавлено поле tg_id + tg_id INTEGER NOT NULL, client_id TEXT NOT NULL, email TEXT NOT NULL, created_at INTEGER NOT NULL, + expiry_time INTEGER NOT NULL, key TEXT NOT NULL, - PRIMARY KEY (tg_id, client_id) -- Изменено на (tg_id, client_id) + PRIMARY KEY (tg_id, client_id) ) ''') await db.commit() -async def add_connection(tg_id: int, client_id: str, email: str, expiry_time: int, balance: float = 0.0): +async def add_connection(tg_id: int, balance: float = 0.0, trial: int = 0): async with aiosqlite.connect(DATABASE_PATH) as db: await db.execute(''' - INSERT INTO connections (tg_id, client_id, email, expiry_time, balance) - VALUES (?, ?, ?, ?, ?) - ''', (tg_id, client_id, email, expiry_time, balance)) + INSERT INTO connections (tg_id, balance, trial) + VALUES (?, ?, ?) + ''', (tg_id, balance, trial)) await db.commit() -async def store_key(tg_id: int, client_id: str, email: str, key: str): +async def store_key(tg_id: int, client_id: str, email: str, expiry_time: int, key: str): async with aiosqlite.connect(DATABASE_PATH) as db: await db.execute(''' - INSERT INTO keys (tg_id, client_id, email, created_at, key) - VALUES (?, ?, ?, ?, ?) - ''', (tg_id, client_id, email, int(datetime.utcnow().timestamp() * 1000), key)) + INSERT INTO keys (tg_id, client_id, email, created_at, expiry_time, key) + VALUES (?, ?, ?, ?, ?, ?) + ''', (tg_id, client_id, email, int(datetime.utcnow().timestamp() * 1000), expiry_time, key)) await db.commit() + async def get_keys(tg_id: int): async with aiosqlite.connect(DATABASE_PATH) as db: async with db.execute(''' @@ -54,33 +52,15 @@ async def get_keys(tg_id: int): async def has_active_key(tg_id: int) -> bool: async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute("SELECT COUNT(*) FROM connections WHERE tg_id = ? AND expiry_time > ?", - (tg_id, int(datetime.utcnow().timestamp() * 1000))) as cursor: + async with db.execute("SELECT COUNT(*) FROM keys WHERE tg_id = ?", (tg_id,)) as cursor: count = await cursor.fetchone() return count[0] > 0 -async def get_active_key_email(tg_id: int) -> str: - async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute("SELECT email FROM connections WHERE tg_id = ? AND expiry_time > ?", - (tg_id, int(datetime.utcnow().timestamp() * 1000))) as cursor: - record = await cursor.fetchone() - return record[0] if record else None - -async def get_key_expiry_time(tg_id: int) -> datetime: - async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute("SELECT expiry_time FROM connections WHERE tg_id = ? AND expiry_time > ?", - (tg_id, int(datetime.utcnow().timestamp() * 1000))) as cursor: - record = await cursor.fetchone() - if record: - expiry_time = record[0] - return datetime.utcfromtimestamp(expiry_time / 1000) - return None - -async def get_balance(tg_id: int) -> str: +async def get_balance(tg_id: int) -> float: async with aiosqlite.connect(DATABASE_PATH) as db: async with db.execute("SELECT balance FROM connections WHERE tg_id = ?", (tg_id,)) as cursor: record = await cursor.fetchone() - return record[0] if record else "Неизвестно" + return record[0] if record else 0.0 async def update_balance(tg_id: int, amount: float): async with aiosqlite.connect(DATABASE_PATH) as db: @@ -91,8 +71,14 @@ async def update_balance(tg_id: int, amount: float): ''', (amount, tg_id)) await db.commit() +async def get_trial(tg_id: int) -> int: + async with aiosqlite.connect(DATABASE_PATH) as db: + async with db.execute("SELECT trial FROM connections WHERE tg_id = ?", (tg_id,)) as cursor: + record = await cursor.fetchone() + return record[0] if record else 0 + async def get_key_count(tg_id: int) -> int: async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute('SELECT COUNT(*) FROM keys k JOIN connections c ON k.client_id = c.client_id WHERE c.tg_id = ?', (tg_id,)) as cursor: + async with db.execute('SELECT COUNT(*) FROM keys WHERE tg_id = ?', (tg_id,)) as cursor: count = await cursor.fetchone() return count[0] if count else 0 diff --git a/handlers/__pycache__/keys.cpython-310.pyc b/handlers/__pycache__/keys.cpython-310.pyc index 59464d1f..458ddd96 100644 Binary files a/handlers/__pycache__/keys.cpython-310.pyc and b/handlers/__pycache__/keys.cpython-310.pyc differ diff --git a/handlers/expiry.py b/handlers/expiry.py deleted file mode 100644 index 71295447..00000000 --- a/handlers/expiry.py +++ /dev/null @@ -1,33 +0,0 @@ -from aiogram import types, Router -from database import get_active_key_email -from datetime import datetime -import aiosqlite -from config import DATABASE_PATH - -router = Router() - -@router.callback_query(lambda c: c.data == 'view_expiry') -async def process_callback_view_expiry(callback_query: types.CallbackQuery): - tg_id = callback_query.from_user.id - - try: - email = await get_active_key_email(tg_id) - if email: - async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute("SELECT expiry_time FROM connections WHERE tg_id = ? AND expiry_time > ?", - (tg_id, int(datetime.utcnow().timestamp() * 1000))) as cursor: - record = await cursor.fetchone() - if record: - expiry_time = record[0] - expiry_date = datetime.utcfromtimestamp(expiry_time / 1000).strftime("%Y-%m-%d %H:%M:%S") - message_text = f"Дата окончания вашего ключа: {expiry_date}" - else: - message_text = "У вас нет активных ключей." - else: - message_text = "У вас нет активных ключей." - - except Exception as e: - message_text = f"Ошибка при получении даты окончания ключа: {e}" - - await callback_query.message.reply(message_text) - await callback_query.answer() diff --git a/handlers/keys.py b/handlers/keys.py index 85ceac7c..eddccbcc 100644 --- a/handlers/keys.py +++ b/handlers/keys.py @@ -2,7 +2,7 @@ from aiogram import types, Router import aiosqlite from bot import bot from datetime import datetime, timedelta -from database import get_balance, update_balance +from database import get_balance, update_balance, get_trial from client import extend_client_key, login_with_credentials from config import ADMIN_USERNAME, DATABASE_PATH, ADMIN_PASSWORD @@ -16,7 +16,7 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery): try: async with aiosqlite.connect(DATABASE_PATH) as db: async with db.execute(''' - SELECT email FROM connections WHERE tg_id = ? + SELECT email FROM keys WHERE tg_id = ? ''', (tg_id,)) as cursor: records = await cursor.fetchall() @@ -49,6 +49,7 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery): await callback_query.answer() + # Обработка запроса на просмотр информации о ключе @router.callback_query(lambda c: c.data.startswith('view_key_')) async def process_callback_view_key(callback_query: types.CallbackQuery): @@ -58,10 +59,10 @@ async def process_callback_view_key(callback_query: types.CallbackQuery): try: async with aiosqlite.connect(DATABASE_PATH) as db: async with db.execute(''' - SELECT k.key, c.expiry_time + SELECT k.key, k.expiry_time FROM keys k - JOIN connections c ON k.client_id = c.client_id - WHERE c.tg_id = ? AND c.email = ? + JOIN connections c ON k.tg_id = c.tg_id + WHERE k.tg_id = ? AND k.email = ? ''', (tg_id, key_name)) as cursor: record = await cursor.fetchone() @@ -105,7 +106,7 @@ async def process_callback_renew_key(callback_query: types.CallbackQuery): try: async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute('SELECT client_id, email, expiry_time FROM connections WHERE tg_id = ?', (tg_id,)) as cursor: + async with db.execute('SELECT client_id, email, expiry_time FROM keys WHERE tg_id = ?', (tg_id,)) as cursor: record = await cursor.fetchone() if record: @@ -145,7 +146,7 @@ async def process_callback_renew_plan(callback_query: types.CallbackQuery): try: async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute('SELECT client_id, email, expiry_time FROM connections WHERE tg_id = ?', (tg_id,)) as cursor: + async with db.execute('SELECT client_id, email, expiry_time FROM keys WHERE tg_id = ?', (tg_id,)) as cursor: record = await cursor.fetchone() if record: @@ -182,7 +183,7 @@ async def process_callback_renew_plan(callback_query: types.CallbackQuery): if success: await update_balance(tg_id, -cost) # Списание средств с баланса - await db.execute('UPDATE connections SET expiry_time = ? WHERE client_id = ?', (new_expiry_time, client_id)) + await db.execute('UPDATE keys SET expiry_time = ? WHERE client_id = ?', (new_expiry_time, client_id)) await db.commit() response_message = f"Ваш ключ был успешно продлен на {days_to_extend // 30} месяц(-)." back_button = types.InlineKeyboardButton(text='Назад', callback_data='view_keys') @@ -207,4 +208,4 @@ async def delete_previous_message(callback_query: types.CallbackQuery): # Обработка ошибок async def handle_error(tg_id, callback_query, message): await delete_previous_message(callback_query) - await bot.send_message(tg_id, message) + await bot.send_message(tg_id, message) \ No newline at end of file diff --git a/handlers/stats.py b/handlers/stats.py deleted file mode 100644 index c0b1ae12..00000000 --- a/handlers/stats.py +++ /dev/null @@ -1,45 +0,0 @@ -from aiogram import types, Router -import re -from database import get_active_key_email -from auth import link, login_with_credentials -from datetime import datetime -import aiosqlite -from config import DATABASE_PATH -from config import ADMIN_USERNAME, ADMIN_PASSWORD - - -router = Router() -session = login_with_credentials(ADMIN_USERNAME, ADMIN_PASSWORD) - -@router.callback_query(lambda c: c.data == 'view_stats') -async def process_callback_view_stats(callback_query: types.CallbackQuery): - tg_id = callback_query.from_user.id - - try: - email = await get_active_key_email(tg_id) - if email: - async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute("SELECT client_id FROM connections WHERE tg_id = ? AND expiry_time > ?", - (tg_id, int(datetime.utcnow().timestamp() * 1000))) as cursor: - record = await cursor.fetchone() - if record: - client_id = record[0] - connection_link = link(session, client_id, email) - - up_match = re.search(r'up=(\d+)', connection_link) - down_match = re.search(r'down=(\d+)', connection_link) - - up = up_match.group(1) if up_match else "Неизвестно" - down = down_match.group(1) if down_match else "Неизвестно" - - statistics = f"Статистика вашего ключа:\nЗагрузка: {up} MB\nВыгрузка: {down} MB" - else: - statistics = "У вас нет активных ключей." - else: - statistics = "У вас нет активных ключей." - - except Exception as e: - statistics = f"Ошибка при получении статистики: {e}" - - await callback_query.message.reply(f"Ваша статистика:\n{statistics}") - await callback_query.answer() diff --git a/key_management.py b/key_management.py index e0c3443d..417326e7 100644 --- a/key_management.py +++ b/key_management.py @@ -10,13 +10,12 @@ from aiogram.fsm.context import FSMContext from aiogram.fsm.state import State, StatesGroup from auth import login_with_credentials, link -from client import add_client, extend_client_key +from client import add_client from config import API_TOKEN, ADMIN_PASSWORD, ADMIN_USERNAME, ADMIN_CHAT_ID, DATABASE_PATH from database import add_connection, has_active_key, get_balance, store_key, update_balance from bot import dp from handlers.start import start_command from handlers.profile import process_callback_view_profile -from handlers.keys import process_callback_view_keys from bot import bot router = Router() @@ -27,7 +26,6 @@ def sanitize_key_name(key_name: str) -> str: class Form(StatesGroup): waiting_for_key_name = State() - waiting_for_expiry_date = State() viewing_profile = State() # Обработка нажатия кнопки создания ключа @@ -41,10 +39,10 @@ async def process_callback_create_key(callback_query: CallbackQuery, state: FSMC "Хотите продолжить?", reply_markup=InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text='Да, создать новый ключ', callback_data='confirm_create_new_key')], - [InlineKeyboardButton(text='Назад', callback_data='cancel_create_key')] # Изменили текст на "Назад" + [InlineKeyboardButton(text='Назад', callback_data='cancel_create_key')] ]) ) - await state.update_data(creating_new_key=True) # Сохраняем состояние создания нового ключа + await state.update_data(creating_new_key=True) else: await callback_query.message.edit_text("Вам будет выдан пробный ключ. Пожалуйста, выберите имя для вашего ключа:") await state.set_state(Form.waiting_for_key_name) @@ -53,31 +51,21 @@ async def process_callback_create_key(callback_query: CallbackQuery, state: FSMC @dp.callback_query(F.data == 'cancel_create_key') async def cancel_create_key(callback_query: CallbackQuery, state: FSMContext): - await process_callback_view_profile(callback_query, state) # Возвращаем в профиль + await process_callback_view_profile(callback_query, state) await callback_query.answer() - - @dp.callback_query(F.data == 'confirm_create_new_key') async def confirm_create_new_key(callback_query: CallbackQuery, state: FSMContext): await callback_query.message.edit_text("Пожалуйста, выберите имя для вашего нового ключа:") await state.set_state(Form.waiting_for_key_name) - await state.update_data(creating_new_key=True) # Убедитесь, что это состояние сохранено + await state.update_data(creating_new_key=True) await callback_query.answer() -@dp.callback_query(F.data == 'cancel_create_key') -async def cancel_create_key(callback_query: CallbackQuery): - await callback_query.message.edit_text("Создание нового ключа отменено.") - await callback_query.answer() - - # Обработка текстовых сообщений @dp.message() async def handle_text(message: Message, state: FSMContext): current_state = await state.get_state() - print(f"Received message: {message.text}, Current state: {current_state}") - - # Обработка команд и переходов + if message.text == "Мой профиль": callback_query = types.CallbackQuery( id="1", @@ -93,7 +81,6 @@ async def handle_text(message: Message, state: FSMContext): await start_command(message) return - # Если ожидается имя ключа if current_state == Form.waiting_for_key_name.state: await handle_key_name_input(message, state) @@ -106,7 +93,6 @@ async def handle_key_name_input(message: Message, state: FSMContext): await state.clear() return - # Получаем данные состояния data = await state.get_data() creating_new_key = data.get('creating_new_key', False) @@ -125,15 +111,23 @@ async def handle_key_name_input(message: Message, state: FSMContext): await state.clear() return - await update_balance(tg_id, -100) # Списание 100 рублей за новый ключ + await update_balance(tg_id, -100) 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") connection_link = link(session, client_id, email) - await add_connection(tg_id, client_id, email, expiry_time, 0) - await store_key(tg_id, client_id, email, connection_link) + # Проверка существующей записи + async with aiosqlite.connect(DATABASE_PATH) as db: + cursor = await db.execute('SELECT * FROM connections WHERE tg_id = ?', (tg_id,)) + existing_connection = await cursor.fetchone() + + if existing_connection: + await db.execute('UPDATE connections SET trial = 1 WHERE tg_id = ?', (tg_id,)) + else: + await add_connection(tg_id, 0, 1) + + await store_key(tg_id, client_id, email, expiry_time, connection_link) keyboard = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text='Инструкции по использованию', callback_data='instructions')], @@ -144,45 +138,9 @@ async def handle_key_name_input(message: Message, state: FSMContext): await message.reply(key_message, parse_mode="HTML", reply_markup=keyboard) except Exception as e: await message.reply(f"Ошибка при создании ключа: {e}") - print(f"Ошибка при создании ключа: {e}") await state.clear() - -# Обработка нажатия кнопки создания ключа -@dp.callback_query(F.data == 'create_key') -async def process_callback_create_key(callback_query: CallbackQuery, state: FSMContext): - tg_id = callback_query.from_user.id - - if await has_active_key(tg_id): - await callback_query.message.edit_text( - "У вас уже есть активный ключ. Вы можете создать новый ключ за дополнительную плату в размере 100 рублей. " - "Хотите продолжить?", - reply_markup=InlineKeyboardMarkup(inline_keyboard=[ - [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 state.set_state(Form.waiting_for_key_name) - - await callback_query.answer() - - -@dp.callback_query(F.data == 'confirm_create_new_key') -async def confirm_create_new_key(callback_query: CallbackQuery, state: FSMContext): - await callback_query.message.edit_text("Пожалуйста, выберите имя для вашего нового ключа:") - await state.set_state(Form.waiting_for_key_name) - await callback_query.answer() - -@dp.callback_query(F.data == 'cancel_create_key') -async def cancel_create_key(callback_query: CallbackQuery): - await callback_query.message.edit_text("Создание нового ключа отменено.") - await callback_query.answer() - -# Обработка кнопки "Инструкции" @dp.callback_query(F.data == 'instructions') async def handle_instructions(callback_query: CallbackQuery): instructions_message = ( @@ -202,47 +160,36 @@ async def handle_instructions(callback_query: CallbackQuery): await callback_query.message.edit_text(instructions_message, parse_mode='Markdown', reply_markup=keyboard) await callback_query.answer() -# Обработка кнопки "Назад" @dp.callback_query(F.data == 'back_to_main') -async def handle_back_to_main(callback_query: CallbackQuery): - tg_id = callback_query.from_user.id - new_callback_query = CallbackQuery( - id=callback_query.id, - from_user=callback_query.from_user, - chat_instance=callback_query.chat_instance, - data='view_keys', - message=callback_query.message - ) - - await process_callback_view_keys(new_callback_query) +async def handle_back_to_main(callback_query: CallbackQuery, state: FSMContext): + await process_callback_view_profile(callback_query, state) await callback_query.answer() -# Фоновая задача для продления ключей async def renew_expired_keys(): while True: current_time = datetime.utcnow() async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute('SELECT tg_id, client_id FROM connections WHERE expiry_time <= ?', (int(current_time.timestamp() * 1000),)) as cursor: - expired_keys = await cursor.fetchall() + async with db.execute('SELECT tg_id FROM connections WHERE trial > 0') as cursor: + active_keys = await cursor.fetchall() - for tg_id, client_id in expired_keys: + for tg_id, in active_keys: balance = await get_balance(tg_id) if balance >= 100: new_expiry_time = int((current_time + timedelta(days=30)).timestamp() * 1000) async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute('UPDATE connections SET expiry_time = ? WHERE tg_id = ? AND client_id = ?', (new_expiry_time, tg_id, client_id)) + await db.execute('UPDATE keys SET expiry_time = ? WHERE tg_id = ?', (new_expiry_time, tg_id)) await db.commit() await update_balance(tg_id, -100) - await extend_client_key(client_id) - print(f"Ключ для клиента {client_id} продлен на месяц и списано 100 рублей.") + print(f"Ключ для пользователя {tg_id} продлен на месяц и списано 100 рублей.") else: - print(f"Недостаточно средств на балансе для клиента {client_id}. Предложение пополнить баланс.") + print(f"Недостаточно средств на балансе для пользователя {tg_id}. Предложение пополнить баланс.") replenish_keyboard = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text='Пополнить баланс', callback_data='replenish_balance')] ]) await bot.send_message(tg_id, "Ваш баланс недостаточен для продления ключа. Пожалуйста, пополните баланс.", reply_markup=replenish_keyboard) await asyncio.sleep(3600) +