diff --git a/.gitignore b/.gitignore index 4ab118b..1fb7ad4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ TBot/ logs/* -.code-workspace \ No newline at end of file +*.code-workspace +__pycache__/ +handlers.py +*.pyc \ No newline at end of file diff --git a/Lark_VPN_Bot.code-workspace b/Lark_VPN_Bot.code-workspace index 15bbdbb..baa3550 100644 --- a/Lark_VPN_Bot.code-workspace +++ b/Lark_VPN_Bot.code-workspace @@ -5,6 +5,9 @@ }, { "path": "../Bot" + }, + { + "path": "../bot/Lark_VPN_Bot" } ], "settings": {} diff --git a/Middleware/__pycache__/anti_spam_middleware.cpython-312.pyc b/Middleware/__pycache__/anti_spam_middleware.cpython-312.pyc deleted file mode 100644 index 07eca31..0000000 Binary files a/Middleware/__pycache__/anti_spam_middleware.cpython-312.pyc and /dev/null differ diff --git a/handlers/__init__.py b/handlers/__init__.py new file mode 100644 index 0000000..697552f --- /dev/null +++ b/handlers/__init__.py @@ -0,0 +1,7 @@ +from .start import router as start_router +from .profile import router as profile_router +from .subscriptions import router as subscriptions_router +from .support import router as support_router + +# Экспортируем все маршрутизаторы +routers = [start_router,profile_router,subscriptions_router,support_router] diff --git a/handlers/__pycache__/handlers.cpython-312.pyc b/handlers/__pycache__/handlers.cpython-312.pyc deleted file mode 100644 index 376f779..0000000 Binary files a/handlers/__pycache__/handlers.cpython-312.pyc and /dev/null differ diff --git a/handlers/handlers.py b/handlers/handlers.py deleted file mode 100644 index 74f7681..0000000 --- a/handlers/handlers.py +++ /dev/null @@ -1,417 +0,0 @@ -from aiogram import types, Dispatcher -from aiogram.filters import Command -import aiohttp -import logging -from datetime import datetime -from instences.config import BASE_URL_FASTAPI -import locale -locale.setlocale(locale.LC_TIME, "ru_RU.UTF-8") -from keyboard.keyboards import subhist_keyboard,confirm_popup_keyboard,tarif_confirm_keyboard,ticket_keyboard, popup_keyboard, main_keyboard,faq_keyboard, account_keyboard, buy_keyboard,balance_keyboard,guide_keyboard,tarif_Lark_keyboard,tarif_Lark_pro_keyboard,tranhist_keyboard -logger = logging.getLogger(__name__) - -# Инициализируем менеджер базы данных - -async def call_api(method, endpoint, data=None): - """ - Выполняет HTTP-запрос к FastAPI. - - :param method: HTTP метод (GET, POST, и т.д.) - :param endpoint: конечная точка API - :param data: тело запроса (если необходимо) - :return: JSON-ответ или "ERROR" при неуспехе - """ - url = f"{BASE_URL_FASTAPI}{endpoint}" - logger.info(f"Инициализация запроса: {method} {url} с данными {data}") - - try: - async with aiohttp.ClientSession() as session: - async with session.request(method, url, json=data) as response: - logger.info(f"Получен ответ от {url}: статус {response.status}") - - if response.status in {200, 201}: - result = await response.json() - logger.debug(f"Ответ JSON: {result}") - return result - - logger.error(f"Ошибка в запросе: статус {response.status}, причина {response.reason}") - return "ERROR" - except Exception as e: - logger.exception(f"Исключение при выполнении запроса к {url}: {e}") - return "ERROR" - - -user_state = {} - -async def start_ticket_creation(message: types.Message): - """ - Начинает процесс создания тикета. - """ - await message.answer( - "Введите тему тикета (или нажмите 'Отмена', чтобы выйти):", - reply_markup=ticket_keyboard() - ) - user_state[message.from_user.id] = {"step": "subject"} - -async def handle_ticket_input(message: types.Message): - """ - Обрабатывает ввод данных для тикета. - """ - user_id = message.from_user.id - text = message.text.lower() - - if text == "отмена": - await message.answer("Создание тикета отменено.", reply_markup=types.ReplyKeyboardRemove()) - user_state.pop(user_id, None) - return - - state = user_state.get(user_id) - if not state: - await message.answer("Нет активного процесса создания тикета. Введите /support для начала.") - return - - if state["step"] == "subject": - state["subject"] = message.text - state["step"] = "message" - await message.answer("Введите описание проблемы:") - elif state["step"] == "message": - state["message"] = message.text - await create_ticket(message, state) - user_state.pop(user_id, None) - -async def create_ticket(message: types.Message, state): - """ - Отправляет запрос на создание тикета через FastAPI. - """ - user_id = message.from_user.id - subject = state["subject"] - ticket_message = state["message"] - - try: - logger.info(f"Создание тикета для пользователя {user_id}: Тема - {subject}, Сообщение - {ticket_message}") - user_data = await call_api("GET", f"/user/{message.from_user.id}") - if not user_data: - await message.edit_text("Вы еще не зарегистрированы.") - await message.answer() - return - # Отправляем запрос через call_api - ticket_data = await call_api( - "POST", - f"/support/tickets?user_id={user_data['id']}", # Передаём user_id как query-параметр - data={"subject": subject, "message": ticket_message} - ) - - - if ticket_data != "ERROR": - await message.answer( - f"✅ Тикет успешно создан!\n" - f"📌 Тема: {ticket_data['subject']}\n" - f"📊 Статус: {ticket_data['status']}\n" - f"📅 Дата создания: {ticket_data['created_at']}" - ) - else: - await message.answer("❌ Ошибка создания тикета. Попробуйте позже.") - except Exception as e: - logger.exception(f"Ошибка при создании тикета для пользователя {user_id}: {e}") - await message.answer("❌ Произошла ошибка при создании тикета.") - - - - -async def subhist_command(message: types.Message): - """ - Обработчик команды для отправки истории подписок. - """ - user_data = await call_api("GET", f"/user/{message.from_user.id}") - if not user_data: - await message.edit_text("Вы еще не зарегистрированы.") - await message.answer() - return - - subscriptions = await call_api("GET", f"/subscriptions/{user_data['id']}") - if not subscriptions: - await message.edit_text("У вас нет активных подписок.", reply_markup=account_keyboard()) - await message.answer() - return - - result = "Ваши подписки:\n" - for count, sub in enumerate(subscriptions, start=1): - result += f"{count}. Тариф: {sub['plan']}, Истекает: {sub['expiry_date']}\n" - await message.edit_text(result, reply_markup=account_keyboard()) - await message.answer() - - await message.answer("subhist", reply_markup=subhist_keyboard()) - -async def start_command(message: types.Message): - """ - Обработчик команды /start. - """ - await message.answer(f"""Приветствуем в рядах птенец {message.from_user.username}🐣 - \nСкорее пополни баланс, приобрети подписку и получай доступ к TikTok, YouTube, Discord, Instagram на всех устройствах без ограничений ❕❕❕ - \nОзнакомься с руководством по пользованию и выбери подходящий тариф 🦅 - \nСледи за акциями, спец-предложениями, а также розыгрышами по ссылке ниже - \n👇👇👇 - \nhttps://t.me/+0z5xqn3F1m02OTJi - \nС любовью ваши пернатые разработчики 🤍🤍🤍""", reply_markup=main_keyboard()) - -async def start_callback_handler(callback: types.CallbackQuery): - """ - Обработчик callback_query с data="base". - """ - await callback.message.edit_text( - f"""Приветствуем в рядах птенец {callback.from_user.username}🐣 - \nСкорее пополни баланс, приобрети подписку и получай доступ к TikTok, YouTube, Discord, Instagram на всех устройствах без ограничений ❕❕❕ - \nОзнакомься с руководством по пользованию и выбери подходящий тариф 🦅 - \nСледи за акциями, спец-предложениями, а также розыгрышами по ссылке ниже - \n👇👇👇 - \nhttps://t.me/+0z5xqn3F1m02OTJi - \nС любовью ваши пернатые разработчики 🤍🤍🤍""", - reply_markup=main_keyboard() - ) - -async def profile_callback_handler(callback: types.CallbackQuery): - try: - # Создание пользователя - user_data = await call_api("POST", "/user/create", {"telegram_id": callback.from_user.id}) - if user_data == "ERROR" or not isinstance(user_data, dict): - raise ValueError("Не удалось создать пользователя.") - - # Получение подписки - sub_data = await call_api("GET", f"/subscription/{user_data['id']}/last") - if sub_data == "ERROR" or not isinstance(sub_data, dict): - sub_data = None - - # Формирование текста баланса - balance_text = f"Баланс: {user_data['balance']} ₽" - - # Если подписки нет - if not sub_data: - text = f"Профиль {callback.from_user.username}\n{balance_text}\nПополните баланс и приобретите подписку чтобы получить активный статус (🐣,🦅)" - else: - # Получение даты окончания подписки - expiry_date = sub_data.get("expiry_date") - formatted_date = None - - # Преобразование времени в презентабельный формат - if expiry_date: - expiry_datetime = datetime.fromisoformat(expiry_date) - formatted_date = expiry_datetime.strftime("%d %B %Y г.") - - # Проверка на истечение подписки - is_expired = datetime.fromisoformat(expiry_date) < datetime.now() if expiry_date else True - plan_type = sub_data.get("plan", "") - status_icon = "✖️" if is_expired else "☑️" - - # Определение статуса - if "Pro" in plan_type: - profile_status = "🦅" - else: - profile_status = "🐣" - - # Формирование текста профиля - sub_text = ( - f"Ваша подписка действует до {formatted_date} {status_icon}" - if not is_expired else f"Статус подписки: {status_icon}" - ) - text = f"Профиль {callback.from_user.username} {profile_status}:\n{sub_text}\n{balance_text}" - - # Отправка текста пользователю - await callback.message.edit_text(text, reply_markup=account_keyboard()) - except ValueError as e: - await callback.message.answer(f"Ошибка: {e}") - except Exception as e: - logger.exception(f"Ошибка в обработчике профиля: {e}") - await callback.message.answer("Произошла ошибка. Попробуйте позже.") - finally: - await callback.answer() - - - -async def balance_callback_handler(callback: types.CallbackQuery): - user_data = await call_api("GET", f"/user/{callback.from_user.id}") - if not user_data: - await callback.message.answer("Вы еще не зарегистрированы.") - await callback.answer() - return - - await callback.message.edit_text( - f"Ваш баланс: {user_data['balance']} ₽. Выберите сумму для пополнения 🐥", - reply_markup=balance_keyboard() - ) - await callback.answer() - - -async def popup_callback_handler(callback: types.CallbackQuery): - """ - Обработчик callback_query с data="popup". - """ - user = await call_api("POST", "/user/create", {"telegram_id": callback.from_user.id}) - if user == "ERROR": - await callback.message.answer( - "Произошла ошибка, попробуйте позже или свяжитесь с администрацией." - ) - await callback.answer() - return - - if user: - await callback.message.edit_text( - f"Работает в режиме теста!!!", - reply_markup=popup_keyboard() - ) - else: - await callback.message.edit_text("Вы еще не зарегистрированы.") - await callback.answer() - -async def tranhist_callback_handler(callback: types.CallbackQuery): - user_data = await call_api("GET", f"/user/{callback.from_user.id}") - if not user_data: - await callback.message.edit_text("Вы еще не зарегистрированы.") - await callback.answer() - return - - transactions = await call_api("GET", f"/user/{user_data['id']}/transactions") - if not transactions: - await callback.message.edit_text("У вас нет транзакций.", reply_markup=tranhist_keyboard()) - await callback.answer() - return - - result = "Ваши транзакции:\n" - for count, tran in enumerate(transactions, start=1): - result += f"{count}. Сумма: {tran['amount']}, Дата: {tran['created_at']}\n" - await callback.message.edit_text(result, reply_markup=tranhist_keyboard()) - await callback.answer() - -async def buy_subscription_callback_handler(callback: types.CallbackQuery): - """ - Обработчик callback_query с data="buy_subscription". - """ - await callback.message.edit_text( - f"Ознакомься с условиями в вкладке \"О тарифах\" и выбери подходящий 🦅", - reply_markup=buy_keyboard() - ) - -async def guide_callback_handler(callback:types.CallbackQuery): - """ - Обработчик callback_query с data="guide". - """ - await callback.message.edit_text( - f"Руководство по использованию продкута что мы высрали;)", - reply_markup=guide_keyboard() - ) - -async def subs_callback_handler(callback: types.CallbackQuery): - """ - Обработчик callback_query с data="subs". - """ - await callback.message.edit_text( - f"Подписки птенчик", - reply_markup=tarif_Lark_keyboard() - ) - -async def subs_pro_callback_handler(callback: types.CallbackQuery): - """ - Обработчик callback_query с data="subs_pro". - """ - await callback.message.edit_text( - f"Подписки птенчик ПРО", - reply_markup=tarif_Lark_pro_keyboard() - ) - -# async def about_tarifs_callback_handler(callback: types.CallbackQuery): -# """ -# Обработчик callback_query с data="about_tarifs". -# """ -# await callback.message.edit_text( -# f"Бла бла бла, хуйня на хуйне", -# reply_markup=about_tarifs_keyboard() -# ) - -async def faq_callback_handler(callback:types.CallbackQuery): - """ - Обработчик callback_query с data="faq". - """ - await callback.message.edit_text( - f"FAQ YOU", - reply_markup=faq_keyboard() - ) - -async def lark_tariff_callback_handler(callback: types.CallbackQuery): - """ - Обработчик для выбора тарифа Lark. - """ - data = callback.data.split(":") - tariff_name = data[0] - tariff_class = data[1] - tariff_time = int(data[2]) - - # Определение окончания для месяцев - if tariff_time == 1: - months = f"{tariff_time} месяц" - elif 2 <= tariff_time <= 4: - months = f"{tariff_time} месяца" - else: - months = f"{tariff_time} месяцев" - - text = f"Тариф {tariff_name} на {months}. Продолжите покупку..." - - # Рендеринг клавиатуры - keyboard = tarif_confirm_keyboard(tariff_name, tariff_time, tariff_class) - await callback.message.edit_text(text=text, reply_markup=keyboard) - -async def popup_confirm_callback_handler(callback: types.CallbackQuery): - """ - Обработчик подтверждения пополнения баланса. - """ - data = callback.data.split(":") - popup_info = data[1] - result = await call_api("POST", f"/user/{callback.from_user.id}/balance/{float(popup_info)}") - if result == "ERROR": - await callback.message.answer( - "Произошла ошибка, попробуйте позже или свяжитесь с администрацией." - ) - await callback.answer() - return - text = f"Вы пополнили свой баланс на {popup_info}. P.S. Мы завтра закрываемся" - await callback.message.edit_text(text=text, reply_markup=confirm_popup_keyboard()) - -async def confirm_callback_handler(callback: types.CallbackQuery): - data = callback.data.split(":")[1] - tariff_info = data.split("_") - plan_id = f"{tariff_info[0]}_{tariff_info[1]}_{tariff_info[2]}" - result = await call_api("POST", "/subscription/buy", {"telegram_id": callback.from_user.id, "plan_id": plan_id}) - error_detail = result.get("detail",{}) - error_code = error_detail.get("code", "") - - if error_code == "ERROR": - await callback.message.edit_text("Произошла ошибка при оформлении подписки.") - if error_code == "INSUFFICIENT_FUNDS": - await callback.message.edit_text("Денег на вашем балансе не достаточно.") - if error_code == "TARIFF_NOT_FOUND": - await callback.message.edit_text("Ваш тариф не найден.") - if error_code == "ACTIVE_SUBSCRIPTION_EXISTS": - await callback.message.edit_text("Вы уже имеете активную подписку.") - else: - await callback.message.edit_text(f"Подписка успешно оформлена!") - await callback.answer() - -def register_handlers(dp: Dispatcher): - """ - Регистрация хэндлеров в диспетчере. - """ - dp.callback_query.register(popup_callback_handler, lambda c: c.data == "popup") - dp.callback_query.register(start_callback_handler, lambda c: c.data == "base") - dp.callback_query.register(subs_callback_handler, lambda c: c.data == "subs") - dp.callback_query.register(subs_pro_callback_handler, lambda c: c.data == "subs_pro") - dp.callback_query.register(faq_callback_handler, lambda c: c.data == "faq") - dp.callback_query.register(profile_callback_handler, lambda c: c.data == "profile") - dp.callback_query.register(tranhist_callback_handler, lambda c: c.data == "tranhist") - dp.callback_query.register(buy_subscription_callback_handler, lambda c: c.data == "buy_subscription") - dp.message.register(start_command, Command("start")) - dp.message.register(start_command, Command("subscriptions")) - dp.message.register(start_ticket_creation, Command("support")) - dp.message.register(handle_ticket_input) # Для любых сообщений - dp.callback_query.register(balance_callback_handler, lambda c: c.data == "balance") - dp.callback_query.register(guide_callback_handler, lambda c: c.data == "guide") - # dp.callback_query.register(about_tarifs_callback_handler, lambda c: c.data == "about_tarifs") - dp.callback_query.register(lark_tariff_callback_handler, lambda c: c.data.startswith("Lark:")) - dp.callback_query.register(confirm_callback_handler, lambda c: c.data.startswith("confirm:")) - dp.callback_query.register(popup_confirm_callback_handler, lambda c: c.data.startswith("popup:")) \ No newline at end of file diff --git a/handlers/profile.py b/handlers/profile.py new file mode 100644 index 0000000..dc348d7 --- /dev/null +++ b/handlers/profile.py @@ -0,0 +1,170 @@ +from aiogram import Router, types +from aiogram.types import CallbackQuery +import logging +from datetime import datetime +from aiogram.enums.parse_mode import ParseMode +import locale +from instences.config import BASE_URL_FASTAPI +import aiohttp +from keyboard.keyboards import account_keyboard, popup_keyboard, tranhist_keyboard, confirm_popup_keyboard, guide_keyboard, balance_keyboard + +locale.setlocale(locale.LC_TIME, "ru_RU.UTF-8") + +router = Router() +logger = logging.getLogger(__name__) + +async def call_api(method, endpoint, data=None): + """ + Выполняет HTTP-запрос к FastAPI. + """ + url = f"{BASE_URL_FASTAPI}{endpoint}" + logger.info(f"Инициализация запроса: {method} {url} с данными {data}") + + try: + async with aiohttp.ClientSession() as session: + async with session.request(method, url, json=data) as response: + logger.info(f"Получен ответ от {url}: статус {response.status}") + + if response.status in {200, 201}: + result = await response.json() + logger.debug(f"Ответ JSON: {result}") + return result + if response.status == 404: + logger.debug(f"Код {response.status}, возвращаю ничего") + return None + logger.error(f"Ошибка в запросе: статус {response.status}, причина {response.reason}") + return "ERROR" + except Exception as e: + logger.exception(f"Исключение при выполнении запроса к {url}: {e}") + return "ERROR" + +@router.callback_query(lambda callback: callback.data == "profile") +async def profile_callback_handler(callback: CallbackQuery): + """ + Обработчик callback_query для профиля. + """ + try: + user_data = await call_api("GET", f"/user/{callback.from_user.id}") + if not user_data: + await callback.message.answer("Произошла ошибка, попробуйте позже или свяжитесь с администрацией.") + await callback.answer() + return + + sub_data = await call_api("GET", f"/subscription/{user_data['id']}/last") + if sub_data == "ERROR" or not isinstance(sub_data, dict): + sub_data = None + + balance_text = f"Баланс: {user_data['balance']} ₽" + + if not sub_data: + text = f"Профиль {callback.from_user.username}\n{balance_text}\nПополните баланс и приобретите подписку, чтобы получить активный статус (🐣,🦅)" + else: + expiry_date = sub_data.get("expiry_date") + formatted_date = datetime.fromisoformat(expiry_date).strftime("%d %B %Y г.") if expiry_date else None + is_expired = datetime.fromisoformat(expiry_date) < datetime.now() if expiry_date else True + status_icon = "✖️" if is_expired else "☑️" + profile_status = "🦅" if "Pro" in sub_data.get("plan", "") else "🐣" + sub_text = ( + f"Ваша подписка действует до {formatted_date} {status_icon}" + if not is_expired else f"Статус подписки: {status_icon}" + ) + text = f"Профиль {callback.from_user.username} {profile_status}:\n{sub_text}\n{balance_text}" + + await callback.message.edit_text(text, reply_markup=account_keyboard()) + except Exception as e: + logger.exception(f"Ошибка в обработчике профиля: {e}") + await callback.message.answer("Произошла ошибка. Попробуйте позже.") + finally: + await callback.answer() + +@router.callback_query(lambda callback: callback.data == "balance") +async def balance_callback_handler(callback: CallbackQuery): + """ + Обработчик callback_query для баланса. + """ + user_data = await call_api("GET", f"/user/{callback.from_user.id}") + if not user_data: + await callback.message.answer("Произошла ошибка, попробуйте позже или свяжитесь с администрацией.") + await callback.answer() + return + + await callback.message.edit_text( + f"Ваш баланс: {user_data['balance']} ₽. Выберите сумму для пополнения 🐥", + reply_markup=balance_keyboard() + ) + await callback.answer() + +@router.callback_query(lambda callback: callback.data == "popup") +async def popup_callback_handler(callback: CallbackQuery): + """ + Обработчик callback_query для пополнения. + """ + user = await call_api("GET", f"/user/{callback.from_user.id}") + if not user: + await callback.message.answer("Произошла ошибка, попробуйте позже или свяжитесь с администрацией.") + await callback.answer() + return + + await callback.message.edit_text("Работает в режиме теста!!!", reply_markup=popup_keyboard()) + await callback.answer() + +@router.callback_query(lambda callback: callback.data == "tranhist") +async def tranhist_callback_handler(callback: CallbackQuery): + """ + Обработчик callback_query для истории транзакций. + """ + user_data = await call_api("GET", f"/user/{callback.from_user.id}") + if not user_data: + await callback.message.edit_text("Вы еще не зарегистрированы.") + await callback.answer() + return + + try: + transactions = await call_api("GET", f"/user/{user_data['id']}/transactions") + if not transactions: + await callback.message.edit_text("У вас нет транзакций.", reply_markup=tranhist_keyboard()) + await callback.answer() + return + + result = "Ваши транзакции:```\n" + for count, tran in enumerate(transactions, start=1): + dt = datetime.fromisoformat(tran['created_at']).strftime("%d.%m.%Y %H:%M:%S") + result += f"{count}. Сумма: {tran['amount']}, Дата: {dt}\n" + if len(result) > 4000: + result += "...\nСлишком много транзакций для отображения." + break + result += "```" + await callback.message.edit_text(result,parse_mode=ParseMode.MARKDOWN_V2, reply_markup=tranhist_keyboard()) + except Exception as e: + logger.error(f"Ошибка обработки транзакций: {e}") + await callback.message.edit_text("Произошла ошибка. Попробуйте позже.") + finally: + await callback.answer() + +@router.callback_query(lambda callback: callback.data.startswith("popup:")) +async def popup_confirm_callback_handler(callback: CallbackQuery): + """ + Обработчик подтверждения пополнения баланса. + """ + data = callback.data.split(":") + popup_info = data[1] + result = await call_api("POST", f"/user/{callback.from_user.id}/balance/{float(popup_info)}") + if result == "ERROR": + await callback.message.answer("Произошла ошибка, попробуйте позже или свяжитесь с администрацией.") + await callback.answer() + return + + text = f"Вы пополнили свой баланс на {popup_info} ₽. Спасибо!" + await callback.message.edit_text(text=text, reply_markup=confirm_popup_keyboard()) + await callback.answer() + +@router.callback_query(lambda callback: callback.data == "guide") +async def guide_callback_handler(callback: CallbackQuery): + """ + Обработчик callback_query для руководства. + """ + await callback.message.edit_text( + "Руководство по использованию продукта:", + reply_markup=guide_keyboard() + ) + await callback.answer() diff --git a/handlers/start.py b/handlers/start.py new file mode 100644 index 0000000..47bbee8 --- /dev/null +++ b/handlers/start.py @@ -0,0 +1,95 @@ +from aiogram import Router, types +from aiogram.filters import Command +from aiogram.types import Message, CallbackQuery +import logging +from instences.config import BASE_URL_FASTAPI +import aiohttp +from keyboard.keyboards import main_keyboard + +router = Router() +logger = logging.getLogger(__name__) + +async def call_api(method, endpoint, data=None): + """ + Выполняет HTTP-запрос к FastAPI. + :param method: HTTP метод (GET, POST, и т.д.) + :param endpoint: конечная точка API + :param data: тело запроса (если необходимо) + :return: JSON-ответ или "ERROR" при неуспехе + """ + url = f"{BASE_URL_FASTAPI}{endpoint}" + logger.info(f"Инициализация запроса: {method} {url} с данными {data}") + + try: + async with aiohttp.ClientSession() as session: + async with session.request(method, url, json=data) as response: + logger.info(f"Получен ответ от {url}: статус {response.status}") + + if response.status in {200, 201}: + result = await response.json() + logger.debug(f"Ответ JSON: {result}") + return result + if response.status == 404: + logger.debug(f"Код {response.status}, возвращаю ничего") + return None + logger.error(f"Ошибка в запросе: статус {response.status}, причина {response.reason}") + return "ERROR" + except Exception as e: + logger.exception(f"Исключение при выполнении запроса к {url}: {e}") + return "ERROR" + +@router.message(Command("start")) +async def start_command(message: Message): + """ + Обработчик команды /start. + """ + logger.info(f"Получена команда /start от пользователя: {message.from_user.id} ({message.from_user.username})") + + try: + user_data = await call_api("GET", f"/user/{message.from_user.id}") + if not user_data: + logger.debug("Пользователь не найден в базе, создаем новую запись.") + await call_api("POST", "/user/create", {"telegram_id": message.from_user.id}) + + logger.debug("Отправка приветственного сообщения пользователю.") + await message.answer( + f"""Приветствуем в рядах птенец {message.from_user.username}🐣 + \nСкорее пополни баланс, приобрети подписку и получай доступ к TikTok, YouTube, Discord, Instagram на всех устройствах без ограничений ❕❕❕ + \nОзнакомься с руководством по пользованию и выбери подходящий тариф 🦅 + \nСледи за акциями, спец-предложениями, а также розыгрышами по ссылке ниже + \n👇👇👇 + \nhttps://t.me/+0z5xqn3F1m02OTJi + \nС любовью ваши пернатые разработчики 🤍🤍🤍""", + reply_markup=main_keyboard() + ) + logger.info("Приветственное сообщение отправлено.") + + except Exception as e: + logger.exception(f"Ошибка при обработке команды /start для пользователя {message.from_user.id}: {e}") + await message.answer("Произошла ошибка. Попробуйте позже.") + +@router.callback_query(lambda callback: callback.data == "base") +async def start_callback_handler(callback: CallbackQuery): + """ + Обработчик callback_query с data="base". + """ + try: + user_data = await call_api("GET", f"/user/{callback.from_user.id}") + if not user_data: + await call_api("POST", "/user/create", {"telegram_id": callback.from_user.id}) + + await callback.message.edit_text( + f"""Приветствуем в рядах птенец {callback.from_user.username}🐣 + \nСкорее пополни баланс, приобрети подписку и получай доступ к TikTok, YouTube, Discord, Instagram на всех устройствах без ограничений ❕❕❕ + \nОзнакомься с руководством по пользованию и выбери подходящий тариф 🦅 + \nСледи за акциями, спец-предложениями, а также розыгрышами по ссылке ниже + \n👇👇👇 + \nhttps://t.me/+0z5xqn3F1m02OTJi + \nС любовью ваши пернатые разработчики 🤍🤍🤍""", + reply_markup=main_keyboard() + ) + except Exception as e: + logger.exception(f"Ошибка при обработке callback с data='base': {e}") + await callback.message.answer("Произошла ошибка. Попробуйте позже.") + finally: + await callback.answer() diff --git a/handlers/subscriptions.py b/handlers/subscriptions.py new file mode 100644 index 0000000..bc85850 --- /dev/null +++ b/handlers/subscriptions.py @@ -0,0 +1,138 @@ +from aiogram import Router, types +import logging +from instences.config import BASE_URL_FASTAPI +import aiohttp +from aiogram.enums.parse_mode import ParseMode +from aiogram.filters import Command +from keyboard.keyboards import tarif_Lark_pro_keyboard, tarif_Lark_keyboard, tarif_confirm_keyboard,buy_keyboard + +router = Router() +logger = logging.getLogger(__name__) + +async def call_api(method, endpoint, data=None): + """ + Выполняет HTTP-запрос к FastAPI. + """ + url = f"{BASE_URL_FASTAPI}{endpoint}" + logger.info(f"Инициализация запроса: {method} {url} с данными {data}") + + try: + async with aiohttp.ClientSession() as session: + async with session.request(method, url, json=data) as response: + logger.info(f"Получен ответ от {url}: статус {response.status}") + + if response.status in {200, 201}: + result = await response.json() + logger.debug(f"Ответ JSON: {result}") + return result + if response.status in {404,400}: + logger.debug(f"Код {response.status}, возвращаю ничего") + return await response.json() + logger.error(f"Ошибка в запросе: статус {response.status}, причина {response.reason}") + return "ERROR" + except Exception as e: + logger.exception(f"Исключение при выполнении запроса к {url}: {e}") + return "ERROR" + +@router.message(Command("subscriptions")) +async def supp(message: types.Message): + """ + Меню сапп системы + """ + text = "" + result = await call_api("GET", f"/uri?telegram_id={message.from_user.id}") + uri = result.get('detail',"Error") + if uri == "SUB_ERROR": + text = f"Вы ещё не приобрели подписки!!" + elif "vless" in uri: + text = f"Ваша подписка:```{uri}```" + else: + text = "Произошла ошибка при получении URI" + await message.answer( + text, + parse_mode=ParseMode.MARKDOWN_V2 + ) + + +@router.callback_query(lambda callback: callback.data == "buy_subscription") +async def buy_subscription_callback_handler(callback: types.CallbackQuery): + """ + Обработчик callback_query с data="buy_subscription". + """ + await callback.message.edit_text( + f"Ознакомься с условиями в вкладке \"О тарифах\" и выбери подходящий 🦅", + reply_markup=buy_keyboard() + ) + +@router.callback_query(lambda callback: callback.data == "subs") +async def subs_callback_handler(callback: types.CallbackQuery): + """ + Обработчик callback_query с data="subs". + """ + await callback.message.edit_text( + "Подписки птенчик", + reply_markup=tarif_Lark_keyboard() + ) + +@router.callback_query(lambda callback: callback.data == "subs_pro") +async def subs_pro_callback_handler(callback: types.CallbackQuery): + """ + Обработчик callback_query с data="subs_pro". + """ + await callback.message.edit_text( + "Подписки птенчик ПРО", + reply_markup=tarif_Lark_pro_keyboard() + ) + +@router.callback_query(lambda callback: callback.data.startswith("Lark:")) +async def lark_tariff_callback_handler(callback: types.CallbackQuery): + """ + Обработчик для выбора тарифа Lark. + """ + data = callback.data.split(":") + tariff_name = data[0] + tariff_class = data[1] + tariff_time = int(data[2]) + + # Определение окончания для месяцев + if tariff_time == 1: + months = f"{tariff_time} месяц" + elif 2 <= tariff_time <= 4: + months = f"{tariff_time} месяца" + else: + months = f"{tariff_time} месяцев" + + text = f"Тариф {tariff_name} на {months}. Продолжите покупку..." + + # Рендеринг клавиатуры + keyboard = tarif_confirm_keyboard(tariff_name, tariff_time, tariff_class) + await callback.message.edit_text(text=text, reply_markup=keyboard) + +@router.callback_query(lambda callback: callback.data.startswith("confirm:")) +async def confirm_callback_handler(callback: types.CallbackQuery): + """ + Обработчик подтверждения подписки. + """ + try: + data = callback.data.split(":")[1] + tariff_info = data.split("_") + plan_id = f"{tariff_info[0]}_{tariff_info[1]}_{tariff_info[2]}" + result = await call_api("POST", "/subscription/buy", {"telegram_id": callback.from_user.id, "plan_id": plan_id}) + detail = result.get("detail", {}) + + if detail == "ERROR": + await callback.message.edit_text("Произошла ошибка при оформлении подписки.") + elif detail == "INSUFFICIENT_FUNDS": + await callback.message.edit_text("Денег на вашем балансе не достаточно.") + elif detail == "TARIFF_NOT_FOUND": + await callback.message.edit_text("Ваш тариф не найден.") + elif detail == "ACTIVE_SUBSCRIPTION_EXISTS": + await callback.message.edit_text("Вы уже имеете активную подписку.") + else: + uri = result.get("message", {}) + await callback.message.edit_text(f"Подписка успешно оформлена!\nВаш конфиг для подключения: ```{uri}```") + except Exception as e: + logger.exception(f"Ошибка при обработке подтверждения подписки: {e}") + await callback.message.edit_text("Произошла ошибка при оформлении подписки.") + finally: + await callback.answer() diff --git a/handlers/support.py b/handlers/support.py new file mode 100644 index 0000000..5c4dcc0 --- /dev/null +++ b/handlers/support.py @@ -0,0 +1,160 @@ +from aiogram import Router, types +from aiogram.filters import Command +import logging +from datetime import datetime +from instences.config import BASE_URL_FASTAPI +import aiohttp +from aiogram.fsm.context import FSMContext +from aiogram.fsm.state import State, StatesGroup +from keyboard.keyboards import faq_keyboard, sup_keyboard, ticket_list_keyboard, ticket_keyboard + +logger = logging.getLogger(__name__) +router = Router() + +class TicketState(StatesGroup): + subject = State() + message = State() + +async def call_api(method, endpoint, data=None): + """ + Выполняет HTTP-запрос к FastAPI. + """ + url = f"{BASE_URL_FASTAPI}{endpoint}" + logger.info(f"Инициализация запроса: {method} {url} с данными {data}") + + try: + async with aiohttp.ClientSession() as session: + async with session.request(method, url, json=data) as response: + logger.info(f"Получен ответ от {url}: статус {response.status}") + + if response.status in {200, 201}: + result = await response.json() + logger.debug(f"Ответ JSON: {result}") + return result + if response.status == 404: + logger.debug(f"Код {response.status}, возвращаю ничего") + return None + logger.error(f"Ошибка в запросе: статус {response.status}, причина {response.reason}") + return "ERROR" + except Exception as e: + logger.exception(f"Исключение при выполнении запроса к {url}: {e}") + return "ERROR" + +@router.callback_query(lambda callback: callback.data == "faq") +async def faq_callback_handler(callback: types.CallbackQuery): + """ + Обработчик callback_query с data="faq". + """ + await callback.message.edit_text( + "FAQ YOU", + reply_markup=faq_keyboard() + ) + +@router.message(Command("support")) +async def supp(message: types.Message): + """ + Меню сапп системы + """ + await message.answer( + "Добро пожаловать в саппорт систему!", + reply_markup=sup_keyboard() + ) + +@router.callback_query(lambda callback: callback.data == "main_sup") +async def supp_callback(callback: types.CallbackQuery): + """ + Меню сапп системы (callback версия) + """ + await callback.message.answer( + "Добро пожаловать в саппорт систему!", + reply_markup=sup_keyboard() + ) + +@router.callback_query(lambda callback: callback.data == "my_tickets") +async def list_tickets_callback(callback: types.CallbackQuery): + user_id = callback.from_user.id + user_data = await call_api("GET", f"/user/{user_id}") + if not user_data: + user_data = await call_api("POST", f"/user/create", {"telegram_id": f"{user_id}"}) + + tickets = await call_api("GET", f"/support/tickets?user_id={user_data['id']}") + + if tickets == "ERROR" or not tickets: + await callback.message.edit_text("У вас нет тикетов.", reply_markup=sup_keyboard()) + return + + await callback.message.edit_text( + "Ваши тикеты:", + reply_markup=ticket_list_keyboard(tickets) + ) + +@router.callback_query(lambda callback: callback.data == "make_ticket") +async def start_ticket_creation(callback: types.CallbackQuery, state: FSMContext): + """ + Начинает процесс создания тикета. + """ + await callback.message.answer( + "Введите тему тикета (или нажмите 'Отмена', чтобы выйти):", + reply_markup=ticket_keyboard() + ) + await state.set_state(TicketState.subject) + +@router.message() +async def handle_ticket_input(message: types.Message, state: FSMContext): + """ + Обрабатывает ввод данных для тикета. + """ + current_state = await state.get_state() + if current_state == TicketState.subject: + await state.update_data(subject=message.text) + await message.answer("Введите описание проблемы:", reply_markup=ticket_keyboard()) + await state.set_state(TicketState.message) + + elif current_state == TicketState.message: + user_data = await state.get_data() + subject = user_data.get("subject") + message_text = message.text + await create_ticket(message, subject, message_text, state) + await state.clear() + +async def create_ticket(message: types.Message, subject: str, message_text: str, state: FSMContext): + """ + Отправляет запрос на создание тикета через FastAPI. + """ + user_id = message.from_user.id + + try: + logger.info(f"Создание тикета для пользователя {user_id}: Тема - {subject}, Сообщение - {message_text}") + + user_data = await call_api("GET", f"/user/{user_id}") + if not user_data: + await message.answer("Вы еще не зарегистрированы.") + return + + ticket_data = await call_api( + "POST", + f"/support/tickets?user_id={user_data['id']}", + data={"subject": subject, "message": message_text} + ) + + if ticket_data != "ERROR": + await message.answer( + f"✅ Тикет успешно создан!\n" + f"📌 Тема: {ticket_data['subject']}\n" + f"📊 Статус: {ticket_data['status']}\n" + f"📅 Дата создания: {ticket_data['created_at']}" + ) + else: + await message.answer("❌ Ошибка создания тикета. Попробуйте позже.") + + except Exception as e: + logger.exception(f"Ошибка при создании тикета для пользователя {user_id}: {e}") + await message.answer("❌ Произошла ошибка при создании тикета.") + +@router.callback_query(lambda callback: callback.data == "cancel_ticket") +async def cancel_ticket_creation(callback: types.CallbackQuery, state: FSMContext): + """ + Отмена создания тикета. + """ + await state.clear() + await callback.message.answer("Создание тикета отменено.", reply_markup=types.ReplyKeyboardRemove()) diff --git a/instences/__pycache__/db_config.cpython-312.pyc b/instences/__pycache__/db_config.cpython-312.pyc deleted file mode 100644 index 29fa471..0000000 Binary files a/instences/__pycache__/db_config.cpython-312.pyc and /dev/null differ diff --git a/instences/__pycache__/postgresql.cpython-312.pyc b/instences/__pycache__/postgresql.cpython-312.pyc deleted file mode 100644 index 732526f..0000000 Binary files a/instences/__pycache__/postgresql.cpython-312.pyc and /dev/null differ diff --git a/instences/config.py b/instences/config.py index 806b6ee..2434edf 100644 --- a/instences/config.py +++ b/instences/config.py @@ -1,4 +1,9 @@ import os +import logging + + + +logger = logging.getLogger(__name__) + -# Настройки PostgreSQL из переменных окружения BASE_URL_FASTAPI = os.getenv("BASE_URL") diff --git a/instences/model.py b/instences/model.py deleted file mode 100644 index cea7a32..0000000 --- a/instences/model.py +++ /dev/null @@ -1,60 +0,0 @@ -from sqlalchemy import Column, String, Numeric, DateTime, Boolean, ForeignKey, Integer -from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine -from sqlalchemy.orm import declarative_base, relationship, sessionmaker -from datetime import datetime -import uuid - -Base = declarative_base() - -def generate_uuid(): - return str(uuid.uuid4()) - -"""Пользователи""" -class User(Base): - __tablename__ = 'users' - - id = Column(String, primary_key=True, default=generate_uuid) - telegram_id = Column(Integer, unique=True, nullable=False) - username = Column(String) - balance = Column(Numeric(10, 2), default=0.0) - created_at = Column(DateTime, default=datetime.utcnow) - updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) - - subscriptions = relationship("Subscription", back_populates="user") - transactions = relationship("Transaction", back_populates="user") - admins = relationship("Administrators", back_populates="user") - -"""Подписки""" -class Subscription(Base): - __tablename__ = 'subscriptions' - - id = Column(String, primary_key=True, default=generate_uuid) - user_id = Column(String, ForeignKey('users.id')) - vpn_server_id = Column(String) - plan = Column(String) - expiry_date = Column(DateTime) - created_at = Column(DateTime, default=datetime.utcnow) - updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) - - user = relationship("User", back_populates="subscriptions") - -"""Транзакции""" -class Transaction(Base): - __tablename__ = 'transactions' - - id = Column(String, primary_key=True, default=generate_uuid) - user_id = Column(String, ForeignKey('users.id')) - amount = Column(Numeric(10, 2)) - transaction_type = Column(String) - created_at = Column(DateTime, default=datetime.utcnow) - - user = relationship("User", back_populates="transactions") - -"""Администраторы""" -class Administrators(Base): - __tablename__ = 'admins' - - id = Column(String, primary_key=True, default=generate_uuid) - user_id = Column(String, ForeignKey('users.id')) - - user = relationship("User", back_populates="admins") diff --git a/keyboard/__pycache__/keyboards.cpython-312.pyc b/keyboard/__pycache__/keyboards.cpython-312.pyc deleted file mode 100644 index 47b68a5..0000000 Binary files a/keyboard/__pycache__/keyboards.cpython-312.pyc and /dev/null differ diff --git a/keyboard/keyboards.py b/keyboard/keyboards.py index 967ec9e..604e5cd 100644 --- a/keyboard/keyboards.py +++ b/keyboard/keyboards.py @@ -24,11 +24,23 @@ def account_keyboard(): builder.row(InlineKeyboardButton(text="Назад", callback_data="base")) return builder.as_markup() +def ticket_list_keyboard(tickets): + builder = InlineKeyboardBuilder() + for ticket in tickets: + builder.row(InlineKeyboardButton(text=f"Тикет: {ticket['subject']}",callback_data=f"ticket_{ticket['id']}")) + builder.row(InlineKeyboardButton(text="Назад", callback_data="main_sup")) + return builder.as_markup() + +def sup_keyboard(): + builder = InlineKeyboardBuilder() + builder.row(InlineKeyboardButton(text="Создать запрос", callback_data="make_ticket")) + builder.row(InlineKeyboardButton(text="Мои запросы", callback_data="my_tickets")) + return builder.as_markup() def ticket_keyboard(): - builder = ReplyKeyboardBuilder() - builder.row(KeyboardButton(text="Отмена")) + builder = InlineKeyboardBuilder() + builder.row(InlineKeyboardButton(text="Отмена", callback_data="cancel")) return builder.as_markup() def buy_keyboard(): diff --git a/main.py b/main.py index c1326fe..c1f3a32 100644 --- a/main.py +++ b/main.py @@ -2,12 +2,13 @@ import os import asyncio from aiogram import Bot, Dispatcher from aiogram.types import BotCommand +from handlers import routers from Middleware.anti_spam_middleware import AntiSpamMiddleware import logging # Получение токена бота из переменных окружения -BOT_TOKEN = os.getenv("TOKEN") +BOT_TOKEN = "8104061818:AAF1lx6ii_h2rguzZHEZ49GRv07VYDh1GYo" if not BOT_TOKEN: raise ValueError("Не задан токен бота. Убедитесь, что переменная окружения 'TOKEN' установлена.") @@ -48,8 +49,8 @@ async def on_shutdown(): async def main(): """Основной цикл работы бота.""" - from handlers.handlers import register_handlers - register_handlers(dp) # Регистрация хендлеров + for router in routers: + dp.include_router(router) # Регистрация хендлеров await on_startup() diff --git a/temp_scripts/ca.pem b/temp_scripts/ca.pem deleted file mode 100644 index 040a2eb..0000000 --- a/temp_scripts/ca.pem +++ /dev/null @@ -1,37 +0,0 @@ ------BEGIN CERTIFICATE----- -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 -MYVC3EGeng== ------END CERTIFICATE----- diff --git a/temp_scripts/insert_server_in_mongodb.py b/temp_scripts/insert_server_in_mongodb.py deleted file mode 100644 index 05e8f89..0000000 --- a/temp_scripts/insert_server_in_mongodb.py +++ /dev/null @@ -1,70 +0,0 @@ -import argparse -from datetime import datetime -import json -import base64 -from pymongo import MongoClient - -def connect_to_mongo(uri, db_name): - """Подключение к MongoDB.""" - client = MongoClient(uri) - db = client[db_name] - return db - -def load_json(json_path): - """Загружает JSON-данные из файла.""" - with open(json_path, "r", encoding="utf-8") as f: - return json.load(f) - -def encode_file(file_path): - """Читает файл и кодирует его в Base64.""" - with open(file_path, "rb") as f: - return base64.b64encode(f.read()).decode("utf-8") - -def insert_certificate(data, cert_path, cert_location): - """Добавляет сертификат в указанное место внутри структуры JSON.""" - # Читаем и кодируем сертификат - certificate_data = encode_file(cert_path) - - # Разбиваем путь на вложенные ключи - keys = cert_location.split(".") - target = data - for key in keys[:-1]: - if key not in target: - target[key] = {} # Создаем вложенные ключи, если их нет - target = target[key] - target[keys[-1]] = { - "data": certificate_data, - "uploaded_at": datetime.utcnow() - } - -def insert_data(db, collection_name, data): - """Вставляет данные в указанную коллекцию MongoDB.""" - collection = db[collection_name] - collection.insert_one(data) - print(f"Данные успешно вставлены в коллекцию '{collection_name}'.") - -def main(): - parser = argparse.ArgumentParser(description="Insert JSON data into MongoDB with certificate") - parser.add_argument("--mongo-uri",default="mongodb://root:itOj4CE2miKR@mongodb:27017" ,required=True, help="MongoDB URI") - parser.add_argument("--db-name",default="MongoDBSub&Ser" ,required=True, help="MongoDB database name") - parser.add_argument("--collection",default="servers", required=True, help="Collection name") - parser.add_argument("--json-path", required=True, help="Path to the JSON file with data") - parser.add_argument("--cert-path", required=True, help="Path to the certificate file (.crt)") - parser.add_argument("--cert-location", required=True, help="Path inside JSON structure to store certificate (e.g., 'server.certificate')") - - args = parser.parse_args() - - # Подключение к MongoDB - db = connect_to_mongo(args.mongo_uri, args.db_name) - - # Загрузка данных из JSON-файла - data = load_json(args.json_path) - - # Вставка сертификата в структуру данных - insert_certificate(data, args.cert_path, args.cert_location) - - # Вставка данных в MongoDB - insert_data(db, args.collection, data) - -if __name__ == "__main__": - main() diff --git a/temp_scripts/insert_subscriptions.py b/temp_scripts/insert_subscriptions.py deleted file mode 100644 index 6d4e79b..0000000 --- a/temp_scripts/insert_subscriptions.py +++ /dev/null @@ -1,74 +0,0 @@ -import argparse -from datetime import datetime -import json -import glob -from pymongo import MongoClient - -def connect_to_mongo(uri, db_name): - """Подключение к MongoDB.""" - client = MongoClient(uri) - db = client[db_name] - return db - -def load_all_json_from_folder(folder_path): - """Загружает все JSON-файлы из указанной папки.""" - all_data = [] - for file_path in glob.glob(f"{folder_path}/*.json"): - try: - with open(file_path, "r", encoding="utf-8") as f: - data = json.load(f) - all_data.append(data) - except Exception as e: - print(f"Ошибка при чтении файла {file_path}: {e}") - return all_data - - -def fetch_all_documents(mongo_uri, db_name, collection_name): - """Выводит все элементы из указанной коллекции MongoDB.""" - try: - client = MongoClient(mongo_uri) - db = client[db_name] - collection = db[collection_name] - - documents = collection.find() - - print(f"Содержимое коллекции '{collection_name}':") - for doc in documents: - print(doc) - - except Exception as e: - print(f"Ошибка при получении данных: {e}") - finally: - client.close() - -def insert_data(db, collection_name, data): - """Вставляет данные в указанную коллекцию MongoDB.""" - collection = db[collection_name] - for i in data: - collection.insert_one(i) - print(f"Данные '{i}'") - print(f"Данные успешно вставлены в коллекцию '{collection_name}'.") - - - -def main(): - parser = argparse.ArgumentParser(description="Insert JSON data into MongoDB with certificate") - parser.add_argument("--mongo-uri",default="mongodb://root:itOj4CE2miKR@mongodb:27017" ,required=True, help="MongoDB URI") - parser.add_argument("--db-name",default="MongoDBSub&Ser" ,required=True, help="MongoDB database name") - parser.add_argument("--collection",default="servers", required=True, help="Collection name") - parser.add_argument("--json-path", required=True, help="Path to the JSON file with data") - - - args = parser.parse_args() - - db = connect_to_mongo(args.mongo_uri, args.db_name) - - data = load_all_json_from_folder(args.json_path) - - insert_data(db, args.collection, data) - - fetch_all_documents(args.mongo_uri, args.db_name,args.collection) - -if __name__ == "__main__": - main() - diff --git a/temp_scripts/ser.json b/temp_scripts/ser.json deleted file mode 100644 index 48919bf..0000000 --- a/temp_scripts/ser.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "server": { - "name": "Poland#1", - "ip": "mydomvlv.freemyip.com", - "port": 2053, - "secretKey": "Hd8OsqN5Jh", - "login": "nc1450nP", - "password": "KmajQOuf" - }, - "clients": [ - { - "email": "j8oajwd3", - "inboundId": "1", - "id": "a31d71a4-6afd-4f36-96f6-860691b52873", - "flow": "xtls-rprx-vision", - "limits": { - "ipLimit": 2, - "reset": 0, - "totalGB": 0 - }, - "subscriptions": { - "subId": "ox2awiqwduryuqnz", - "tgId": 1342351277 - } - }, - { - "email": "j8oajwd3121", - "inboundId": "1", - "id": "b6882942-d69d-4d5e-be9a-168ac89b20b6", - "flow": "xtls-rprx-direct", - "limits": { - "ipLimit": 1, - "reset": 0, - "totalGB": 0 - }, - "subscriptions": { - "subId": "jk289x00uf7vbr9x", - "tgId": 123144325 - } - } - ], - "connection": { - "destination": "google.com:443", - "serverNames": [ - "google.com", - "www.google.com" - ], - "security": "reality", - "publicKey": "Bha0eW7nfRc69CdZyF9HlmGVvtAeOJKammhwf4WShTU", - "fingerprint": "random", - "shortIds": [ - "edfaf8ab" - ], - "tcpSettings": { - "acceptProxyProtocol": false, - "headerType": "none" - }, - "sniffing": { - "enabled": true, - "destOverride": [ - "http", - "tls", - "quic", - "fakedns" - ] - } - } - } \ No newline at end of file diff --git a/temp_scripts/subs/sub1.json b/temp_scripts/subs/sub1.json deleted file mode 100644 index f8e7a72..0000000 --- a/temp_scripts/subs/sub1.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "Lark_Standart_1", - "normalName": "Lark Standart", - "type": "standart", - "duration_months": 1, - "ip_limit": 1, - "price": 200 - } \ No newline at end of file diff --git a/temp_scripts/subs/sub2.json b/temp_scripts/subs/sub2.json deleted file mode 100644 index 98a4b61..0000000 --- a/temp_scripts/subs/sub2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "Lark_Standart_6", - "normalName": "Lark Standart", - "type": "standart", - "duration_months": 6, - "ip_limit": 1, - "price": 1000 -} \ No newline at end of file diff --git a/temp_scripts/subs/sub3.json b/temp_scripts/subs/sub3.json deleted file mode 100644 index 2e0b277..0000000 --- a/temp_scripts/subs/sub3.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "Lark_Standart_12", - "normalName": "Lark Standart", - "type": "standart", - "duration_months": 12, - "ip_limit": 1, - "price": 2000 - } \ No newline at end of file diff --git a/temp_scripts/subs/sub4.json b/temp_scripts/subs/sub4.json deleted file mode 100644 index fa67c74..0000000 --- a/temp_scripts/subs/sub4.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "Lark_Pro_1", - "normalName": "Lark Pro", - "type": "pro", - "duration_months": 1, - "ip_limit": 5, - "price": 600 - } \ No newline at end of file diff --git a/temp_scripts/subs/sub5.json b/temp_scripts/subs/sub5.json deleted file mode 100644 index 3fb1251..0000000 --- a/temp_scripts/subs/sub5.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "Lark_Pro_6", - "normalName": "Lark Pro", - "type": "pro", - "duration_months": 6, - "ip_limit": 5, - "price": 3000 - } \ No newline at end of file diff --git a/temp_scripts/subs/sub6.json b/temp_scripts/subs/sub6.json deleted file mode 100644 index 2f24325..0000000 --- a/temp_scripts/subs/sub6.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "Lark_Pro_12", - "normalName": "Lark Pro", - "type": "pro", - "duration_months": 12, - "ip_limit": 5, - "price": 5000 - } \ No newline at end of file diff --git a/utils/LogCon.py b/utils/LogCon.py index b60bf01..e78444f 100644 --- a/utils/LogCon.py +++ b/utils/LogCon.py @@ -22,4 +22,6 @@ def setup_logger(): logger.addHandler(handler) - return logger \ No newline at end of file + return logger + +app_logger = setup_logger() \ No newline at end of file diff --git a/utils/__pycache__/LogCon.cpython-312.pyc b/utils/__pycache__/LogCon.cpython-312.pyc deleted file mode 100644 index 32de622..0000000 Binary files a/utils/__pycache__/LogCon.cpython-312.pyc and /dev/null differ