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 login_manager.login_view = 'auth.login' login_manager.login_message = '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. Parámetro explícito en la URL (?lang=es o ?lang=en) lang = request.args.get('lang') if lang and lang in app.config['LANGUAGES']: session['language'] = lang return lang # 2. Si el usuario está autenticado y tiene idioma configurado en su perfil, prevalece en toda la sesión from flask_login import current_user if current_user.is_authenticated and getattr(current_user, 'preferred_language', None): if current_user.preferred_language in app.config['LANGUAGES']: return current_user.preferred_language # 3. En la pantalla de Login (usuario no autenticado): # El idioma predeterminado del login debe ser español o respetar el idioma del navegador. # No debe verse afectado por cookies o sesiones residuales de otros usuarios. is_login = (request.endpoint == 'auth.login' or request.path.rstrip('/') == '/login') if is_login: # Solo si el usuario cambió el idioma explícitamente en el selector del login if session.get('login_lang_explicit') in app.config['LANGUAGES']: return session['login_lang_explicit'] # Detectar según el navegador del usuario (soporta es-419, es-AR, es-ES, etc.) if request.accept_languages: for accepted_lang, _quality in request.accept_languages: primary = accepted_lang.split('-')[0].lower() if primary in app.config['LANGUAGES']: return primary # Idioma predeterminado por defecto del login: Español return 'es' # 4. Para otras rutas: verificar si hay idioma en sesión (ej. selector manual) if 'language' in session and session['language'] in app.config['LANGUAGES']: return session['language'] # 5. Detección automática del navegador por defecto (soporta subtags regionales) if request.accept_languages: for accepted_lang, _quality in request.accept_languages: primary = accepted_lang.split('-')[0].lower() if primary in app.config['LANGUAGES']: 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