326 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from typing import Dict, Any, Optional, List
 | |
| from flask import current_app
 | |
| from models import db, AppConfig, CompetenceScaleValue, Competence
 | |
| 
 | |
| class ConfigManager:
 | |
|     """Gestionnaire de configuration de l'application Notytex utilisant SQLAlchemy."""
 | |
|     
 | |
|     @property
 | |
|     def default_config(self) -> Dict[str, Any]:
 | |
|         """Configuration par défaut de l'application."""
 | |
|         return {
 | |
|             'context': {
 | |
|                 'school_year': '2025-2026'
 | |
|             },
 | |
|             'evaluations': {
 | |
|                 'default_grading_system': 'competences',
 | |
|                 'competence_scale': {
 | |
|                     'values': {
 | |
|                         '0': {
 | |
|                             'label': 'A revoir',
 | |
|                             'color': '#ef4444',
 | |
|                             'included_in_total': True
 | |
|                         },
 | |
|                         '1': {
 | |
|                             'label': 'Des choses justes',
 | |
|                             'color': '#f6d32d',
 | |
|                             'included_in_total': True
 | |
|                         },
 | |
|                         '2': {
 | |
|                             'label': 'Globalement ok',
 | |
|                             'color': '#8ff0a4',
 | |
|                             'included_in_total': True
 | |
|                         },
 | |
|                         '3': {
 | |
|                             'label': 'Parfait',
 | |
|                             'color': '#008000',
 | |
|                             'included_in_total': True
 | |
|                         },
 | |
|                         '.': {
 | |
|                             'label': 'Pas de réponse',
 | |
|                             'color': '#6b7280',
 | |
|                             'included_in_total': True
 | |
|                         },
 | |
|                         'd': {
 | |
|                             'label': 'Dispensé',
 | |
|                             'color': '#c0bfbc',
 | |
|                             'included_in_total': False
 | |
|                         }
 | |
|                     }
 | |
|                 },
 | |
|                 'competences': [
 | |
|                     {
 | |
|                         'name': 'Calculer',
 | |
|                         'color': '#3b82f6',
 | |
|                         'icon': 'calculator'
 | |
|                     },
 | |
|                     {
 | |
|                         'name': 'Raisonner',
 | |
|                         'color': '#8b5cf6',
 | |
|                         'icon': 'lightbulb'
 | |
|                     },
 | |
|                     {
 | |
|                         'name': 'Communiquer',
 | |
|                         'color': '#06b6d4',
 | |
|                         'icon': 'chat-bubble-left-right'
 | |
|                     },
 | |
|                     {
 | |
|                         'name': 'Modéliser',
 | |
|                         'color': '#10b981',
 | |
|                         'icon': 'cube'
 | |
|                     },
 | |
|                     {
 | |
|                         'name': 'Représenter',
 | |
|                         'color': '#f59e0b',
 | |
|                         'icon': 'chart-bar'
 | |
|                     },
 | |
|                     {
 | |
|                         'name': 'Chercher',
 | |
|                         'color': '#ef4444',
 | |
|                         'icon': 'magnifying-glass'
 | |
|                     }
 | |
|                 ]
 | |
|             }
 | |
|         }
 | |
|     
 | |
|     def initialize_default_config(self) -> None:
 | |
|         """Initialise la configuration par défaut en base de données si elle n'existe pas."""
 | |
|         # Configuration simple
 | |
|         for section, values in self.default_config.items():
 | |
|             if section == 'context':
 | |
|                 for key, value in values.items():
 | |
|                     config_key = f"{section}.{key}"
 | |
|                     if not AppConfig.query.filter_by(key=config_key).first():
 | |
|                         config = AppConfig(key=config_key, value=str(value))
 | |
|                         db.session.add(config)
 | |
|             elif section == 'evaluations':
 | |
|                 # Système de notation par défaut
 | |
|                 if 'default_grading_system' in values:
 | |
|                     config_key = f"{section}.default_grading_system"
 | |
|                     if not AppConfig.query.filter_by(key=config_key).first():
 | |
|                         config = AppConfig(key=config_key, value=values['default_grading_system'])
 | |
|                         db.session.add(config)
 | |
|         
 | |
|         # Échelle des compétences
 | |
|         if CompetenceScaleValue.query.count() == 0:
 | |
|             scale_values = self.default_config['evaluations']['competence_scale']['values']
 | |
|             for value, config in scale_values.items():
 | |
