190 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify, current_app
 | |
| from models import db, Assessment, ClassGroup
 | |
| from forms import AssessmentForm
 | |
| from services import AssessmentService
 | |
| from utils import handle_db_errors, ValidationError
 | |
| from datetime import datetime
 | |
| 
 | |
| bp = Blueprint('assessments', __name__, url_prefix='/assessments')
 | |
| 
 | |
| @bp.route('/')
 | |
| @handle_db_errors
 | |
| def list():
 | |
|     from sqlalchemy.orm import joinedload
 | |
|     
 | |
|     # Récupérer les paramètres de filtrage
 | |
|     trimester_filter = request.args.get('trimester', '')
 | |
|     class_filter = request.args.get('class', '')
 | |
|     sort_by = request.args.get('sort', 'date_desc')
 | |
|     
 | |
|     # Construire la requête de base
 | |
|     query = Assessment.query.options(joinedload(Assessment.class_group))
 | |
|     
 | |
|     # Appliquer les filtres
 | |
|     if trimester_filter:
 | |
|         query = query.filter(Assessment.trimester == int(trimester_filter))
 | |
|     
 | |
|     if class_filter:
 | |
|         query = query.filter(Assessment.class_group_id == int(class_filter))
 | |
|     
 | |
|     # Appliquer le tri
 | |
|     if sort_by == 'date_desc':
 | |
|         query = query.order_by(Assessment.date.desc())
 | |
|     elif sort_by == 'date_asc':
 | |
|         query = query.order_by(Assessment.date.asc())
 | |
|     elif sort_by == 'title':
 | |
|         query = query.order_by(Assessment.title.asc())
 | |
|     elif sort_by == 'class':
 | |
|         query = query.join(ClassGroup).order_by(ClassGroup.name.asc())
 | |
|     
 | |
|     assessments = query.all()
 | |
|     
 | |
|     # Récupérer toutes les classes pour le filtre
 | |
|     classes = ClassGroup.query.order_by(ClassGroup.name.asc()).all()
 | |
|     
 | |
|     return render_template('assessments.html', 
 | |
|                          assessments=assessments, 
 | |
|                          classes=classes,
 | |
|                          current_trimester=trimester_filter,
 | |
|                          current_class=class_filter,
 | |
|                          current_sort=sort_by)
 | |
| 
 | |
| # Route obsolète supprimée - utiliser new_unified à la place
 | |
| 
 | |
| @bp.route('/<int:id>')
 | |
| @handle_db_errors
 | |
| def detail(id):
 | |
|     from sqlalchemy.orm import joinedload
 | |
|     from models import Exercise, GradingElement
 | |
|     assessment = Assessment.query.options(
 | |
|         joinedload(Assessment.class_group),
 | |
|         joinedload(Assessment.exercises).joinedload(Exercise.grading_elements)
 | |
|     ).get_or_404(id)
 | |
|     return render_template('assessment_detail.html', assessment=assessment)
 | |
| 
 | |
| def _handle_unified_assessment_request(form, assessment=None, is_edit=False):
 | |
|     """Fonction helper pour traiter les requêtes JSON d'évaluation unifiée"""
 | |
|     # Ne traiter que les requêtes POST
 | |
|     if request.method != 'POST':
 | |
|         return None
 | |
|         
 | |
|     if request.is_json:
 | |
|         try:
 | |
|             data = request.get_json()
 | |
|             if not data:
 | |
|                 return jsonify({'success': False, 'error': 'Aucune donnée fournie'}), 400
 | |
|             
 | |
|             # Peupler le formulaire pour validation CSRF
 | |
|             form.csrf_token.data = data.get('csrf_token')
 | |
|             
 | |
|             # Traitement via le service
 | |
|             if is_edit and assessment:
 | |
|                 processed_assessment = AssessmentService.process_assessment_with_exercises(
 | |
|                     data, is_edit=True, existing_assessment=assessment
 | |
|                 )
 | |
|             else:
 | |
|                 processed_assessment = AssessmentService.process_assessment_with_exercises(data)
 | |
|             
 | |
|             db.session.commit()
 | |
|             flash('Évaluation ' + ('modifiée' if is_edit else 'créée') + ' avec succès !', 'success')
 | |
|             return jsonify({'success': True, 'assessment_id': processed_assessment.id})
 | |
|             
 | |
|         except ValidationError as e:
 | |
|             current_app.logger.warning(f'Erreur de validation: {e}')
 | |
|             return jsonify({'success': False, 'error': str(e)}), 400
 | |
