Files
notytex/app_config.py

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()