|                 scale_value = CompetenceScaleValue(
 | |
|                     value=value,
 | |
|                     label=config['label'],
 | |
|                     color=config['color'],
 | |
|                     included_in_total=config['included_in_total']
 | |
|                 )
 | |
|                 db.session.add(scale_value)
 | |
|         
 | |
|         # Compétences
 | |
|         if Competence.query.count() == 0:
 | |
|             competences = self.default_config['evaluations']['competences']
 | |
|             for i, comp in enumerate(competences):
 | |
|                 competence = Competence(
 | |
|                     name=comp['name'],
 | |
|                     color=comp['color'],
 | |
|                     icon=comp['icon'],
 | |
|                     order_index=i
 | |
|                 )
 | |
|                 db.session.add(competence)
 | |
|         
 | |
|         db.session.commit()
 | |
|     
 | |
|     def get(self, key_path: str, default: Any = None) -> Any:
 | |
|         """
 | |
|         Récupère une valeur de configuration.
 | |
|         
 | |
|         Args:
 | |
|             key_path: Chemin vers la valeur (ex: 'context.school_year')
 | |
|             default: Valeur par défaut si la clé n'existe pas
 | |
|             
 | |
|         Returns:
 | |
|             La valeur de configuration ou la valeur par défaut
 | |
|         """
 | |
|         # Configuration simple stockée dans AppConfig
 | |
|         config = AppConfig.query.filter_by(key=key_path).first()
 | |
|         if config:
 | |
|             return config.value
 | |
|         
 | |
|         # Valeurs par défaut pour les cas non trouvés
 | |
|         return self._get_default_value(key_path, default)
 | |
|     
 | |
|     def _get_default_value(self, key_path: str, fallback: Any) -> Any:
 | |
|         """Récupère une valeur par défaut depuis la configuration par défaut."""
 | |
|         if fallback is not None:
 | |
|             return fallback
 | |
|         
 | |
|         keys = key_path.split('.')
 | |
|         value = self.default_config
 | |
|         
 | |
|         try:
 | |
|             for key in keys:
 | |
|                 value = value[key]
 | |
|             return value
 | |
|         except (KeyError, TypeError):
 | |
|             return None
 | |
|     
 | |
|     def set(self, key_path: str, value: Any) -> None:
 | |
|         """
 | |
|         Définit une valeur de configuration.
 | |
|         
 | |
|         Args:
 | |
|             key_path: Chemin vers la valeur (ex: 'context.school_year')
 | |
|             value: Nouvelle valeur
 | |
|         """
 | |
|         config = AppConfig.query.filter_by(key=key_path).first()
 | |
|         if config:
 | |
|             config.value = str(value)
 | |
|         else:
 | |
|             config = AppConfig(key=key_path, value=str(value))
 | |
|             db.session.add(config)
 | |
|     
 | |
|     def save(self) -> bool:
 | |
|         """Sauvegarde la configuration en base de données."""
 | |
|         try:
 | |
|             db.session.commit()
 | |
|             return True
 | |
|         except Exception as e:
 | |
|             db.session.rollback()
 | |
|             print(f"Erreur lors de la sauvegarde de la configuration: {e}")
 | |
|             return False
 | |
|     
 | |
|     def get_competence_scale_values(self) -> Dict[str, Dict[str, Any]]:
 | |
|         """Récupère les valeurs de l'échelle des compétences."""
 | |
|         scale_values = CompetenceScaleValue.query.all()
 | |
|         result = {}
 | |
|         for scale_value in scale_values:
 | |
|             # Convertir en int si c'est un nombre, sinon garder string
 | |
|             key = int(scale_value.value) if scale_value.value.isdigit() else scale_value.value
 | |
|             result[key] = {
 | |
|                 'label': scale_value.label,
 | |
|                 'color': scale_value.color,
 | |
|                 'included_in_total': scale_value.included_in_total
 | |
|             }
 | |
|         return result
 | |
|     
 | |
|     def get_competences_list(self) -> List[Dict[str, Any]]:
 | |
|         """Récupère la liste des compétences configurées."""
 | |
|         competences = Competence.query.order_by(Competence.order_index).all()
 | |
|         return [
 | |
|             {
 | |
|                 'name': comp.name,
 | |
|                 'color': comp.color,
 | |
|                 'icon': comp.icon
 | |
|             }
 | |
|             for comp in competences
 | |
|         ]
 | |
|     
 | |
|     def get_school_year(self) -> str:
 | |
|         """Récupère l'année scolaire courante."""
 | |
|         return self.get('context.school_year', '2025-2026')
 | |
|     
 | |
|     def get_default_grading_system(self) -> str:
 | |
