From ee8c0ad5a057b9e96afcaf55a5588c0584386ce9 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 21 Aug 2026 17:35:46 +0000 Subject: [PATCH] Filtrer le tableau de bord selon les permissions --- app_new/core/routes/dashboard.py | 132 +++++++++++++++---------- app_new/templates/dashboard/index.html | 86 ++++++++-------- 2 files changed, 128 insertions(+), 90 deletions(-) diff --git a/app_new/core/routes/dashboard.py b/app_new/core/routes/dashboard.py index b3a052c..9f9fc8f 100644 --- a/app_new/core/routes/dashboard.py +++ b/app_new/core/routes/dashboard.py @@ -13,6 +13,7 @@ from ..models.college import Building, Room from ..models.company import Part from app_new.constants import INTERVENTION_STATUSES, EQUIPMENT_STATUSES from sqlalchemy import func +from ..authorization import has_permission dashboard_bp = Blueprint('dashboard', __name__) @@ -25,20 +26,33 @@ def index(): from ..services.planning_service import PlanningService from ..models.planning import ScheduledTask, AdminTask from ..models.maintenance import Lot + + dashboard_permissions = { + 'intervention': has_permission('intervention.view', current_user), + 'intervention_manage': has_permission('intervention.manage', current_user), + 'patrimoine': has_permission('patrimoine.view', current_user), + 'planning': has_permission('planning.view', current_user), + 'planning_manage': has_permission('planning.manage', current_user), + 'stock': has_permission('stock.view', current_user), + 'prevention': has_permission('prevention.view', current_user), + 'ent': has_permission('integration.ent.view', current_user), + 'outlook': has_permission('integration.outlook.view', current_user), + 'ai': has_permission('system.configure', current_user), + } # Statistiques stats = { - 'interventions_total': Intervention.query.count(), - 'interventions_en_cours': Intervention.query.filter_by(status='en_cours').count(), - 'interventions_en_attente': Intervention.query.filter_by(status='en_attente').count(), - 'interventions_urgentes': Intervention.query.filter_by(priority='urgente', is_deleted=False).count(), - 'equipments_total': Equipment.query.count(), - 'equipments_actifs': Equipment.query.filter_by(status='en_service', is_deleted=False).count(), - 'equipments_panne': Equipment.query.filter(Equipment.status.in_(['en_panne', 'hors_service', 'hs']), Equipment.is_deleted.is_(False)).count(), - 'buildings_total': Building.query.count(), - 'rooms_total': Room.query.count(), - 'companies_total': Company.query.count(), - 'parts_low_stock': Part.query.filter(Part.quantity <= Part.min_quantity).count(), + 'interventions_total': Intervention.query.count() if dashboard_permissions['intervention'] else 0, + 'interventions_en_cours': Intervention.query.filter_by(status='en_cours').count() if dashboard_permissions['intervention'] else 0, + 'interventions_en_attente': Intervention.query.filter_by(status='en_attente').count() if dashboard_permissions['intervention'] else 0, + 'interventions_urgentes': Intervention.query.filter_by(priority='urgente', is_deleted=False).count() if dashboard_permissions['intervention'] else 0, + 'equipments_total': Equipment.query.count() if dashboard_permissions['patrimoine'] else 0, + 'equipments_actifs': Equipment.query.filter_by(status='en_service', is_deleted=False).count() if dashboard_permissions['patrimoine'] else 0, + 'equipments_panne': Equipment.query.filter(Equipment.status.in_(['en_panne', 'hors_service', 'hs']), Equipment.is_deleted.is_(False)).count() if dashboard_permissions['patrimoine'] else 0, + 'buildings_total': Building.query.count() if dashboard_permissions['patrimoine'] else 0, + 'rooms_total': Room.query.count() if dashboard_permissions['patrimoine'] else 0, + 'companies_total': Company.query.count() if dashboard_permissions['intervention'] else 0, + 'parts_low_stock': Part.query.filter(Part.quantity <= Part.min_quantity).count() if dashboard_permissions['stock'] else 0, } # Contrôle des lots : un lot présent doit être rattaché à au moins un @@ -52,8 +66,9 @@ def index(): ) .group_by(Equipment.lot_id) .all() + if dashboard_permissions['patrimoine'] else {} ) - lots = Lot.query.order_by(Lot.name).all() + lots = Lot.query.order_by(Lot.name).all() if dashboard_permissions['patrimoine'] else [] lots_without_equipment = [ lot for lot in lots if lot.is_present and equipment_counts.get(lot.id, 0) == 0 @@ -77,14 +92,14 @@ def index(): stats['lots_missing_duration'] = len(lots_missing_duration) # Dernières interventions - recent_interventions = Intervention.query.order_by(Intervention.created_at.desc()).limit(10).all() + recent_interventions = Intervention.query.order_by(Intervention.created_at.desc()).limit(10).all() if dashboard_permissions['intervention'] else [] # Interventions urgentes - urgent_interventions = Intervention.query.filter_by(priority='urgente', is_deleted=False).limit(5).all() + urgent_interventions = Intervention.query.filter_by(priority='urgente', is_deleted=False).limit(5).all() if dashboard_permissions['intervention'] else [] # Interventions du jour (planning) today = date.today() - day_schedule = PlanningService.get_day_schedule(today) + day_schedule = PlanningService.get_day_schedule(today) if dashboard_permissions['planning'] else None # Interprétations en attente (non traitées) from ...outlook.models import OutlookMailInterpretation @@ -94,12 +109,12 @@ def index(): outlook_interpretations = OutlookMailInterpretation.query.filter_by( status='pending', user_id=current_user.id - ).order_by(OutlookMailInterpretation.created_at.desc()).limit(10).all() + ).order_by(OutlookMailInterpretation.created_at.desc()).limit(10).all() if dashboard_permissions['outlook'] else [] # Récupérer les interprétations ENT ent_interpretations = EntMessageInterpretation.query.filter_by( status='pending' - ).order_by(EntMessageInterpretation.created_at.desc()).limit(10).all() + ).order_by(EntMessageInterpretation.created_at.desc()).limit(10).all() if dashboard_permissions['ent'] else [] # Combiner les deux listes avec une source pending_interpretations = [] @@ -148,7 +163,8 @@ def index(): lots_without_equipment=lots_without_equipment, lots_missing_duration=lots_missing_duration, today=today, - statuses=INTERVENTION_STATUSES) + statuses=INTERVENTION_STATUSES, + dashboard_permissions=dashboard_permissions) @dashboard_bp.route('/api/stats') @@ -158,28 +174,33 @@ def api_stats(): from datetime import date, timedelta from sqlalchemy import func + can_intervention = has_permission('intervention.view', current_user) + can_patrimoine = has_permission('patrimoine.view', current_user) + # Interventions par mois (6 derniers mois) six_months_ago = date.today() - timedelta(days=180) monthly = db.session.query( func.date_format(Intervention.created_at, '%Y-%m').label('month'), func.count().label('count') - ).filter(Intervention.created_at >= six_months_ago).group_by('month').order_by('month').all() + ).filter(Intervention.created_at >= six_months_ago).group_by('month').order_by('month').all() if can_intervention else [] monthly_data = [{'month': r.month, 'count': r.count} for r in monthly] # Interventions par statut status_data = {} - for status_val, info in INTERVENTION_STATUSES.items(): - count = Intervention.query.filter_by(status=status_val).count() - if count > 0: - status_data[info['label']] = count + if can_intervention: + for status_val, info in INTERVENTION_STATUSES.items(): + count = Intervention.query.filter_by(status=status_val).count() + if count > 0: + status_data[info['label']] = count # Equipements par statut equip_status = {} - for s in EQUIPMENT_STATUSES: - count = Equipment.query.filter_by(status=s).count() - if count > 0: - equip_status[s] = count + if can_patrimoine: + for s in EQUIPMENT_STATUSES: + count = Equipment.query.filter_by(status=s).count() + if count > 0: + equip_status[s] = count # Top 5 equipements les plus intervenus top_equip = db.session.query( @@ -188,7 +209,7 @@ def api_stats(): ).join(Intervention, Intervention.equipment_id == Equipment.id)\ .group_by(Equipment.id)\ .order_by(func.count(Intervention.id).desc())\ - .limit(5).all() + .limit(5).all() if can_intervention and can_patrimoine else [] top_data = [{'name': r.name, 'count': r.count} for r in top_equip] @@ -213,26 +234,26 @@ def search(): } if query: - # Recherche interventions - results['interventions'] = Intervention.query.filter( - db.or_( - Intervention.title.ilike(f'%{query}%'), - Intervention.description.ilike(f'%{query}%') - ) - ).limit(10).all() + if has_permission('intervention.view', current_user): + results['interventions'] = Intervention.query.filter( + db.or_( + Intervention.title.ilike(f'%{query}%'), + Intervention.description.ilike(f'%{query}%') + ) + ).limit(10).all() - # Recherche équipements - results['equipments'] = Equipment.query.filter( - db.or_( - Equipment.name.ilike(f'%{query}%'), - Equipment.serial_number.ilike(f'%{query}%') - ) - ).limit(10).all() + if has_permission('patrimoine.view', current_user): + results['equipments'] = Equipment.query.filter( + db.or_( + Equipment.name.ilike(f'%{query}%'), + Equipment.serial_number.ilike(f'%{query}%') + ) + ).limit(10).all() - # Recherche salles - results['rooms'] = Room.query.filter( - Room.name.ilike(f'%{query}%') - ).limit(10).all() + if has_permission('patrimoine.view', current_user): + results['rooms'] = Room.query.filter( + Room.name.ilike(f'%{query}%') + ).limit(10).all() return render_template('dashboard/search.html', query=query, results=results) @@ -245,31 +266,36 @@ def alerts(): from app_new.core.models.company import Alert alerts_list = Alert.query.filter_by(is_read=False).order_by(Alert.created_at.desc()).all() + can_intervention = has_permission('intervention.view', current_user) + can_patrimoine = has_permission('patrimoine.view', current_user) + can_outlook = has_permission('integration.outlook.view', current_user) + can_ent = has_permission('integration.ent.view', current_user) + # Interventions urgentes (statut haute priorité) urgent_interventions = Intervention.query.filter( Intervention.priority == 'haute', Intervention.status.in_(['planifiee', 'en_cours', 'en_attente']) - ).order_by(Intervention.scheduled_date.desc()).all() + ).order_by(Intervention.scheduled_date.desc()).all() if can_intervention else [] # Équipements en panne from app_new.core.models.equipment import Equipment equipments_panne = Equipment.query.filter( Equipment.status.in_(['en_panne', 'hors_service', 'hs']), Equipment.is_deleted.is_(False), - ).all() + ).all() if can_patrimoine else [] # Équipements à jeter - equipments_to_trash = Equipment.query.filter_by(status='a_jeter').all() + equipments_to_trash = Equipment.query.filter_by(status='a_jeter').all() if can_patrimoine else [] # Interprétations en attente from ...outlook.models import OutlookMailInterpretation from ...ent.interpretation_models import EntMessageInterpretation pending_outlook = OutlookMailInterpretation.query.filter_by( status='pending', user_id=current_user.id - ).order_by(OutlookMailInterpretation.created_at.desc()).all() + ).order_by(OutlookMailInterpretation.created_at.desc()).all() if can_outlook else [] pending_ent = EntMessageInterpretation.query.filter_by( status='pending' - ).order_by(EntMessageInterpretation.created_at.desc()).all() + ).order_by(EntMessageInterpretation.created_at.desc()).all() if can_ent else [] return render_template('dashboard/alerts.html', alerts=alerts_list, @@ -301,6 +327,10 @@ def create_month_interventions(): from ..models.maintenance import Intervention from ..models.company import Company from flask_login import current_user + + if not (has_permission('planning.manage', current_user) or has_permission('intervention.manage', current_user)): + from flask import abort + abort(403) today = date.today() one_month_later = today + timedelta(days=30) diff --git a/app_new/templates/dashboard/index.html b/app_new/templates/dashboard/index.html index f5ffda3..f4e0e36 100644 --- a/app_new/templates/dashboard/index.html +++ b/app_new/templates/dashboard/index.html @@ -11,33 +11,35 @@ {% block content %}

