from flask import Flask, request, jsonify from flask_sqlalchemy import SQLAlchemy from datetime import datetime, timedelta from functools import wraps import secrets, random, os, logging from logging.handlers import RotatingFileHandler from flasgger import Swagger from flask_apscheduler import APScheduler app = Flask(__name__) app.config['SECRET_KEY'] = 'YY3_5BdticAM6E1k_3vYpg' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) class Config: SCHEDULER_API_ENABLED = True app.config.from_object(Config()) scheduler = APScheduler() scheduler.init_app(app) scheduler.start() def deactivate_expired_api_keys(): with app.app_context(): now = datetime.now() expired_keys = ApiKey.query.filter(ApiKey.expires_at < now, ApiKey.active == True).all() for key in expired_keys: key.active = False db.session.commit() scheduler.add_job(id='Deactivate Expired Keys', func=deactivate_expired_api_keys, trigger='interval', minutes=15) logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) handler = RotatingFileHandler('moja_aplikacja.log', maxBytes=10000, backupCount=3) logger.addHandler(handler) class Game(db.Model): id = db.Column(db.Integer, primary_key = True) number_to_guess = db.Column(db.Integer) def __init__(self, number_to_guess): self.number_to_guess = number_to_guess class ApiKey(db.Model): id = db.Column(db.Integer, primary_key=True) key = db.Column(db.String(80), unique=True, nullable=False) user_name = db.Column(db.String(100)) expires_at = db.Column(db.DateTime) active = db.Column(db.Boolean, default=True) def __init__(self, key, user_name, expires_at=None, active=True): self.key = key self.user_name = user_name self.expires_at = datetime.now() + timedelta(minutes=15) self.active = active def require_api_key(f): @wraps(f) def decorated_function(*args, **kwargs): api_key = request.headers.get('API-Key') api_key_record = ApiKey.query.filter_by(key=api_key).first() if not api_key or not api_key_record or not api_key_record.active or api_key_record.expires_at < datetime.now(): logger.warning(f"Błędny lub wygasły klucz API: {api_key}") return jsonify({'message': 'Brak ważnego klucza API lub klucz wygasł'}), 401 return f(*args, **kwargs) return decorated_function @app.route('/generate-api-key', methods=['POST']) def generate_api_key(): """ Generuje nowy klucz API --- tags: - API Key Management responses: 200: description: Wygenerowany klucz API schema: id: api_key properties: api_key: type: string description: Wygenerowany klucz API """ new_key = secrets.token_urlsafe(16) expires_at = datetime.now() + timedelta(minutes=15) logger.info(f"Generowanie nowego klucza API dla użytkownika: NazwaUzytkownika") api_key = ApiKey(key=new_key, user_name="NazwaUzytkownika", expires_at=expires_at) db.session.add(api_key) db.session.commit() return jsonify({'api_key': new_key}) @app.route('/guess', methods=['POST']) @require_api_key def guess_number(): """ Zgaduje liczbę --- tags: - Game consumes: - application/json produces: - application/json parameters: - in: body name: body description: Zgadywana liczba required: true schema: type: object required: - guess properties: guess: type: integer format: int32 example: 25 responses: 200: description: Wynik zgadywania schema: type: object properties: message: type: string success: type: boolean """ game = Game.query.first() if not game or request.json.get('new game', False): if game: db.session.delete(game) game = Game(random.randint(1,100)) try: db.session.add(game) db.session.commit() except Exception as e: logger.error(f"Błąd przy zapisywaniu do bazy danych: {e}") guess = request.json.get('guess') if not isinstance(guess, int): return jsonify({'message': 'Nieprawidłowe dane. Proszę podać liczbę.'}), 400 if guess == game.number_to_guess: try: db.session.delete(game) db.session.commit() except Exception as e: logger.error(f"Błąd przy usuwaniu z bazy danych: {e}") return jsonify({'message': 'Gratulacje, zgadłeś!', 'success': True}) elif guess < game.number_to_guess: return jsonify({'message': 'Za mało.', 'success': False}) else: return jsonify({'message': 'Za dużo.', 'success': False}) Swagger(app) if __name__ == '__main__': with app.app_context(): db.create_all() app.run(debug=True)