|         """Récupère le système de notation par défaut."""
 | |
|         return self.get('evaluations.default_grading_system', 'competences')
 | |
|     
 | |
|     # Méthodes spécifiques pour la gestion des compétences
 | |
|     
 | |
|     def add_competence(self, name: str, color: str, icon: str) -> bool:
 | |
|         """Ajoute une nouvelle compétence."""
 | |
|         try:
 | |
|             # Obtenir le prochain index d'ordre
 | |
|             max_order = db.session.query(db.func.max(Competence.order_index)).scalar() or 0
 | |
|             
 | |
|             competence = Competence(
 | |
|                 name=name,
 | |
|                 color=color,
 | |
|                 icon=icon,
 | |
|                 order_index=max_order + 1
 | |
|             )
 | |
|             db.session.add(competence)
 | |
|             db.session.commit()
 | |
|             return True
 | |
|         except Exception as e:
 | |
|             db.session.rollback()
 | |
|             print(f"Erreur lors de l'ajout de la compétence: {e}")
 | |
|             return False
 | |
|     
 | |
|     def update_competence(self, competence_id: int, name: str, color: str, icon: str) -> bool:
 | |
|         """Met à jour une compétence."""
 | |
|         try:
 | |
|             competence = Competence.query.get(competence_id)
 | |
|             if competence:
 | |
|                 competence.name = name
 | |
|                 competence.color = color
 | |
|                 competence.icon = icon
 | |
|                 db.session.commit()
 | |
|                 return True
 | |
|             return False
 | |
|         except Exception as e:
 | |
|             db.session.rollback()
 | |
|             print(f"Erreur lors de la mise à jour de la compétence: {e}")
 | |
|             return False
 | |
|     
 | |
|     def delete_competence(self, competence_id: int) -> bool:
 | |
|         """Supprime une compétence."""
 | |
|         try:
 | |
|             competence = Competence.query.get(competence_id)
 | |
|             if competence:
 | |
|                 db.session.delete(competence)
 | |
|                 db.session.commit()
 | |
|                 return True
 | |
|             return False
 | |
|         except Exception as e:
 | |
|             db.session.rollback()
 | |
|             print(f"Erreur lors de la suppression de la compétence: {e}")
 | |
|             return False
 | |
|     
 | |
|     # Méthodes spécifiques pour la gestion de l'échelle
 | |
|     
 | |
|     def add_scale_value(self, value: str, label: str, color: str, included_in_total: bool = True) -> bool:
 | |
|         """Ajoute une nouvelle valeur à l'échelle."""
 | |
|         try:
 | |
|             scale_value = CompetenceScaleValue(
 | |
|                 value=value,
 | |
|                 label=label,
 | |
|                 color=color,
 | |
|                 included_in_total=included_in_total
 | |
|             )
 | |
|             db.session.add(scale_value)
 | |
|             db.session.commit()
 | |
|             return True
 | |
|         except Exception as e:
 | |
|             db.session.rollback()
 | |
|             print(f"Erreur lors de l'ajout de la valeur d'échelle: {e}")
 | |
|             return False
 | |
|     
 | |
|     def update_scale_value(self, value: str, label: str, color: str, included_in_total: bool) -> bool:
 | |
|         """Met à jour une valeur de l'échelle."""
 | |
|         try:
 | |
|             scale_value = CompetenceScaleValue.query.get(value)
 | |
|             if scale_value:
 | |
|                 scale_value.label = label
 | |
|                 scale_value.color = color
 | |
|                 scale_value.included_in_total = included_in_total
 | |
|                 db.session.commit()
 | |
|                 return True
 | |
|             return False
 | |
|         except Exception as e:
 | |
|             db.session.rollback()
 | |
|             print(f"Erreur lors de la mise à jour de la valeur d'échelle: {e}")
 | |
|             return False
 | |
|     
 | |
|     def delete_scale_value(self, value: str) -> bool:
 | |
|         """Supprime une valeur de l'échelle."""
 | |
|         try:
 | |
|             scale_value = CompetenceScaleValue.query.get(value)
 | |
|             if scale_value:
 | |
|                 db.session.delete(scale_value)
 | |
|                 db.session.commit()
 | |
|                 return True
 | |
|             return False
 | |
|         except Exception as e:
 | |
|             db.session.rollback()
 | |
|             print(f"Erreur lors de la suppression de la valeur d'échelle: {e}")
 | |
|             return False
 | |
| 
 | |
| 
 | |
| # Instance globale de configuration
 | |
| config_manager = ConfigManager() |