Tableau de bord

- +{% if dashboard_permissions.ai %} +{% endif %} - +{% if dashboard_permissions.planning %} +{% endif %}
-
+ {% if dashboard_permissions.intervention_manage or dashboard_permissions.planning_manage %}
-
+
{% endif %} -
+ {% if dashboard_permissions.intervention %}
Interventions @@ -45,8 +47,8 @@ {{ stats.interventions_en_cours }} en cours
-
-
+
{% endif %} + {% if dashboard_permissions.intervention %}
Curatif / Préventif @@ -54,8 +56,8 @@ {{ stats.interventions_recurrentes }} récurrentes
-
-
+
{% endif %} + {% if dashboard_permissions.patrimoine %}
Équipements @@ -63,8 +65,8 @@ {{ stats.equipments_hors_service }} hors service
-
-
+
{% endif %} + {% if dashboard_permissions.stock %}
Stock bas @@ -72,10 +74,10 @@ pièce(s)
-
+
{% endif %}
- +{% if dashboard_permissions.planning %}
- +{% endif %} - +{% if dashboard_permissions.patrimoine %}
@@ -177,9 +179,9 @@
- +{% endif %} - +{% if dashboard_permissions.intervention or dashboard_permissions.patrimoine or dashboard_permissions.ent or dashboard_permissions.outlook %} {% if alerts %}
@@ -196,9 +198,9 @@ {% endif %}
-{% endif %} +{% endif %}{% endif %} - +{% if dashboard_permissions.planning %} {% if day_schedule and day_schedule.items %}
@@ -299,9 +301,9 @@

