from flask import Flask, request, jsonify from databases.model import User, Subscription, Transaction 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 app = Flask(__name__) # Настройка логирования logger = logging.getLogger(__name__) mongo_repo = MongoDBRepository() # Генератор сессий передаётся извне (например, через dependency injection) session_generator = None def generate_string(length): """ Генерирует случайную строку заданной длины. """ characters = string.ascii_lowercase + string.digits return ''.join(random.choices(characters, k=length)) @app.route('/create_user', methods=['POST']) def create_user(): telegram_id = request.json.get('telegram_id') if not telegram_id: return jsonify({'error': 'Telegram ID is required'}), 400 async def process(): async for session in session_generator(): try: username = 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 jsonify({'user': new_user.id, 'username': new_user.username}), 201 return jsonify({'user': user.id, 'username': user.username}), 200 except SQLAlchemyError as e: logger.error(f"Ошибка при создании пользователя {telegram_id}: {e}") await session.rollback() return jsonify({'error': 'Internal server error'}), 500 return asyncio.run(process()) @app.route('/get_user/', methods=['GET']) def get_user_by_telegram_id(telegram_id): async def process(): async for session in session_generator(): try: result = await session.execute(select(User).where(User.telegram_id == telegram_id)) user = result.scalars().first() if user: return jsonify({'id': user.id, 'username': user.username, 'balance': user.balance}), 200 return jsonify({'error': 'User not found'}), 404 except SQLAlchemyError as e: logger.error(f"Ошибка при получении пользователя {telegram_id}: {e}") return jsonify({'error': 'Internal server error'}), 500 return asyncio.run(process()) @app.route('/update_balance', methods=['POST']) def update_balance(): data = request.json telegram_id = data.get('telegram_id') amount = data.get('amount') if not telegram_id or amount is None: return jsonify({'error': 'Telegram ID and amount are required'}), 400 async def process(): async for session in 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) transaction = Transaction(user_id=user.id, amount=amount) session.add(transaction) await session.commit() return jsonify({'balance': user.balance}), 200 return jsonify({'error': 'User not found'}), 404 except SQLAlchemyError as e: logger.error(f"Ошибка при обновлении баланса: {e}") await session.rollback() return jsonify({'error': 'Internal server error'}), 500 return asyncio.run(process()) @app.route('/buy_subscription', methods=['POST']) def buy_subscription(): data = request.json telegram_id = data.get('telegram_id') plan_id = data.get('plan_id') if not telegram_id or not plan_id: return jsonify({'error': 'Telegram ID and Plan ID are required'}), 400 async def process(): async for session in session_generator(): try: result = await session.execute(select(User).where(User.telegram_id == telegram_id)) user = result.scalars().first() if not user: return jsonify({'error': 'User not found'}), 404 plan = await mongo_repo.get_subscription_plan(plan_id) if not plan: return jsonify({'error': 'Plan not found'}), 404 cost = int(plan['price']) if user.balance >= cost: user.balance -= cost expiry_date = datetime.utcnow() + relativedelta(months=plan['duration_months']) server = await mongo_repo.get_server_with_least_clients() new_subscription = Subscription(user_id=user.id, vpn_server_id=str(server['server']['name']), plan=plan_id, expiry_date=expiry_date) session.add(new_subscription) await session.commit() return jsonify({'message': 'Subscription purchased successfully'}), 200 return jsonify({'error': 'Insufficient funds'}), 400 except SQLAlchemyError as e: logger.error(f"Ошибка при покупке подписки {plan_id} для пользователя {telegram_id}: {e}") await session.rollback() return jsonify({'error': 'Internal server error'}), 500 return asyncio.run(process()) @app.route('/add_to_server', methods=['POST']) def add_to_server(): data = request.json telegram_id = data.get('telegram_id') if not telegram_id: return jsonify({'error': 'Telegram ID is required'}), 400 async def process(): async for session in session_generator(): try: result = await session.execute(select(Subscription).join(User).where(User.telegram_id == int(telegram_id))) user_sub = result.scalars().first() if not user_sub: logger.error(f"Не удалось найти подписку для пользователя с Telegram ID {telegram_id}.") return jsonify({'error': 'Subscription not found'}), 404 user_result = await session.execute(select(User).where(User.telegram_id == telegram_id)) user = user_result.scalars().first() server = await mongo_repo.get_server(user_sub.vpn_server_id) if not server: logger.error(f"Не удалось найти сервер с ID {user_sub.vpn_server_id}.") return jsonify({'error': 'Server not found'}), 404 server_info = server['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, logger) expiry_date_iso = user_sub.expiry_date.isoformat() response = await panel.add_client(user.id, expiry_date_iso, user.username) if response == "OK": logger.info(f"Клиент {telegram_id} успешно добавлен на сервер.") return jsonify({'message': 'Client added successfully'}), 200 else: logger.error(f"Ошибка при добавлении клиента {telegram_id} на сервер: {response}") return jsonify({'error': 'Failed to add client to server'}), 500 except Exception as e: logger.error(f"Ошибка при установке на сервер для пользователя {telegram_id}: {e}") return jsonify({'error': 'Internal server error'}), 500 return asyncio.run(process()) if __name__ == '__main__': app.run(debug=True)