оптимизация

This commit is contained in:
Vlad
2024-09-18 04:09:38 +03:00
parent 864c099b2f
commit bfc7ffe024
9 changed files with 188 additions and 96 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+8 -1
View File
@@ -25,11 +25,18 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery):
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')
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[instructions_button]])
await bot.send_message(tg_id, response_message, parse_mode="HTML", reply_markup=keyboard)
else:
response_message = "У вас нет ключей."
await bot.send_message(tg_id, response_message, reply_to_message_id=callback_query.message.message_id)
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 bot.send_message(tg_id, response_message, parse_mode="HTML", reply_to_message_id=callback_query.message.message_id)
await callback_query.answer()
+44 -46
View File
@@ -17,100 +17,98 @@ class ReplenishBalanceState(StatesGroup):
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')]
[InlineKeyboardButton(text='По реквизитам', callback_data='transfer_method_requisites')]
])
await callback_query.message.answer("Выберите метод перевода:", reply_markup=keyboard)
await callback_query.answer()
await bot.send_message(callback_query.from_user.id, "Выберите метод перевода:", reply_markup=keyboard)
await callback_query.answer() # Уведомляем Telegram, что запрос обработан
@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("Неверные данные для выбора метода перевода.")
await bot.send_message(callback_query.from_user.id, "Неверные данные для выбора метода перевода.")
return
transfer_method = data[2] # 'requisites' или 'sbp'
transfer_method = data[2] # 'requisites'
if transfer_method == 'requisites':
message = (
"Реквизиты для пополнения:\n"
f'\n'
"Банк: Пример Банк\n"
"Расчетный счет: 12345678901234567890\n"
"Получатель: ИП Иванов Иван Иванович"
f'\n'
"после перевода отправьте чек и ждите подтверждения"
"Банк: Т-Банк\n"
"2200701036597224\n"
"Получатель: Лисицын В.Д.\n"
f"\n"
"После перевода отправьте чек и дождитесь подтверждения."
)
elif transfer_method == 'sbp':
message = (
"СБП для пополнения:\n"
f'\n'
"Номер банка: 1234567890\n"
"ФИО: Иванов Иван Иванович\n"
f'\n'
"после перевода отправьте чек и ждите подтверждения"
# Удаляем старое сообщение о выборе метода
await bot.edit_message_text(
text="Вы выбрали метод перевода. Теперь вы увидите реквизиты.",
chat_id=callback_query.from_user.id,
message_id=callback_query.message.message_id
)
# Отправляем реквизиты в новом сообщении
await bot.send_message(callback_query.from_user.id, message)
else:
await callback_query.answer("Неверный метод перевода.")
await bot.send_message(callback_query.from_user.id, "Неверный метод перевода.")
return
await callback_query.message.answer(message)
await state.update_data(transfer_method=transfer_method)
await state.set_state(ReplenishBalanceState.waiting_for_admin_confirmation)
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}')]
])
admin_message = (
f"Пользователь {callback_query.from_user.full_name} запросил пополнение баланса.\n"
f"Метод перевода: {transfer_method}\n"
"Пожалуйста, подтвердите или отклоните запрос."
)
await bot.send_message(ADMIN_ID, admin_message, reply_markup=admin_keyboard)
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("Вы не являетесь администратором.")
await bot.send_message(callback_query.from_user.id, "Вы не являетесь администратором.")
return
data = callback_query.data.split('_', 4)
if len(data) < 4:
await callback_query.answer("Неверные данные для обработки запроса.")
await bot.send_message(callback_query.from_user.id, "Неверные данные для обработки запроса.")
return
action = data[1] # 'confirm' или 'decline'
user_id_str = data[3]
user_id_str = data[2]
transfer_method = 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
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 callback_query.message.answer(f"Баланс пользователя успешно пополнен на {amount} единиц.\nТекущий баланс: {balance}")
# Сообщаем пользователю о пополнении
await bot.send_message(callback_query.from_user.id, f"Баланс пользователя успешно пополнен на {amount} RUB.\nТекущий баланс: {balance}")
await bot.send_message(user_id, f"Ваш баланс был успешно пополнен на {amount} RUB.")
elif action == 'decline':
await callback_query.message.answer("Пополнение баланса отклонено.")
# Сообщаем пользователю об отклонении
await bot.send_message(callback_query.from_user.id, "Пополнение баланса отклонено.")
await bot.send_message(user_id, "Ваш запрос на пополнение баланса был отклонен.")
except Exception as e:
# Отладочное сообщение
await callback_query.message.answer(f"Ошибка при пополнении баланса: {e}")
await bot.send_message(callback_query.from_user.id, f"Ошибка при пополнении баланса: {e}")
print(f"Ошибка при пополнении баланса: {e}") # Отладочное сообщение в консоль
# Очистка состояния
await state.clear()
await callback_query.answer()
+14 -6
View File
@@ -35,24 +35,32 @@ async def process_callback_view_profile(callback_query: types.CallbackQuery, sta
balance = await get_balance(tg_id)
profile_message = (
f"Профиль \n\n"
f"ID: @{tg_id}\n"
f"Ключ: {email if email else 'Нет активного ключа'}\n"
f"ID: {tg_id}\n"
f"Ключ: {email if expiry_date else 'Нет активного ключа'}\n"
f"Баланс: {balance} RUB\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')
keyboard = InlineKeyboardMarkup(inline_keyboard=[[button_view_keys], [button_replenish_balance]])
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[button_create_key], # Добавляем кнопку "Создать ключ"
[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.message.bot.send_message(
chat_id=callback_query.message.chat.id,
text=profile_message,
parse_mode='Markdown',
reply_markup=keyboard
)
await callback_query.answer()
@router.callback_query(lambda c: c.data == 'view_profile')
+76 -21
View File
@@ -1,31 +1,37 @@
from aiogram import types, Router
from aiogram import Bot, Dispatcher, Router, types
from aiogram.filters import Command
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, ReplyKeyboardMarkup, KeyboardButton
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery, Message, ReplyKeyboardMarkup, KeyboardButton
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 bot import dp, bot # Убедитесь, что bot и dp импортируются из правильного места
router = Router()
async def start_command(message: types.Message, callback_data: str = None):
class FeedbackState(StatesGroup):
waiting_for_feedback = State()
async def start_command(message: types.Message):
welcome_text = (
"Добро пожаловать! Вы можете создать ключ для подключения VPN, "
"просмотреть статистику использования, узнать дату окончания ключа или "
"просмотреть ваш профиль."
"*Добро пожаловать в наш сервис!*\n\n"
"Вы можете воспользоваться следующими функциями:\n\n"
"🔑 *Создать ключ для подключения VPN* - Получите уникальный ключ для доступа к VPN.\n"
"📅 *Узнать дату окончания ключа* - Проверьте, когда истекает срок действия вашего ключа.\n"
"👤 *Просмотреть ваш профиль* - Получите информацию о вашем аккаунте и балансе.\n\n"
"Нажмите на соответствующую кнопку ниже, чтобы начать!"
)
# Создаем кнопки для команд
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_profile = InlineKeyboardButton(text='Мой профиль', callback_data='view_profile')
button_about_vpn = InlineKeyboardButton(text='О VPN', callback_data='about_vpn')
button_feedback = InlineKeyboardButton(text='Обратная связь', callback_data='feedback')
# Создаем клавиатуру с кнопками
inline_keyboard = InlineKeyboardMarkup(inline_keyboard=[
[button_create_key],
# [button_view_stats],
# [button_view_expiry],
[button_view_profile]
[button_view_profile],
[button_about_vpn],
[button_feedback]
])
# Создаем кнопку для возврата в начало
reply_keyboard = ReplyKeyboardMarkup(
keyboard=[
[KeyboardButton(text="В начало")],
@@ -34,9 +40,58 @@ async def start_command(message: types.Message, callback_data: str = None):
resize_keyboard=True
)
# Отправляем сообщение с кнопками
await message.reply(welcome_text, reply_markup=inline_keyboard)
await message.answer(
"",
await message.bot.send_message(
chat_id=message.chat.id,
text=welcome_text,
parse_mode='Markdown',
reply_markup=inline_keyboard
)
await message.bot.send_message(
chat_id=message.chat.id,
text="Выберите действие:",
reply_markup=reply_keyboard
)
)
@router.callback_query(lambda c: c.data == 'about_vpn')
async def handle_about_vpn(callback_query: CallbackQuery):
info_message = (
"*О VPN*\n\n"
"Мы используем VLESS для обеспечения безопасного и надежного подключения к интернету. "
"Каждому пользователю предоставляется индивидуальный ключ для подключения. "
"Этот ключ необходим для использования нашего VPN-сервиса."
)
await callback_query.message.answer(
info_message,
parse_mode='Markdown'
)
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'
)
await state.set_state(FeedbackState.waiting_for_feedback)
await state.update_data(user_id=callback_query.from_user.id)
await callback_query.answer()
@router.message(FeedbackState.waiting_for_feedback)
async def receive_feedback(message: types.Message, state: FSMContext):
user_data = await state.get_data()
user_id = user_data.get('user_id')
feedback_message = (
f"Обратная связь от пользователя {user_id}:\n\n"
f"{message.text}"
)
try:
await bot.send_message(ADMIN_ID, feedback_message)
await message.answer("Спасибо за ваше сообщение! Мы свяжемся с вами, если это будет необходимо.")
except Exception as e:
await message.answer("Произошла ошибка при отправке вашего сообщения.")
print(f"Ошибка при отправке обратной связи: {e}") # Логирование ошибок
await state.clear()
+46 -22
View File
@@ -1,6 +1,6 @@
from aiogram import Bot, Dispatcher, Router, F, types
from aiogram.filters import Command
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery, Message, ReplyKeyboardMarkup, KeyboardButton
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
@@ -19,7 +19,6 @@ from handlers.profile import process_callback_view_profile
router = Router()
def escape_markdown(text: str) -> str:
"""
Экранирование специальных символов для Markdown.
@@ -27,21 +26,26 @@ def escape_markdown(text: str) -> str:
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()
viewing_profile = State()
@dp.callback_query(F.data == 'create_key')
async def process_callback_create_key(callback_query: types.CallbackQuery, state: FSMContext):
await callback_query.message.reply("Введите имя вашего профиля VPN:")
await bot.send_message(callback_query.from_user.id, "Введите имя вашего профиля VPN:")
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()
@@ -68,16 +72,16 @@ async def handle_text(message: types.Message, state: FSMContext):
if current_state == Form.waiting_for_key_name.state:
tg_id = message.from_user.id
key_name = message.text
key_name = sanitize_key_name(message.text)
tg_name = message.from_user.username
if not key_name:
await message.reply("Имя клиента не указано.")
await bot.send_message(tg_id, "Имя клиента не указано.")
await state.clear()
return
if await has_active_key(tg_id):
await message.reply("У вас уже есть активный ключ. Вы не можете создать новый.")
await bot.send_message(tg_id, "У вас уже есть активный ключ. Вы не можете создать новый.")
await state.clear()
return
@@ -98,8 +102,7 @@ async def handle_text(message: types.Message, state: FSMContext):
])
await bot.send_message(ADMIN_CHAT_ID, admin_message, reply_markup=keyboard)
await state.set_state(Form.waiting_for_admin_confirmation)
await message.reply("Ожидайте подтверждения администратора.")
await bot.send_message(tg_id, "Ожидайте подтверждения администратора.")
await state.clear()
@dp.callback_query(F.data.startswith('confirm_key_'))
@@ -114,7 +117,7 @@ async def handle_admin_confirmation(callback_query: CallbackQuery, state: FSMCon
try:
client_id = str(uuid.uuid4())
email = key_name
email = key_name.lower() # Приведение email к нижнему регистру
limit_ip = 1
total_gb = 0
current_time = datetime.utcnow()
@@ -123,25 +126,46 @@ async def handle_admin_confirmation(callback_query: CallbackQuery, state: FSMCon
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)
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 bot.send_message(tg_id, f"Ключ создан:\n<pre>{connection_link}</pre>", parse_mode="HTML")
await callback_query.message.reply("Ключ создан и отправлен клиенту.")
# Создаем кнопки
instructions_button = InlineKeyboardButton(text='Инструкции по использованию', callback_data='instructions')
keyboard = InlineKeyboardMarkup(inline_keyboard=[[instructions_button]])
# Отправляем сообщение с ключом и кнопкой
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, "Ключ создан и отправлен клиенту.")
except Exception as e:
await callback_query.message.reply(f"Ошибка при создании ключа: {e}")
await bot.send_message(callback_query.message.chat.id, f"Ошибка при создании ключа: {e}")
print(f"Ошибка при создании ключа: {e}") # Отладочное сообщение в консоль
await callback_query.answer()
@dp.callback_query(F.data.startswith('reject_key_'))
async def handle_rejection(callback_query: CallbackQuery, state: FSMContext):
if callback_query.message.chat.id != int(ADMIN_CHAT_ID):
return
tg_id = int(callback_query.data.split('_', 3)[2])
await bot.send_message(tg_id, "Создание ключа отклонено.")
await callback_query.message.reply("Запрос отклонен.")
@dp.callback_query(F.data == 'instructions')
async def handle_instructions(callback_query: CallbackQuery):
instructions_message = (
"*Инструкции по использованию вашего ключа:*\n\n"
"1. Скачайте приложение для вашего устройства:\n"
" - Для Android: [V2Ray](https://play.google.com/store/apps/details?id=com.v2ray.ang&hl=ru&pli=1)\n"
" - Для iPhone: [Streisand](https://apps.apple.com/ru/app/streisand/id6450534064)\n\n"
"2. Скопируйте предоставленный ключ, который вы получили ранее.\n"
"3. Откройте приложение и нажмите на плюсик сверху справа.\n"
"4. Выберите 'Вставить из буфера обмена' для добавления ключа.\n\n"
"Если у вас возникнут вопросы, не стесняйтесь обращаться в поддержку."
)
await callback_query.message.answer(
instructions_message,
parse_mode='Markdown'
)
await callback_query.answer()