{{ day_schedule.leave }}

-{% endif %} +{% endif %}{% endif %} - +{% if dashboard_permissions.planning %}
@@ -376,9 +378,9 @@
- +{% endif %} - +{% if dashboard_permissions.intervention %}
@@ -433,39 +435,40 @@
- +{% endif %} - +{% if dashboard_permissions.intervention or dashboard_permissions.patrimoine %}
-
+ {% if dashboard_permissions.intervention %}
Interventions par mois
-
-
+
{% endif %} + {% if dashboard_permissions.intervention %}
Interventions par statut
-
-
-
-
+
{% endif %} +
{% endif %} +{% if dashboard_permissions.patrimoine or (dashboard_permissions.intervention and dashboard_permissions.patrimoine) %}
+ {% if dashboard_permissions.patrimoine %}
Equipements par statut
-
-
+
{% endif %} + {% if dashboard_permissions.intervention and dashboard_permissions.patrimoine %}
Top 5 equipements
-
+
{% endif %}
+{% endif %} - +{% if dashboard_permissions.intervention %}
Dernières interventions @@ -516,10 +519,10 @@
Aucune intervention.
{% endif %}
-
+ {% endif %} -{% if pending_interpretations %} +{% if pending_interpretations and (dashboard_permissions.ent or dashboard_permissions.outlook) %}
Interprétations en attente {{ pending_interpretations|length }} @@ -684,7 +687,8 @@ document.addEventListener('DOMContentLoaded', function() { }); - +{% endif %} {% endblock %}