from flask import Blueprint, jsonify, request, current_app from models import db, Domain from app_config import config_manager from utils import handle_db_errors bp = Blueprint('domains', __name__, url_prefix='/api/domains') @bp.route('/', methods=['GET']) @handle_db_errors def list_domains(): """Liste tous les domaines disponibles.""" domains = config_manager.get_domains_list() return jsonify({'success': True, 'domains': domains}) @bp.route('/', methods=['POST']) @handle_db_errors def create_domain(): """Crée un nouveau domaine dynamiquement.""" data = request.get_json() if not data or not data.get('name'): return jsonify({'success': False, 'error': 'Nom du domaine requis'}), 400 name = data['name'].strip() color = data.get('color', '#6B7280') description = data.get('description', '') # Vérifier que le domaine n'existe pas déjà if Domain.query.filter_by(name=name).first(): return jsonify({'success': False, 'error': 'Un domaine avec ce nom existe déjà'}), 400 success = config_manager.add_domain(name, color, description) if success: # Récupérer le domaine créé domain = Domain.query.filter_by(name=name).first() return jsonify({ 'success': True, 'domain': { 'id': domain.id, 'name': domain.name, 'color': domain.color, 'description': domain.description or '' } }) else: return jsonify({'success': False, 'error': 'Erreur lors de la création du domaine'}), 500 @bp.route('/search', methods=['GET']) @handle_db_errors def search_domains(): """Recherche des domaines avec autocomplétion avancée.""" query = request.args.get('q', '').strip() if not query or len(query) < 1: return jsonify({'success': True, 'domains': []}) # Utiliser la recherche directe en base pour plus d'efficacité domains_query = Domain.query.filter( Domain.name.ilike(f'%{query}%') ).order_by( # Prioriser les correspondances exactes, puis celles qui commencent par la requête db.case( (Domain.name.ilike(query), 1), (Domain.name.ilike(f'{query}%'), 2), else_=3 ), Domain.name.asc() ).limit(8) domains = domains_query.all() # Convertir en format JSON domains_data = [{ 'id': domain.id, 'name': domain.name, 'color': domain.color, 'description': domain.description or '' } for domain in domains] return jsonify({'success': True, 'domains': domains_data}) @bp.route('/', methods=['PUT']) @handle_db_errors def update_domain(domain_id): """Met à jour un domaine existant.""" data = request.get_json() domain = Domain.query.get_or_404(domain_id) if data.get('name'): domain.name = data['name'].strip() if data.get('color'): domain.color = data['color'] if 'description' in data: domain.description = data['description'] try: db.session.commit() return jsonify({'success': True}) except Exception as e: db.session.rollback() current_app.logger.error(f"Erreur lors de la mise à jour du domaine: {e}") return jsonify({'success': False, 'error': 'Erreur lors de la sauvegarde'}), 500 @bp.route('/', methods=['DELETE']) @handle_db_errors def delete_domain(domain_id): """Supprime un domaine (si non utilisé).""" domain = Domain.query.get_or_404(domain_id) # Vérifier que le domaine n'est pas utilisé if domain.grading_elements: return jsonify({ 'success': False, 'error': f'Ce domaine est utilisé par {len(domain.grading_elements)} éléments de notation' }), 400 try: db.session.delete(domain) db.session.commit() return jsonify({'success': True}) except Exception as e: db.session.rollback() current_app.logger.error(f"Erreur lors de la suppression du domaine: {e}") return jsonify({'success': False, 'error': 'Erreur lors de la suppression'}), 500 @bp.route('//usage', methods=['GET']) @handle_db_errors def domain_usage(domain_id): """Récupère les informations d'utilisation d'un domaine.""" domain = Domain.query.get_or_404(domain_id) # Compter les éléments de notation utilisant ce domaine elements_count = len(domain.grading_elements) # Récupérer les évaluations concernées assessments = set() for element in domain.grading_elements: assessments.add(element.exercise.assessment) return jsonify({ 'success': True, 'usage': { 'elements_count': elements_count, 'assessments_count': len(assessments), 'assessments': [ { 'id': assessment.id, 'title': assessment.title, 'class_name': assessment.class_group.name } for assessment in assessments ] } })