Перенос части логики на бекенд 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 import types, Dispatcher
|
||||||
from aiogram.filters import Command
|
from aiogram.filters import Command
|
||||||
from databases.postgresql import DatabaseManager
|
import aiohttp
|
||||||
from databases.model import User, Subscription, Transaction, Administrators
|
from instences.config import BASE_URL_FASTAPI
|
||||||
from databases.db_config import get_postgres_session
|
|
||||||
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
|
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):
|
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):
|
async def profile_callback_handler(callback: types.CallbackQuery):
|
||||||
"""
|
user_data = await call_api("POST", "/user/create", {"telegram_id": callback.from_user.id})
|
||||||
Обработчик callback_query с data="profile".
|
if not user_data:
|
||||||
"""
|
await callback.message.answer("Произошла ошибка, попробуйте позже.")
|
||||||
user = await db_manager.create_user(telegram_id=callback.from_user.id)
|
|
||||||
if user == "ERROR":
|
|
||||||
await callback.message.answer(
|
|
||||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
|
||||||
)
|
|
||||||
await callback.answer()
|
await callback.answer()
|
||||||
return
|
return
|
||||||
|
|
||||||
if user:
|
text = f"Ваш профиль:\nID: {user_data['username']}\nБаланс: {user_data['balance']} ₽"
|
||||||
text = f"""Ваш профиль:\nID: {user.username}\nБаланс: {user.balance}"""
|
await callback.message.edit_text(text, reply_markup=account_keyboard())
|
||||||
await callback.message.edit_text(
|
|
||||||
text,
|
|
||||||
reply_markup=account_keyboard()
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
await callback.message.edit_text("Вы еще не зарегистрированы.")
|
|
||||||
await callback.answer()
|
await callback.answer()
|
||||||
|
|
||||||
async def balance_callback_handler(callback: types.CallbackQuery):
|
async def balance_callback_handler(callback: types.CallbackQuery):
|
||||||
"""
|
user_data = await call_api("GET", f"/user/{callback.from_user.id}")
|
||||||
Обработчик callback_query с data="balance".
|
if not user_data:
|
||||||
"""
|
await callback.message.answer("Вы еще не зарегистрированы.")
|
||||||
user = await db_manager.create_user(telegram_id=callback.from_user.id)
|
|
||||||
if user == "ERROR":
|
|
||||||
await callback.message.answer(
|
|
||||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
|
||||||
)
|
|
||||||
await callback.answer()
|
await callback.answer()
|
||||||
return
|
return
|
||||||
|
|
||||||
if user:
|
|
||||||
await callback.message.edit_text(
|
await callback.message.edit_text(
|
||||||
f"Ваш баланс: {user.balance} ₽. Выберите сумму для пополнения 🐥",
|
f"Ваш баланс: {user_data['balance']} ₽. Выберите сумму для пополнения 🐥",
|
||||||
reply_markup=balance_keyboard()
|
reply_markup=balance_keyboard()
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
await callback.message.edit_text("Вы еще не зарегистрированы.")
|
|
||||||
await callback.answer()
|
await callback.answer()
|
||||||
|
|
||||||
|
|
||||||
@@ -95,7 +81,7 @@ async def popup_callback_handler(callback: types.CallbackQuery):
|
|||||||
"""
|
"""
|
||||||
Обработчик callback_query с data="popup".
|
Обработчик 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":
|
if user == "ERROR":
|
||||||
await callback.message.answer(
|
await callback.message.answer(
|
||||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
||||||
@@ -113,69 +99,42 @@ async def popup_callback_handler(callback: types.CallbackQuery):
|
|||||||
await callback.answer()
|
await callback.answer()
|
||||||
|
|
||||||
async def tranhist_callback_handler(callback: types.CallbackQuery):
|
async def tranhist_callback_handler(callback: types.CallbackQuery):
|
||||||
"""
|
user_data = await call_api("GET", f"/user/{callback.from_user.id}")
|
||||||
Обработчик callback_query с data="tranhist".
|
if not user_data:
|
||||||
"""
|
await callback.message.edit_text("Вы еще не зарегистрированы.")
|
||||||
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(
|
|
||||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
|
||||||
)
|
|
||||||
await callback.answer()
|
await callback.answer()
|
||||||
return
|
return
|
||||||
if not trans:
|
|
||||||
await callback.message.edit_text(
|
transactions = await call_api("GET", f"/user/{user_data['id']}/transactions")
|
||||||
"У вас нет транзакций. Пожалуйста, пополните баланс.",
|
if not transactions:
|
||||||
reply_markup=tranhist_keyboard()
|
await callback.message.edit_text("У вас нет транзакций.", reply_markup=tranhist_keyboard())
|
||||||
)
|
|
||||||
await callback.answer()
|
await callback.answer()
|
||||||
return
|
return
|
||||||
|
|
||||||
result = "Ваши транзакции:\n"
|
result = "Ваши транзакции:\n"
|
||||||
for count, tran in enumerate(trans, start=1):
|
for count, tran in enumerate(transactions, start=1):
|
||||||
result += f"{count}. Сумма: {tran.amount}, Дата: {tran.created_at}\n"
|
result += f"{count}. Сумма: {tran['amount']}, Дата: {tran['created_at']}\n"
|
||||||
await callback.message.edit_text(
|
await callback.message.edit_text(result, reply_markup=tranhist_keyboard())
|
||||||
result,
|
|
||||||
reply_markup=tranhist_keyboard()
|
|
||||||
)
|
|
||||||
await callback.answer()
|
await callback.answer()
|
||||||
|
|
||||||
async def subhist_callback_handler(callback: types.CallbackQuery):
|
async def subhist_callback_handler(callback: types.CallbackQuery):
|
||||||
"""
|
user_data = await call_api("GET", f"/user/{callback.from_user.id}")
|
||||||
Обработчик callback_query с data="subhist".
|
if not user_data:
|
||||||
"""
|
|
||||||
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:
|
|
||||||
await callback.message.edit_text("Вы еще не зарегистрированы.")
|
await callback.message.edit_text("Вы еще не зарегистрированы.")
|
||||||
await callback.answer()
|
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):
|
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(":")
|
data = callback.data.split(":")
|
||||||
popup_info = data[1]
|
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":
|
if result == "ERROR":
|
||||||
await callback.message.answer(
|
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())
|
await callback.message.edit_text(text=text, reply_markup=confirm_popup_keyboard())
|
||||||
|
|
||||||
async def confirm_callback_handler(callback: types.CallbackQuery):
|
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]}"
|
||||||
tariff_info = callback.data.split(":")[1].split("_")
|
result = await call_api("POST", "/subscription/buy", {"telegram_id": callback.from_user.id, "plan_id": plan_id})
|
||||||
tariff_name = tariff_info[0]
|
|
||||||
tariff_class = tariff_info[1]
|
|
||||||
tariff_amount = int(tariff_info[2])
|
|
||||||
|
|
||||||
sub = await db_manager.buy_sub(callback.from_user.id, f"{tariff_name}_{tariff_class}_{tariff_amount}")
|
if result and result.get("message"):
|
||||||
if sub == "ERROR":
|
await callback.message.edit_text(f"Подписка успешно оформлена!")
|
||||||
await callback.message.answer(
|
else:
|
||||||
"Произошла ошибка, попробуйте позже или свяжитесь с администрацией."
|
await callback.message.edit_text("Произошла ошибка при оформлении подписки.")
|
||||||
)
|
|
||||||
await callback.answer()
|
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):
|
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 import types, Dispatcher
|
||||||
from aiogram.types import InlineKeyboardButton
|
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():
|
# Личный кабинет клавиатура
|
||||||
"""
|
def personal_menu_keyboard():
|
||||||
База
|
keyboard = InlineKeyboardMarkup()
|
||||||
"""
|
keyboard.add(InlineKeyboardButton("Баланс", callback_data="personal:balance"))
|
||||||
builder = InlineKeyboardBuilder()
|
keyboard.add(InlineKeyboardButton("Приобрести подписку", callback_data="personal:subscribe"))
|
||||||
builder.row(InlineKeyboardButton(text="Профиль", callback_data="profile"))
|
keyboard.add(InlineKeyboardButton("Руководство по использованию", callback_data="personal:guide"))
|
||||||
builder.row(InlineKeyboardButton(text="FAQ", callback_data="faq"))
|
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:main"))
|
||||||
builder.row(InlineKeyboardButton(text="О нас", url="https://www.youtube.com/watch?v=Zirn-CKck-c"))
|
return keyboard
|
||||||
return builder.as_markup()
|
|
||||||
|
|
||||||
def account_keyboard():
|
# Подписка меню клавиатура
|
||||||
"""
|
def subscribe_menu_keyboard():
|
||||||
Аккаунт
|
keyboard = InlineKeyboardMarkup()
|
||||||
"""
|
keyboard.add(InlineKeyboardButton("Lark", callback_data="subscribe:lark"))
|
||||||
builder = InlineKeyboardBuilder()
|
keyboard.add(InlineKeyboardButton("Lark Pro", callback_data="subscribe:lark_pro"))
|
||||||
builder.row(InlineKeyboardButton(text="Баланс", callback_data="balance"))
|
keyboard.add(InlineKeyboardButton("О тарифах", callback_data="subscribe:about_tariffs"))
|
||||||
builder.row(InlineKeyboardButton(text="Приобрести подписку", callback_data="buy_subscription"))
|
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:personal"))
|
||||||
builder.row(InlineKeyboardButton(text="Руководство по подключению", callback_data="guide"))
|
return keyboard
|
||||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="base"))
|
|
||||||
return builder.as_markup()
|
|
||||||
|
|
||||||
|
# Тарифы 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():
|
# Тарифы Lark Pro клавиатура
|
||||||
"""
|
def lark_pro_tariffs_keyboard():
|
||||||
Приобрести подписку
|
keyboard = InlineKeyboardMarkup()
|
||||||
"""
|
keyboard.add(InlineKeyboardButton("Lark Pro 1 месяц", callback_data="lark_pro:1"))
|
||||||
builder = InlineKeyboardBuilder()
|
keyboard.add(InlineKeyboardButton("Lark Pro 6 месяцев", callback_data="lark_pro:6"))
|
||||||
builder.row(InlineKeyboardButton(text="Тариф Lark", callback_data="subs"))
|
keyboard.add(InlineKeyboardButton("Lark Pro 12 месяцев", callback_data="lark_pro:12"))
|
||||||
builder.row(InlineKeyboardButton(text="Тариф Lark Pro", callback_data="subs_pro"))
|
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:subscribe"))
|
||||||
builder.row(InlineKeyboardButton(text="О тарифах", url="https://t.me/proxylark/19"))
|
return keyboard
|
||||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="profile"))
|
|
||||||
return builder.as_markup()
|
|
||||||
|
|
||||||
def subhist_keyboard():
|
# Руководство меню клавиатура
|
||||||
"""
|
def guide_menu_keyboard():
|
||||||
Подписки
|
keyboard = InlineKeyboardMarkup()
|
||||||
"""
|
keyboard.add(InlineKeyboardButton("iOS, Android", callback_data="guide:ios_android"))
|
||||||
builder = InlineKeyboardBuilder()
|
keyboard.add(InlineKeyboardButton("Windows, Macintosh", callback_data="guide:windows_mac"))
|
||||||
builder.button(text="Назад", callback_data="profile")
|
keyboard.add(InlineKeyboardButton("Назад", callback_data="back:personal"))
|
||||||
return builder.as_markup()
|
return keyboard
|
||||||
|
|
||||||
def popup_keyboard():
|
async def start_command(message: types.Message):
|
||||||
"""
|
"""Обработчик команды /start."""
|
||||||
Пополнение
|
await message.answer("Главное меню", reply_markup=main_menu_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()
|
|
||||||
|
|
||||||
def balance_keyboard():
|
async def callback_handler(callback: CallbackQuery):
|
||||||
"""
|
"""Обработчик callback."""
|
||||||
Баланс
|
data = callback.data.split(":")
|
||||||
"""
|
action = data[0]
|
||||||
builder = InlineKeyboardBuilder()
|
sub_action = data[1] if len(data) > 1 else None
|
||||||
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()
|
|
||||||
|
|
||||||
def tarif_Lark_keyboard():
|
if action == "main":
|
||||||
"""
|
if sub_action == "personal":
|
||||||
Тариф Lark
|
await callback.message.edit_text("Личный кабинет", reply_markup=personal_menu_keyboard())
|
||||||
"""
|
elif sub_action == "faq":
|
||||||
builder = InlineKeyboardBuilder()
|
await callback.message.edit_text("FAQ", reply_markup=InlineKeyboardMarkup().add(
|
||||||
builder.row(InlineKeyboardButton(text="Тариф Lark 1 Месяц", callback_data="Lark:Standart:1"))
|
InlineKeyboardButton("Назад", callback_data="back:main")))
|
||||||
builder.row(InlineKeyboardButton(text="Тариф Lark 6 Месяц", callback_data="Lark:Standart:6"))
|
elif sub_action == "about":
|
||||||
builder.row(InlineKeyboardButton(text="Тариф Lark 12 Месяц", callback_data="Lark:Standart:12"))
|
await callback.message.edit_text("Наш сайт: {URL}", reply_markup=InlineKeyboardMarkup().add(
|
||||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="buy_subscription"))
|
InlineKeyboardButton("Назад", callback_data="back:main")))
|
||||||
return builder.as_markup()
|
|
||||||
|
|
||||||
def tarif_Lark_pro_keyboard():
|
elif action == "personal":
|
||||||
"""
|
if sub_action == "balance":
|
||||||
Тариф Lark Pro
|
await callback.message.edit_text("Баланс:", reply_markup=InlineKeyboardMarkup().add(
|
||||||
"""
|
InlineKeyboardButton("Пополнение", callback_data="balance:topup"),
|
||||||
builder = InlineKeyboardBuilder()
|
InlineKeyboardButton("История транзакций", callback_data="balance:history"),
|
||||||
builder.row(InlineKeyboardButton(text="Тариф Lark Pro 1 Месяц", callback_data="Lark:Pro:1"))
|
InlineKeyboardButton("Назад", callback_data="back:personal")
|
||||||
builder.row(InlineKeyboardButton(text="Тариф Lark Pro 6 Месяц", callback_data="Lark:Pro:6"))
|
))
|
||||||
builder.row(InlineKeyboardButton(text="Тариф Lark Pro 12 Месяц", callback_data="Lark:Pro:12"))
|
elif sub_action == "subscribe":
|
||||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="buy_subscription"))
|
await callback.message.edit_text("Выберите подписку:", reply_markup=subscribe_menu_keyboard())
|
||||||
return builder.as_markup()
|
elif sub_action == "guide":
|
||||||
|
await callback.message.edit_text("Руководство по использованию", reply_markup=guide_menu_keyboard())
|
||||||
|
|
||||||
def guide_keyboard():
|
elif action == "subscribe":
|
||||||
"""
|
if sub_action == "lark":
|
||||||
Руководство по подключению
|
await callback.message.edit_text("Тарифы Lark", reply_markup=lark_tariffs_keyboard())
|
||||||
"""
|
elif sub_action == "lark_pro":
|
||||||
builder = InlineKeyboardBuilder()
|
await callback.message.edit_text("Тарифы Lark Pro", reply_markup=lark_pro_tariffs_keyboard())
|
||||||
builder.row(InlineKeyboardButton(text="IOS,Android", callback_data="mob"))
|
elif sub_action == "about_tariffs":
|
||||||
builder.row(InlineKeyboardButton(text="Windows,MacOS", callback_data="pc"))
|
await callback.message.edit_text("О тарифах", reply_markup=InlineKeyboardMarkup().add(
|
||||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="profile"))
|
InlineKeyboardButton("Назад", callback_data="back:subscribe")
|
||||||
return builder.as_markup()
|
))
|
||||||
|
|
||||||
|
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():
|
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")
|
||||||
# builder = InlineKeyboardBuilder()
|
))
|
||||||
# builder.row(InlineKeyboardButton(text="Назад", callback_data="buy_subscription"))
|
|
||||||
# return builder.as_markup()
|
|
||||||
|
|
||||||
|
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():
|
await callback.answer()
|
||||||
"""
|
|
||||||
FAQ
|
|
||||||
"""
|
|
||||||
builder = InlineKeyboardBuilder()
|
|
||||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="base"))
|
|
||||||
return builder.as_markup()
|
|
||||||
|
|
||||||
def tranhist_keyboard():
|
def register_handlers(dp: Dispatcher):
|
||||||
"""
|
dp.message.register(start_command, Command("start"))
|
||||||
История транзакций
|
dp.callback_query.register(callback_handler)
|
||||||
"""
|
|
||||||
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()
|
|
||||||
|
|||||||
9
main.py
9
main.py
@@ -1,7 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import asyncio
|
import asyncio
|
||||||
from aiogram import Bot, Dispatcher
|
from aiogram import Bot, Dispatcher
|
||||||
from databases.db_config import init_postgresql, init_mongodb, close_connections
|
|
||||||
from aiogram.types import BotCommand
|
from aiogram.types import BotCommand
|
||||||
from Middleware.anti_spam_middleware import AntiSpamMiddleware
|
from Middleware.anti_spam_middleware import AntiSpamMiddleware
|
||||||
import logging
|
import logging
|
||||||
@@ -30,14 +29,9 @@ async def set_commands():
|
|||||||
|
|
||||||
async def on_startup():
|
async def on_startup():
|
||||||
"""Действия при запуске бота."""
|
"""Действия при запуске бота."""
|
||||||
# Инициализация баз данных
|
|
||||||
await init_mongodb()
|
|
||||||
await init_postgresql()
|
|
||||||
|
|
||||||
# Установка команд бота
|
|
||||||
await set_commands()
|
await set_commands()
|
||||||
|
|
||||||
# Настройка логирования
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.info("Бот запущен!")
|
logger.info("Бот запущен!")
|
||||||
@@ -45,10 +39,7 @@ async def on_startup():
|
|||||||
|
|
||||||
async def on_shutdown():
|
async def on_shutdown():
|
||||||
"""Действия при остановке бота."""
|
"""Действия при остановке бота."""
|
||||||
# Закрытие подключений к базам данных
|
|
||||||
await close_connections()
|
|
||||||
|
|
||||||
# Закрытие сессии бота
|
|
||||||
await bot.session.close()
|
await bot.session.close()
|
||||||
print("Бот остановлен.")
|
print("Бот остановлен.")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user