переработка интерфейса

This commit is contained in:
Vlad
2024-09-18 01:44:27 +03:00
parent b181aff960
commit 864c099b2f
10 changed files with 193 additions and 152 deletions
+1
View File
@@ -20,6 +20,7 @@ dp.include_router(stats.router)
dp.include_router(expiry.router)
dp.include_router(balance.router)
dp.include_router(key_management_router)
dp.include_router(pay.router)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+6 -2
View File
@@ -2,6 +2,8 @@ from aiogram import types, Router
import aiosqlite
from config import DATABASE_PATH
from bot import bot
from datetime import datetime
router = Router()
@router.callback_query(lambda c: c.data == 'view_keys')
@@ -11,7 +13,7 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery):
try:
async with aiosqlite.connect(DATABASE_PATH) as db:
async with db.execute('''
SELECT k.key
SELECT k.key, c.expiry_time
FROM keys k
JOIN connections c ON k.client_id = c.client_id
WHERE c.tg_id = ?
@@ -20,7 +22,9 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery):
if record:
key = record[0]
response_message = f"Ваш ключ:\n<pre>{key}</pre>"
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>"
else:
response_message = "У вас нет ключей."
+116
View File
@@ -0,0 +1,116 @@
from aiogram import types, Router
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 database import get_balance, update_balance
from bot import bot
router = Router()
class ReplenishBalanceState(StatesGroup):
choosing_transfer_method = State()
waiting_for_admin_confirmation = State()
@router.callback_query(lambda c: c.data == 'replenish_balance')
async def process_callback_replenish_balance(callback_query: types.CallbackQuery, state: FSMContext):
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_sbp')]
])
await callback_query.message.answer("Выберите метод перевода:", reply_markup=keyboard)
await callback_query.answer()
@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 callback_query.answer("Неверные данные для выбора метода перевода.")
return
transfer_method = data[2] # 'requisites' или 'sbp'
if transfer_method == 'requisites':
message = (
"Реквизиты для пополнения:\n"
f'\n'
"Банк: Пример Банк\n"
"Расчетный счет: 12345678901234567890\n"
"Получатель: ИП Иванов Иван Иванович"
f'\n'
"после перевода отправьте чек и ждите подтверждения"
)
elif transfer_method == 'sbp':
message = (
"СБП для пополнения:\n"
f'\n'
"Номер банка: 1234567890\n"
"ФИО: Иванов Иван Иванович\n"
f'\n'
"после перевода отправьте чек и ждите подтверждения"
)
else:
await callback_query.answer("Неверный метод перевода.")
return
await callback_query.message.answer(message)
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 callback_query.answer("Вы не являетесь администратором.")
return
data = callback_query.data.split('_', 4)
if len(data) < 4:
await callback_query.answer("Неверные данные для обработки запроса.")
return
action = data[1] # 'confirm' или 'decline'
user_id_str = data[3]
try:
user_id = int(user_id_str) # Преобразование user_id в целое число
if action == 'confirm':
amount_str = data[4].split('_')[0]
# Убедимся, что amount_str действительно является числом
if amount_str.isdigit():
amount = int(amount_str) # Преобразование amount в целое число
else:
await callback_query.answer("Неверная сумма для пополнения. Проверьте формат данных.")
print(f"Ошибка преобразования суммы: amount_str='{amount_str}'") # Отладочное сообщение в консоль
return
async with aiosqlite.connect(DATABASE_PATH) as db:
# Обновляем баланс пользователя
await update_balance(user_id, amount)
await db.commit()
balance = await get_balance(user_id)
await callback_query.message.answer(f"Баланс пользователя успешно пополнен на {amount} единиц.\nТекущий баланс: {balance}")
# Сообщаем пользователю о пополнении
await bot.send_message(user_id, f"Ваш баланс был успешно пополнен на {amount} RUB.")
elif action == 'decline':
await callback_query.message.answer("Пополнение баланса отклонено.")
# Сообщаем пользователю об отклонении
await bot.send_message(user_id, "Ваш запрос на пополнение баланса был отклонен.")
except Exception as e:
# Отладочное сообщение
await callback_query.message.answer(f"Ошибка при пополнении баланса: {e}")
print(f"Ошибка при пополнении баланса: {e}") # Отладочное сообщение в консоль
# Очистка состояния
await state.clear()
await callback_query.answer()
+28 -132
View File
@@ -1,12 +1,11 @@
from aiogram import Bot, Dispatcher, Router, types
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery
from aiogram import types, Router
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, ADMIN_ID
from database import get_balance, update_balance, has_active_key
from bot import bot
from config import DATABASE_PATH
from database import get_balance, has_active_key
router = Router()
@@ -14,14 +13,15 @@ class ReplenishBalanceState(StatesGroup):
choosing_transfer_method = State()
waiting_for_admin_confirmation = State()
@router.callback_query(lambda c: c.data == 'view_profile')
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(
@@ -29,136 +29,32 @@ async def process_callback_view_profile(callback_query: types.CallbackQuery, sta
(tg_id, int(datetime.utcnow().timestamp() * 1000))
) as cursor:
record = await cursor.fetchone()
expiry_date = "Неизвестно" if record is None else datetime.utcfromtimestamp(record[0] / 1000).strftime("%Y-%m-%d %H:%M:%S")
balance = await get_balance(tg_id)
profile_message = (
f"Профиль клиента:\n"
f"Никнейм: @{username}\n"
f"Email: {email}\n"
f"Дата окончания ключа: {expiry_date}\n"
f"Баланс: {balance}\n"
)
button_view_keys = InlineKeyboardButton(text='Мои ключи', callback_data='view_keys')
button_replenish_balance = InlineKeyboardButton(text='Пополнить баланс', callback_data='replenish_balance')
keyboard = InlineKeyboardMarkup(inline_keyboard=[[button_view_keys], [button_replenish_balance]])
profile_message += "Вы можете просмотреть ваши ключи или пополнить баланс ниже:"
else:
profile_message = "У вас нет активных ключей."
keyboard = None
if record:
expiry_date = datetime.utcfromtimestamp(record[0] / 1000).strftime("%Y-%m-%d %H:%M:%S")
balance = await get_balance(tg_id)
profile_message = (
f"Профиль \n\n"
f"ID: @{tg_id}\n"
f"Ключ: {email if email else 'Нет активного ключа'}\n"
f"Баланс: {balance} RUB\n"
)
# Кнопки для действий в профиле
button_view_keys = InlineKeyboardButton(text='Мои ключи', callback_data='view_keys')
button_replenish_balance = InlineKeyboardButton(text='Пополнить баланс', callback_data='replenish_balance')
keyboard = InlineKeyboardMarkup(inline_keyboard=[[button_view_keys], [button_replenish_balance]])
profile_message += "\nВы можете просмотреть ваши ключи или пополнить баланс ниже:"
except Exception as e:
profile_message = f"Ошибка при получении данных профиля: {e}"
keyboard = None
# Отправляем сообщение с клавиатурой внизу
# Отправляем сообщение с клавиатурой
await callback_query.message.reply(profile_message, reply_markup=keyboard)
await callback_query.answer()
@router.callback_query(lambda c: c.data == 'replenish_balance')
async def process_callback_replenish_balance(callback_query: types.CallbackQuery, state: FSMContext):
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_sbp')]
])
await callback_query.message.answer("Выберите метод перевода:", reply_markup=keyboard)
await callback_query.answer()
@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 callback_query.answer("Неверные данные для выбора метода перевода.")
return
transfer_method = data[2] # 'requisites' или 'sbp'
amount = 100 # Можно заменить на 300, если нужно
user_id = callback_query.from_user.id
# Сохраняем данные в состояние
await state.update_data(transfer_method=transfer_method, amount=amount, user_id=user_id)
# Выводим состояние для отладки
state_data = await state.get_data()
print("Сохраненные данные состояния:", state_data)
# Отправляем запрос на подтверждение администратору
admin_message = (
f"Запрос на пополнение баланса:\n"
f"Метод перевода: {transfer_method.replace('requisites', 'По реквизитам').replace('sbp', 'По СБП')}\n"
f"Сумма: {amount} единиц\n"
f"Пользователь: {user_id}\n\n"
f"Подтвердите или отклоните пополнение."
)
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='Подтвердить', callback_data=f'admin_confirm_replenish_{user_id}_{amount}_{transfer_method}')],
[InlineKeyboardButton(text='Отклонить', callback_data=f'admin_decline_replenish_{user_id}')]
])
# Отправляем сообщение администратору
await callback_query.message.answer("Запрос на пополнение отправлен администратору.")
await bot.send_message(ADMIN_ID, admin_message, reply_markup=keyboard)
await state.set_state(ReplenishBalanceState.waiting_for_admin_confirmation)
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 callback_query.answer("Вы не являетесь администратором.")
return
data = callback_query.data.split('_', 4)
if len(data) < 4:
await callback_query.answer("Неверные данные для обработки запроса.")
return
action = data[1] # 'confirm' или 'decline'
user_id_str = data[3]
try:
user_id = int(user_id_str) # Преобразование user_id в целое число
if action == 'confirm':
amount_str = data[4].split('_')[0]
# Убедимся, что amount_str действительно является числом
if amount_str.isdigit():
amount = int(amount_str) # Преобразование amount в целое число
else:
await callback_query.answer("Неверная сумма для пополнения. Проверьте формат данных.")
print(f"Ошибка преобразования суммы: amount_str='{amount_str}'") # Отладочное сообщение в консоль
return
async with aiosqlite.connect(DATABASE_PATH) as db:
# Обновляем баланс пользователя
await update_balance(user_id, amount)
await db.commit()
balance = await get_balance(user_id)
await callback_query.message.answer(f"Баланс пользователя успешно пополнен на {amount} единиц.\nТекущий баланс: {balance}")
# Сообщаем пользователю о пополнении
await bot.send_message(user_id, f"Ваш баланс был успешно пополнен на {amount} RUB.")
elif action == 'decline':
await callback_query.message.answer("Пополнение баланса отклонено.")
# Сообщаем пользователю об отклонении
await bot.send_message(user_id, "Ваш запрос на пополнение баланса был отклонен.")
except Exception as e:
# Отладочное сообщение
await callback_query.message.answer(f"Ошибка при пополнении баланса: {e}")
print(f"Ошибка при пополнении баланса: {e}") # Отладочное сообщение в консоль
# Очистка состояния
await state.clear()
await callback_query.answer()
@router.callback_query(lambda c: c.data == 'view_profile')
async def view_profile_handler(callback_query: types.CallbackQuery, state: FSMContext):
await process_callback_view_profile(callback_query, state)
+27 -18
View File
@@ -4,30 +4,39 @@ from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, ReplyKeybo
router = Router()
@router.message(Command("start"))
async def start_command(message: types.Message):
welcome_text = "Добро пожаловать! Вы можете создать ключ для подключения VPN, просмотреть статистику использования, узнать дату окончания ключа или просмотреть ваш профиль."
async def start_command(message: types.Message, callback_data: str = None):
welcome_text = (
"Добро пожаловать! Вы можете создать ключ для подключения VPN, "
"просмотреть статистику использования, узнать дату окончания ключа или "
"просмотреть ваш профиль."
)
# Создаем кнопки для команд
button_create_key = InlineKeyboardButton(text='Создать ключ', callback_data='create_key')
button_view_stats = InlineKeyboardButton(text='Посмотреть статистику', callback_data='view_stats')
button_view_expiry = InlineKeyboardButton(text='Дата окончания ключа', callback_data='view_expiry')
# button_view_stats = InlineKeyboardButton(text='Посмотреть статистику', callback_data='view_stats')
# button_view_expiry = InlineKeyboardButton(text='Дата окончания ключа', callback_data='view_expiry')
button_view_profile = InlineKeyboardButton(text='Мой профиль', callback_data='view_profile')
# Основное меню
keyboard = InlineKeyboardMarkup(inline_keyboard=[
# Создаем клавиатуру с кнопками
inline_keyboard = InlineKeyboardMarkup(inline_keyboard=[
[button_create_key],
[button_view_stats],
[button_view_expiry],
# [button_view_stats],
# [button_view_expiry],
[button_view_profile]
])
# Отправка приветственного сообщения
await message.reply(welcome_text, reply_markup=keyboard)
# Кнопка "В начало" для возвращения
main_menu_keyboard = ReplyKeyboardMarkup(
keyboard=[[KeyboardButton(text="В начало")]],
# Создаем кнопку для возврата в начало
reply_keyboard = ReplyKeyboardMarkup(
keyboard=[
[KeyboardButton(text="В начало")],
[KeyboardButton(text="Мой профиль")]
],
resize_keyboard=True
)
await message.answer("Чтобы вернуться в начало, нажмите кнопку ниже:", reply_markup=main_menu_keyboard)
# Отправляем сообщение с кнопками
await message.reply(welcome_text, reply_markup=inline_keyboard)
await message.answer(
"",
reply_markup=reply_keyboard
)
+15
View File
@@ -15,9 +15,11 @@ import re
from bot import dp
from handlers.start import start_command
from bot import bot
from handlers.profile import process_callback_view_profile
router = Router()
def escape_markdown(text: str) -> str:
"""
Экранирование специальных символов для Markdown.
@@ -39,10 +41,23 @@ async def process_callback_create_key(callback_query: types.CallbackQuery, state
await state.set_state(Form.waiting_for_key_name)
await callback_query.answer()
@dp.message()
async def handle_text(message: types.Message, state: FSMContext):
current_state = await state.get_state()
if message.text == "Мой профиль":
# Создайте фейковый объект CallbackQuery для вызова функции
callback_query = types.CallbackQuery(
id="1", # Используйте уникальный идентификатор
from_user=message.from_user,
chat_instance='',
data='view_profile',
message=message
)
await process_callback_view_profile(callback_query, state)
return
if message.text == "/start":
await start_command(message)
return