refactor: restructure codebase into modular architecture
- Split monolithic app.py (400+ lines) into organized modules - Extract models, forms, and commands into separate files - Implement Flask blueprints for route organization - Maintain full functionality with cleaner architecture - Update all templates to use new blueprint URLs - Enhance README with technical documentation Structure: ├── app.py (50 lines) - Flask app factory ├── models.py (62 lines) - SQLAlchemy models ├── forms.py (43 lines) - WTForms definitions ├── commands.py (74 lines) - CLI commands └── routes/ - Blueprint modules for each feature 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		
							
								
								
									
										113
									
								
								routes/exercises.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								routes/exercises.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,113 @@ | ||||
| from flask import Blueprint, render_template, redirect, url_for, flash, request | ||||
| from models import db, Assessment, Exercise, GradingElement | ||||
| from forms import ExerciseForm, GradingElementForm | ||||
|  | ||||
| bp = Blueprint('exercises', __name__) | ||||
|  | ||||
| # Exercise routes | ||||
| @bp.route('/assessments/<int:assessment_id>/exercises/new', methods=['GET', 'POST']) | ||||
| def new(assessment_id): | ||||
|     assessment = Assessment.query.get_or_404(assessment_id) | ||||
|     form = ExerciseForm() | ||||
|      | ||||
|     # Set default order to next available | ||||
|     if form.order.data == 1:  # Only if it's the default value | ||||
|         max_order = db.session.query(db.func.max(Exercise.order)).filter_by(assessment_id=assessment_id).scalar() | ||||
|         form.order.data = (max_order or 0) + 1 | ||||
|      | ||||
|     if form.validate_on_submit(): | ||||
|         exercise = Exercise( | ||||
|             assessment_id=assessment_id, | ||||
|             title=form.title.data, | ||||
|             description=form.description.data, | ||||
|             order=form.order.data | ||||
|         ) | ||||
|         db.session.add(exercise) | ||||
|         db.session.commit() | ||||
|         flash('Exercice créé avec succès !', 'success') | ||||
|         return redirect(url_for('exercises.detail', assessment_id=assessment_id, id=exercise.id)) | ||||
|      | ||||
|     return render_template('exercise_form.html', form=form, assessment=assessment, title='Nouvel exercice') | ||||
|  | ||||
| @bp.route('/assessments/<int:assessment_id>/exercises/<int:id>') | ||||
| def detail(assessment_id, id): | ||||
|     assessment = Assessment.query.get_or_404(assessment_id) | ||||
|     exercise = Exercise.query.filter_by(id=id, assessment_id=assessment_id).first_or_404() | ||||
|     return render_template('exercise_detail.html', assessment=assessment, exercise=exercise) | ||||
|  | ||||
| @bp.route('/assessments/<int:assessment_id>/exercises/<int:id>/edit', methods=['GET', 'POST']) | ||||
| def edit(assessment_id, id): | ||||
|     assessment = Assessment.query.get_or_404(assessment_id) | ||||
|     exercise = Exercise.query.filter_by(id=id, assessment_id=assessment_id).first_or_404() | ||||
|     form = ExerciseForm(obj=exercise) | ||||
|      | ||||
|     if form.validate_on_submit(): | ||||
|         exercise.title = form.title.data | ||||
|         exercise.description = form.description.data | ||||
|         exercise.order = form.order.data | ||||
|         db.session.commit() | ||||
|         flash('Exercice modifié avec succès !', 'success') | ||||
|         return redirect(url_for('exercises.detail', assessment_id=assessment_id, id=exercise.id)) | ||||
|      | ||||
|     return render_template('exercise_form.html', form=form, assessment=assessment, exercise=exercise, title='Modifier l\'exercice') | ||||
|  | ||||
| @bp.route('/assessments/<int:assessment_id>/exercises/<int:id>/delete', methods=['POST']) | ||||
| def delete(assessment_id, id): | ||||
|     assessment = Assessment.query.get_or_404(assessment_id) | ||||
|     exercise = Exercise.query.filter_by(id=id, assessment_id=assessment_id).first_or_404() | ||||
|     db.session.delete(exercise) | ||||
|     db.session.commit() | ||||
|     flash('Exercice supprimé avec succès !', 'success') | ||||
|     return redirect(url_for('assessments.detail', id=assessment_id)) | ||||
|  | ||||
| # GradingElement routes | ||||
| @bp.route('/assessments/<int:assessment_id>/exercises/<int:exercise_id>/elements/new', methods=['GET', 'POST']) | ||||
| def new_grading_element(assessment_id, exercise_id): | ||||
|     assessment = Assessment.query.get_or_404(assessment_id) | ||||
|     exercise = Exercise.query.filter_by(id=exercise_id, assessment_id=assessment_id).first_or_404() | ||||
|     form = GradingElementForm() | ||||
|      | ||||
|     if form.validate_on_submit(): | ||||
|         element = GradingElement( | ||||
|             exercise_id=exercise_id, | ||||
|             label=form.label.data, | ||||
|             description=form.description.data, | ||||
|             skill=form.skill.data, | ||||
|             max_points=form.max_points.data, | ||||
|             grading_type=form.grading_type.data | ||||
|         ) | ||||
|         db.session.add(element) | ||||
|         db.session.commit() | ||||
|         flash('Élément de notation créé avec succès !', 'success') | ||||
|         return redirect(url_for('exercises.detail', assessment_id=assessment_id, id=exercise_id)) | ||||
|      | ||||
|     return render_template('grading_element_form.html', form=form, assessment=assessment, exercise=exercise, title='Nouvel élément de notation') | ||||
|  | ||||
| @bp.route('/assessments/<int:assessment_id>/exercises/<int:exercise_id>/elements/<int:id>/edit', methods=['GET', 'POST']) | ||||
| def edit_grading_element(assessment_id, exercise_id, id): | ||||
|     assessment = Assessment.query.get_or_404(assessment_id) | ||||
|     exercise = Exercise.query.filter_by(id=exercise_id, assessment_id=assessment_id).first_or_404() | ||||
|     element = GradingElement.query.filter_by(id=id, exercise_id=exercise_id).first_or_404() | ||||
|     form = GradingElementForm(obj=element) | ||||
|      | ||||
|     if form.validate_on_submit(): | ||||
|         element.label = form.label.data | ||||
|         element.description = form.description.data | ||||
|         element.skill = form.skill.data | ||||
|         element.max_points = form.max_points.data | ||||
|         element.grading_type = form.grading_type.data | ||||
|         db.session.commit() | ||||
|         flash('Élément de notation modifié avec succès !', 'success') | ||||
|         return redirect(url_for('exercises.detail', assessment_id=assessment_id, id=exercise_id)) | ||||
|      | ||||
|     return render_template('grading_element_form.html', form=form, assessment=assessment, exercise=exercise, element=element, title='Modifier l\'élément de notation') | ||||
|  | ||||
| @bp.route('/assessments/<int:assessment_id>/exercises/<int:exercise_id>/elements/<int:id>/delete', methods=['POST']) | ||||
| def delete_grading_element(assessment_id, exercise_id, id): | ||||
|     assessment = Assessment.query.get_or_404(assessment_id) | ||||
|     exercise = Exercise.query.filter_by(id=exercise_id, assessment_id=assessment_id).first_or_404() | ||||
|     element = GradingElement.query.filter_by(id=id, exercise_id=exercise_id).first_or_404() | ||||
|     db.session.delete(element) | ||||
|     db.session.commit() | ||||
|     flash('Élément de notation supprimé avec succès !', 'success') | ||||
|     return redirect(url_for('exercises.detail', assessment_id=assessment_id, id=exercise_id)) | ||||
		Reference in New Issue
	
	Block a user