переход на postresql
This commit is contained in:
@@ -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'
|
||||
|
||||
+65
-65
@@ -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
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+143
-133
@@ -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<pre>{key}</pre>\n"
|
||||
f"Дата окончания: <b>{expiry_date.strftime('%Y-%m-%d %H:%M:%S')}</b>\n"
|
||||
f"{days_left_message}")
|
||||
days_left_message = f"Осталось дней: {days_left}" if days_left > 0 else "Ключ истек."
|
||||
response_message = (f"Ваш ключ:\n<pre>{key}</pre>\n"
|
||||
f"Дата окончания: <b>{expiry_date.strftime('%Y-%m-%d %H:%M:%S')}</b>\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"Баланс: <b>{balance} руб.</b>\n"
|
||||
f"Действующий ключ истекает <b>{datetime.utcfromtimestamp(expiry_time / 1000).strftime('%Y-%m-%d %H:%M:%S')}</b>")
|
||||
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"Баланс: <b>{balance} руб.</b>\n"
|
||||
f"Действующий ключ истекает <b>{datetime.utcfromtimestamp(expiry_time / 1000).strftime('%Y-%m-%d %H:%M:%S')}</b>")
|
||||
|
||||
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)
|
||||
await bot.send_message(tg_id, message)
|
||||
|
||||
+30
-25
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
+28
-20
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user