- Nuevo modelo StudentEnrollment (tabla student_enrollments)
con inscripcion unica por alumno/comision, estado y notas
- Migracion automatica en init_db.py (CREATE TABLE IF NOT EXISTS)
- Rutas /admin/commissions/ para Bedelia y Admin:
listado con filtros, detalle, asignar docente,
inscribir/dar de baja alumnos, cambiar estado
- Blueprint my_subjects_bp en /mis-materias:
Docente ve solo sus comisiones asignadas
Alumno ve solo sus inscripciones activas
Admin/Bedelia ven todo
- Templates: admin/commissions/list.html, detail.html
my_subjects/list.html, detail.html
- Navbar actualizado por rol:
Docente y Alumno: 'Mis Materias'
Bedelia y Admin: 'Gestion de Comisiones'
124 lines
5.0 KiB
Python
124 lines
5.0 KiB
Python
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 |