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:
@@ -6,14 +6,14 @@
|
||||
<div class="space-y-6">
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<a href="{{ url_for('assessments') }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium mb-2 inline-block">
|
||||
<a href="{{ url_for('assessments.list') }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium mb-2 inline-block">
|
||||
← Retour aux évaluations
|
||||
</a>
|
||||
<h1 class="text-2xl font-bold text-gray-900">{{ assessment.title }}</h1>
|
||||
<p class="text-gray-600">{{ assessment.class_group.name }} - {{ assessment.date.strftime('%d/%m/%Y') }}</p>
|
||||
</div>
|
||||
<div class="flex space-x-3">
|
||||
<a href="{{ url_for('edit_assessment', id=assessment.id) }}" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-md text-sm font-medium transition-colors">
|
||||
<a href="{{ url_for('assessments.edit', id=assessment.id) }}" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-md text-sm font-medium transition-colors">
|
||||
Modifier
|
||||
</a>
|
||||
<button onclick="if(confirm('Êtes-vous sûr de vouloir supprimer cette évaluation ?')) { document.getElementById('delete-form').submit(); }"
|
||||
@@ -23,7 +23,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="delete-form" method="POST" action="{{ url_for('delete_assessment', id=assessment.id) }}" style="display: none;"></form>
|
||||
<form id="delete-form" method="POST" action="{{ url_for('assessments.delete', id=assessment.id) }}" style="display: none;"></form>
|
||||
|
||||
<!-- Informations de l'évaluation -->
|
||||
<div class="bg-white shadow rounded-lg">
|
||||
@@ -62,7 +62,7 @@
|
||||
<div class="bg-white shadow rounded-lg">
|
||||
<div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
|
||||
<h2 class="text-lg font-medium text-gray-900">Exercices</h2>
|
||||
<a href="{{ url_for('new_exercise', assessment_id=assessment.id) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md text-sm font-medium transition-colors">
|
||||
<a href="{{ url_for('exercises.new', assessment_id=assessment.id) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md text-sm font-medium transition-colors">
|
||||
Ajouter un exercice
|
||||
</a>
|
||||
</div>
|
||||
@@ -82,10 +82,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-2 ml-4">
|
||||
<a href="{{ url_for('exercise_detail', assessment_id=assessment.id, id=exercise.id) }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium">
|
||||
<a href="{{ url_for('exercises.detail', assessment_id=assessment.id, id=exercise.id) }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium">
|
||||
Voir détails
|
||||
</a>
|
||||
<a href="{{ url_for('edit_exercise', assessment_id=assessment.id, id=exercise.id) }}" class="text-gray-600 hover:text-gray-800 text-sm font-medium">
|
||||
<a href="{{ url_for('exercises.edit', assessment_id=assessment.id, id=exercise.id) }}" class="text-gray-600 hover:text-gray-800 text-sm font-medium">
|
||||
Modifier
|
||||
</a>
|
||||
</div>
|
||||
@@ -101,7 +101,7 @@
|
||||
<h3 class="mt-2 text-sm font-medium text-gray-900">Aucun exercice</h3>
|
||||
<p class="mt-1 text-sm text-gray-500">Commencez par ajouter le premier exercice de cette évaluation.</p>
|
||||
<div class="mt-6">
|
||||
<a href="{{ url_for('new_exercise', assessment_id=assessment.id) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md text-sm font-medium transition-colors">
|
||||
<a href="{{ url_for('exercises.new', assessment_id=assessment.id) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md text-sm font-medium transition-colors">
|
||||
Ajouter un exercice
|
||||
</a>
|
||||
</div>
|
||||
@@ -117,7 +117,7 @@
|
||||
</div>
|
||||
<div class="px-6 py-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<a href="{{ url_for('assessment_grading', assessment_id=assessment.id) }}" class="flex items-center justify-center px-4 py-3 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
<a href="{{ url_for('grading.assessment_grading', assessment_id=assessment.id) }}" class="flex items-center justify-center px-4 py-3 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
<svg class="w-5 h-5 mr-2 text-green-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H4a1 1 0 01-1-1V4zm0 4a1 1 0 011-1h12a1 1 0 011 1v6a1 1 0 01-1 1H4a1 1 0 01-1-1V8z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{% block content %}
|
||||
<div class="max-w-2xl mx-auto">
|
||||
<div class="mb-6">
|
||||
<a href="{{ url_for('assessments') }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium">
|
||||
<a href="{{ url_for('assessments.list') }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium">
|
||||
← Retour aux évaluations
|
||||
</a>
|
||||
</div>
|
||||
@@ -91,7 +91,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end space-x-3 pt-4 border-t border-gray-200">
|
||||
<a href="{{ url_for('assessments') }}" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
<a href="{{ url_for('assessments.list') }}" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
Annuler
|
||||
</a>
|
||||
{{ form.submit(class="px-4 py-2 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700 transition-colors") }}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="space-y-6">
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<a href="{{ url_for('assessment_detail', id=assessment.id) }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium mb-2 inline-block">
|
||||
<a href="{{ url_for('assessments.detail', id=assessment.id) }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium mb-2 inline-block">
|
||||
← Retour à l'évaluation
|
||||
</a>
|
||||
<h1 class="text-2xl font-bold text-gray-900">Saisie des notes</h1>
|
||||
@@ -28,7 +28,7 @@
|
||||
<p>Cette évaluation n'a pas encore d'éléments de notation configurés. Vous devez d'abord créer des exercices et leurs éléments de notation.</p>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<a href="{{ url_for('assessment_detail', id=assessment.id) }}" class="text-sm font-medium text-yellow-800 underline hover:text-yellow-900">
|
||||
<a href="{{ url_for('assessments.detail', id=assessment.id) }}" class="text-sm font-medium text-yellow-800 underline hover:text-yellow-900">
|
||||
Configurer l'évaluation →
|
||||
</a>
|
||||
</div>
|
||||
@@ -36,7 +36,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<form method="POST" action="{{ url_for('save_grades', assessment_id=assessment.id) }}" class="space-y-6">
|
||||
<form method="POST" action="{{ url_for('grading.save_grades', assessment_id=assessment.id) }}" class="space-y-6">
|
||||
<!-- Informations sur les types de notation -->
|
||||
<div class="bg-blue-50 border border-blue-200 rounded-md p-4">
|
||||
<h3 class="text-sm font-medium text-blue-900 mb-2">Guide de saisie</h3>
|
||||
@@ -117,7 +117,7 @@
|
||||
</div>
|
||||
|
||||
<div class="px-6 py-4 bg-gray-50 border-t border-gray-200 flex justify-end space-x-3">
|
||||
<a href="{{ url_for('assessment_detail', id=assessment.id) }}" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
<a href="{{ url_for('assessments.detail', id=assessment.id) }}" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
Annuler
|
||||
</a>
|
||||
<button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700 transition-colors">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="space-y-6">
|
||||
<div class="flex justify-between items-center">
|
||||
<h1 class="text-2xl font-bold text-gray-900">Gestion des évaluations</h1>
|
||||
<a href="{{ url_for('new_assessment') }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md transition-colors">
|
||||
<a href="{{ url_for('assessments.new') }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md transition-colors">
|
||||
Nouvelle évaluation
|
||||
</a>
|
||||
</div>
|
||||
@@ -42,13 +42,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
<a href="{{ url_for('assessment_detail', id=assessment.id) }}" class="text-indigo-600 hover:text-indigo-900 text-sm font-medium">
|
||||
<a href="{{ url_for('assessments.detail', id=assessment.id) }}" class="text-indigo-600 hover:text-indigo-900 text-sm font-medium">
|
||||
Voir détails
|
||||
</a>
|
||||
<a href="{{ url_for('assessment_grading', assessment_id=assessment.id) }}" class="text-green-600 hover:text-green-900 text-sm font-medium">
|
||||
<a href="{{ url_for('grading.assessment_grading', assessment_id=assessment.id) }}" class="text-green-600 hover:text-green-900 text-sm font-medium">
|
||||
Saisir notes
|
||||
</a>
|
||||
<a href="{{ url_for('edit_assessment', id=assessment.id) }}" class="text-gray-600 hover:text-gray-900 text-sm font-medium">
|
||||
<a href="{{ url_for('assessments.edit', id=assessment.id) }}" class="text-gray-600 hover:text-gray-900 text-sm font-medium">
|
||||
Modifier
|
||||
</a>
|
||||
</div>
|
||||
@@ -66,7 +66,7 @@
|
||||
<h3 class="mt-2 text-sm font-medium text-gray-900">Aucune évaluation</h3>
|
||||
<p class="mt-1 text-sm text-gray-500">Commencez par créer votre première évaluation.</p>
|
||||
<div class="mt-6">
|
||||
<a href="{{ url_for('new_assessment') }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md transition-colors">
|
||||
<a href="{{ url_for('assessments.new') }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md transition-colors">
|
||||
Nouvelle évaluation
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<a href="{{ url_for('index') }}" class="hover:text-blue-200 transition-colors">Accueil</a>
|
||||
<a href="{{ url_for('classes') }}" class="hover:text-blue-200 transition-colors">Classes</a>
|
||||
<a href="{{ url_for('students') }}" class="hover:text-blue-200 transition-colors">Élèves</a>
|
||||
<a href="{{ url_for('assessments') }}" class="hover:text-blue-200 transition-colors">Évaluations</a>
|
||||
<a href="{{ url_for('assessments.list') }}" class="hover:text-blue-200 transition-colors">Évaluations</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
<div class="space-y-6">
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<a href="{{ url_for('assessment_detail', id=assessment.id) }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium mb-2 inline-block">
|
||||
<a href="{{ url_for('assessments.detail', id=assessment.id) }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium mb-2 inline-block">
|
||||
← Retour à l'évaluation "{{ assessment.title }}"
|
||||
</a>
|
||||
<h1 class="text-2xl font-bold text-gray-900">{{ exercise.title }}</h1>
|
||||
<p class="text-gray-600">{{ assessment.title }} - {{ assessment.class_group.name }}</p>
|
||||
</div>
|
||||
<div class="flex space-x-3">
|
||||
<a href="{{ url_for('edit_exercise', assessment_id=assessment.id, id=exercise.id) }}" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-md text-sm font-medium transition-colors">
|
||||
<a href="{{ url_for('exercises.edit', assessment_id=assessment.id, id=exercise.id) }}" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-md text-sm font-medium transition-colors">
|
||||
Modifier
|
||||
</a>
|
||||
<button onclick="if(confirm('Êtes-vous sûr de vouloir supprimer cet exercice ?')) { document.getElementById('delete-form').submit(); }"
|
||||
@@ -23,7 +23,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="delete-form" method="POST" action="{{ url_for('delete_exercise', assessment_id=assessment.id, id=exercise.id) }}" style="display: none;"></form>
|
||||
<form id="delete-form" method="POST" action="{{ url_for('exercises.delete', assessment_id=assessment.id, id=exercise.id) }}" style="display: none;"></form>
|
||||
|
||||
<!-- Informations de l'exercice -->
|
||||
<div class="bg-white shadow rounded-lg">
|
||||
@@ -54,7 +54,7 @@
|
||||
<div class="bg-white shadow rounded-lg">
|
||||
<div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
|
||||
<h2 class="text-lg font-medium text-gray-900">Éléments de notation</h2>
|
||||
<a href="{{ url_for('new_grading_element', assessment_id=assessment.id, exercise_id=exercise.id) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md text-sm font-medium transition-colors">
|
||||
<a href="{{ url_for('exercises.new_grading_element', assessment_id=assessment.id, exercise_id=exercise.id) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md text-sm font-medium transition-colors">
|
||||
Ajouter un élément
|
||||
</a>
|
||||
</div>
|
||||
@@ -83,13 +83,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-2 ml-4">
|
||||
<a href="{{ url_for('edit_grading_element', assessment_id=assessment.id, exercise_id=exercise.id, id=element.id) }}" class="text-gray-600 hover:text-gray-800 text-sm font-medium">
|
||||
<a href="{{ url_for('exercises.edit_grading_element', assessment_id=assessment.id, exercise_id=exercise.id, id=element.id) }}" class="text-gray-600 hover:text-gray-800 text-sm font-medium">
|
||||
Modifier
|
||||
</a>
|
||||
<button onclick="if(confirm('Êtes-vous sûr de vouloir supprimer cet élément ?')) { document.getElementById('delete-element-{{ element.id }}').submit(); }" class="text-red-600 hover:text-red-800 text-sm font-medium">
|
||||
Supprimer
|
||||
</button>
|
||||
<form id="delete-element-{{ element.id }}" method="POST" action="{{ url_for('delete_grading_element', assessment_id=assessment.id, exercise_id=exercise.id, id=element.id) }}" style="display: none;"></form>
|
||||
<form id="delete-element-{{ element.id }}" method="POST" action="{{ url_for('exercises.delete_grading_element', assessment_id=assessment.id, exercise_id=exercise.id, id=element.id) }}" style="display: none;"></form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -119,7 +119,7 @@
|
||||
</div>
|
||||
<div class="px-6 py-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<a href="{{ url_for('assessment_grading', assessment_id=assessment.id) }}" class="flex items-center justify-center px-4 py-3 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
<a href="{{ url_for('grading.assessment_grading', assessment_id=assessment.id) }}" class="flex items-center justify-center px-4 py-3 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
<svg class="w-5 h-5 mr-2 text-green-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H4a1 1 0 01-1-1V4zm0 4a1 1 0 011-1h12a1 1 0 011 1v6a1 1 0 01-1 1H4a1 1 0 01-1-1V8z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{% block content %}
|
||||
<div class="max-w-2xl mx-auto">
|
||||
<div class="mb-6">
|
||||
<a href="{{ url_for('assessment_detail', id=assessment.id) }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium">
|
||||
<a href="{{ url_for('assessments.detail', id=assessment.id) }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium">
|
||||
← Retour à l'évaluation "{{ assessment.title }}"
|
||||
</a>
|
||||
</div>
|
||||
@@ -63,7 +63,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end space-x-3 pt-4 border-t border-gray-200">
|
||||
<a href="{{ url_for('assessment_detail', id=assessment.id) }}" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
<a href="{{ url_for('assessments.detail', id=assessment.id) }}" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
Annuler
|
||||
</a>
|
||||
{{ form.submit(class="px-4 py-2 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700 transition-colors") }}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{% block content %}
|
||||
<div class="max-w-2xl mx-auto">
|
||||
<div class="mb-6">
|
||||
<a href="{{ url_for('exercise_detail', assessment_id=assessment.id, id=exercise.id) }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium">
|
||||
<a href="{{ url_for('exercises.detail', assessment_id=assessment.id, id=exercise.id) }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium">
|
||||
← Retour à l'exercice "{{ exercise.title }}"
|
||||
</a>
|
||||
</div>
|
||||
@@ -103,7 +103,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end space-x-3 pt-4 border-t border-gray-200">
|
||||
<a href="{{ url_for('exercise_detail', assessment_id=assessment.id, id=exercise.id) }}" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
<a href="{{ url_for('exercises.detail', assessment_id=assessment.id, id=exercise.id) }}" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
Annuler
|
||||
</a>
|
||||
{{ form.submit(class="px-4 py-2 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700 transition-colors") }}
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
<div class="text-sm font-medium text-gray-900">Gérer les élèves</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="{{ url_for('assessments') }}" class="block p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors">
|
||||
<a href="{{ url_for('assessments.list') }}" class="block p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors">
|
||||
<div class="text-center">
|
||||
<div class="w-8 h-8 bg-purple-100 rounded-full flex items-center justify-center mx-auto mb-2">
|
||||
<svg class="w-4 h-4 text-purple-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
|
||||
Reference in New Issue
Block a user