редизайн, кнопки назад
This commit is contained in:
@@ -69,10 +69,17 @@ def extend_client_key(session, tg_id, client_id, email: str, new_expiry_time: in
|
||||
if not client_data:
|
||||
print("Не удалось получить данные клиента.")
|
||||
return False
|
||||
|
||||
# Получаем текущий срок действия
|
||||
current_expiry_time = client_data.get('expiryTime', 0)
|
||||
|
||||
# Обновляем данные клиента
|
||||
client_data['expiryTime'] = new_expiry_time
|
||||
|
||||
# Если нет текущего срока, используем новый срок
|
||||
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 динамически изменяется, замените это значение
|
||||
@@ -81,14 +88,14 @@ def extend_client_key(session, tg_id, client_id, email: str, new_expiry_time: in
|
||||
{
|
||||
"id": client_id,
|
||||
"alterId": 0,
|
||||
"email": client_data['email'],
|
||||
"limitIp": 1,
|
||||
# "totalGB": 2,
|
||||
"expiryTime": new_expiry_time,
|
||||
"enable": client_data['enable'],
|
||||
"email": email.lower(), # Приведение email к нижнему регистру
|
||||
"limitIp": 2,
|
||||
"totalGB": 429496729600000,
|
||||
"expiryTime": updated_expiry_time,
|
||||
"enable": True,
|
||||
"tgId": tg_id,
|
||||
"subId": '',
|
||||
"flow": 'xtls-rprx-vision'
|
||||
"subId": "",
|
||||
"flow": "xtls-rprx-vision"
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
+7
-1
@@ -89,4 +89,10 @@ async def update_balance(tg_id: int, amount: float):
|
||||
SET balance = balance + ?
|
||||
WHERE tg_id = ?
|
||||
''', (amount, tg_id))
|
||||
await db.commit()
|
||||
await db.commit()
|
||||
|
||||
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:
|
||||
count = await cursor.fetchone()
|
||||
return count[0] if count else 0
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+104
-37
@@ -2,16 +2,23 @@ from aiogram import types, Router
|
||||
import aiosqlite
|
||||
from bot import bot
|
||||
from datetime import datetime, timedelta
|
||||
from database import get_active_key_email, get_balance, store_key, update_balance
|
||||
from client import extend_client_key
|
||||
from database import get_balance, update_balance
|
||||
from client import extend_client_key, login_with_credentials
|
||||
from config import ADMIN_ID, ADMIN_PASSWORD, ADMIN_USERNAME, DATABASE_PATH
|
||||
from config import ADMIN_USERNAME, DATABASE_PATH, ADMIN_PASSWORD
|
||||
|
||||
router = Router()
|
||||
|
||||
# Обработка запроса на просмотр ключей
|
||||
@router.callback_query(lambda c: c.data == 'view_keys')
|
||||
async def process_callback_view_keys(callback_query: types.CallbackQuery):
|
||||
tg_id = callback_query.from_user.id
|
||||
|
||||
# Создаем клавиатуру
|
||||
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[
|
||||
[types.InlineKeyboardButton(text='Инструкции по использованию', callback_data='instructions')],
|
||||
[types.InlineKeyboardButton(text='Продлить ключ', callback_data='renew_key')],
|
||||
[types.InlineKeyboardButton(text='Назад', callback_data='view_profile')]
|
||||
])
|
||||
|
||||
try:
|
||||
async with aiosqlite.connect(DATABASE_PATH) as db:
|
||||
@@ -22,33 +29,30 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery):
|
||||
WHERE c.tg_id = ?
|
||||
''', (tg_id,)) as cursor:
|
||||
record = await cursor.fetchone()
|
||||
|
||||
|
||||
if record:
|
||||
key = record[0]
|
||||
expiry_time = record[1]
|
||||
expiry_date = datetime.utcfromtimestamp(expiry_time / 1000).strftime("%Y-%m-%d %H:%M:%S")
|
||||
response_message = f"Ваш ключ:\n<pre>{key}</pre>\nДата окончания: <b>{expiry_date}</b>"
|
||||
|
||||
# Кнопки для инструкций и продления
|
||||
instructions_button = types.InlineKeyboardButton(text='Инструкции по использованию', callback_data='instructions')
|
||||
renew_button = types.InlineKeyboardButton(text='Продлить ключ', callback_data='renew_key')
|
||||
|
||||
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[
|
||||
[instructions_button],
|
||||
[renew_button]
|
||||
])
|
||||
|
||||
await bot.send_message(tg_id, response_message, parse_mode="HTML", reply_markup=keyboard)
|
||||
key, expiry_time = record
|
||||
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}")
|
||||
|
||||
else:
|
||||
response_message = "У вас нет ключей."
|
||||
await bot.send_message(tg_id, response_message, reply_to_message_id=callback_query.message.message_id)
|
||||
|
||||
|
||||
await delete_previous_message(callback_query)
|
||||
await bot.send_message(tg_id, response_message, parse_mode="HTML", reply_markup=keyboard)
|
||||
|
||||
except Exception as e:
|
||||
response_message = f"Ошибка при получении ключей: {e}"
|
||||
await bot.send_message(tg_id, response_message, reply_to_message_id=callback_query.message.message_id)
|
||||
|
||||
await handle_error(tg_id, callback_query, f"Ошибка при получении ключей: {e}")
|
||||
|
||||
await callback_query.answer()
|
||||
|
||||
# Обработка запроса на продление ключа
|
||||
@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
|
||||
@@ -57,22 +61,71 @@ async def process_callback_renew_key(callback_query: types.CallbackQuery):
|
||||
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:
|
||||
record = await cursor.fetchone()
|
||||
|
||||
|
||||
if record:
|
||||
client_id = record[0]
|
||||
email = record[1] # Получаем email
|
||||
expiry_time = record[2]
|
||||
client_id, email, expiry_time = record
|
||||
current_time = datetime.utcnow().timestamp() * 1000
|
||||
new_expiry_time = int((datetime.utcnow() + timedelta(days=30)).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')]
|
||||
])
|
||||
|
||||
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)
|
||||
|
||||
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 connections 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 < 100:
|
||||
await callback_query.message.answer("Недостаточно средств для продления ключа.")
|
||||
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-запросов
|
||||
@@ -82,16 +135,30 @@ async def process_callback_renew_key(callback_query: types.CallbackQuery):
|
||||
success = extend_client_key(session, tg_id, client_id, email, new_expiry_time)
|
||||
|
||||
if success:
|
||||
await update_balance(tg_id, -100) # Списание 100 рублей с баланса
|
||||
await update_balance(tg_id, -cost) # Списание средств с баланса
|
||||
await db.execute('UPDATE connections SET expiry_time = ? WHERE client_id = ?', (new_expiry_time, client_id))
|
||||
await db.commit()
|
||||
await callback_query.message.answer("Ваш ключ был успешно продлен на месяц.")
|
||||
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 callback_query.message.answer("Ошибка при продлении ключа.")
|
||||
await bot.send_message(tg_id, "Ошибка при продлении ключа.")
|
||||
else:
|
||||
await callback_query.message.answer("У вас нет ключей для продления.")
|
||||
await bot.send_message(tg_id, "У вас нет ключей для продления.")
|
||||
|
||||
except Exception as e:
|
||||
await callback_query.message.answer(f"Ошибка при продлении ключа: {e}")
|
||||
await bot.send_message(tg_id, f"Ошибка при продлении ключа: {e}")
|
||||
|
||||
await callback_query.answer()
|
||||
await callback_query.answer()
|
||||
|
||||
|
||||
# Удаление предыдущего сообщения
|
||||
async def delete_previous_message(callback_query: types.CallbackQuery):
|
||||
if callback_query.message.message_id:
|
||||
await bot.delete_message(chat_id=callback_query.from_user.id, message_id=callback_query.message.message_id)
|
||||
|
||||
# Обработка ошибок
|
||||
async def handle_error(tg_id, callback_query, message):
|
||||
await delete_previous_message(callback_query)
|
||||
await bot.send_message(tg_id, message)
|
||||
|
||||
+140
-42
@@ -4,111 +4,209 @@ from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
import aiosqlite
|
||||
from config import DATABASE_PATH, ADMIN_ID
|
||||
from database import get_balance, update_balance
|
||||
from database import get_balance, update_balance, get_key_count
|
||||
from bot import bot
|
||||
from handlers.profile import process_callback_view_profile
|
||||
|
||||
router = Router()
|
||||
|
||||
# Определение состояний
|
||||
class ReplenishBalanceState(StatesGroup):
|
||||
choosing_transfer_method = State()
|
||||
choosing_amount = State()
|
||||
waiting_for_admin_confirmation = State()
|
||||
|
||||
async def send_message_with_deletion(chat_id, text, reply_markup=None, state=None, message_key='last_message_id'):
|
||||
"""
|
||||
Отправляет сообщение и удаляет предыдущее, если оно существует.
|
||||
"""
|
||||
if state:
|
||||
try:
|
||||
state_data = await state.get_data()
|
||||
previous_message_id = state_data.get(message_key)
|
||||
|
||||
if previous_message_id:
|
||||
await bot.delete_message(chat_id=chat_id, message_id=previous_message_id)
|
||||
|
||||
sent_message = await bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
|
||||
await state.update_data({message_key: sent_message.message_id})
|
||||
|
||||
except Exception as e:
|
||||
print(f"Ошибка при удалении/отправке сообщения: {e}")
|
||||
return None
|
||||
|
||||
return sent_message
|
||||
|
||||
@router.callback_query(lambda c: c.data == 'replenish_balance')
|
||||
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)
|
||||
if key_count <= 0:
|
||||
await send_message_with_deletion(
|
||||
tg_id,
|
||||
"У вас нет ключей. Пополнение баланса возможно только при наличии ключа.",
|
||||
state=state,
|
||||
message_key='key_error_message_id'
|
||||
)
|
||||
create_key_button = InlineKeyboardButton(text='Создать ключ', callback_data='create_key')
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[[create_key_button]])
|
||||
|
||||
await callback_query.message.edit_text(
|
||||
text="Пожалуйста, создайте ключ для продолжения.",
|
||||
reply_markup=keyboard
|
||||
)
|
||||
return
|
||||
|
||||
await state.set_state(ReplenishBalanceState.choosing_transfer_method)
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='По реквизитам', callback_data='transfer_method_requisites')]
|
||||
[InlineKeyboardButton(text='По реквизитам', callback_data='transfer_method_requisites')],
|
||||
[InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')]
|
||||
])
|
||||
await bot.send_message(callback_query.from_user.id, "Выберите метод перевода:", reply_markup=keyboard)
|
||||
await callback_query.answer() # Уведомляем Telegram, что запрос обработан
|
||||
|
||||
await callback_query.message.edit_text(
|
||||
text="Выберите метод перевода:",
|
||||
reply_markup=keyboard
|
||||
)
|
||||
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)
|
||||
|
||||
if len(data) != 3:
|
||||
await bot.send_message(callback_query.from_user.id, "Неверные данные для выбора метода перевода.")
|
||||
await send_message_with_deletion(callback_query.from_user.id, "Неверные данные для выбора метода перевода.", state=state, message_key='transfer_method_error_message_id')
|
||||
return
|
||||
|
||||
transfer_method = data[2] # 'requisites'
|
||||
transfer_method = data[2]
|
||||
|
||||
if transfer_method == 'requisites':
|
||||
message = (
|
||||
"Банк: Т-Банк\n"
|
||||
"2200701036597224\n"
|
||||
"Получатель: Лисицын В.Д.\n"
|
||||
f"\n"
|
||||
"После перевода отправьте чек и дождитесь подтверждения."
|
||||
)
|
||||
amount_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[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')]
|
||||
])
|
||||
|
||||
# Удаляем старое сообщение о выборе метода
|
||||
await bot.edit_message_text(
|
||||
text="Вы выбрали метод перевода. Теперь вы увидите реквизиты.",
|
||||
chat_id=callback_query.from_user.id,
|
||||
message_id=callback_query.message.message_id
|
||||
await callback_query.message.edit_text(
|
||||
text="Выберите сумму пополнения:",
|
||||
reply_markup=amount_keyboard
|
||||
)
|
||||
|
||||
# Отправляем реквизиты в новом сообщении
|
||||
await bot.send_message(callback_query.from_user.id, message)
|
||||
|
||||
await state.update_data(transfer_method=transfer_method)
|
||||
await state.set_state(ReplenishBalanceState.choosing_amount)
|
||||
else:
|
||||
await bot.send_message(callback_query.from_user.id, "Неверный метод перевода.")
|
||||
await send_message_with_deletion(callback_query.from_user.id, "Неверный метод перевода.", state=state, message_key='transfer_method_error_message_id')
|
||||
|
||||
@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)
|
||||
|
||||
if len(data) != 2:
|
||||
await send_message_with_deletion(callback_query.from_user.id, "Неверные данные для выбора суммы.", state=state, message_key='amount_error_message_id')
|
||||
return
|
||||
|
||||
await state.update_data(transfer_method=transfer_method)
|
||||
|
||||
amount_str = data[1]
|
||||
amount = int(amount_str)
|
||||
|
||||
# Удаляем сообщение с кнопками выбора суммы
|
||||
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)
|
||||
|
||||
transfer_method = state_data.get('transfer_method')
|
||||
message = (
|
||||
"Банк: Т-Банк\n"
|
||||
"2200701036597224\n"
|
||||
"Получатель: Лисицын В.Д.\n"
|
||||
"\n"
|
||||
"После перевода отправьте чек и дождитесь подтверждения."
|
||||
)
|
||||
|
||||
await callback_query.message.edit_text(text=message, reply_markup=None)
|
||||
|
||||
admin_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='Подтвердить', callback_data=f'admin_confirm_{callback_query.from_user.id}_{transfer_method}')],
|
||||
[InlineKeyboardButton(text='Отклонить', callback_data=f'admin_decline_{callback_query.from_user.id}_{transfer_method}')]
|
||||
[InlineKeyboardButton(text='Подтвердить', callback_data=f'admin_confirm_{callback_query.from_user.id}_{transfer_method}_{amount}')],
|
||||
[InlineKeyboardButton(text='Отклонить', callback_data=f'admin_decline_{callback_query.from_user.id}_{transfer_method}_{amount}')]
|
||||
])
|
||||
|
||||
|
||||
admin_message = (
|
||||
f"Пользователь {callback_query.from_user.full_name} запросил пополнение баланса.\n"
|
||||
f"Метод перевода: {transfer_method}\n"
|
||||
f"Сумма пополнения: {amount} RUB\n"
|
||||
"Пожалуйста, подтвердите или отклоните запрос."
|
||||
)
|
||||
|
||||
await bot.send_message(ADMIN_ID, admin_message, reply_markup=admin_keyboard)
|
||||
|
||||
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:
|
||||
await bot.send_message(callback_query.from_user.id, "Вы не являетесь администратором.")
|
||||
await send_message_with_deletion(callback_query.from_user.id, "Вы не являетесь администратором.", state=state, message_key='admin_error_message_id')
|
||||
return
|
||||
|
||||
data = callback_query.data.split('_', 4)
|
||||
|
||||
if len(data) < 4:
|
||||
await bot.send_message(callback_query.from_user.id, "Неверные данные для обработки запроса.")
|
||||
await send_message_with_deletion(callback_query.from_user.id, "Неверные данные для обработки запроса.", state=state, message_key='admin_error_message_id')
|
||||
return
|
||||
|
||||
action = data[1] # 'confirm' или 'decline'
|
||||
user_id_str = data[2]
|
||||
action = data[1]
|
||||
user_id = int(data[2])
|
||||
transfer_method = data[3]
|
||||
amount = int(data[4])
|
||||
|
||||
try:
|
||||
user_id = int(user_id_str) # Преобразование user_id в целое число
|
||||
|
||||
if action == 'confirm':
|
||||
amount = 100 # Пример суммы, на которую нужно пополнить баланс
|
||||
|
||||
async with aiosqlite.connect(DATABASE_PATH) as db:
|
||||
await update_balance(user_id, amount)
|
||||
await db.commit()
|
||||
|
||||
balance = await get_balance(user_id)
|
||||
await bot.send_message(callback_query.from_user.id, f"Баланс пользователя успешно пополнен на {amount} RUB.\nТекущий баланс: {balance}")
|
||||
|
||||
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.")
|
||||
|
||||
# Удаляем сообщение с реквизитами
|
||||
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}")
|
||||
|
||||
profile_button = InlineKeyboardButton(text='Профиль', callback_data='view_profile')
|
||||
profile_keyboard = InlineKeyboardMarkup(inline_keyboard=[[profile_button]])
|
||||
await bot.send_message(user_id, "После пополнения баланса вы можете просмотреть свой профиль.", reply_markup=profile_keyboard)
|
||||
|
||||
elif action == 'decline':
|
||||
await bot.send_message(callback_query.from_user.id, "Пополнение баланса отклонено.")
|
||||
await send_message_with_deletion(callback_query.from_user.id, "Пополнение баланса отклонено.", state=state, message_key='admin_decline_message_id')
|
||||
await bot.send_message(user_id, "Ваш запрос на пополнение баланса был отклонен.")
|
||||
|
||||
except Exception as e:
|
||||
await bot.send_message(callback_query.from_user.id, f"Ошибка при пополнении баланса: {e}")
|
||||
print(f"Ошибка при пополнении баланса: {e}") # Отладочное сообщение в консоль
|
||||
await send_message_with_deletion(callback_query.from_user.id, f"Ошибка при пополнении баланса: {e}", state=state, message_key='admin_error_message_id')
|
||||
print(f"Ошибка при пополнении баланса: {e}")
|
||||
|
||||
await state.clear()
|
||||
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
|
||||
replenish_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='Пополнить баланс', callback_data='replenish_balance')]
|
||||
])
|
||||
await send_message_with_deletion(user_id, "Ваш баланс недостаточен для продления ключа. Пожалуйста, пополните баланс.", reply_markup=replenish_keyboard, state=None, message_key='insufficient_funds_message_id')
|
||||
|
||||
+20
-25
@@ -5,7 +5,7 @@ from aiogram.fsm.state import State, StatesGroup
|
||||
from datetime import datetime
|
||||
import aiosqlite
|
||||
from config import DATABASE_PATH
|
||||
from database import get_balance, has_active_key
|
||||
from database import get_balance, get_key_count
|
||||
|
||||
router = Router()
|
||||
|
||||
@@ -15,50 +15,45 @@ class ReplenishBalanceState(StatesGroup):
|
||||
|
||||
async def process_callback_view_profile(callback_query: types.CallbackQuery, state: FSMContext):
|
||||
tg_id = callback_query.from_user.id
|
||||
username = callback_query.from_user.username
|
||||
|
||||
try:
|
||||
# Проверяем наличие активного ключа
|
||||
email = await has_active_key(tg_id)
|
||||
expiry_date = "Нет активного ключа"
|
||||
|
||||
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_date = datetime.utcfromtimestamp(record[0] / 1000).strftime("%Y-%m-%d %H:%M:%S")
|
||||
# Получаем количество ключей
|
||||
key_count = await get_key_count(tg_id)
|
||||
|
||||
# Получаем баланс
|
||||
balance = await get_balance(tg_id)
|
||||
if balance is None:
|
||||
balance = 0 # По умолчанию 0, если баланс неизвестен
|
||||
|
||||
profile_message = (
|
||||
f"Профиль \n\n"
|
||||
f"ID: {tg_id}\n"
|
||||
f"Ключ: {email if expiry_date else 'Нет активного ключа'}\n"
|
||||
f"Баланс: {balance} RUB\n"
|
||||
f"<b>Профиль пользователя</b>\n\n"
|
||||
f"🔹 <b>ID:</b> {tg_id}\n"
|
||||
f"🔹 <b>Количество ключей:</b> {key_count}\n"
|
||||
f"🔹 <b>Баланс:</b> {balance} RUB\n"
|
||||
f"🔹 <b>Дата регистрации:</b> {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')}\n"
|
||||
)
|
||||
|
||||
# Кнопки для действий в профиле
|
||||
button_create_key = InlineKeyboardButton(text='Создать ключ', callback_data='create_key')
|
||||
button_view_keys = InlineKeyboardButton(text='Мои ключи', callback_data='view_keys')
|
||||
button_replenish_balance = InlineKeyboardButton(text='Пополнить баланс', callback_data='replenish_balance')
|
||||
button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_menu') # Добавляем кнопку "Назад"
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[button_create_key], # Добавляем кнопку "Создать ключ"
|
||||
[button_view_keys],
|
||||
[button_replenish_balance]
|
||||
[button_replenish_balance],
|
||||
[button_back] # Добавляем кнопку "Назад" в клавиатуру
|
||||
])
|
||||
|
||||
except Exception as e:
|
||||
profile_message = f"Ошибка при получении данных профиля: {e}"
|
||||
profile_message = f"❗️ Ошибка при получении данных профиля: {e}"
|
||||
keyboard = None
|
||||
|
||||
# Отправляем сообщение с клавиатурой
|
||||
await callback_query.message.bot.send_message(
|
||||
chat_id=callback_query.message.chat.id,
|
||||
# Редактируем существующее сообщение, а не отправляем новое
|
||||
await callback_query.message.edit_text(
|
||||
text=profile_message,
|
||||
parse_mode='Markdown',
|
||||
parse_mode='HTML',
|
||||
reply_markup=keyboard
|
||||
)
|
||||
await callback_query.answer()
|
||||
|
||||
+73
-12
@@ -4,7 +4,7 @@ from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQu
|
||||
from aiogram.fsm.storage.memory import MemoryStorage
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from config import API_TOKEN, ADMIN_ID
|
||||
from config import API_TOKEN, ADMIN_ID, CHANNEL_URL
|
||||
from bot import dp, bot # Убедитесь, что bot и dp импортируются из правильного места
|
||||
|
||||
router = Router()
|
||||
@@ -22,20 +22,22 @@ async def start_command(message: types.Message):
|
||||
"Нажмите на соответствующую кнопку ниже, чтобы начать!"
|
||||
)
|
||||
|
||||
button_view_profile = InlineKeyboardButton(text='Мой профиль', callback_data='view_profile')
|
||||
button_about_vpn = InlineKeyboardButton(text='О VPN', callback_data='about_vpn')
|
||||
button_feedback = InlineKeyboardButton(text='Обратная связь', callback_data='feedback')
|
||||
button_view_profile = InlineKeyboardButton(text='👤 Мой профиль', callback_data='view_profile')
|
||||
button_about_vpn = InlineKeyboardButton(text='🔒 О VPN', callback_data='about_vpn')
|
||||
button_feedback = InlineKeyboardButton(text='📝 Обратная связь', callback_data='feedback')
|
||||
button_channel = InlineKeyboardButton(text='📢 Наш канал', url=CHANNEL_URL)
|
||||
|
||||
inline_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[button_view_profile],
|
||||
[button_about_vpn],
|
||||
[button_feedback]
|
||||
[button_feedback],
|
||||
[button_channel]
|
||||
])
|
||||
|
||||
reply_keyboard = ReplyKeyboardMarkup(
|
||||
keyboard=[
|
||||
[KeyboardButton(text="В начало")],
|
||||
[KeyboardButton(text="Мой профиль")]
|
||||
[KeyboardButton(text="Меню")],
|
||||
# [KeyboardButton(text="Мой профиль")]
|
||||
],
|
||||
resize_keyboard=True
|
||||
)
|
||||
@@ -61,18 +63,72 @@ async def handle_about_vpn(callback_query: CallbackQuery):
|
||||
"Каждому пользователю предоставляется индивидуальный ключ для подключения. "
|
||||
"Этот ключ необходим для использования нашего VPN-сервиса."
|
||||
)
|
||||
await callback_query.message.answer(
|
||||
|
||||
# Кнопка "Назад"
|
||||
button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_menu')
|
||||
|
||||
# Обновлённая клавиатура с кнопкой "Назад"
|
||||
inline_keyboard_back = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[button_back]
|
||||
])
|
||||
|
||||
await callback_query.message.edit_text(
|
||||
info_message,
|
||||
parse_mode='Markdown'
|
||||
parse_mode='Markdown',
|
||||
reply_markup=inline_keyboard_back # Добавление клавиатуры с кнопкой "Назад"
|
||||
)
|
||||
await callback_query.answer()
|
||||
|
||||
@router.callback_query(lambda c: c.data == 'back_to_menu')
|
||||
async def handle_back_to_menu(callback_query: CallbackQuery):
|
||||
welcome_text = (
|
||||
"*Добро пожаловать в наш сервис!*\n\n"
|
||||
"Вы можете воспользоваться следующими функциями:\n\n"
|
||||
"🔑 *Создать ключ для подключения VPN* - Получите уникальный ключ для доступа к VPN.\n"
|
||||
"📅 *Узнать дату окончания ключа* - Проверьте, когда истекает срок действия вашего ключа.\n"
|
||||
"👤 *Просмотреть ваш профиль* - Получите информацию о вашем аккаунте и балансе.\n\n"
|
||||
"Нажмите на соответствующую кнопку ниже, чтобы начать!"
|
||||
)
|
||||
|
||||
button_view_profile = InlineKeyboardButton(text='👤 Мой профиль', callback_data='view_profile')
|
||||
button_about_vpn = InlineKeyboardButton(text='🔒 О VPN', callback_data='about_vpn')
|
||||
button_feedback = InlineKeyboardButton(text='📝 Обратная связь', callback_data='feedback')
|
||||
button_channel = InlineKeyboardButton(text='📢 Наш канал', url=CHANNEL_URL)
|
||||
|
||||
inline_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[button_view_profile],
|
||||
[button_about_vpn],
|
||||
[button_feedback],
|
||||
[button_channel]
|
||||
])
|
||||
|
||||
# Редактирование сообщения на главное меню
|
||||
await callback_query.message.edit_text(
|
||||
welcome_text,
|
||||
parse_mode='Markdown',
|
||||
reply_markup=inline_keyboard
|
||||
)
|
||||
await callback_query.answer()
|
||||
|
||||
@router.callback_query(lambda c: c.data == 'feedback')
|
||||
async def handle_feedback(callback_query: CallbackQuery, state: FSMContext):
|
||||
await callback_query.message.answer(
|
||||
"Напишите нам, если у вас возникли трудности с подключением, есть отзыв или предложение. Ваше сообщение будет отправлено админу.",
|
||||
parse_mode='Markdown'
|
||||
feedback_text = "Напишите нам, если у вас возникли трудности с подключением, есть отзыв или предложение. @pocomacho"
|
||||
|
||||
# Кнопка "Назад"
|
||||
button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_menu')
|
||||
|
||||
# Обновлённая клавиатура с кнопкой "Назад"
|
||||
inline_keyboard_back = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[button_back]
|
||||
])
|
||||
|
||||
# Редактирование сообщения с кнопкой "Назад"
|
||||
await callback_query.message.edit_text(
|
||||
feedback_text,
|
||||
parse_mode='Markdown',
|
||||
reply_markup=inline_keyboard_back # Клавиатура с кнопкой "Назад"
|
||||
)
|
||||
|
||||
await state.set_state(FeedbackState.waiting_for_feedback)
|
||||
await state.update_data(user_id=callback_query.from_user.id)
|
||||
await callback_query.answer()
|
||||
@@ -95,3 +151,8 @@ async def receive_feedback(message: types.Message, state: FSMContext):
|
||||
print(f"Ошибка при отправке обратной связи: {e}") # Логирование ошибок
|
||||
|
||||
await state.clear()
|
||||
|
||||
# Пример обработки команды старт
|
||||
@router.message(Command('start'))
|
||||
async def cmd_start(message: Message):
|
||||
await start_command(message)
|
||||
+85
-119
@@ -1,63 +1,52 @@
|
||||
from aiogram import Bot, Dispatcher, Router, F, types
|
||||
from aiogram.filters import Command
|
||||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery, Message
|
||||
from aiogram.fsm.storage.memory import MemoryStorage
|
||||
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
|
||||
from datetime import datetime, timedelta
|
||||
from config import API_TOKEN, ADMIN_PASSWORD, ADMIN_USERNAME, ADMIN_CHAT_ID, DATABASE_PATH
|
||||
from database import add_connection, has_active_key, get_active_key_email, get_balance, store_key, update_balance
|
||||
from client import extend_client_key
|
||||
import asyncio
|
||||
import re
|
||||
import uuid
|
||||
import aiosqlite
|
||||
import re
|
||||
from aiogram import Bot, Dispatcher, Router, types, F
|
||||
from aiogram.filters import Command
|
||||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery, Message
|
||||
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 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 bot import bot
|
||||
from handlers.profile import process_callback_view_profile
|
||||
import asyncio
|
||||
|
||||
from handlers.keys import process_callback_view_keys
|
||||
from bot import bot
|
||||
|
||||
router = Router()
|
||||
|
||||
def escape_markdown(text: str) -> str:
|
||||
"""
|
||||
Экранирование специальных символов для Markdown.
|
||||
"""
|
||||
escape_chars = r'_*[]()~`>#+-=|{}.!'
|
||||
return re.sub(r'([%s])' % re.escape(escape_chars), r'\\\1', text)
|
||||
|
||||
# Удаляем специальные символы из имени ключа
|
||||
def sanitize_key_name(key_name: str) -> str:
|
||||
"""
|
||||
Очищает имя ключа от недопустимых символов и приводит его к нижнему регистру.
|
||||
"""
|
||||
# Оставляем только строчные буквы, цифры, символы @._-
|
||||
return re.sub(r'[^a-z0-9@._-]', '', key_name.lower())
|
||||
|
||||
class Form(StatesGroup):
|
||||
waiting_for_key_name = State()
|
||||
waiting_for_admin_confirmation = State()
|
||||
waiting_for_statistics = State()
|
||||
waiting_for_expiry_date = State()
|
||||
viewing_profile = State()
|
||||
|
||||
# Обработка нажатия кнопки создания ключа
|
||||
@dp.callback_query(F.data == 'create_key')
|
||||
async def process_callback_create_key(callback_query: types.CallbackQuery, state: FSMContext):
|
||||
await bot.send_message(callback_query.from_user.id, "Введите имя вашего профиля VPN:")
|
||||
async def process_callback_create_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.message()
|
||||
async def handle_text(message: types.Message, state: FSMContext):
|
||||
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 == "Мой профиль":
|
||||
# Создайте фейковый объект CallbackQuery для вызова функции
|
||||
callback_query = types.CallbackQuery(
|
||||
id="1", # Используйте уникальный идентификатор
|
||||
id="1",
|
||||
from_user=message.from_user,
|
||||
chat_instance='',
|
||||
data='view_profile',
|
||||
@@ -66,103 +55,59 @@ async def handle_text(message: types.Message, state: FSMContext):
|
||||
await process_callback_view_profile(callback_query, state)
|
||||
return
|
||||
|
||||
if message.text == "/start":
|
||||
await start_command(message)
|
||||
return
|
||||
|
||||
if message.text == "В начало":
|
||||
if message.text in ["/start", "Меню"]:
|
||||
await start_command(message)
|
||||
return
|
||||
|
||||
# Если ожидается имя ключа
|
||||
if current_state == Form.waiting_for_key_name.state:
|
||||
tg_id = message.from_user.id
|
||||
key_name = sanitize_key_name(message.text)
|
||||
tg_name = message.from_user.username
|
||||
await handle_key_name_input(message, state)
|
||||
|
||||
if not key_name:
|
||||
await bot.send_message(tg_id, "Имя клиента не указано.")
|
||||
await state.clear()
|
||||
return
|
||||
# Обработка ввода имени ключа
|
||||
async def handle_key_name_input(message: Message, state: FSMContext):
|
||||
tg_id = message.from_user.id
|
||||
key_name = sanitize_key_name(message.text)
|
||||
|
||||
if await has_active_key(tg_id):
|
||||
await bot.send_message(tg_id, "У вас уже есть активный ключ. Вы не можете создать новый.")
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
# Сохраняем информацию о запросе в контексте состояния
|
||||
await state.update_data(key_name=key_name, tg_id=tg_id)
|
||||
|
||||
# Отправляем запрос на подтверждение админу
|
||||
admin_message = (
|
||||
f"Новый запрос на создание ключа:\n"
|
||||
f"Телеграм-ID: {tg_id}\n"
|
||||
f"Имя ключа: {key_name}\n"
|
||||
f"Имя пользователя Telegram: @{tg_name}\n"
|
||||
f"Введите 'yes' для подтверждения или 'no' для отклонения."
|
||||
)
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='Да', callback_data=f'confirm_key_{tg_id}_{key_name}')],
|
||||
[InlineKeyboardButton(text='Нет', callback_data=f'reject_key_{tg_id}')]
|
||||
])
|
||||
await bot.send_message(ADMIN_CHAT_ID, admin_message, reply_markup=keyboard)
|
||||
|
||||
await bot.send_message(tg_id, "Ожидайте подтверждения администратора.")
|
||||
if not key_name:
|
||||
await message.reply("Имя профиля не указано. Введите имя на английском языке.")
|
||||
await state.clear()
|
||||
|
||||
@dp.callback_query(F.data.startswith('confirm_key_'))
|
||||
async def handle_admin_confirmation(callback_query: CallbackQuery, state: FSMContext):
|
||||
if callback_query.message.chat.id != int(ADMIN_CHAT_ID):
|
||||
return
|
||||
|
||||
|
||||
if await has_active_key(tg_id):
|
||||
await message.reply("У вас уже есть активный ключ. Вы не можете создать новый.")
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
await state.update_data(key_name=key_name, tg_id=tg_id)
|
||||
|
||||
session = login_with_credentials(ADMIN_USERNAME, ADMIN_PASSWORD)
|
||||
data = callback_query.data.split('_', 3)
|
||||
tg_id = int(data[2])
|
||||
key_name = data[3]
|
||||
client_id = str(uuid.uuid4())
|
||||
email = key_name.lower()
|
||||
current_time = datetime.utcnow()
|
||||
expiry_time = int((current_time + timedelta(days=1)).timestamp() * 1000)
|
||||
|
||||
try:
|
||||
client_id = str(uuid.uuid4())
|
||||
email = key_name.lower() # Приведение email к нижнему регистру
|
||||
limit_ip = 1
|
||||
total_gb = 0
|
||||
current_time = datetime.utcnow()
|
||||
|
||||
# Определяем время истечения ключа
|
||||
if await has_active_key(tg_id):
|
||||
# Если есть активный ключ, устанавливаем срок действия на 30 дней
|
||||
expiry_time = int((current_time + timedelta(days=30)).timestamp() * 1000)
|
||||
else:
|
||||
# Первый ключ устанавливаем на 1 день
|
||||
expiry_time = int((current_time + timedelta(days=1)).timestamp() * 1000)
|
||||
|
||||
enable = True
|
||||
flow = "xtls-rprx-vision"
|
||||
balance = 0
|
||||
|
||||
# Проверка данных перед созданием ключа
|
||||
print(f"Creating key with client_id={client_id}, email={email}, tg_id={tg_id}")
|
||||
|
||||
add_client(session, client_id, email, tg_id, limit_ip, total_gb, expiry_time, enable, flow)
|
||||
|
||||
# Создание клиента и получение ссылки
|
||||
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, balance)
|
||||
await store_key(client_id, email, connection_link)
|
||||
await add_connection(tg_id, client_id, email, expiry_time, 0)
|
||||
await store_key(client_id, email, connection_link)
|
||||
|
||||
# Создаем кнопки
|
||||
instructions_button = InlineKeyboardButton(text='Инструкции по использованию', callback_data='instructions')
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[[instructions_button]])
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='Инструкции по использованию', callback_data='instructions')],
|
||||
[InlineKeyboardButton(text='Перейти в профиль', callback_data='view_profile')]
|
||||
])
|
||||
|
||||
# Отправляем сообщение с ключом и кнопкой
|
||||
key_message = f"Ключ создан:\n<pre>{connection_link}</pre>"
|
||||
await bot.send_message(tg_id, key_message, parse_mode="HTML", reply_markup=keyboard)
|
||||
await bot.send_message(callback_query.message.chat.id, "Ключ создан и отправлен клиенту.")
|
||||
await message.reply(key_message, parse_mode="HTML", reply_markup=keyboard)
|
||||
except Exception as e:
|
||||
await bot.send_message(callback_query.message.chat.id, f"Ошибка при создании ключа: {e}")
|
||||
print(f"Ошибка при создании ключа: {e}") # Отладочное сообщение в консоль
|
||||
|
||||
await callback_query.answer()
|
||||
await message.reply(f"Ошибка при создании ключа: {e}")
|
||||
print(f"Ошибка при создании ключа: {e}")
|
||||
|
||||
await state.clear()
|
||||
|
||||
# Обработка кнопки "Инструкции"
|
||||
@dp.callback_query(F.data == 'instructions')
|
||||
async def handle_instructions(callback_query: CallbackQuery):
|
||||
instructions_message = (
|
||||
@@ -175,12 +120,29 @@ async def handle_instructions(callback_query: CallbackQuery):
|
||||
"4. Выберите 'Вставить из буфера обмена' для добавления ключа.\n\n"
|
||||
"Если у вас возникнут вопросы, не стесняйтесь обращаться в поддержку."
|
||||
)
|
||||
await callback_query.message.answer(
|
||||
instructions_message,
|
||||
parse_mode='Markdown'
|
||||
)
|
||||
|
||||
back_button = InlineKeyboardButton(text='Назад', callback_data='back_to_main')
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[[back_button]])
|
||||
|
||||
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)
|
||||
await callback_query.answer()
|
||||
|
||||
# Фоновая задача для продления ключей
|
||||
async def renew_expired_keys():
|
||||
while True:
|
||||
current_time = datetime.utcnow()
|
||||
@@ -192,16 +154,20 @@ async def renew_expired_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.commit()
|
||||
|
||||
await update_balance(tg_id, -100)
|
||||
await extend_client_key(client_id)
|
||||
|
||||
|
||||
print(f"Ключ для клиента {client_id} продлен на месяц и списано 100 рублей.")
|
||||
else:
|
||||
print(f"Недостаточно средств на балансе для клиента {client_id}.")
|
||||
print(f"Недостаточно средств на балансе для клиента {client_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)
|
||||
await asyncio.sleep(3600)
|
||||
|
||||
Reference in New Issue
Block a user