summaryrefslogtreecommitdiff
path: root/files/TG_bot_VPN-main/handlers
diff options
context:
space:
mode:
authorvlapa <vlapa@ya.ru>2026-06-13 20:33:26 +0300
committervlapa <vlapa@ya.ru>2026-06-13 20:33:26 +0300
commite5abc1fe99340b979b18864d978179f71fe8f5c5 (patch)
tree98fd0ad7c6d0744894d6e74e446daacd9e6dd1b5 /files/TG_bot_VPN-main/handlers
First
Diffstat (limited to 'files/TG_bot_VPN-main/handlers')
-rw-r--r--files/TG_bot_VPN-main/handlers/__init__.py2
-rw-r--r--files/TG_bot_VPN-main/handlers/custom_heandlers/__init__.py3
-rw-r--r--files/TG_bot_VPN-main/handlers/custom_heandlers/admin_handlers.py405
-rw-r--r--files/TG_bot_VPN-main/handlers/custom_heandlers/instruction_handlers.py26
-rw-r--r--files/TG_bot_VPN-main/handlers/custom_heandlers/location_handlers.py135
-rw-r--r--files/TG_bot_VPN-main/handlers/default_heandlers/__init__.py6
-rw-r--r--files/TG_bot_VPN-main/handlers/default_heandlers/echo.py21
-rw-r--r--files/TG_bot_VPN-main/handlers/default_heandlers/help.py13
-rw-r--r--files/TG_bot_VPN-main/handlers/default_heandlers/start.py99
9 files changed, 710 insertions, 0 deletions
diff --git a/files/TG_bot_VPN-main/handlers/__init__.py b/files/TG_bot_VPN-main/handlers/__init__.py
new file mode 100644
index 0000000..3fb88a6
--- /dev/null
+++ b/files/TG_bot_VPN-main/handlers/__init__.py
@@ -0,0 +1,2 @@
+from . import custom_heandlers
+from . import default_heandlers
diff --git a/files/TG_bot_VPN-main/handlers/custom_heandlers/__init__.py b/files/TG_bot_VPN-main/handlers/custom_heandlers/__init__.py
new file mode 100644
index 0000000..f34731f
--- /dev/null
+++ b/files/TG_bot_VPN-main/handlers/custom_heandlers/__init__.py
@@ -0,0 +1,3 @@
+from . import admin_handlers
+from. import location_handlers
+from. import instruction_handlers
diff --git a/files/TG_bot_VPN-main/handlers/custom_heandlers/admin_handlers.py b/files/TG_bot_VPN-main/handlers/custom_heandlers/admin_handlers.py
new file mode 100644
index 0000000..51fe601
--- /dev/null
+++ b/files/TG_bot_VPN-main/handlers/custom_heandlers/admin_handlers.py
@@ -0,0 +1,405 @@
+import os
+
+import peewee
+import qrcode
+from telebot.types import Message
+from config_data.config import ALLOWED_USERS, DEFAULT_COMMANDS, ADMIN_COMMANDS, QR_CODE_DIR
+from database.models import User, Server, VPNKey
+from keyboards.inline.admin_buttons import (
+ users_markup,
+ admin_markup,
+ get_vpn_markup,
+ get_servers_markup,
+ delete_vpn_markup,
+ key_actions_markup
+)
+from loader import bot, app_logger
+from states.states import AdminPanel
+from utils.functions import valid_ip, convert_amnezia_xray_json_to_vless_str, get_all_commands_bot
+from utils.generate_vpn_keys import setup_server, generate_key
+from utils.work_vpn_keys import suspend_key, resume_key, revoke_key, cleanup_server
+
+
+@bot.message_handler(commands=["admin_panel"])
+def admin_panel(message: Message):
+ """ Хендлер для админ панели """
+ if message.from_user.id in ALLOWED_USERS:
+ app_logger.info(f"Администратор {message.from_user.full_name} зашел в админ панель.")
+ bot.send_message(message.from_user.id, "🔧 Добро пожаловать в админ панель!\n\nВыберите нужную опцию ниже 👇",
+ reply_markup=admin_markup())
+ bot.set_state(message.from_user.id, AdminPanel.get_option)
+ else:
+ bot.send_message(message.from_user.id, "❌ У вас недостаточно прав")
+ app_logger.warning(f"Пользователь {message.from_user.full_name} пытался войти в админ панель")
+
+
+@bot.callback_query_handler(func=None, state=AdminPanel.get_option)
+def admin_panel_handler(call):
+ """ Callback handler для выбора раздела админ панели """
+ bot.answer_callback_query(callback_query_id=call.id)
+
+ if call.data == "Exit":
+ bot.send_message(call.message.chat.id, "🚪 Вы успешно вышли из админ панели. До встречи!")
+ bot.set_state(call.message.chat.id, None)
+ app_logger.info(f"Администратор {call.from_user.full_name} вышел из админ панели.")
+ elif call.data == "users":
+ app_logger.info(f"Администратор {call.from_user.full_name} зашел в юзер панель.")
+ bot.send_message(call.message.chat.id, "👥 Список всех пользователей базы данных:", reply_markup=users_markup())
+ bot.set_state(call.message.chat.id, AdminPanel.get_users)
+ elif call.data == "servers":
+ app_logger.info(f"Администратор {call.from_user.full_name} зашел в панель управления серверами.")
+ bot.send_message(call.message.chat.id, "🖥 Панель управления серверами:", reply_markup=get_servers_markup())
+ bot.set_state(call.message.chat.id, AdminPanel.get_servers)
+
+
+@bot.callback_query_handler(func=None, state=AdminPanel.get_users)
+def get_user(call):
+ """ Хендлер для работы с юзерами из админ панели """
+ bot.answer_callback_query(callback_query_id=call.id)
+ if call.data == "Exit":
+
+ bot.send_message(call.message.chat.id, "Выберите опцию", reply_markup=admin_markup())
+ bot.set_state(call.message.chat.id, AdminPanel.get_option)
+ app_logger.info(f"Администратор {call.from_user.full_name} вернулся обратно к выбору опций.")
+ else:
+ user_obj: User = User.get_by_id(call.data)
+ try:
+ vpn_key: VPNKey = user_obj.vpn_key
+ vpn_key = vpn_key.name
+ except Exception:
+ vpn_key = "отсутствует"
+ app_logger.info(f"Администратор {call.from_user.full_name} запросил "
+ f"информацию о пользователе {user_obj.full_name}")
+ bot.send_message(call.message.chat.id,
+ f"👤 Имя: {user_obj.full_name}\n"
+ f"📱 Телеграм: @{user_obj.username}\n"
+ f"📢 Подписан на канал: {user_obj.is_subscribed}\n"
+ f"🔑 VPN ключ: {vpn_key}"
+ )
+
+
+@bot.callback_query_handler(func=None, state=AdminPanel.get_servers)
+def server_panel_handler(call):
+ """ Хендлер для управления серверами """
+ bot.answer_callback_query(callback_query_id=call.id)
+
+ if call.data == "Add":
+ bot.send_message(call.message.chat.id,
+ "📄 Введите данные сервера в следующем формате:\n"
+ "🏙 Location (например, США)\n"
+ "👤 Username (например, root)\n"
+ "🔒 Password (пароль от root)\n"
+ "🌐 IP address"
+ )
+ bot.set_state(call.message.chat.id, AdminPanel.add_server)
+ return
+
+ server_id = call.data
+ server_obj: Server = Server.get_by_id(server_id)
+
+ app_logger.info(f"Администратор {call.from_user.full_name} запросил информацию о сервере {server_obj.location}")
+
+ # Проверка настроен ли сервер
+ status = "✅ Настроен" if server_obj.public_key else "❌ Требует настройки"
+
+ bot.send_message(call.message.chat.id,
+ f"🖥 Сервер: {server_obj.location}\n"
+ f"🔰 Статус: {status}\n"
+ f"🌐 IP адрес: {server_obj.ip_address}\n"
+ f"🔑 Количество ключей: {server_obj.keys.count()}",
+ reply_markup=get_vpn_markup(server_id))
+ bot.set_state(call.message.chat.id, AdminPanel.get_vpn_keys)
+
+
+@bot.message_handler(state=AdminPanel.add_server)
+def add_server(message: Message):
+ """ Добавление нового сервера """
+ try:
+ server_data = [item.strip() for item in message.text.split("\n")]
+ if len(server_data) != 4: # Убрали порт X-UI
+ raise ValueError("❌ Неверное количество полей!")
+ elif valid_ip(server_data[3]) is False:
+ raise ValueError("❌ Неверный формат IP адреса!")
+
+ # Создаем сервер и настраиваем
+ server = Server.create(
+ location=server_data[0],
+ username=server_data[1],
+ password=server_data[2],
+ ip_address=server_data[3]
+ )
+ app_logger.info(f"Администратор {message.from_user.full_name} начинает настройку сервера {server.location}")
+ bot.send_message(message.from_user.id, "Начинаю настройку сервера, подождите...")
+ # Автоматическая настройка сервера
+ if setup_server(server):
+ bot.send_message(message.from_user.id, "✅ Сервер успешно настроен!")
+ else:
+ bot.send_message(message.from_user.id, "❌ Ошибка настройки сервера!")
+ server.delete_instance()
+ bot.set_state(message.from_user.id, None)
+ return
+
+ bot.set_state(message.from_user.id, None)
+ app_logger.info(f"Администратор {message.from_user.full_name} добавил сервер {server.location}")
+
+ except Exception as ex:
+ bot.send_message(message.from_user.id, f"❌ Некорректные данные!\n{ex}")
+ app_logger.error(f"Ошибка при добавлении сервера {ex}")
+ bot.set_state(message.from_user.id, None)
+
+
+@bot.callback_query_handler(func=None, state=AdminPanel.get_vpn_keys)
+def vpn_panel_handler(call):
+ """ Хендлер для управления всеми привязанными к серверу VPN ключами """
+ bot.answer_callback_query(callback_query_id=call.id)
+
+ if "Generate" in call.data:
+ # Генерация нового ключа
+ server_id = call.data.split()[1]
+ server = Server.get_by_id(server_id)
+ app_logger.info(f"Администратор {call.from_user.full_name} запросил генерацию"
+ f" VPN ключа для сервера {server.location}")
+ bot.send_message(call.message.chat.id, f"⌛ Пожалуйста, подождите... Идет генерация нового VPN ключа...")
+ key = generate_key(server)
+ if key:
+ bot.send_message(call.message.chat.id, f"✅ Отлично! VPN ключ «{key.name}» успешно создан!")
+ app_logger.info(f"Администратор {call.from_user.full_name} успешно создал "
+ f"VPN ключ {key.name} для сервера {server.location}")
+ else:
+ bot.send_message(call.message.chat.id, "❌ Ошибка генерации ключа!")
+
+ bot.set_state(call.message.chat.id, AdminPanel.get_vpn_keys)
+ return
+
+ if "Delete" in call.data:
+ server_id = call.data.split()[1]
+ server_obj: Server = Server.get_by_id(server_id)
+ bot.send_message(call.message.chat.id, f"🗑 Начинается полная очистка сервера. Пожалуйста, подождите...")
+ if cleanup_server(server_obj):
+ app_logger.info(f"Администратор {call.from_user.full_name} удалил сервер {server_obj.location}")
+ bot.send_message(call.message.chat.id, f"✅ Сервер {server_obj.location} успешно удалён вместе "
+ f"с привязанными VPN ключами!")
+ bot.set_state(call.message.chat.id, AdminPanel.get_servers)
+ else:
+ bot.send_message(call.message.chat.id, "❌ Ошибка удаления сервера!")
+ bot.set_state(call.message.chat.id, AdminPanel.get_servers)
+ return
+
+ if "VPN - " in call.data:
+ # Выдача всей информации по VPN ключу
+ vpn_obj: VPNKey = VPNKey.get_by_id(call.data.split("VPN - ")[1])
+ app_logger.info(f"Администратор {call.from_user.full_name} запросил информацию о VPN ключе {vpn_obj.name}")
+ status = "✅ Активен" if vpn_obj.is_valid else "⏸ Приостановлен / Занят"
+ users = ", ".join([user.full_name for user in vpn_obj.users]) if vpn_obj.users else "Нет пользователей"
+ text = (
+ f"🔑 Ключ: {vpn_obj.name}\n"
+ f"📍 Сервер: {vpn_obj.server.location}\n"
+ f"📡 Статус: {status}\n"
+ f"👤 Пользователи: {users}\n"
+ f"🕒 Создан: {vpn_obj.created_at.strftime('%d.%m.%Y %H:%M')}"
+ )
+
+ # Отправляем QR-код если есть
+ if os.path.exists(vpn_obj.qr_code):
+ with open(vpn_obj.qr_code, 'rb') as qr_file:
+ bot.send_photo(call.message.chat.id, qr_file, caption=text,
+ reply_markup=key_actions_markup(vpn_obj.id))
+ else:
+ bot.send_message(call.message.chat.id, text,
+ reply_markup=key_actions_markup(vpn_obj.id))
+ bot.set_state(call.message.chat.id, AdminPanel.delete_vpn)
+ elif "Cancel" in call.data:
+ # Возврат в меню серверов
+ bot.send_message(call.message.chat.id, "Вы вернулись в меню серверов.",
+ reply_markup=get_servers_markup())
+ app_logger.info(f"Администратор {call.from_user.full_name} вернулся в меню серверов")
+ bot.set_state(call.message.chat.id, AdminPanel.get_servers)
+ else:
+ bot.set_state(call.message.chat.id, AdminPanel.get_vpn_keys)
+
+@bot.callback_query_handler(func=None, state=AdminPanel.delete_vpn)
+def vpn_panel_handler(call):
+ """ Хендлер для удаления VPN ключа """
+ bot.answer_callback_query(callback_query_id=call.id)
+
+ if "action_" in call.data:
+ action, key_id = call.data.split("_")[1], call.data.split("_")[2]
+ vpn_key = VPNKey.get_by_id(key_id)
+
+ if action == "suspend":
+ app_logger.info(f"Администратор {call.message.from_user.full_name} запросил остановку "
+ f"VPN ключа {vpn_key.name}")
+ if suspend_key(vpn_key):
+ bot.send_message(call.message.chat.id, f"⏸ Ключ {vpn_key.name} приостановлен")
+ else:
+ bot.send_message(call.message.chat.id, "❌ Ошибка приостановки ключа!")
+
+ elif action == "resume":
+ app_logger.info(f"Администратор {call.message.from_user.full_name} запросил возобновление работы "
+ f"VPN ключа {vpn_key.name}")
+ if resume_key(vpn_key):
+ bot.send_message(call.message.chat.id, f"▶️ Ключ {vpn_key.name} возобновлен")
+ else:
+ bot.send_message(call.message.chat.id, "❌ Ошибка возобновления ключа!")
+
+ elif action == "revoke":
+ app_logger.info(f"Администратор {call.message.from_user.full_name} запросил отзыв "
+ f"VPN ключа {vpn_key.name}")
+ if revoke_key(vpn_key):
+ for user in User.select().where(User.vpn_key == vpn_key):
+ user.vpn_key = None
+ user.save()
+ bot.send_message(call.message.chat.id, f"🗑 Ключ {vpn_key.name} отозван")
+ else:
+ bot.send_message(call.message.chat.id, "❌ Ошибка отзыва ключа!")
+
+ bot.set_state(call.message.chat.id, AdminPanel.get_servers)
+ return
+
+ if "Cancel" in call.data:
+ bot.send_message(call.message.chat.id, "Вы вернулись в админку.",
+ reply_markup=admin_markup())
+ app_logger.info(f"Администратор {call.from_user.full_name} вернулся в админку")
+ bot.set_state(call.message.chat.id, AdminPanel.get_option)
+ return
+ else:
+ # Скорее всего, пользователь выбрал другой VPN ключ
+ bot.set_state(call.message.chat.id, AdminPanel.get_vpn_keys)
+ vpn_panel_handler(call)
+
+
+@bot.message_handler(commands=["message_sending"])
+def message_sending_handler(message: Message):
+ """ Хендлер рассылки сообщений юзерам """
+ if message.from_user.id in ALLOWED_USERS:
+ app_logger.info(f"Администратор {message.from_user.full_name} вызвал команду /message_sending.")
+ bot.send_message(message.from_user.id, "✉️ Введите текст сообщения для рассылки пользователям:")
+ bot.set_state(message.from_user.id, AdminPanel.send_message)
+ else:
+ bot.send_message(message.from_user.id, "❌ У вас недостаточно прав для выполнения этой команды!")
+ app_logger.warning(f"Попытка доступа к /message_sending без прав администратора {message.from_user.full_name}")
+
+
+@bot.message_handler(state=AdminPanel.send_message)
+def send_message_to_users_handler(message: Message):
+ """ Отправка сообщений пользователям """
+ # Проверка, что сообщение для рассылки - не одна из команд бота
+
+ if message.text in get_all_commands_bot():
+ bot.send_message(message.from_user.id, "Это одна из команд бота")
+ bot.set_state(message.from_user.id, None)
+ return
+
+ # Проверка, что сообщение не пустое
+ if not message.text:
+ bot.send_message(message.from_user.id, "Сообщение не может быть пустым.")
+ return
+ app_logger.info(f"Администратор {message.from_user.full_name} начал рассылку сообщений: {message.text}")
+
+ bot.send_message(message.chat.id, "Начинаю рассылку...")
+ bot.send_chat_action(message.chat.id, "typing")
+ for user_obj in User.select():
+ if int(user_obj.user_id) not in ALLOWED_USERS:
+ bot.send_message(user_obj.user_id, message.text)
+ bot.send_message(message.chat.id, "✅ Рассылка сообщений завершена!")
+ bot.set_state(message.from_user.id, None)
+
+
+@bot.message_handler(commands=["add_vpn_key"])
+def add_vpn_key_handler(message: Message):
+ """ Хендлер для ручного добавления VPN ключа """
+ if message.from_user.id in ALLOWED_USERS:
+ app_logger.info(f"Администратор {message.from_user.full_name} вызвал команду /add_vpn_key.")
+ bot.send_message(message.from_user.id, "🔑 Введите название нового VPN ключа:")
+ bot.set_state(message.from_user.id, AdminPanel.add_vpn_key_name)
+ else:
+ bot.send_message(message.from_user.id, "У вас недостаточно прав!")
+
+
+@bot.message_handler(state=AdminPanel.add_vpn_key_name)
+def add_vpn_key_name_handler(message: Message):
+ """ Обработка ввода названия VPN ключа """
+ app_logger.info(f"Администратор {message.from_user.full_name} ввел название VPN ключа: {message.text}")
+ with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
+ data["vpn_key_name"] = message.text
+ bot.send_message(message.from_user.id, "🔑 Введите VPN KEY в формате JSON или "
+ "VLESS-ссылку (например, vless://...) :")
+ bot.set_state(message.from_user.id, AdminPanel.add_vpn_key_key)
+
+
+@bot.message_handler(state=AdminPanel.add_vpn_key_key)
+def add_vpn_key_key_handler(message: Message):
+ """ Обработка ввода VPN ключа """
+
+ if message.text in get_all_commands_bot():
+ bot.send_message(message.from_user.id, "Это одна из команд бота")
+ bot.set_state(message.from_user.id, None)
+ return
+
+ app_logger.info(f"Администратор {message.from_user.full_name} ввел VPN ключ")
+ if "vless://" not in message.text:
+ vless_str = convert_amnezia_xray_json_to_vless_str(message.text)
+ if vless_str is None:
+ bot.send_message(message.from_user.id, "Не удалось преобразовать JSON в VLESS строку. "
+ "Проверьте правильность ввода.")
+ app_logger.warning("Не удалось преобразовать json конфиг в vless строку!")
+ return
+ else:
+ vless_str = message.text
+ with bot.retrieve_data(message.from_user.id, message.chat.id) as data:
+ data["vpn_key_key"] = vless_str
+ bot.send_message(message.from_user.id, "Выберите сервер, к которому принадлежит ключ",
+ reply_markup=get_servers_markup())
+ bot.set_state(message.from_user.id, AdminPanel.save_vpn_key)
+
+
+@bot.callback_query_handler(func=None, state=AdminPanel.save_vpn_key)
+def save_vpn_handler(call):
+ """ Хендлер для сохранения в БД VPN ключа """
+ bot.answer_callback_query(callback_query_id=call.id)
+
+ if call.data == "Add":
+ bot.send_message(call.message.chat.id,
+ "📄 Введите данные сервера в следующем формате:\n"
+ "🏙 Location (например, США)\n"
+ "👤 Username (например, root)\n"
+ "🔒 Password (пароль от root)\n"
+ "🌐 IP address"
+ )
+ bot.set_state(call.message.chat.id, AdminPanel.add_server)
+ return
+
+ server_id = call.data
+ server_obj: Server = Server.get_by_id(server_id)
+ with bot.retrieve_data(call.from_user.id, call.from_user.id) as data:
+ try:
+ key_number = len(server_obj.keys) + 1 if hasattr(server_obj, "keys") else 1
+ qr_code_filename = f"vpn_key_{server_obj.id}_{key_number}.png"
+ qr_code_path = os.path.join(QR_CODE_DIR, qr_code_filename)
+ qr = qrcode.QRCode(
+ version=1,
+ error_correction=qrcode.constants.ERROR_CORRECT_H,
+ box_size=10,
+ border=4
+ )
+ qr.add_data(data["vpn_key_key"])
+ qr.make(fit=True)
+ img = qr.make_image(fill_color="black", back_color="white")
+ img.save(qr_code_path)
+ app_logger.info(f"QR-код сгенерирован и сохранён по пути: {qr_code_path}")
+ vpn_key = VPNKey.create(
+ name=data["vpn_key_name"],
+ key=data["vpn_key_key"],
+ qr_code=qr_code_path,
+ server=server_obj,
+ )
+ except peewee.IntegrityError:
+ bot.send_message(call.message.chat.id, "Такой ключ уже существует!")
+ bot.send_message(call.message.chat.id, "Вы вышли в главное меню")
+ app_logger.warning(f"Попытка создания дубликата VPN ключа {data['vpn_key_name']}!")
+
+ else:
+ app_logger.info(f"Администратор {call.message.from_user.full_name} добавил VPN ключ {vpn_key.name} "
+ f"к серверу {server_obj.location}")
+ bot.send_message(call.message.chat.id, f"VPN ключ {vpn_key.name} добавлен к серверу {server_obj.location}.")
+ bot.set_state(call.message.chat.id, None)
diff --git a/files/TG_bot_VPN-main/handlers/custom_heandlers/instruction_handlers.py b/files/TG_bot_VPN-main/handlers/custom_heandlers/instruction_handlers.py
new file mode 100644
index 0000000..4702212
--- /dev/null
+++ b/files/TG_bot_VPN-main/handlers/custom_heandlers/instruction_handlers.py
@@ -0,0 +1,26 @@
+from telebot.types import Message
+
+from config_data.config import CHANNEL_ID
+from database.models import User
+from loader import bot, app_logger
+from keyboards.inline.app_buttons import get_apps_murkup
+
+
+@bot.message_handler(commands=["instruction"])
+def instruction_handler(message: Message):
+ """ Хендлер для выбора сервера подключения """
+ app_logger.info(f"Пользователь {message.from_user.full_name} вызвал команду /location")
+ cur_user = User.get(User.user_id == message.from_user.id)
+
+ if cur_user.is_subscribed:
+ instruction_text = (
+ "📖 Подробная инструкция по подключению доступна по [ссылке]"
+ "(https://telegra.ph/Kak-ispolzovat-VPN-servis-Guard-Tunnel-01-16).\n\n"
+ "💡 Для использования VPN, пожалуйста, скачайте приложение **Hiddify**.\n\n"
+ "Желаем вам безопасного и комфортного подключения! 🚀"
+ )
+ bot.send_message(message.chat.id, instruction_text, parse_mode="Markdown", reply_markup=get_apps_murkup())
+ else:
+ bot.send_message(message.chat.id, f"🚫 Вы не подписаны на [наш канал](https://t.me/{CHANNEL_ID[1:]})!\n"
+ f"Подпишитесь, чтобы получить доступ ко всему функционалу.",
+ parse_mode="Markdown")
diff --git a/files/TG_bot_VPN-main/handlers/custom_heandlers/location_handlers.py b/files/TG_bot_VPN-main/handlers/custom_heandlers/location_handlers.py
new file mode 100644
index 0000000..45490e4
--- /dev/null
+++ b/files/TG_bot_VPN-main/handlers/custom_heandlers/location_handlers.py
@@ -0,0 +1,135 @@
+from telebot.types import Message
+
+from config_data.config import CHANNEL_ID
+from database.models import User, Server, VPNKey
+from loader import bot, app_logger, scheduler
+from keyboards.inline.servers import get_locations_markup, get_instruction_markup
+from states.states import GetVPNKey
+from utils.functions import is_subscribed
+from utils.generate_vpn_keys import generate_key
+from utils.tasks import cancel_key_revocation
+from utils.work_vpn_keys import revoke_key
+
+
+@bot.message_handler(commands=["location"])
+def location_handler(message: Message):
+ """ Хендлер для выбора сервера подключения """
+ app_logger.info(f"Пользователь {message.from_user.full_name} вызвал команду /location")
+ cur_user = User.get(User.user_id == message.from_user.id)
+
+ if is_subscribed(CHANNEL_ID, message.from_user.id):
+ cur_user.is_subscribed = True
+ bot.send_message(message.chat.id, "🌍 Пожалуйста, выберите сервер для подключения:", reply_markup=get_locations_markup())
+ bot.set_state(message.chat.id, GetVPNKey.get_server)
+ else:
+ bot.send_message(message.chat.id, f"🚫 Вы не подписаны на [наш канал](https://t.me/{CHANNEL_ID[1:]})!\n"
+ f"Подпишитесь, чтобы получить доступ ко всему функционалу.",
+ parse_mode="Markdown")
+ cur_user.is_subscribed = False
+ cur_user.save()
+
+
+@bot.callback_query_handler(func=None, state=GetVPNKey.get_server)
+def get_server_handler(call):
+ """ Хендлер для получения сервера подключения """
+ bot.answer_callback_query(callback_query_id=call.id)
+
+ server_id = call.data
+
+ cur_user: User = User.get(User.user_id == call.from_user.id)
+ cur_server: Server = Server.get_by_id(server_id)
+
+ # Проверка на то, что текущий VPN ключ пользователя удален.
+ try:
+ VPNKey.get_by_id(cur_user.vpn_key)
+ except Exception:
+ app_logger.warning(f"Внимание! У пользователя {cur_user.full_name} не нашлось ключа VPN!")
+ cur_user.vpn_key = None
+ cur_user.save()
+
+ app_logger.info(f"Пользователь {cur_user.full_name} выбрал сервер {cur_server.location}")
+
+ # Получение всех vpn ключей данного сервера и выбор одного
+ for vpn_key_obj in cur_server.keys:
+ if vpn_key_obj.is_valid:
+ if cur_user.vpn_key is not None:
+ users_vpn = VPNKey.get_by_id(cur_user.vpn_key)
+ users_vpn.is_valid = True
+ users_vpn.save()
+ app_logger.info(f"VPN ключ {users_vpn.name} теперь свободен.")
+ cur_user.vpn_key = vpn_key_obj
+ cur_user.save()
+ vpn_key_obj.is_valid = False
+ vpn_key_obj.save()
+ app_logger.info(f"Пользователь {cur_user.full_name} зарезервировал ключ {vpn_key_obj.name}")
+ with open(vpn_key_obj.qr_code, "rb") as qr_code:
+ bot.send_photo(
+ call.message.chat.id,
+ qr_code,
+ caption=(
+ "🔒 Мы не храним информацию о ваших подключениях!\n\n"
+ f"🔑 Имя ключа: *{vpn_key_obj.name}*\n"
+ f"🌍 Сервер: *{cur_server.location}*\n"
+ f"🔗 URL для подключения:\n\n`{vpn_key_obj.key}`"
+ ),
+ parse_mode="Markdown",
+ reply_markup=get_instruction_markup()
+ )
+ bot.set_state(call.message.chat.id, None)
+ return
+
+ # Если нет свободных ключей, генерируем новый
+ app_logger.warning(f"Внимание! Для сервера {cur_server.location} не нашлось свободных VPN ключей! "
+ f"Генерирую новый...")
+ bot.send_message(call.message.chat.id, "⌛ Пожалуйста, подождите... Идет генерация нового VPN ключа...")
+
+ new_key: VPNKey = generate_key(cur_server)
+ if new_key is None:
+ app_logger.error("Внимание! Не удалось сгенерировать новый ключ!")
+ bot.send_message(call.message.chat.id, "❌ Ведутся технические работы на стороне сервера, поэтому "
+ "генерация нового ключа пока невозможна!\n"
+ "Мы приносим свои извинения, попробуйте позже 😊")
+ bot.set_state(call.message.chat.id, None)
+ return
+ app_logger.info(f"Сгенерирован новый ключ {new_key.name}!")
+
+ if cur_user.vpn_key is not None:
+ users_vpn = VPNKey.get_by_id(cur_user.vpn_key)
+ revoke_key(users_vpn)
+
+ cur_user.vpn_key = new_key
+ cur_user.save()
+
+ new_key.is_valid = False
+ new_key.save()
+ app_logger.info(f"Пользователь {cur_user.full_name} зарезервировал новый ключ {new_key.name}")
+ with open(new_key.qr_code, "rb") as qr_code:
+ bot.send_photo(
+ call.message.chat.id,
+ qr_code,
+ caption=(
+ "🔒 Мы не храним информацию о ваших подключениях!\n\n"
+ f"🔑 Имя ключа: *{new_key.name}*\n"
+ f"🌍 Сервер: *{cur_server.location}*\n"
+ f"🔗 URL для подключения:\n\n`{new_key.key}`"
+ ),
+ parse_mode="Markdown",
+ reply_markup=get_instruction_markup()
+ )
+ bot.set_state(call.message.chat.id, None)
+
+
+@bot.callback_query_handler(func=lambda call: call.data.startswith("renew_"))
+def renew_key_handler(call):
+ bot.answer_callback_query(callback_query_id=call.id)
+ try:
+ vpn_key_id = int(call.data.split("_")[1])
+ vpn_key = VPNKey.get_by_id(vpn_key_id)
+ # Отменяем запланированную задачу отзыва
+ cancel_key_revocation(vpn_key, scheduler)
+ bot.send_message(call.message.chat.id,
+ f"✅ Ваш VPN ключ «{vpn_key.name}» успешно продлён!")
+ app_logger.info(f"VPN ключ {vpn_key.name} продлён пользователем {call.from_user.full_name}.")
+ except Exception as e:
+ app_logger.error(f"Ошибка в обработчике продления ключа: {e}")
+ bot.send_message(call.message.chat.id, "❌ Произошла ошибка при продлении ключа.")
diff --git a/files/TG_bot_VPN-main/handlers/default_heandlers/__init__.py b/files/TG_bot_VPN-main/handlers/default_heandlers/__init__.py
new file mode 100644
index 0000000..4e4b225
--- /dev/null
+++ b/files/TG_bot_VPN-main/handlers/default_heandlers/__init__.py
@@ -0,0 +1,6 @@
+from . import start
+from . import help
+from . import echo
+
+
+__all__ = ['start', 'help', 'echo']
diff --git a/files/TG_bot_VPN-main/handlers/default_heandlers/echo.py b/files/TG_bot_VPN-main/handlers/default_heandlers/echo.py
new file mode 100644
index 0000000..f8f5904
--- /dev/null
+++ b/files/TG_bot_VPN-main/handlers/default_heandlers/echo.py
@@ -0,0 +1,21 @@
+from telebot.types import Message
+from loader import bot
+from handlers.custom_heandlers.location_handlers import location_handler
+from handlers.default_heandlers.help import bot_help
+from handlers.custom_heandlers.instruction_handlers import instruction_handler
+
+
+# Эхо хендлер, куда летят текстовые сообщения без указанного состояния
+
+@bot.message_handler(state=None)
+def bot_echo(message: Message):
+ if message.text == "🌍 Серверы":
+ location_handler(message)
+ elif message.text == "❓ Справка":
+ bot_help(message)
+ elif message.text == "📖 Инструкция":
+ instruction_handler(message)
+ else:
+ bot.reply_to(message, f"Введите любую команду из меню, чтобы я начал работать\n"
+ f"Либо выберите одну из кнопок, которые я вам прислал 👇")
+
diff --git a/files/TG_bot_VPN-main/handlers/default_heandlers/help.py b/files/TG_bot_VPN-main/handlers/default_heandlers/help.py
new file mode 100644
index 0000000..fc77dd4
--- /dev/null
+++ b/files/TG_bot_VPN-main/handlers/default_heandlers/help.py
@@ -0,0 +1,13 @@
+from telebot.types import Message
+
+from config_data.config import DEFAULT_COMMANDS, ADMIN_COMMANDS, ALLOWED_USERS
+from loader import bot
+
+
+@bot.message_handler(commands=['help'])
+def bot_help(message: Message):
+ commands = [f"/{command} - {description}" for command, description in DEFAULT_COMMANDS]
+ if message.from_user.id in ALLOWED_USERS:
+ commands.extend([f"/{command} - {description}" for command, description in ADMIN_COMMANDS])
+ bot.reply_to(message, "📋 Доступные команды:\n" + "\n".join(commands))
+ bot.send_message(message.chat.id, "🤝 Для поддержки обращайтесь: @guardtunnel_support")
diff --git a/files/TG_bot_VPN-main/handlers/default_heandlers/start.py b/files/TG_bot_VPN-main/handlers/default_heandlers/start.py
new file mode 100644
index 0000000..32beca8
--- /dev/null
+++ b/files/TG_bot_VPN-main/handlers/default_heandlers/start.py
@@ -0,0 +1,99 @@
+from telebot.types import Message
+from loader import bot, app_logger
+from config_data.config import DEFAULT_COMMANDS, ADMIN_COMMANDS, ALLOWED_USERS, CHANNEL_ID
+from database.models import User, Group
+from utils.functions import is_subscribed
+from keyboards.inline.subscribed import is_subscribed_markup
+from keyboards.reply.handlers_reply import handlers_reply
+from states.states import SubscribedState
+
+
+start_text = """*Вы не подписались на канал!*
+
+☺️ Для доступа к полному функционалу бота вам необходимо подписаться на наш новостной канал [Guard Tunnel VPN](https://t.me/{channel_id})
+
+🎁 В подарок вы получите *бесплатный доступ* на использование нашего сервиса
+
+*С Уважением, команда Guard Tunnel VPN*
+
+_После подписки на наш канал нажмите ниже на кнопку: ✅ Я подписался_"""
+
+
+@bot.message_handler(commands=['start'])
+def bot_start(message: Message):
+ if message.chat.type == "private":
+ is_sub = True if message.from_user.id in ALLOWED_USERS else False
+ if User.get_or_none(user_id=message.from_user.id) is None:
+ app_logger.info(f"Внимание! Новый юзер: {message.from_user.full_name} - {message.from_user.username}")
+ User.create(user_id=message.from_user.id,
+ full_name=message.from_user.full_name,
+ username=message.from_user.username if message.from_user.username is not None else "None",
+ is_premium=message.from_user.is_premium,
+ is_subscribed=is_sub)
+ commands = [f"/{command} - {description}" for command, description in DEFAULT_COMMANDS]
+ if message.from_user.id in ALLOWED_USERS:
+ commands.extend([f"/{command} - {description}" for command, description in ADMIN_COMMANDS])
+ bot.send_message(
+ message.from_user.id,
+ f"Здравствуйте, {message.from_user.full_name}! 👋\n"
+ f"Вы вошли как администратор. Доступны следующие команды:\n{'\n'.join(commands)}",
+ reply_markup=handlers_reply()
+ )
+ else:
+ if is_subscribed(CHANNEL_ID, message.from_user.id):
+ # Если пользователь подписан на канал, тогда ему можно пользоваться ботом.
+ bot.send_message(message.from_user.id, f"Приветствуем, {message.from_user.full_name}.\n"
+ f"Рады приветствовать вас на нашем сервисе!\n"
+ f"Что бы использовать наш VPN сервис, "
+ f"следуйте инструкциям ниже 👇\n"
+ f"{'\n'.join(commands)}",
+ reply_markup=handlers_reply())
+ cur_user = User.get(User.user_id == message.from_user.id)
+ cur_user.is_subscribed = True
+ cur_user.save()
+ else:
+ bot.send_message(message.from_user.id, start_text.format(channel_id=CHANNEL_ID[1:]),
+ reply_markup=is_subscribed_markup(), parse_mode='Markdown',
+ disable_web_page_preview=True)
+ bot.set_state(message.from_user.id, SubscribedState.subscribe)
+
+ else:
+ bot.send_message(message.chat.id, "Здравствуйте! Я - телеграм бот, модератор каналов и групп. "
+ "Чтобы получить больше информации, "
+ "обратитесь к администратору, или напишите мне в личку)")
+ if Group.get_or_none(group_id=message.chat.id) is None:
+ Group.create(group_id=message.chat.id,
+ title=message.chat.title,
+ description=message.chat.description,
+ bio=message.chat.bio,
+ invite_link=message.chat.invite_link,
+ location=message.chat.location,
+ username=message.chat.username)
+ app_logger.info(f"Внимание! Новая группа: {message.chat.title} - {message.chat.invite_link}")
+ if User.get_or_none(user_id=message.from_user.id) is None:
+ User.create(user_id=message.from_user.id,
+ full_name=message.from_user.full_name,
+ username=message.from_user.username,
+ is_premium=message.from_user.is_premium)
+ app_logger.info(f"Внимание! Новый юзер: {message.from_user.full_name} - {message.from_user.username}")
+
+@bot.callback_query_handler(func=None, state=SubscribedState.subscribe)
+def is_subscribed_handler(call):
+ if is_subscribed(CHANNEL_ID, call.from_user.id):
+ commands = [f"/{command} - {description}" for command, description in DEFAULT_COMMANDS]
+ app_logger.info(f"Пользователь {call.from_user.full_name} подписался на канал!")
+
+ cur_user = User.get(User.user_id == call.from_user.id)
+ cur_user.is_subscribed = True
+ cur_user.save()
+
+ bot.answer_callback_query(callback_query_id=call.id)
+ bot.send_message(call.message.chat.id, "Спасибо, что выбрали наш сервис, приятного использования!\n"
+ f"Вам доступны следующие команды:\n"
+ f"{'\n'.join(commands)}")
+ bot.set_state(call.message.chat.id, None)
+ else:
+ bot.answer_callback_query(callback_query_id=call.id)
+ bot.send_message(call.message.chat.id, start_text.format(channel_id=CHANNEL_ID[1:]),
+ reply_markup=is_subscribed_markup(), parse_mode='Markdown',
+ disable_web_page_preview=True)