|         except ValueError as e:
 | |
|             current_app.logger.warning(f'Erreur de données: {e}')
 | |
|             return jsonify({'success': False, 'error': str(e)}), 400
 | |
|             
 | |
|     else:  # request.method == 'POST' and not request.is_json
 | |
|         # Traitement classique du formulaire (fallback)
 | |
|         if form.validate_on_submit():
 | |
|             if is_edit and assessment:
 | |
|                 AssessmentService.update_assessment_basic_info(assessment, {
 | |
|                     'title': form.title.data,
 | |
|                     'description': form.description.data,
 | |
|                     'date': form.date.data,
 | |
|                     'trimester': form.trimester.data,
 | |
|                     'class_group_id': form.class_group_id.data,
 | |
|                     'coefficient': form.coefficient.data
 | |
|                 })
 | |
|             else:
 | |
|                 assessment = AssessmentService.create_assessment({
 | |
|                     'title': form.title.data,
 | |
|                     'description': form.description.data,
 | |
|                     'date': form.date.data,
 | |
|                     'trimester': form.trimester.data,
 | |
|                     'class_group_id': form.class_group_id.data,
 | |
|                     'coefficient': form.coefficient.data
 | |
|                 })
 | |
|             db.session.commit()
 | |
|             flash('Évaluation ' + ('modifiée' if is_edit else 'créée') + ' avec succès !', 'success')
 | |
|             return redirect(url_for('assessments.detail', id=assessment.id))
 | |
|     
 | |
|     return None
 | |
| 
 | |
| @bp.route('/<int:id>/edit', methods=['GET', 'POST'])
 | |
| @handle_db_errors
 | |
| def edit(id):
 | |
|     from sqlalchemy.orm import joinedload
 | |
|     from models import Exercise, GradingElement
 | |
|     assessment = Assessment.query.options(
 | |
|         joinedload(Assessment.class_group),
 | |
|         joinedload(Assessment.exercises).joinedload(Exercise.grading_elements)
 | |
|     ).get_or_404(id)
 | |
|     form = AssessmentForm(obj=assessment)
 | |
|     
 | |
|     result = _handle_unified_assessment_request(form, assessment, is_edit=True)
 | |
|     if result:
 | |
|         return result
 | |
|     
 | |
|     # Préparer les exercices pour la sérialisation JSON
 | |
|     exercises_data = []
 | |
|     for exercise in assessment.exercises:
 | |
|         exercise_data = {
 | |
|             'id': exercise.id,
 | |
|             'title': exercise.title,
 | |
|             'description': exercise.description or '',
 | |
|             'order': exercise.order,
 | |
|             'grading_elements': []
 | |
|         }
 | |
|         for element in exercise.grading_elements:
 | |
|             element_data = {
 | |
|                 'id': element.id,
 | |
|                 'label': element.label,
 | |
|                 'description': element.description or '',
 | |
|                 'skill': element.skill or '',
 | |
|                 'max_points': float(element.max_points),
 | |
|                 'grading_type': element.grading_type
 | |
|             }
 | |
|             exercise_data['grading_elements'].append(element_data)
 | |
|         exercises_data.append(exercise_data)
 | |
|     
 | |
|     return render_template('assessment_form_unified.html', 
 | |
|                          form=form, 
 | |
|                          title='Modifier l\'évaluation complète', 
 | |
|                          assessment=assessment, 
 | |
|                          exercises_json=exercises_data,
 | |
|                          is_edit=True)
 | |
| 
 | |
| @bp.route('/new', methods=['GET', 'POST'])
 | |
| @handle_db_errors
 | |
| def new():
 | |
|     form = AssessmentForm()
 | |
|     
 | |
|     result = _handle_unified_assessment_request(form, is_edit=False)
 | |
|     if result:
 | |
|         return result
 | |
|     
 | |
|     return render_template('assessment_form_unified.html', form=form, title='Nouvelle évaluation complète')
 | |
| 
 | |
| @bp.route('/<int:id>/delete', methods=['POST'])
 | |
| @handle_db_errors
 | |
| def delete(id):
 | |
|     assessment = Assessment.query.get_or_404(id)
 | |
|     title = assessment.title  # Conserver pour le log
 | |
|     db.session.delete(assessment)
 | |
|     db.session.commit()
 | |
|     current_app.logger.info(f'Évaluation supprimée: {title} (ID: {id})')
 | |
|     flash('Évaluation supprimée avec succès !', 'success')
 | |
|     return redirect(url_for('assessments.list')) |