gmao/app_new/__init__.py
root ed6675b9d3
Some checks are pending
CI - Tests et Syntax / lint-and-test (push) Waiting to run
Structure le suivi de la prévention et du DUERP
2026-08-14 21:43:13 +00:00

254 lines
9.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
GMAO Collège - Application Flask Modulaire
Structure par domaine métier
"""
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_migrate import Migrate
from flask_wtf.csrf import CSRFProtect
from datetime import timedelta
import os
import json
# Extensions (définies dans extensions.py)
from .extensions import db, login_manager, migrate, csrf
# Import all models to register them in SQLAlchemy metadata
from .core import models
def create_app(config_name='default'):
"""Factory pour créer l'application Flask."""
# Chemin absolu vers le répertoire app_new
app_dir = os.path.dirname(os.path.abspath(__file__))
# Chemins absolus pour templates et instance
template_dir = os.path.join(app_dir, 'templates')
instance_dir = os.path.join(app_dir, 'instance')
# Créer le dossier instance s'il n'existe pas
os.makedirs(instance_dir, exist_ok=True)
# Charger les variables d'environnement depuis .env AVANT la config
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__,
instance_path=instance_dir,
instance_relative_config=True,
template_folder=template_dir,
static_folder=os.path.join(app_dir, 'static'))
# Tolerer les slashs finaux dans les URLs
app.url_map.strict_slashes = False
# Configuration
from .config import config as config_dict
config_class = config_dict[config_name]
app.config.from_object(config_class)
config_class.init_app(app)
# Initialisation des extensions
db.init_app(app)
login_manager.init_app(app)
migrate.init_app(app, db)
csrf.init_app(app)
from .core.authorization import enforce_route_permission, has_permission
app.before_request(enforce_route_permission)
app.jinja_env.globals["has_permission"] = has_permission
from .core.audit import record_mutation
app.after_request(record_mutation)
# Configuration du login manager
login_manager.login_view = 'auth.login'
login_manager.login_message = 'Veuillez vous connecter pour accéder à cette page.'
login_manager.login_message_category = 'warning'
# Import des modèles AVANT les blueprints
from .core import models as core_models
from .pronote import models as pronote_models
from .ent import models as ent_models
from .outlook import models as outlook_models
from .yeastar import models as yeastar_models
# Enregistrement des blueprints
from .core.routes import auth_bp, admin_bp, dashboard_bp, setup_wizard_bp
app.register_blueprint(auth_bp, url_prefix='/auth')
app.register_blueprint(admin_bp, url_prefix='/admin')
app.register_blueprint(dashboard_bp, url_prefix='/')
app.register_blueprint(setup_wizard_bp, url_prefix='/setup-wizard')
# Blueprints des modules métier
from .equipments.routes import (
equipments_bp, meters_bp, documents_bp, restrictions_bp, scheduled_bp
)
from .equipments.buildings import buildings_bp
from .equipments.zones import zones_bp
from .equipments.rooms import rooms_bp
app.register_blueprint(equipments_bp, url_prefix='/equipments')
app.register_blueprint(buildings_bp, url_prefix='/equipments/buildings')
app.register_blueprint(zones_bp, url_prefix='/equipments/zones')
app.register_blueprint(rooms_bp, url_prefix='/equipments/rooms')
app.register_blueprint(meters_bp, url_prefix='/equipments')
app.register_blueprint(documents_bp, url_prefix='/equipments')
app.register_blueprint(restrictions_bp, url_prefix='/equipments')
app.register_blueprint(scheduled_bp, url_prefix='/equipments')
from .interventions.routes import interventions_bp, interventions_planning_bp
app.register_blueprint(interventions_bp, url_prefix='/interventions')
app.register_blueprint(interventions_planning_bp, url_prefix='/interventions')
from .planning.routes import planning_bp
app.register_blueprint(planning_bp, url_prefix='/planning')
from .companies.routes import companies_bp
app.register_blueprint(companies_bp, url_prefix='/companies')
from .lots.routes import lots_bp
app.register_blueprint(lots_bp, url_prefix='/lots')
from .training.routes import training_bp
app.register_blueprint(training_bp, url_prefix='/training')
from .meters.routes import meters_bp
app.register_blueprint(meters_bp, url_prefix='/meters')
from .parts.routes import parts_bp
app.register_blueprint(parts_bp, url_prefix='/parts')
from .services_module.routes import services_bp
app.register_blueprint(services_bp, url_prefix='/services')
from .room_types.routes import room_types_bp
app.register_blueprint(room_types_bp, url_prefix='/room-types')
from .documents.routes import documents_bp
app.register_blueprint(documents_bp, url_prefix='/documents')
from .gmao_config.routes import gmao_config_bp
app.register_blueprint(gmao_config_bp, url_prefix='/gmao-config')
from .wizard.routes import wizard_bp
app.register_blueprint(wizard_bp)
from .housing import housing_bp
app.register_blueprint(housing_bp, url_prefix='/housing')
from .prevention import prevention_bp
app.register_blueprint(prevention_bp, url_prefix='/prevention')
# Blueprints des intégrations
from .pronote.routes import pronote_bp
app.register_blueprint(pronote_bp, url_prefix='/pronote')
from .ent.routes import ent_bp
app.register_blueprint(ent_bp, url_prefix='/ent')
from .outlook.routes import outlook_bp, outlook_auth_bp, outlook_sync_bp, outlook_dashboard_bp
app.register_blueprint(outlook_bp, url_prefix='/outlook')
app.register_blueprint(outlook_auth_bp, url_prefix='/outlook')
app.register_blueprint(outlook_sync_bp, url_prefix='/outlook')
app.register_blueprint(outlook_dashboard_bp, url_prefix='/outlook')
from .yeastar.routes import yeastar_bp
app.register_blueprint(yeastar_bp, url_prefix='/yeastar')
from .chatbot.routes import chatbot_bp
app.register_blueprint(chatbot_bp, url_prefix='/chatbot')
# Blueprint status systeme
from .status.routes import status_bp
app.register_blueprint(status_bp)
from .health import health_bp
app.register_blueprint(health_bp)
# Logs centralises des watchdogs
from .logs.routes import logs_bp
app.register_blueprint(logs_bp)
# API REST v1
from .api.routes import api_bp
app.register_blueprint(api_bp)
csrf.exempt(api_bp)
# Notifications temps reel
from .notifications.routes import notifications_bp
app.register_blueprint(notifications_bp)
# Exports PDF/CSV
from .exports.routes import exports_bp
app.register_blueprint(exports_bp)
# Messagerie unifiee
from .messagerie.routes import messagerie_bp
app.register_blueprint(messagerie_bp)
# Contrats d'entreprise
from .contracts.models import Contract
from .contracts.routes import contracts_bp
app.register_blueprint(contracts_bp)
# Configuration IA (OpenRouter)
from .ai_config.routes import ai_config_bp
app.register_blueprint(ai_config_bp)
# Contraintes de zone
from .constraints.routes import constraints_bp
app.register_blueprint(constraints_bp)
# Planificateur automatique
from .scheduler.routes import scheduler_bp
app.register_blueprint(scheduler_bp)
# Filtres Jinja2 pour les templates
from .utils import format_status, status_badge_class, priority_badge_class, bootstrap_color_to_hex, bootstrap_text_color
app.jinja_env.filters["date_fmt"] = lambda value: value.strftime("%d/%m/%Y") if value else ""
app.jinja_env.filters["datetime_fmt"] = lambda value: value.strftime("%d/%m/%Y %H:%M") if value else ""
app.jinja_env.filters["format_status"] = format_status
app.jinja_env.filters["status_badge"] = status_badge_class
app.jinja_env.filters["priority_badge"] = priority_badge_class
app.jinja_env.filters["from_json"] = lambda value: json.loads(value) if value else []
app.jinja_env.filters["hex_color"] = bootstrap_color_to_hex
app.jinja_env.filters["text_color"] = bootstrap_text_color
app.jinja_env.globals["timedelta"] = timedelta
# Gestionnaires d'erreurs personnalisées
@app.errorhandler(404)
def not_found_error(e):
return render_template('errors/error.html',
error_code='404',
error_title='Page non trouvée',
error_message='La page demandée nexiste pas ou a été déplacée.'), 404
@app.errorhandler(500)
def internal_error(e):
try:
db.session.rollback()
except Exception:
pass
return render_template('errors/error.html',
error_code='500',
error_title='Erreur serveur',
error_message='Une erreur est survenue. Elle a été signalée automatiquement.'), 500
@app.errorhandler(403)
def forbidden_error(e):
return render_template('errors/error.html',
error_code='403',
error_title='Accès refusé',
error_message='Vous navez pas les droits nécessaires pour accéder à cette page.'), 403
return app
# User loader pour Flask-Login
@login_manager.user_loader
def load_user(user_id):
"""Charge un utilisateur par son ID."""
from .core.models.user import User
return User.query.get(int(user_id))