Перенос части логики на бекенд rest api и изменение логики работы бота так же из за бекенда
This commit is contained in:
@@ -1,65 +0,0 @@
|
||||
import os
|
||||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
from databases.model import Base
|
||||
|
||||
# Настройки PostgreSQL из переменных окружения
|
||||
POSTGRES_DSN = os.getenv("POSTGRES_URL")
|
||||
|
||||
# Создание движка для PostgreSQL
|
||||
postgres_engine = create_async_engine(POSTGRES_DSN, echo=False)
|
||||
AsyncSessionLocal = sessionmaker(bind=postgres_engine, class_=AsyncSession, expire_on_commit=False)
|
||||
|
||||
# Настройки MongoDB из переменных окружения
|
||||
MONGO_URI = os.getenv("MONGO_URL")
|
||||
DATABASE_NAME = os.getenv("DB_NAME")
|
||||
|
||||
# Создание клиента MongoDB
|
||||
mongo_client = AsyncIOMotorClient(MONGO_URI)
|
||||
mongo_db = mongo_client[DATABASE_NAME]
|
||||
|
||||
# Инициализация PostgreSQL
|
||||
async def init_postgresql():
|
||||
"""
|
||||
Инициализация подключения к PostgreSQL.
|
||||
"""
|
||||
try:
|
||||
async with postgres_engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
print("PostgreSQL connected.")
|
||||
except Exception as e:
|
||||
print(f"Failed to connect to PostgreSQL: {e}")
|
||||
|
||||
# Инициализация MongoDB
|
||||
async def init_mongodb():
|
||||
"""
|
||||
Проверка подключения к MongoDB.
|
||||
"""
|
||||
try:
|
||||
# Проверяем подключение к MongoDB
|
||||
await mongo_client.admin.command("ping")
|
||||
print("MongoDB connected.")
|
||||
except Exception as e:
|
||||
print(f"Failed to connect to MongoDB: {e}")
|
||||
|
||||
# Получение сессии PostgreSQL
|
||||
async def get_postgres_session():
|
||||
"""
|
||||
Асинхронный генератор сессий PostgreSQL.
|
||||
"""
|
||||
async with AsyncSessionLocal() as session:
|
||||
yield session
|
||||
|
||||
# Закрытие соединений
|
||||
async def close_connections():
|
||||
"""
|
||||
Закрытие всех соединений с базами данных.
|
||||
"""
|
||||
# Закрытие PostgreSQL
|
||||
await postgres_engine.dispose()
|
||||
print("PostgreSQL connection closed.")
|
||||
|
||||
# Закрытие MongoDB
|
||||
mongo_client.close()
|
||||
print("MongoDB connection closed.")
|
||||
@@ -1,103 +0,0 @@
|
||||
import os
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
import logging
|
||||
|
||||
|
||||
class MongoDBRepository:
|
||||
def __init__(self):
|
||||
# Настройки MongoDB из переменных окружения
|
||||
mongo_uri = os.getenv("MONGO_URL")
|
||||
database_name = os.getenv("DB_NAME")
|
||||
server_collection = os.getenv("SERVER_COLLECTION", "servers")
|
||||
plan_collection = os.getenv("PLAN_COLLECTION", "plans")
|
||||
|
||||
# Подключение к базе данных и коллекциям
|
||||
self.client = AsyncIOMotorClient(mongo_uri)
|
||||
self.db = self.client[database_name]
|
||||
self.collection = self.db[server_collection] # Коллекция серверов
|
||||
self.plans_collection = self.db[plan_collection] # Коллекция тарифных планов
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
async def add_subscription_plan(self, plan_data):
|
||||
"""Добавляет новый тарифный план в коллекцию."""
|
||||
result = await self.plans_collection.insert_one(plan_data)
|
||||
self.logger.debug(f"Тарифный план добавлен с ID: {result.inserted_id}")
|
||||
return result.inserted_id
|
||||
|
||||
async def get_subscription_plan(self, plan_name):
|
||||
"""Получает тарифный план по его имени."""
|
||||
plan = await self.plans_collection.find_one({"name": plan_name})
|
||||
if plan:
|
||||
self.logger.debug(f"Найден тарифный план: {plan}")
|
||||
else:
|
||||
self.logger.error(f"Тарифный план {plan_name} не найден.")
|
||||
return plan
|
||||
|
||||
async def add_server(self, server_data):
|
||||
"""Добавляет новый VPN сервер в коллекцию."""
|
||||
result = await self.collection.insert_one(server_data)
|
||||
self.logger.debug(f"VPN сервер добавлен с ID: {result.inserted_id}")
|
||||
return result.inserted_id
|
||||
|
||||
async def get_server(self, server_name: str):
|
||||
"""Получает сервер VPN по его ID."""
|
||||
server = await self.collection.find_one({"server.name": server_name})
|
||||
if server:
|
||||
self.logger.debug(f"Найден VPN сервер: {server}")
|
||||
else:
|
||||
self.logger.debug(f"VPN сервер с ID {server_name} не найден.")
|
||||
return server
|
||||
|
||||
async def get_server_with_least_clients(self):
|
||||
"""Возвращает сервер с наименьшим количеством подключенных клиентов."""
|
||||
pipeline = [
|
||||
{
|
||||
"$addFields": {
|
||||
"current_clients": {"$size": {"$ifNull": ["$clients", []]}}
|
||||
}
|
||||
},
|
||||
{
|
||||
"$sort": {"current_clients": 1}
|
||||
},
|
||||
{
|
||||
"$limit": 1
|
||||
}
|
||||
]
|
||||
|
||||
result = await self.collection.aggregate(pipeline).to_list(length=1)
|
||||
if result:
|
||||
server = result[0]
|
||||
self.logger.debug(f"Найден сервер с наименьшим количеством клиентов: {server}")
|
||||
return server
|
||||
else:
|
||||
self.logger.debug("Не найдено серверов.")
|
||||
return None
|
||||
|
||||
async def update_server(self, server_id, update_data):
|
||||
"""Обновляет данные VPN сервера."""
|
||||
result = await self.collection.update_one({"_id": server_id}, {"$set": update_data})
|
||||
if result.matched_count > 0:
|
||||
self.logger.debug(f"VPN сервер с ID {server_id} обновлен.")
|
||||
else:
|
||||
self.logger.debug(f"VPN сервер с ID {server_id} не найден.")
|
||||
return result.matched_count > 0
|
||||
|
||||
async def delete_server(self, server_id):
|
||||
"""Удаляет VPN сервер по его ID."""
|
||||
result = await self.collection.delete_one({"_id": server_id})
|
||||
if result.deleted_count > 0:
|
||||
self.logger.debug(f"VPN сервер с ID {server_id} удален.")
|
||||
else:
|
||||
self.logger.debug(f"VPN сервер с ID {server_id} не найден.")
|
||||
return result.deleted_count > 0
|
||||
|
||||
async def list_servers(self):
|
||||
"""Возвращает список всех VPN серверов."""
|
||||
servers = await self.collection.find().to_list(length=1000) # Получить до 1000 серверов (можно настроить)
|
||||
self.logger.debug(f"Найдено {len(servers)} VPN серверов.")
|
||||
return servers
|
||||
|
||||
async def close_connection(self):
|
||||
"""Закрывает подключение к базе данных MongoDB."""
|
||||
self.client.close()
|
||||
self.logger.debug("Подключение к MongoDB закрыто.")
|
||||
@@ -1,211 +0,0 @@
|
||||
from databases.model import User, Subscription, Transaction, Administrators
|
||||
from sqlalchemy.future import select
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy import desc
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from datetime import datetime
|
||||
from utils.panel import PanelInteraction
|
||||
from databases.mongodb import MongoDBRepository
|
||||
import random
|
||||
import string
|
||||
import logging
|
||||
import asyncio
|
||||
|
||||
class DatabaseManager:
|
||||
def __init__(self, session_generator):
|
||||
"""
|
||||
Инициализация с асинхронным генератором сессий (например, get_postgres_session).
|
||||
"""
|
||||
self.session_generator = session_generator
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.mongo_repo = MongoDBRepository()
|
||||
|
||||
async def create_user(self, telegram_id: int):
|
||||
"""
|
||||
Создаёт нового пользователя, если его нет.
|
||||
"""
|
||||
async for session in self.session_generator():
|
||||
try:
|
||||
username = self.generate_string(6)
|
||||
result = await session.execute(select(User).where(User.telegram_id == int(telegram_id)))
|
||||
user = result.scalars().first()
|
||||
if not user:
|
||||
new_user = User(telegram_id=int(telegram_id), username=username)
|
||||
session.add(new_user)
|
||||
await session.commit()
|
||||
return new_user
|
||||
return user
|
||||
except SQLAlchemyError as e:
|
||||
self.logger.error(f"Ошибка при создании пользователя {telegram_id}: {e}")
|
||||
await session.rollback()
|
||||
return "ERROR"
|
||||
|
||||
async def get_user_by_telegram_id(self, telegram_id: int):
|
||||
"""
|
||||
Возвращает пользователя по Telegram ID.
|
||||
"""
|
||||
async for session in self.session_generator():
|
||||
try:
|
||||
result = await session.execute(select(User).where(User.telegram_id == telegram_id))
|
||||
return result.scalars().first()
|
||||
except SQLAlchemyError as e:
|
||||
self.logger.error(f"Ошибка при получении пользователя {telegram_id}: {e}")
|
||||
return None
|
||||
|
||||
async def add_transaction(self, user_id: int, amount: float):
|
||||
"""
|
||||
Добавляет транзакцию для пользователя.
|
||||
"""
|
||||
async for session in self.session_generator():
|
||||
try:
|
||||
transaction = Transaction(user_id=user_id, amount=amount)
|
||||
session.add(transaction)
|
||||
await session.commit()
|
||||
except SQLAlchemyError as e:
|
||||
self.logger.error(f"Ошибка добавления транзакции для пользователя {user_id}: {e}")
|
||||
await session.rollback()
|
||||
|
||||
async def update_balance(self, telegram_id: int, amount: float):
|
||||
"""
|
||||
Обновляет баланс пользователя и добавляет транзакцию.
|
||||
"""
|
||||
async for session in self.session_generator():
|
||||
try:
|
||||
result = await session.execute(select(User).where(User.telegram_id == telegram_id))
|
||||
user = result.scalars().first()
|
||||
if user:
|
||||
user.balance += int(amount)
|
||||
await self.add_transaction(user.id, amount)
|
||||
await session.commit()
|
||||
else:
|
||||
self.logger.warning(f"Пользователь с Telegram ID {telegram_id} не найден.")
|
||||
return "ERROR"
|
||||
except SQLAlchemyError as e:
|
||||
self.logger.error(f"Ошибка при обновлении баланса: {e}")
|
||||
await session.rollback()
|
||||
return "ERROR"
|
||||
|
||||
async def last_subscription(self, user_id: int):
|
||||
"""
|
||||
Возвращает список подписок пользователя.
|
||||
"""
|
||||
async for session in self.session_generator():
|
||||
try:
|
||||
result = await session.execute(
|
||||
select(Subscription)
|
||||
.where(Subscription.user_id == user_id)
|
||||
.order_by(desc(Subscription.created_at))
|
||||
)
|
||||
return result.scalars().all()
|
||||
except SQLAlchemyError as e:
|
||||
self.logger.error(f"Ошибка при получении последней подписки пользователя {user_id}: {e}")
|
||||
return "ERROR"
|
||||
|
||||
async def last_transaction(self, user_id: int):
|
||||
"""
|
||||
Возвращает список транзакций пользователя.
|
||||
"""
|
||||
async for session in self.session_generator():
|
||||
try:
|
||||
result = await session.execute(
|
||||
select(Transaction)
|
||||
.where(Transaction.user_id == user_id)
|
||||
.order_by(desc(Transaction.created_at))
|
||||
)
|
||||
transactions = result.scalars().all()
|
||||
return transactions
|
||||
except SQLAlchemyError as e:
|
||||
self.logger.error(f"Ошибка при получении транзакций пользователя {user_id}: {e}")
|
||||
return "ERROR"
|
||||
|
||||
async def buy_sub(self, telegram_id: str, plan_id: str):
|
||||
async for session in self.session_generator():
|
||||
try:
|
||||
result = await self.create_user(telegram_id)
|
||||
if not result:
|
||||
self.logger.error(f"Пользователь с Telegram ID {telegram_id} не найден.")
|
||||
return "ERROR"
|
||||
|
||||
# Получение тарифного плана из MongoDB
|
||||
plan = await self.mongo_repo.get_subscription_plan(plan_id)
|
||||
if not plan:
|
||||
self.logger.error(f"Тарифный план {plan_id} не найден.")
|
||||
return "ERROR"
|
||||
|
||||
# Проверка достаточности средств
|
||||
cost = int(plan["price"])
|
||||
if result.balance < cost:
|
||||
self.logger.error(f"Недостаточно средств у пользователя {telegram_id} для покупки плана {plan_id}.")
|
||||
return "INSUFFICIENT_FUNDS"
|
||||
|
||||
# Списываем средства
|
||||
result.balance -= cost
|
||||
|
||||
# Создаем подписку
|
||||
expiry_date = datetime.utcnow() + relativedelta(months=plan["duration_months"])
|
||||
server = await self.mongo_repo.get_server_with_least_clients()
|
||||
self.logger.info(f"Выбран сервер для подписки: {server}")
|
||||
new_subscription = Subscription(
|
||||
user_id=result.id,
|
||||
vpn_server_id=str(server['server']["name"]),
|
||||
plan=plan_id,
|
||||
expiry_date=expiry_date
|
||||
)
|
||||
session.add(new_subscription)
|
||||
|
||||
# Попытка добавить пользователя на сервер
|
||||
# Получаем информацию о пользователе
|
||||
user = result # так как result уже содержит пользователя
|
||||
if not user:
|
||||
self.logger.error(f"Не удалось найти пользователя для добавления на сервер.")
|
||||
await session.rollback()
|
||||
return "ERROR"
|
||||
|
||||
# Получаем сервер из MongoDB
|
||||
server_data = await self.mongo_repo.get_server(new_subscription.vpn_server_id)
|
||||
if not server_data:
|
||||
self.logger.error(f"Не удалось найти сервер с ID {new_subscription.vpn_server_id}.")
|
||||
await session.rollback()
|
||||
return "ERROR"
|
||||
|
||||
server_info = server_data['server']
|
||||
url_base = f"https://{server_info['ip']}:{server_info['port']}/{server_info['secretKey']}"
|
||||
login_data = {
|
||||
'username': server_info['login'],
|
||||
'password': server_info['password'],
|
||||
}
|
||||
|
||||
panel = PanelInteraction(url_base, login_data, self.logger,server_info['certificate']['data'])
|
||||
expiry_date_iso = new_subscription.expiry_date.isoformat()
|
||||
|
||||
# Добавляем на сервер
|
||||
response = await panel.add_client(user.id, expiry_date_iso, user.username)
|
||||
|
||||
if response != "OK":
|
||||
self.logger.error(f"Ошибка при добавлении клиента {telegram_id} на сервер: {response}")
|
||||
# Если не получилось добавить на сервер, откатываем транзакцию
|
||||
await session.rollback()
|
||||
return "ERROR"
|
||||
|
||||
# Если мы здесь - значит и подписка, и добавление на сервер успешны
|
||||
await session.commit()
|
||||
self.logger.info(f"Подписка успешно оформлена для пользователя {telegram_id} на план {plan_id} и клиент добавлен на сервер.")
|
||||
return "OK"
|
||||
|
||||
except SQLAlchemyError as e:
|
||||
self.logger.error(f"Ошибка при покупке подписки {plan_id} для пользователя {telegram_id}: {e}")
|
||||
await session.rollback()
|
||||
return "ERROR"
|
||||
except Exception as e:
|
||||
self.logger.error(f"Непредвиденная ошибка: {e}")
|
||||
await session.rollback()
|
||||
return "ERROR"
|
||||
|
||||
|
||||
@staticmethod
|
||||
def generate_string(length):
|
||||
"""
|
||||
Генерирует случайную строку заданной длины.
|
||||
"""
|
||||
characters = string.ascii_lowercase + string.digits
|
||||
return ''.join(random.choices(characters, k=length))
|
||||
76
docker-compose.yml
Normal file
76
docker-compose.yml
Normal file
@@ -0,0 +1,76 @@
|
||||
|
||||
networks:
|
||||
bot_network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
mongo_data:
|
||||
postgres_data:
|
||||
logs_data:
|
||||
|
||||
services:
|
||||
# MongoDB
|
||||
mongodb:
|
||||
networks:
|
||||
- bot_network
|
||||
image: mongo:latest
|
||||
container_name: mongodb
|
||||
ports:
|
||||
- "27017:27017"
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: itOj4CE2miKR
|
||||
volumes:
|
||||
- mongo_data:/data/db
|
||||
|
||||
# PostgreSQL
|
||||
postgres:
|
||||
networks:
|
||||
- bot_network
|
||||
image: postgres:latest
|
||||
container_name: postgres
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
POSTGRES_USER: AH3J9GSPBYOP
|
||||
POSTGRES_PASSWORD: uPS9?y~mcu2
|
||||
POSTGRES_DB: bot_db
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
|
||||
# Бэкенд (FastAPI)
|
||||
backend:
|
||||
networks:
|
||||
- bot_network
|
||||
build:
|
||||
context: ./Flask-Backend-All
|
||||
dockerfile: Dockerfile
|
||||
container_name: backend
|
||||
environment:
|
||||
POSTGRES_URL: "postgresql+asyncpg://AH3J9GSPBYOP:uPS9?y~mcu2@postgres:5432/bot_db"
|
||||
MONGO_URL: "mongodb://root:itOj4CE2miKR@mongodb:27017"
|
||||
DB_NAME: "MongoDBSub&Ser"
|
||||
SERVER_COLLECTION: "servers"
|
||||
PLAN_COLLECTION: "plans"
|
||||
BASE_URL: "http://backend:8000"
|
||||
ports:
|
||||
- "8000:8000"
|
||||
depends_on:
|
||||
- postgres
|
||||
- mongodb
|
||||
|
||||
# Telegram Bot
|
||||
bot:
|
||||
networks:
|
||||
- bot_network
|
||||
build:
|
||||
context: ./Lark_VPN_Bot
|
||||
dockerfile: Dockerfile
|
||||
container_name: telegram_bot
|
||||
environment:
|
||||
BASE_URL: "http://backend:8000"
|
||||
TOKEN: "8104061818:AAGJ6H1PTFmfJm-_mZqGv7EnHxGl4dZndnU"
|
||||
volumes:
|
||||
- logs_data:/app/logs
|
||||
depends_on:
|
||||
- backend
|
||||
@@ -1,37 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
bot_network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
mongo_data:
|
||||
postgres_data:
|
||||
|
||||
services:
|
||||
mongodb:
|
||||
networks:
|
||||
- bot_network
|
||||
image: mongo:latest
|
||||
container_name: mongodb
|
||||
ports:
|
||||
- "27017:27017"
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: itOj4CE2miKR
|
||||
volumes:
|
||||
- mongo_data:/data/db
|
||||
|
||||
postgres:
|
||||
networks:
|
||||
- bot_network
|
||||
image: postgres:latest
|
||||
container_name: postgres
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
POSTGRES_USER: AH3J9GSPBYOP
|
||||
POSTGRES_PASSWORD: uPS9?y~mcu2
|
||||
POSTGRES_DB: bot_db
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
@@ -1,27 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
bot_network:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
logs_data:
|
||||
|
||||
services:
|
||||
bot:
|
||||
networks:
|
||||
- bot_network
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
container_name: telegram_bot
|
||||
environment:
|
||||
TOKEN: "8104061818:AAGJ6H1PTFmfJm-_mZqGv7EnHxGl4dZndnU"
|
||||
POSTGRES_URL: "postgresql+asyncpg://AH3J9GSPBYOP:uPS9?y~mcu2@postgres:5432/bot_db"
|
||||
MONGO_URL: "mongodb://root:itOj4CE2miKR@mongodb:27017"
|
||||
DB_NAME: "MongoDBSub&Ser"
|
||||
SERVER_COLLECTION: "servers"
|
||||
PLAN_COLLECTION: "plans"
|
||||
volumes:
|
||||
- logs_data:/app/logs
|
||||
command: ["python", "main.py"]
|
||||
@@ -1,12 +1,17 @@
|
||||
from aiogram import types, Dispatcher
|
||||
from aiogram.filters import Command
|
||||
from databases.postgresql import DatabaseManager
|
||||
from databases.model import User, Subscription, Transaction, Administrators
|
||||
from databases.db_config import get_postgres_session
|
||||
import aiohttp
|
||||
from instences.config import BASE_URL_FASTAPI
|
||||
from keyboard.keyboards import subhist_keyboard,confirm_popup_keyboard,tarif_confirm_keyboard, popup_keyboard, main_keyboard,faq_keyboard, account_keyboard, buy_keyboard,balance_keyboard,guide_keyboard,tarif_Lark_keyboard,tarif_Lark_pro_keyboard,tranhist_keyboard
|
||||
|
||||
# Инициализируем менеджер базы данных
|
||||
db_manager = DatabaseManager(get_postgres_session)
|
||||
async def call_api(method, endpoint, data=None):
|
||||
async with aiohttp.ClientSession() as session:
|
||||
url = f"{BASE_URL_FASTAPI}{endpoint}"
|
||||
async with session.request(method, url, json=data) as response:
|
||||
if response.status in {200, 201}:
|
||||
return await response.json()
|
||||
return "ERROR"
|
||||
|
||||
async def popup_command(message: types.Message):
|
||||
"""
|
||||
@@ -48,46 +53,27 @@ async def start_callback_handler(callback: types.CallbackQuery):
|
||||
)
|
||||
|
||||
async def profile_callback_handler(callback: types.CallbackQuery):
|
||||
"""
|
||||
Обработчик callback_query с data="profile".
|
||||
"""
|
||||
user = await db_manager.create_user(telegram_id=callback.from_user.id)
|
||||
if user == "ERROR":
|
||||
await callback.message.answer(
|
||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
||||
)
|
||||
user_data = await call_api("POST", "/user/create", {"telegram_id": callback.from_user.id})
|
||||
if not user_data:
|
||||
await callback.message.answer("Произошла ошибка, попробуйте позже.")
|
||||
await callback.answer()
|
||||
return
|
||||
|
||||
if user:
|
||||
text = f"""Ваш профиль:\nID: {user.username}\nБаланс: {user.balance}"""
|
||||
await callback.message.edit_text(
|
||||
text,
|
||||
reply_markup=account_keyboard()
|
||||
)
|
||||
else:
|
||||
await callback.message.edit_text("Вы еще не зарегистрированы.")
|
||||
text = f"Ваш профиль:\nID: {user_data['username']}\nБаланс: {user_data['balance']} ₽"
|
||||
await callback.message.edit_text(text, reply_markup=account_keyboard())
|
||||
await callback.answer()
|
||||
|
||||
async def balance_callback_handler(callback: types.CallbackQuery):
|
||||
"""
|
||||
Обработчик callback_query с data="balance".
|
||||
"""
|
||||
user = await db_manager.create_user(telegram_id=callback.from_user.id)
|
||||
if user == "ERROR":
|
||||
await callback.message.answer(
|
||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
||||
)
|
||||
user_data = await call_api("GET", f"/user/{callback.from_user.id}")
|
||||
if not user_data:
|
||||
await callback.message.answer("Вы еще не зарегистрированы.")
|
||||
await callback.answer()
|
||||
return
|
||||
|
||||
if user:
|
||||
await callback.message.edit_text(
|
||||
f"Ваш баланс: {user.balance} ₽. Выберите сумму для пополнения 🐥",
|
||||
f"Ваш баланс: {user_data['balance']} ₽. Выберите сумму для пополнения 🐥",
|
||||
reply_markup=balance_keyboard()
|
||||
)
|
||||
else:
|
||||
await callback.message.edit_text("Вы еще не зарегистрированы.")
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@@ -95,7 +81,7 @@ async def popup_callback_handler(callback: types.CallbackQuery):
|
||||
"""
|
||||
Обработчик callback_query с data="popup".
|
||||
"""
|
||||
user = await db_manager.create_user(telegram_id=callback.from_user.id)
|
||||
user = await call_api("POST", "/user/create", {"telegram_id": callback.from_user.id})
|
||||
if user == "ERROR":
|
||||
await callback.message.answer(
|
||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
||||
@@ -113,69 +99,42 @@ async def popup_callback_handler(callback: types.CallbackQuery):
|
||||
await callback.answer()
|
||||
|
||||
async def tranhist_callback_handler(callback: types.CallbackQuery):
|
||||
"""
|
||||
Обработчик callback_query с data="tranhist".
|
||||
"""
|
||||
user = await db_manager.create_user(callback.from_user.id)
|
||||
trans = await db_manager.last_transaction(user.id)
|
||||
if trans == "ERROR":
|
||||
await callback.message.answer(
|
||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
||||
)
|
||||
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
|
||||
if not trans:
|
||||
await callback.message.edit_text(
|
||||
"У вас нет транзакций. Пожалуйста, пополните баланс.",
|
||||
reply_markup=tranhist_keyboard()
|
||||
)
|
||||
|
||||
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(trans, start=1):
|
||||
result += f"{count}. Сумма: {tran.amount}, Дата: {tran.created_at}\n"
|
||||
await callback.message.edit_text(
|
||||
result,
|
||||
reply_markup=tranhist_keyboard()
|
||||
)
|
||||
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 subhist_callback_handler(callback: types.CallbackQuery):
|
||||
"""
|
||||
Обработчик callback_query с data="subhist".
|
||||
"""
|
||||
user = await db_manager.create_user(callback.from_user.id)
|
||||
subs = await db_manager.last_subscription(user.id)
|
||||
if subs == "ERROR":
|
||||
await callback.message.answer(
|
||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
||||
)
|
||||
await callback.answer()
|
||||
return
|
||||
if subs is None:
|
||||
await callback.message.edit_text(
|
||||
f"Ты хули тут забыл, ты ж не покупаешь нихуя",
|
||||
reply_markup=account_keyboard()
|
||||
)
|
||||
await callback.answer()
|
||||
return
|
||||
result = ""
|
||||
count = 0
|
||||
for sub in subs:
|
||||
if count > 0:
|
||||
result += f"Последняя подписка истекает: {sub.expiry_date}\n"
|
||||
count += 1
|
||||
result += f"{count}. Истекла {sub.expiry_date}"
|
||||
count += 1
|
||||
|
||||
if subs:
|
||||
await callback.message.edit_text(
|
||||
result,
|
||||
reply_markup=account_keyboard()
|
||||
)
|
||||
else:
|
||||
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
|
||||
|
||||
subscriptions = await call_api("GET", f"/subscription/{user_data['id']}/last")
|
||||
if not subscriptions:
|
||||
await callback.message.edit_text("У вас нет активных подписок.", reply_markup=account_keyboard())
|
||||
await callback.answer()
|
||||
return
|
||||
|
||||
result = "Ваши подписки:\n"
|
||||
for count, sub in enumerate(subscriptions, start=1):
|
||||
result += f"{count}. Тариф: {sub['plan']}, Истекает: {sub['expiry_date']}\n"
|
||||
await callback.message.edit_text(result, reply_markup=account_keyboard())
|
||||
await callback.answer()
|
||||
|
||||
async def buy_subscription_callback_handler(callback: types.CallbackQuery):
|
||||
"""
|
||||
@@ -260,7 +219,7 @@ async def popup_confirm_callback_handler(callback: types.CallbackQuery):
|
||||
"""
|
||||
data = callback.data.split(":")
|
||||
popup_info = data[1]
|
||||
result = await db_manager.update_balance(callback.from_user.id,popup_info)
|
||||
result = await call_api("POST", f"/user/{callback.from_user.id}/balance", {"telegram_id": callback.from_user.id, "amount": popup_info})
|
||||
if result == "ERROR":
|
||||
await callback.message.answer(
|
||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
||||
@@ -271,40 +230,16 @@ async def popup_confirm_callback_handler(callback: types.CallbackQuery):
|
||||
await callback.message.edit_text(text=text, reply_markup=confirm_popup_keyboard())
|
||||
|
||||
async def confirm_callback_handler(callback: types.CallbackQuery):
|
||||
"""
|
||||
Обработчик подтверждения покупки тарифа.
|
||||
"""
|
||||
tariff_info = callback.data.split(":")[1].split("_")
|
||||
tariff_name = tariff_info[0]
|
||||
tariff_class = tariff_info[1]
|
||||
tariff_amount = int(tariff_info[2])
|
||||
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})
|
||||
|
||||
sub = await db_manager.buy_sub(callback.from_user.id, f"{tariff_name}_{tariff_class}_{tariff_amount}")
|
||||
if sub == "ERROR":
|
||||
await callback.message.answer(
|
||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
||||
)
|
||||
if result and result.get("message"):
|
||||
await callback.message.edit_text(f"Подписка успешно оформлена!")
|
||||
else:
|
||||
await callback.message.edit_text("Произошла ошибка при оформлении подписки.")
|
||||
await callback.answer()
|
||||
return
|
||||
elif sub == "INSUFFICIENT_FUNDS":
|
||||
await callback.message.answer(
|
||||
"Произошла ошибка, не достаточно средств на балансе."
|
||||
)
|
||||
await callback.answer()
|
||||
return
|
||||
add_to_server = await db_manager.add_to_server(callback.from_user.id)
|
||||
if add_to_server == "ERROR":
|
||||
await callback.message.answer(
|
||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
||||
)
|
||||
await callback.answer()
|
||||
return
|
||||
|
||||
# Текст подтверждения на основе тарифа
|
||||
months_text = f"{tariff_amount} месяцев" if tariff_amount > 1 else f"{tariff_amount} месяц"
|
||||
text = f"Вы успешно оформили тариф {tariff_name} на {months_text}. Спасибо за покупку!"
|
||||
|
||||
await callback.message.edit_text(text=text)
|
||||
|
||||
def register_handlers(dp: Dispatcher):
|
||||
"""
|
||||
|
||||
4
instences/config.py
Normal file
4
instences/config.py
Normal file
@@ -0,0 +1,4 @@
|
||||
import os
|
||||
|
||||
# Настройки PostgreSQL из переменных окружения
|
||||
BASE_URL_FASTAPI = os.getenv("BASE_URL")
|
||||
@@ -1,140 +1,123 @@
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from aiogram.types import InlineKeyboardButton
|
||||
from aiogram import types, Dispatcher
|
||||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery
|
||||
from aiogram.filters import Command
|
||||
|
||||
# Главное меню клавиатура
|
||||
def main_menu_keyboard():
|
||||
keyboard = InlineKeyboardMarkup()
|
||||
keyboard.add(InlineKeyboardButton("Личный кабинет", callback_data="main:personal"))
|
||||
keyboard.add(InlineKeyboardButton("FAQ", callback_data="main:faq"))
|
||||
keyboard.add(InlineKeyboardButton("О нас", callback_data="main:about"))
|
||||
return keyboard
|
||||
|
||||
def main_keyboard():
|
||||
"""
|
||||
База
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="Профиль", callback_data="profile"))
|
||||
builder.row(InlineKeyboardButton(text="FAQ", callback_data="faq"))
|
||||
builder.row(InlineKeyboardButton(text="О нас", url="https://www.youtube.com/watch?v=Zirn-CKck-c"))
|
||||
return builder.as_markup()
|
||||
# Личный кабинет клавиатура
|
||||
def personal_menu_keyboard():
|
||||
keyboard = InlineKeyboardMarkup()
|
||||
keyboard.add(InlineKeyboardButton("Баланс", callback_data="personal:balance"))
|
||||
keyboard.add(InlineKeyboardButton("Приобрести подписку", callback_data="personal:subscribe"))
|
||||
keyboard.add(InlineKeyboardButton("Руководство по использованию", callback_data="personal:guide"))
|
||||
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:main"))
|
||||
return keyboard
|
||||
|
||||
def account_keyboard():
|
||||
"""
|
||||
Аккаунт
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="Баланс", callback_data="balance"))
|
||||
builder.row(InlineKeyboardButton(text="Приобрести подписку", callback_data="buy_subscription"))
|
||||
builder.row(InlineKeyboardButton(text="Руководство по подключению", callback_data="guide"))
|
||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="base"))
|
||||
return builder.as_markup()
|
||||
# Подписка меню клавиатура
|
||||
def subscribe_menu_keyboard():
|
||||
keyboard = InlineKeyboardMarkup()
|
||||
keyboard.add(InlineKeyboardButton("Lark", callback_data="subscribe:lark"))
|
||||
keyboard.add(InlineKeyboardButton("Lark Pro", callback_data="subscribe:lark_pro"))
|
||||
keyboard.add(InlineKeyboardButton("О тарифах", callback_data="subscribe:about_tariffs"))
|
||||
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:personal"))
|
||||
return keyboard
|
||||
|
||||
# Тарифы Lark клавиатура
|
||||
def lark_tariffs_keyboard():
|
||||
keyboard = InlineKeyboardMarkup()
|
||||
keyboard.add(InlineKeyboardButton("Lark 1 месяц", callback_data="lark:1"))
|
||||
keyboard.add(InlineKeyboardButton("Lark 6 месяцев", callback_data="lark:6"))
|
||||
keyboard.add(InlineKeyboardButton("Lark 12 месяцев", callback_data="lark:12"))
|
||||
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:subscribe"))
|
||||
return keyboard
|
||||
|
||||
def buy_keyboard():
|
||||
"""
|
||||
Приобрести подписку
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="Тариф Lark", callback_data="subs"))
|
||||
builder.row(InlineKeyboardButton(text="Тариф Lark Pro", callback_data="subs_pro"))
|
||||
builder.row(InlineKeyboardButton(text="О тарифах", url="https://t.me/proxylark/19"))
|
||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="profile"))
|
||||
return builder.as_markup()
|
||||
# Тарифы Lark Pro клавиатура
|
||||
def lark_pro_tariffs_keyboard():
|
||||
keyboard = InlineKeyboardMarkup()
|
||||
keyboard.add(InlineKeyboardButton("Lark Pro 1 месяц", callback_data="lark_pro:1"))
|
||||
keyboard.add(InlineKeyboardButton("Lark Pro 6 месяцев", callback_data="lark_pro:6"))
|
||||
keyboard.add(InlineKeyboardButton("Lark Pro 12 месяцев", callback_data="lark_pro:12"))
|
||||
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:subscribe"))
|
||||
return keyboard
|
||||
|
||||
def subhist_keyboard():
|
||||
"""
|
||||
Подписки
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text="Назад", callback_data="profile")
|
||||
return builder.as_markup()
|
||||
# Руководство меню клавиатура
|
||||
def guide_menu_keyboard():
|
||||
keyboard = InlineKeyboardMarkup()
|
||||
keyboard.add(InlineKeyboardButton("iOS, Android", callback_data="guide:ios_android"))
|
||||
keyboard.add(InlineKeyboardButton("Windows, Macintosh", callback_data="guide:windows_mac"))
|
||||
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:personal"))
|
||||
return keyboard
|
||||
|
||||
def popup_keyboard():
|
||||
"""
|
||||
Пополнение
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="200₽", callback_data="popup:200"),InlineKeyboardButton(text="500₽", callback_data="popup:500"))
|
||||
builder.row(InlineKeyboardButton(text="1000₽", callback_data="popup:1000"),InlineKeyboardButton(text="2000₽", callback_data="popup:2000"))
|
||||
builder.row(InlineKeyboardButton(text="3000₽", callback_data="popup:3000"),InlineKeyboardButton(text="5000₽", callback_data="popup:5000"))
|
||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="balance"))
|
||||
return builder.as_markup()
|
||||
async def start_command(message: types.Message):
|
||||
"""Обработчик команды /start."""
|
||||
await message.answer("Главное меню", reply_markup=main_menu_keyboard())
|
||||
|
||||
def balance_keyboard():
|
||||
"""
|
||||
Баланс
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="Пополнение", callback_data="popup"))
|
||||
builder.row(InlineKeyboardButton(text="История транзакций", callback_data="tranhist"))
|
||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="profile"))
|
||||
return builder.as_markup()
|
||||
async def callback_handler(callback: CallbackQuery):
|
||||
"""Обработчик callback."""
|
||||
data = callback.data.split(":")
|
||||
action = data[0]
|
||||
sub_action = data[1] if len(data) > 1 else None
|
||||
|
||||
def tarif_Lark_keyboard():
|
||||
"""
|
||||
Тариф Lark
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="Тариф Lark 1 Месяц", callback_data="Lark:Standart:1"))
|
||||
builder.row(InlineKeyboardButton(text="Тариф Lark 6 Месяц", callback_data="Lark:Standart:6"))
|
||||
builder.row(InlineKeyboardButton(text="Тариф Lark 12 Месяц", callback_data="Lark:Standart:12"))
|
||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="buy_subscription"))
|
||||
return builder.as_markup()
|
||||
if action == "main":
|
||||
if sub_action == "personal":
|
||||
await callback.message.edit_text("Личный кабинет", reply_markup=personal_menu_keyboard())
|
||||
elif sub_action == "faq":
|
||||
await callback.message.edit_text("FAQ", reply_markup=InlineKeyboardMarkup().add(
|
||||
InlineKeyboardButton("Назад", callback_data="back:main")))
|
||||
elif sub_action == "about":
|
||||
await callback.message.edit_text("Наш сайт: {URL}", reply_markup=InlineKeyboardMarkup().add(
|
||||
InlineKeyboardButton("Назад", callback_data="back:main")))
|
||||
|
||||
def tarif_Lark_pro_keyboard():
|
||||
"""
|
||||
Тариф Lark Pro
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="Тариф Lark Pro 1 Месяц", callback_data="Lark:Pro:1"))
|
||||
builder.row(InlineKeyboardButton(text="Тариф Lark Pro 6 Месяц", callback_data="Lark:Pro:6"))
|
||||
builder.row(InlineKeyboardButton(text="Тариф Lark Pro 12 Месяц", callback_data="Lark:Pro:12"))
|
||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="buy_subscription"))
|
||||
return builder.as_markup()
|
||||
elif action == "personal":
|
||||
if sub_action == "balance":
|
||||
await callback.message.edit_text("Баланс:", reply_markup=InlineKeyboardMarkup().add(
|
||||
InlineKeyboardButton("Пополнение", callback_data="balance:topup"),
|
||||
InlineKeyboardButton("История транзакций", callback_data="balance:history"),
|
||||
InlineKeyboardButton("Назад", callback_data="back:personal")
|
||||
))
|
||||
elif sub_action == "subscribe":
|
||||
await callback.message.edit_text("Выберите подписку:", reply_markup=subscribe_menu_keyboard())
|
||||
elif sub_action == "guide":
|
||||
await callback.message.edit_text("Руководство по использованию", reply_markup=guide_menu_keyboard())
|
||||
|
||||
def guide_keyboard():
|
||||
"""
|
||||
Руководство по подключению
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="IOS,Android", callback_data="mob"))
|
||||
builder.row(InlineKeyboardButton(text="Windows,MacOS", callback_data="pc"))
|
||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="profile"))
|
||||
return builder.as_markup()
|
||||
elif action == "subscribe":
|
||||
if sub_action == "lark":
|
||||
await callback.message.edit_text("Тарифы Lark", reply_markup=lark_tariffs_keyboard())
|
||||
elif sub_action == "lark_pro":
|
||||
await callback.message.edit_text("Тарифы Lark Pro", reply_markup=lark_pro_tariffs_keyboard())
|
||||
elif sub_action == "about_tariffs":
|
||||
await callback.message.edit_text("О тарифах", reply_markup=InlineKeyboardMarkup().add(
|
||||
InlineKeyboardButton("Назад", callback_data="back:subscribe")
|
||||
))
|
||||
|
||||
elif action == "lark":
|
||||
await callback.message.edit_text(f"Вы выбрали тариф Lark {sub_action} месяцев.", reply_markup=InlineKeyboardMarkup().add(
|
||||
InlineKeyboardButton("Подтвердить", callback_data=f"confirm:lark:{sub_action}"),
|
||||
InlineKeyboardButton("Отменить", callback_data="back:subscribe")
|
||||
))
|
||||
|
||||
# def about_tarifs_keyboard():
|
||||
# """
|
||||
# О тарифах
|
||||
# """
|
||||
# builder = InlineKeyboardBuilder()
|
||||
# builder.row(InlineKeyboardButton(text="Назад", callback_data="buy_subscription"))
|
||||
# return builder.as_markup()
|
||||
elif action == "lark_pro":
|
||||
await callback.message.edit_text(f"Вы выбрали тариф Lark Pro {sub_action} месяцев.", reply_markup=InlineKeyboardMarkup().add(
|
||||
InlineKeyboardButton("Подтвердить", callback_data=f"confirm:lark_pro:{sub_action}"),
|
||||
InlineKeyboardButton("Отменить", callback_data="back:subscribe")
|
||||
))
|
||||
|
||||
elif action == "back":
|
||||
if sub_action == "main":
|
||||
await callback.message.edit_text("Главное меню", reply_markup=main_menu_keyboard())
|
||||
elif sub_action == "personal":
|
||||
await callback.message.edit_text("Личный кабинет", reply_markup=personal_menu_keyboard())
|
||||
elif sub_action == "subscribe":
|
||||
await callback.message.edit_text("Выберите подписку:", reply_markup=subscribe_menu_keyboard())
|
||||
|
||||
def faq_keyboard():
|
||||
"""
|
||||
FAQ
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="base"))
|
||||
return builder.as_markup()
|
||||
await callback.answer()
|
||||
|
||||
def tranhist_keyboard():
|
||||
"""
|
||||
История транзакций
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="Назад",callback_data="balance"))
|
||||
return builder.as_markup()
|
||||
|
||||
def tarif_confirm_keyboard(name,amount,classif):
|
||||
"""
|
||||
Подтверждение покупки тарифа
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="Подтвердить", callback_data=f"confirm:{name}_{classif}_{amount}"))
|
||||
builder.row(InlineKeyboardButton(text="Отменить",callback_data="buy_subscription"))
|
||||
return builder.as_markup()
|
||||
|
||||
def confirm_popup_keyboard():
|
||||
"""
|
||||
Подтверждение пополнения
|
||||
"""
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="Теперь иди нахуй", callback_data="balance"))
|
||||
return builder.as_markup()
|
||||
def register_handlers(dp: Dispatcher):
|
||||
dp.message.register(start_command, Command("start"))
|
||||
dp.callback_query.register(callback_handler)
|
||||
|
||||
9
main.py
9
main.py
@@ -1,7 +1,6 @@
|
||||
import os
|
||||
import asyncio
|
||||
from aiogram import Bot, Dispatcher
|
||||
from databases.db_config import init_postgresql, init_mongodb, close_connections
|
||||
from aiogram.types import BotCommand
|
||||
from Middleware.anti_spam_middleware import AntiSpamMiddleware
|
||||
import logging
|
||||
@@ -30,14 +29,9 @@ async def set_commands():
|
||||
|
||||
async def on_startup():
|
||||
"""Действия при запуске бота."""
|
||||
# Инициализация баз данных
|
||||
await init_mongodb()
|
||||
await init_postgresql()
|
||||
|
||||
# Установка команд бота
|
||||
await set_commands()
|
||||
|
||||
# Настройка логирования
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.info("Бот запущен!")
|
||||
@@ -45,10 +39,7 @@ async def on_startup():
|
||||
|
||||
async def on_shutdown():
|
||||
"""Действия при остановке бота."""
|
||||
# Закрытие подключений к базам данных
|
||||
await close_connections()
|
||||
|
||||
# Закрытие сессии бота
|
||||
await bot.session.close()
|
||||
print("Бот остановлен.")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user