from flask import Flask, request, session from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from flask_login import LoginManager from flask_cors import CORS from flask_babel import Babel, gettext as _ from config.config import Config # Initialize extensions db = SQLAlchemy() migrate = Migrate() login_manager = LoginManager() cors = CORS() babel = Babel() def create_app(config_class=Config): app = Flask(__name__) app.config.from_object(config_class) # Initialize extensions with app db.init_app(app) migrate.init_app(app, db) login_manager.init_app(app) cors.init_app(app) # Login manager configuration from flask_babel import lazy_gettext login_manager.login_view = 'auth.login' login_manager.login_message = lazy_gettext('Por favor inicia sesión para acceder a esta página.') login_manager.login_message_category = 'info' # Import models to ensure they are registered from app.models import user # Register blueprints from app.routes import auth_bp, classrooms_bp, buildings_bp, main_bp, schedule_bp, genetic_bp, genetic_web_bp, admin_bp, my_subjects_bp from app.routes.api import api_auth_bp, api_classrooms_bp, api_reservations_bp, api_optimizer_bp from app.security import SecurityFilterChain app.register_blueprint(auth_bp, url_prefix="/") app.register_blueprint(classrooms_bp, url_prefix="/classrooms") app.register_blueprint(buildings_bp) app.register_blueprint(main_bp, url_prefix="/") app.register_blueprint(schedule_bp, url_prefix="/schedule") app.register_blueprint(genetic_bp) app.register_blueprint(genetic_web_bp) app.register_blueprint(admin_bp) app.register_blueprint(my_subjects_bp) # Register REST API (v1) Blueprints with Stateless JWT support app.register_blueprint(api_auth_bp) app.register_blueprint(api_classrooms_bp) app.register_blueprint(api_reservations_bp) app.register_blueprint(api_optimizer_bp) # Initialize Enterprise Security Pipeline (SecurityFilterChain) SecurityFilterChain(app) # Language selector function def get_locale(): # 1. Si el usuario está autenticado y tiene idioma configurado explícitamente en su perfil, prevalece. from flask_login import current_user if current_user.is_authenticated: if getattr(current_user, 'preferred_language', None) and current_user.preferred_language in app.config['LANGUAGES']: return current_user.preferred_language # El idioma por defecto siempre será español a menos que se configure a mano return app.config['BABEL_DEFAULT_LOCALE'] # 2. Parámetro explícito en la URL (?lang=es o ?lang=en) (para usuarios no autenticados o login) lang = request.args.get('lang') if lang and lang in app.config['LANGUAGES']: session['language'] = lang return lang # 3. Si ya hay un idioma guardado en la sesión if 'language' in session and session['language'] in app.config['LANGUAGES']: return session['language'] # 4. Primera vez que se accede a la web (sin sesión): respetar el idioma del navegador if request.accept_languages: for accepted_lang, _quality in request.accept_languages: primary = accepted_lang.split('-')[0].lower() if primary in app.config['LANGUAGES']: session['language'] = primary # Se guarda para la sesión actual return primary # Fallback del sistema: Español return app.config['BABEL_DEFAULT_LOCALE'] # Babel context processor @app.context_processor def inject_conf_vars(): return dict( languages=app.config['LANGUAGES'], current_lang=str(get_locale()) ) # Configure Babel babel.init_app(app, locale_selector=get_locale) # Register localized date and datetime formatters for Jinja2 templates from flask_babel import format_date, format_datetime app.jinja_env.globals['format_date'] = format_date app.jinja_env.globals['format_datetime'] = format_datetime app.jinja_env.filters['format_date'] = format_date app.jinja_env.filters['format_datetime'] = format_datetime return app