diff --git a/client.py b/client.py index a6ae8247..8522dc46 100644 --- a/client.py +++ b/client.py @@ -1,10 +1,4 @@ -import requests import json -from config import ADMIN_USERNAME, ADMIN_PASSWORD, GET_INBOUNDS_URL, DATABASE_PATH -import uuid -from auth import login_with_credentials -from datetime import datetime, timedelta -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' diff --git a/database.py b/database.py index 4497275a..983762fe 100644 --- a/database.py +++ b/database.py @@ -1,84 +1,84 @@ -import aiosqlite +import asyncpg from datetime import datetime -from config import DATABASE_PATH +from config import DATABASE_URL # Example: "postgresql://user:password@localhost:5432/dbname" async def init_db(): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - CREATE TABLE IF NOT EXISTS connections ( - tg_id INTEGER PRIMARY KEY NOT NULL, - balance REAL NOT NULL DEFAULT 0.0, - trial INTEGER NOT NULL DEFAULT 0 - ) - ''') - await db.execute(''' - CREATE TABLE IF NOT EXISTS keys ( - 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) - ) - ''') - await db.commit() + conn = await asyncpg.connect(DATABASE_URL) + await conn.execute(''' + CREATE TABLE IF NOT EXISTS connections ( + tg_id BIGINT PRIMARY KEY NOT NULL, + balance REAL NOT NULL DEFAULT 0.0, + trial INTEGER NOT NULL DEFAULT 0 + ) + ''') + await conn.execute(''' + CREATE TABLE IF NOT EXISTS keys ( + tg_id BIGINT NOT NULL, + client_id TEXT NOT NULL, + email TEXT NOT NULL, + created_at BIGINT NOT NULL, + expiry_time BIGINT NOT NULL, + key TEXT NOT NULL, + PRIMARY KEY (tg_id, client_id) + ) + ''') + await conn.close() 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, balance, trial) - VALUES (?, ?, ?) - ''', (tg_id, balance, trial)) - await db.commit() + conn = await asyncpg.connect(DATABASE_URL) + await conn.execute(''' + INSERT INTO connections (tg_id, balance, trial) + VALUES ($1, $2, $3) + ''', tg_id, balance, trial) + await conn.close() 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, expiry_time, key) - VALUES (?, ?, ?, ?, ?, ?) - ''', (tg_id, client_id, email, int(datetime.utcnow().timestamp() * 1000), expiry_time, key)) - await db.commit() - + conn = await asyncpg.connect(DATABASE_URL) + await conn.execute(''' + INSERT INTO keys (tg_id, client_id, email, created_at, expiry_time, key) + VALUES ($1, $2, $3, $4, $5, $6) + ''', tg_id, client_id, email, int(datetime.utcnow().timestamp() * 1000), expiry_time, key) + await conn.close() async def get_keys(tg_id: int): - async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute(''' - SELECT client_id, email, created_at, key - FROM keys - WHERE tg_id = ? - ''', (tg_id,)) as cursor: - return await cursor.fetchall() + conn = await asyncpg.connect(DATABASE_URL) + records = await conn.fetch(''' + SELECT client_id, email, created_at, key + FROM keys + WHERE tg_id = $1 + ''', tg_id) + await conn.close() + return records async def has_active_key(tg_id: int) -> bool: - async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute("SELECT COUNT(*) FROM keys WHERE tg_id = ?", (tg_id,)) as cursor: - count = await cursor.fetchone() - return count[0] > 0 + conn = await asyncpg.connect(DATABASE_URL) + count = await conn.fetchval("SELECT COUNT(*) FROM keys WHERE tg_id = $1", tg_id) + await conn.close() + return count > 0 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 0.0 + conn = await asyncpg.connect(DATABASE_URL) + balance = await conn.fetchval("SELECT balance FROM connections WHERE tg_id = $1", tg_id) + await conn.close() + return balance if balance is not None else 0.0 async def update_balance(tg_id: int, amount: float): - async with aiosqlite.connect(DATABASE_PATH) as db: - await db.execute(''' - UPDATE connections - SET balance = balance + ? - WHERE tg_id = ? - ''', (amount, tg_id)) - await db.commit() + conn = await asyncpg.connect(DATABASE_URL) + await conn.execute(''' + UPDATE connections + SET balance = balance + $1 + WHERE tg_id = $2 + ''', amount, tg_id) + await conn.close() 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 + conn = await asyncpg.connect(DATABASE_URL) + trial = await conn.fetchval("SELECT trial FROM connections WHERE tg_id = $1", tg_id) + await conn.close() + return trial if trial is not None 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 WHERE tg_id = ?', (tg_id,)) as cursor: - count = await cursor.fetchone() - return count[0] if count else 0 + conn = await asyncpg.connect(DATABASE_URL) + 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 diff --git a/handlers/__pycache__/keys.cpython-310.pyc b/handlers/__pycache__/keys.cpython-310.pyc index 458ddd96..5b23c2fd 100644 Binary files a/handlers/__pycache__/keys.cpython-310.pyc and b/handlers/__pycache__/keys.cpython-310.pyc differ diff --git a/handlers/__pycache__/pay.cpython-310.pyc b/handlers/__pycache__/pay.cpython-310.pyc index 7845c031..1dfa3905 100644 Binary files a/handlers/__pycache__/pay.cpython-310.pyc and b/handlers/__pycache__/pay.cpython-310.pyc differ diff --git a/handlers/__pycache__/profile.cpython-310.pyc b/handlers/__pycache__/profile.cpython-310.pyc index a59a06fb..a8600673 100644 Binary files a/handlers/__pycache__/profile.cpython-310.pyc and b/handlers/__pycache__/profile.cpython-310.pyc differ diff --git a/handlers/keys.py b/handlers/keys.py index eddccbcc..f03a708e 100644 --- a/handlers/keys.py +++ b/handlers/keys.py @@ -1,10 +1,11 @@ +import asyncpg from aiogram import types, Router -import aiosqlite from bot import bot from datetime import datetime, timedelta 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 +from client import extend_client_key +from config import ADMIN_USERNAME, DATABASE_URL, ADMIN_PASSWORD +from auth import login_with_credentials router = Router() @@ -14,35 +15,38 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery): tg_id = callback_query.from_user.id try: - async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute(''' - SELECT email FROM keys WHERE tg_id = ? - ''', (tg_id,)) as cursor: - records = await cursor.fetchall() + conn = await asyncpg.connect(DATABASE_URL) + try: + records = await conn.fetch(''' + SELECT email FROM keys WHERE tg_id = $1 + ''', tg_id) - if records: - # Создаем кнопки для каждого ключа - buttons = [] - for record in records: - key_name = record[0] # Предполагается, что email - это название ключа - button = types.InlineKeyboardButton(text=key_name, callback_data=f'view_key_{key_name}') - buttons.append([button]) + if records: + # Создаем кнопки для каждого ключа + buttons = [] + for record in records: + key_name = record['email'] # Предполагается, что email - это название ключа + button = types.InlineKeyboardButton(text=key_name, callback_data=f'view_key_{key_name}') + buttons.append([button]) - # Создаем клавиатуру с кнопками - inline_keyboard = types.InlineKeyboardMarkup(inline_keyboard=buttons) - response_message = "Выберите ключ для просмотра информации:" - - # Редактируем сообщение с клавиатурой - await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=inline_keyboard) - else: - # Если нет ключей, добавляем кнопку "Создать ключ" - response_message = "У вас нет ключей." - - # Кнопка "Создать ключ" - create_key_button = types.InlineKeyboardButton(text='Создать ключ', callback_data='create_key') - keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[create_key_button]]) - - await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=keyboard) + # Создаем клавиатуру с кнопками + inline_keyboard = types.InlineKeyboardMarkup(inline_keyboard=buttons) + response_message = "Выберите ключ для просмотра информации:" + + # Редактируем сообщение с клавиатурой + await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=inline_keyboard) + else: + # Если нет ключей, добавляем кнопку "Создать ключ" + response_message = "У вас нет ключей." + + # Кнопка "Создать ключ" + create_key_button = types.InlineKeyboardButton(text='Создать ключ', callback_data='create_key') + keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[create_key_button]]) + + await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=keyboard) + + finally: + await conn.close() except Exception as e: await handle_error(tg_id, callback_query, f"Ошибка при получении ключей: {e}") @@ -57,146 +61,152 @@ async def process_callback_view_key(callback_query: types.CallbackQuery): key_name = callback_query.data.split('_', 2)[2] # Получаем имя ключа try: - async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute(''' + conn = await asyncpg.connect(DATABASE_URL) + try: + record = await conn.fetchrow(''' SELECT k.key, k.expiry_time FROM keys k 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() + WHERE k.tg_id = $1 AND k.email = $2 + ''', tg_id, key_name) - if record: - key, expiry_time = record - expiry_date = datetime.utcfromtimestamp(expiry_time / 1000) - current_date = datetime.utcnow() - days_left = (expiry_date - current_date).days + if record: + key = record['key'] + expiry_time = record['expiry_time'] + expiry_date = datetime.utcfromtimestamp(expiry_time / 1000) + current_date = datetime.utcnow() + days_left = (expiry_date - current_date).days - 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}") + 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}") - # Кнопки для продления и инструкций - renew_button = types.InlineKeyboardButton(text='Продлить ключ', callback_data='renew_key') - instructions_button = types.InlineKeyboardButton(text='Инструкции по использованию', callback_data='instructions') - back_button = types.InlineKeyboardButton(text='Назад в профиль', callback_data='view_profile') - keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[renew_button], [instructions_button], [back_button]]) + # Кнопки для продления и инструкций + renew_button = types.InlineKeyboardButton(text='Продлить ключ', callback_data='renew_key') + instructions_button = types.InlineKeyboardButton(text='Инструкции по использованию', callback_data='instructions') + back_button = types.InlineKeyboardButton(text='Назад в профиль', callback_data='view_profile') + keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[renew_button], [instructions_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(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") + + finally: + await conn.close() except Exception as e: await handle_error(tg_id, callback_query, f"Ошибка при получении информации о ключе: {e}") 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, parse_mode="HTML") - # Обработка запроса на продление ключа @router.callback_query(lambda c: c.data == 'renew_key') async def process_callback_renew_key(callback_query: types.CallbackQuery): tg_id = callback_query.from_user.id - + try: - async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute('SELECT client_id, email, expiry_time FROM keys WHERE tg_id = ?', (tg_id,)) as cursor: - record = await cursor.fetchone() + conn = await asyncpg.connect(DATABASE_URL) + try: + record = await conn.fetchrow('SELECT client_id, email, expiry_time FROM keys WHERE tg_id = $1', tg_id) - if record: - client_id, email, expiry_time = record - current_time = datetime.utcnow().timestamp() * 1000 - - if expiry_time <= current_time: - await callback_query.message.answer("Ваш ключ уже истек и не может быть продлен.") - return - - # Создаем клавиатуру для выбора плана продления - keyboard = types.InlineKeyboardMarkup(inline_keyboard=[ - [types.InlineKeyboardButton(text='Продлить на 1 месяц (100 руб.)', callback_data='renew_1_month')], - [types.InlineKeyboardButton(text='Продлить на 3 месяца (250 руб.)', callback_data='renew_3_months')], - [types.InlineKeyboardButton(text='Назад', callback_data='view_profile')] - ]) + if record: + client_id = record['client_id'] + email = record['email'] + expiry_time = record['expiry_time'] + current_time = datetime.utcnow().timestamp() * 1000 - 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')}") + if expiry_time <= current_time: + await callback_query.message.answer("Ваш ключ уже истек и не может быть продлен.") + return - await delete_previous_message(callback_query) - await bot.send_message(tg_id, response_message, parse_mode="HTML", reply_markup=keyboard) + # Создаем клавиатуру для выбора плана продления + keyboard = types.InlineKeyboardMarkup(inline_keyboard=[ + [types.InlineKeyboardButton(text='Продлить на 1 месяц (100 руб.)', callback_data='renew_1_month')], + [types.InlineKeyboardButton(text='Продлить на 3 месяца (250 руб.)', callback_data='renew_3_months')], + [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 delete_previous_message(callback_query) + await bot.send_message(tg_id, response_message, parse_mode="HTML", reply_markup=keyboard) + + finally: + await conn.close() except Exception as e: await callback_query.message.answer(f"Ошибка при выборе плана: {e}") await callback_query.answer() + # Обработка выбора плана продления @router.callback_query(lambda c: c.data.startswith('renew_')) async def process_callback_renew_plan(callback_query: types.CallbackQuery): tg_id = callback_query.from_user.id plan = callback_query.data.split('_')[1] # '1' или '3' days_to_extend = 30 * int(plan) # 30 дней или 90 дней - + try: - async with aiosqlite.connect(DATABASE_PATH) as db: - 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: - client_id = record[0] - email = record[1] - expiry_time = record[2] - current_time = datetime.utcnow().timestamp() * 1000 - - if expiry_time <= current_time: - await callback_query.message.answer("Ваш ключ уже истек и не может быть продлен.") - return - - # Рассчитываем новый срок окончания, добавляя дни в зависимости от выбранного плана - new_expiry_time = int(expiry_time + timedelta(days=days_to_extend).total_seconds() * 1000) - - # Определяем стоимость продления - cost = 100 if plan == '1' else 250 - - # Проверка баланса - balance = await get_balance(tg_id) - if balance < cost: - replenish_button = types.InlineKeyboardButton(text='Пополнить баланс', callback_data='replenish_balance') - back_button = types.InlineKeyboardButton(text='Назад', callback_data='view_keys') - keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[replenish_button], [back_button]]) - - await callback_query.message.answer("Недостаточно средств для продления ключа.", reply_markup=keyboard) - return - - # Создаем сессию для API-запросов - session = login_with_credentials(ADMIN_USERNAME, ADMIN_PASSWORD) - - # Обновляем ключ через API - success = extend_client_key(session, tg_id, client_id, email, new_expiry_time) - - if success: - await update_balance(tg_id, -cost) # Списание средств с баланса - 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') - keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[back_button]]) - await bot.send_message(tg_id, response_message, reply_markup=keyboard) - else: - await bot.send_message(tg_id, "Ошибка при продлении ключа.") + conn = await asyncpg.connect(DATABASE_URL) + try: + record = await conn.fetchrow('SELECT client_id, email, expiry_time FROM keys WHERE tg_id = $1', tg_id) + + if record: + client_id = record['client_id'] + email = record['email'] + expiry_time = record['expiry_time'] + current_time = datetime.utcnow().timestamp() * 1000 + + if expiry_time <= current_time: + await callback_query.message.answer("Ваш ключ уже истек и не может быть продлен.") + return + + # Рассчитываем новый срок окончания + new_expiry_time = int(expiry_time + timedelta(days=days_to_extend).total_seconds() * 1000) + + # Определяем стоимость продления + cost = 100 if plan == '1' else 250 + + # Проверка баланса + balance = await get_balance(tg_id) + if balance < cost: + replenish_button = types.InlineKeyboardButton(text='Пополнить баланс', callback_data='replenish_balance') + back_button = types.InlineKeyboardButton(text='Назад', callback_data='view_keys') + keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[replenish_button], [back_button]]) + + await callback_query.message.answer("Недостаточно средств для продления ключа.", reply_markup=keyboard) + return + + # Создаем сессию для API-запросов + session = login_with_credentials(ADMIN_USERNAME, ADMIN_PASSWORD) + + # Обновляем ключ через API + success = extend_client_key(session, tg_id, client_id, email, new_expiry_time) + + if success: + await update_balance(tg_id, -cost) # Списание средств с баланса + await conn.execute('UPDATE keys SET expiry_time = $1 WHERE client_id = $2', new_expiry_time, client_id) + response_message = f"Ваш ключ был успешно продлен на {days_to_extend // 30} месяц(-)." + back_button = types.InlineKeyboardButton(text='Назад', callback_data='view_keys') + keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[back_button]]) + await bot.send_message(tg_id, response_message, reply_markup=keyboard) else: - await bot.send_message(tg_id, "У вас нет ключей для продления.") - + await bot.send_message(tg_id, "Ошибка при продлении ключа.") + else: + await bot.send_message(tg_id, "У вас нет ключей для продления.") + + finally: + await conn.close() + except Exception as e: await bot.send_message(tg_id, f"Ошибка при продлении ключа: {e}") - + await callback_query.answer() @@ -208,4 +218,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) \ No newline at end of file + await bot.send_message(tg_id, message) diff --git a/handlers/pay.py b/handlers/pay.py index 2ad6a0e9..5d7be13c 100644 --- a/handlers/pay.py +++ b/handlers/pay.py @@ -3,10 +3,11 @@ from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup from aiogram.fsm.context import FSMContext from aiogram.fsm.state import State, StatesGroup import aiosqlite -from config import DATABASE_PATH, ADMIN_ID +from config import ADMIN_ID, DATABASE_URL from database import get_balance, update_balance, get_key_count from bot import bot from handlers.profile import process_callback_view_profile +import asyncpg router = Router() @@ -183,36 +184,41 @@ async def process_admin_confirmation(callback_query: types.CallbackQuery, state: state_data = await state.get_data() requisites_message_id = state_data.get('requisites_message_id') - if action == 'confirm': - async with aiosqlite.connect(DATABASE_PATH) as db: + # Подключаемся к базе данных PostgreSQL + conn = await asyncpg.connect(DATABASE_URL) + try: + # Обновляем баланс пользователя await update_balance(user_id, amount) - await db.commit() - balance = await get_balance(user_id) + # Получаем обновленный баланс + balance = await get_balance(user_id) - # Создаем клавиатуру с кнопкой "Профиль" - profile_button = InlineKeyboardButton(text='Профиль', callback_data='view_profile') - profile_keyboard = InlineKeyboardMarkup(inline_keyboard=[[profile_button]]) + # Создаем клавиатуру с кнопкой "Профиль" + 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 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 - ) + # Отправляем уведомление пользователю с кнопкой "Профиль" + await bot.send_message( + user_id, + f"Ваш баланс был успешно пополнен на {amount} RUB.", + reply_markup=profile_keyboard + ) - # Удаляем сообщение с реквизитами - state_data = await state.get_data() - requisites_message_id = state_data.get('requisites_message_id') - if requisites_message_id: - try: - await bot.delete_message(chat_id=user_id, message_id=requisites_message_id) - except Exception as e: - print(f"Ошибка при удалении сообщения с реквизитами: {e}") + # Удаляем сообщение с реквизитами + requisites_message_id = state_data.get('requisites_message_id') + if requisites_message_id: + try: + await bot.delete_message(chat_id=user_id, message_id=requisites_message_id) + except Exception as e: + print(f"Ошибка при удалении сообщения с реквизитами: {e}") + + finally: + # Закрываем соединение с базой данных + await conn.close() elif action == 'decline': await send_message_with_deletion(callback_query.from_user.id, "Пополнение баланса отклонено.", state=state, message_key='admin_decline_message_id') @@ -226,7 +232,6 @@ async def process_admin_confirmation(callback_query: types.CallbackQuery, state: await callback_query.answer() - @router.message(lambda m: m.text and m.text.startswith('Недостаточно средств для продления')) async def handle_insufficient_funds(message: types.Message): user_id = message.from_user.id diff --git a/handlers/profile.py b/handlers/profile.py index c5fb2432..6089ff66 100644 --- a/handlers/profile.py +++ b/handlers/profile.py @@ -3,8 +3,6 @@ from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup from aiogram.fsm.context import FSMContext from aiogram.fsm.state import State, StatesGroup from datetime import datetime -import aiosqlite -from config import DATABASE_PATH from database import get_balance, get_key_count router = Router() diff --git a/key_management.py b/key_management.py index 417326e7..6a595d6c 100644 --- a/key_management.py +++ b/key_management.py @@ -1,8 +1,7 @@ -from datetime import datetime, timedelta -import asyncio import re import uuid -import aiosqlite +import asyncio +from datetime import datetime, timedelta from aiogram import Bot, Dispatcher, Router, types, F from aiogram.filters import Command from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery, Message @@ -11,12 +10,13 @@ from aiogram.fsm.state import State, StatesGroup from auth import login_with_credentials, link from client import add_client -from config import API_TOKEN, ADMIN_PASSWORD, ADMIN_USERNAME, ADMIN_CHAT_ID, DATABASE_PATH +from config import API_TOKEN, ADMIN_PASSWORD, ADMIN_USERNAME, ADMIN_CHAT_ID, DATABASE_URL 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 bot import dp, bot from handlers.profile import process_callback_view_profile -from bot import bot +from handlers.start import start_command + +import asyncpg router = Router() @@ -118,15 +118,18 @@ async def handle_key_name_input(message: Message, state: FSMContext): connection_link = link(session, client_id, email) # Проверка существующей записи - 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() + conn = await asyncpg.connect(DATABASE_URL) + try: + existing_connection = await conn.fetchrow('SELECT * FROM connections WHERE tg_id = $1', tg_id) if existing_connection: - await db.execute('UPDATE connections SET trial = 1 WHERE tg_id = ?', (tg_id,)) + 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) keyboard = InlineKeyboardMarkup(inline_keyboard=[ @@ -168,20 +171,25 @@ async def handle_back_to_main(callback_query: CallbackQuery, state: FSMContext): 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 FROM connections WHERE trial > 0') as cursor: - active_keys = await cursor.fetchall() + conn = await asyncpg.connect(DATABASE_URL) + try: + active_keys = await conn.fetch('SELECT tg_id FROM connections WHERE trial > 0') - for tg_id, in active_keys: + finally: + await conn.close() + + for record in active_keys: + tg_id = record['tg_id'] 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 keys SET expiry_time = ? WHERE tg_id = ?', (new_expiry_time, tg_id)) - await db.commit() - - await update_balance(tg_id, -100) + conn = await asyncpg.connect(DATABASE_URL) + try: + await conn.execute('UPDATE keys SET expiry_time = $1 WHERE tg_id = $2', new_expiry_time, tg_id) + await update_balance(tg_id, -100) + finally: + await conn.close() print(f"Ключ для пользователя {tg_id} продлен на месяц и списано 100 рублей.") else: