diff --git a/Back-End/Auth/migrations/0001_initial.py b/Back-End/Auth/migrations/0001_initial.py index f4492ff..6ed472e 100644 --- a/Back-End/Auth/migrations/0001_initial.py +++ b/Back-End/Auth/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.3 on 2025-05-28 11:14 +# Generated by Django 5.1.3 on 2025-11-30 11:02 import django.contrib.auth.models import django.contrib.auth.validators diff --git a/Back-End/Common/migrations/0001_initial.py b/Back-End/Common/migrations/0001_initial.py index 5725c9e..b45b14a 100644 --- a/Back-End/Common/migrations/0001_initial.py +++ b/Back-End/Common/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.3 on 2025-05-28 11:14 +# Generated by Django 5.1.3 on 2025-11-30 11:02 import django.db.models.deletion from django.db import migrations, models diff --git a/Back-End/Establishment/migrations/0001_initial.py b/Back-End/Establishment/migrations/0001_initial.py index 4ec0546..c718cca 100644 --- a/Back-End/Establishment/migrations/0001_initial.py +++ b/Back-End/Establishment/migrations/0001_initial.py @@ -1,5 +1,6 @@ -# Generated by Django 5.1.3 on 2025-05-28 11:14 +# Generated by Django 5.1.3 on 2025-11-30 11:02 +import Establishment.models import django.contrib.postgres.fields from django.db import migrations, models @@ -24,6 +25,7 @@ class Migration(migrations.Migration): ('licence_code', models.CharField(blank=True, max_length=100)), ('is_active', models.BooleanField(default=True)), ('created_at', models.DateTimeField(auto_now_add=True)), + ('logo', models.FileField(blank=True, null=True, upload_to=Establishment.models.registration_logo_upload_to)), ], ), ] diff --git a/Back-End/Establishment/migrations/0002_establishment_api_docuseal.py b/Back-End/Establishment/migrations/0002_establishment_api_docuseal.py deleted file mode 100644 index 568376b..0000000 --- a/Back-End/Establishment/migrations/0002_establishment_api_docuseal.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.1.3 on 2025-05-30 07:39 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('Establishment', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='establishment', - name='api_docuseal', - field=models.CharField(blank=True, max_length=255, null=True), - ), - ] diff --git a/Back-End/Establishment/migrations/0003_establishment_logo.py b/Back-End/Establishment/migrations/0003_establishment_logo.py deleted file mode 100644 index 1d89e51..0000000 --- a/Back-End/Establishment/migrations/0003_establishment_logo.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.1.3 on 2025-05-31 09:56 - -import Establishment.models -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('Establishment', '0002_establishment_api_docuseal'), - ] - - operations = [ - migrations.AddField( - model_name='establishment', - name='logo', - field=models.FileField(blank=True, null=True, upload_to=Establishment.models.registration_logo_upload_to), - ), - ] diff --git a/Back-End/GestionMessagerie/migrations/0001_initial.py b/Back-End/GestionMessagerie/migrations/0001_initial.py index 914c079..c36fba9 100644 --- a/Back-End/GestionMessagerie/migrations/0001_initial.py +++ b/Back-End/GestionMessagerie/migrations/0001_initial.py @@ -1,6 +1,8 @@ -# Generated by Django 5.1.3 on 2025-05-28 11:14 +# Generated by Django 5.1.3 on 2025-11-30 11:02 import django.db.models.deletion +import django.utils.timezone +import uuid from django.conf import settings from django.db import migrations, models @@ -14,6 +16,39 @@ class Migration(migrations.Migration): ] operations = [ + migrations.CreateModel( + name='Conversation', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('name', models.CharField(blank=True, max_length=255, null=True)), + ('conversation_type', models.CharField(choices=[('private', 'Privée'), ('group', 'Groupe')], default='private', max_length=10)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('last_activity', models.DateTimeField(default=django.utils.timezone.now)), + ('is_active', models.BooleanField(default=True)), + ], + ), + migrations.CreateModel( + name='Message', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('content', models.TextField()), + ('message_type', models.CharField(choices=[('text', 'Texte'), ('file', 'Fichier'), ('image', 'Image'), ('system', 'Système')], default='text', max_length=10)), + ('file_url', models.URLField(blank=True, null=True)), + ('file_name', models.CharField(blank=True, max_length=255, null=True)), + ('file_size', models.BigIntegerField(blank=True, null=True)), + ('file_type', models.CharField(blank=True, max_length=100, null=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('is_edited', models.BooleanField(default=False)), + ('is_deleted', models.BooleanField(default=False)), + ('conversation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to='GestionMessagerie.conversation')), + ('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['created_at'], + }, + ), migrations.CreateModel( name='Messagerie', fields=[ @@ -27,4 +62,40 @@ class Migration(migrations.Migration): ('emetteur', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='messages_envoyes', to=settings.AUTH_USER_MODEL)), ], ), + migrations.CreateModel( + name='UserPresence', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('status', models.CharField(choices=[('online', 'En ligne'), ('away', 'Absent'), ('busy', 'Occupé'), ('offline', 'Hors ligne')], default='offline', max_length=10)), + ('last_seen', models.DateTimeField(default=django.utils.timezone.now)), + ('is_typing_in', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='typing_users', to='GestionMessagerie.conversation')), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='presence', to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='ConversationParticipant', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('joined_at', models.DateTimeField(auto_now_add=True)), + ('last_read_at', models.DateTimeField(default=django.utils.timezone.now)), + ('is_active', models.BooleanField(default=True)), + ('conversation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='participants', to='GestionMessagerie.conversation')), + ('participant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='conversation_participants', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('conversation', 'participant')}, + }, + ), + migrations.CreateModel( + name='MessageRead', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('read_at', models.DateTimeField(auto_now_add=True)), + ('message', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='read_by', to='GestionMessagerie.message')), + ('participant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='read_messages', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('message', 'participant')}, + }, + ), ] diff --git a/Back-End/GestionMessagerie/migrations/0002_conversation_message_userpresence_and_more.py b/Back-End/GestionMessagerie/migrations/0002_conversation_message_userpresence_and_more.py deleted file mode 100644 index abe623e..0000000 --- a/Back-End/GestionMessagerie/migrations/0002_conversation_message_userpresence_and_more.py +++ /dev/null @@ -1,87 +0,0 @@ -# Generated by Django 5.1.3 on 2025-05-30 07:40 - -import django.db.models.deletion -import django.utils.timezone -import uuid -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('GestionMessagerie', '0001_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='Conversation', - fields=[ - ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('name', models.CharField(blank=True, max_length=255, null=True)), - ('conversation_type', models.CharField(choices=[('private', 'Privée'), ('group', 'Groupe')], default='private', max_length=10)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('last_activity', models.DateTimeField(default=django.utils.timezone.now)), - ('is_active', models.BooleanField(default=True)), - ], - ), - migrations.CreateModel( - name='Message', - fields=[ - ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('content', models.TextField()), - ('message_type', models.CharField(choices=[('text', 'Texte'), ('file', 'Fichier'), ('image', 'Image'), ('system', 'Système')], default='text', max_length=10)), - ('file_url', models.URLField(blank=True, null=True)), - ('file_name', models.CharField(blank=True, max_length=255, null=True)), - ('file_size', models.BigIntegerField(blank=True, null=True)), - ('file_type', models.CharField(blank=True, max_length=100, null=True)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('is_edited', models.BooleanField(default=False)), - ('is_deleted', models.BooleanField(default=False)), - ('conversation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to='GestionMessagerie.conversation')), - ('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'ordering': ['created_at'], - }, - ), - migrations.CreateModel( - name='UserPresence', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('status', models.CharField(choices=[('online', 'En ligne'), ('away', 'Absent'), ('busy', 'Occupé'), ('offline', 'Hors ligne')], default='offline', max_length=10)), - ('last_seen', models.DateTimeField(default=django.utils.timezone.now)), - ('is_typing_in', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='typing_users', to='GestionMessagerie.conversation')), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='presence', to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name='ConversationParticipant', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('joined_at', models.DateTimeField(auto_now_add=True)), - ('last_read_at', models.DateTimeField(default=django.utils.timezone.now)), - ('is_active', models.BooleanField(default=True)), - ('conversation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='participants', to='GestionMessagerie.conversation')), - ('participant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='conversation_participants', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'unique_together': {('conversation', 'participant')}, - }, - ), - migrations.CreateModel( - name='MessageRead', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('read_at', models.DateTimeField(auto_now_add=True)), - ('message', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='read_by', to='GestionMessagerie.message')), - ('participant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='read_messages', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'unique_together': {('message', 'participant')}, - }, - ), - ] diff --git a/Back-End/GestionNotification/migrations/0001_initial.py b/Back-End/GestionNotification/migrations/0001_initial.py index 3517e45..4500122 100644 --- a/Back-End/GestionNotification/migrations/0001_initial.py +++ b/Back-End/GestionNotification/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.3 on 2025-05-28 11:14 +# Generated by Django 5.1.3 on 2025-11-30 11:02 import django.db.models.deletion from django.conf import settings diff --git a/Back-End/N3wtSchool/Configuration/application.default.json b/Back-End/N3wtSchool/Configuration/application.default.json deleted file mode 100644 index 3e9effc..0000000 --- a/Back-End/N3wtSchool/Configuration/application.default.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "hostSMTP": "", - "portSMTP": 25, - "username": "", - "password": "", - "useSSL": false, - "useTLS": false -} \ No newline at end of file diff --git a/Back-End/N3wtSchool/mailManager.py b/Back-End/N3wtSchool/mailManager.py index 183c1b4..7bf9cce 100644 --- a/Back-End/N3wtSchool/mailManager.py +++ b/Back-End/N3wtSchool/mailManager.py @@ -17,9 +17,12 @@ def getConnection(id_establishement): try: # Récupérer l'instance de l'établissement establishment = Establishment.objects.get(id=id_establishement) + logger.info(f"Establishment trouvé: {establishment.name} (ID: {id_establishement})") + try: # Récupérer les paramètres SMTP associés à l'établissement smtp_settings = SMTPSettings.objects.get(establishment=establishment) + logger.info(f"Paramètres SMTP trouvés pour {establishment.name}: {smtp_settings.smtp_server}:{smtp_settings.smtp_port}") # Créer une connexion SMTP avec les paramètres récupérés connection = get_connection( @@ -32,9 +35,11 @@ def getConnection(id_establishement): ) return connection except SMTPSettings.DoesNotExist: + logger.warning(f"Aucun paramètre SMTP spécifique trouvé pour l'établissement {establishment.name} (ID: {id_establishement})") # Aucun paramètre SMTP spécifique, retournera None return None except Establishment.DoesNotExist: + logger.error(f"Aucun établissement trouvé avec l'ID {id_establishement}") raise NotFound(f"Aucun établissement trouvé avec l'ID {id_establishement}") def sendMail(subject, message, recipients, cc=[], bcc=[], attachments=[], connection=None): @@ -53,11 +58,13 @@ def sendMail(subject, message, recipients, cc=[], bcc=[], attachments=[], connec plain_message = strip_tags(message) if connection is not None: from_email = username + logger.info(f"Utilisation de la connexion SMTP spécifique: {username}") else: from_email = settings.EMAIL_HOST_USER - + logger.info(f"Utilisation de la configuration SMTP par défaut: {from_email}") logger.info(f"From email: {from_email}") + logger.info(f"Configuration par défaut - Host: {settings.EMAIL_HOST}, Port: {settings.EMAIL_PORT}, Use TLS: {settings.EMAIL_USE_TLS}") email = EmailMultiAlternatives( subject=subject, @@ -79,6 +86,8 @@ def sendMail(subject, message, recipients, cc=[], bcc=[], attachments=[], connec return Response({'message': 'Email envoyé avec succès.'}, status=status.HTTP_200_OK) except Exception as e: logger.error(f"Erreur lors de l'envoi de l'email: {str(e)}") + logger.error(f"Settings : {connection}") + logger.error(f"Settings : {connection}") logger.error(f"Type d'erreur: {type(e)}") import traceback logger.error(f"Traceback: {traceback.format_exc()}") diff --git a/Back-End/Planning/migrations/0001_initial.py b/Back-End/Planning/migrations/0001_initial.py index e6472c6..3d41fdb 100644 --- a/Back-End/Planning/migrations/0001_initial.py +++ b/Back-End/Planning/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.3 on 2025-05-28 11:14 +# Generated by Django 5.1.3 on 2025-11-30 11:02 import django.db.models.deletion from django.db import migrations, models diff --git a/Back-End/School/migrations/0001_initial.py b/Back-End/School/migrations/0001_initial.py index 4289620..d0eb4e4 100644 --- a/Back-End/School/migrations/0001_initial.py +++ b/Back-End/School/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.3 on 2025-05-28 11:14 +# Generated by Django 5.1.3 on 2025-11-30 11:02 import django.contrib.postgres.fields import django.db.models.deletion diff --git a/Back-End/Settings/migrations/0001_initial.py b/Back-End/Settings/migrations/0001_initial.py index c05340d..ebc8792 100644 --- a/Back-End/Settings/migrations/0001_initial.py +++ b/Back-End/Settings/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.3 on 2025-05-28 11:14 +# Generated by Django 5.1.3 on 2025-11-30 11:02 import django.db.models.deletion from django.db import migrations, models diff --git a/Back-End/Subscriptions/Configuration/inscriptions.json b/Back-End/Subscriptions/Configuration/inscriptions.json deleted file mode 100644 index 0170a43..0000000 --- a/Back-End/Subscriptions/Configuration/inscriptions.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "activationMailRelance": "Oui", - "delaiRelance": "30", - "ambiances": [ - "2-3 ans", - "3-6 ans", - "6-12 ans" - ], - "genres": [ - "Fille", - "Garçon" - ], - "modesPaiement": [ - "Chèque", - "Virement", - "Prélèvement SEPA" - ] -} \ No newline at end of file diff --git a/Back-End/Subscriptions/management/__init__.py b/Back-End/Subscriptions/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Back-End/Subscriptions/management/commands/__init__.py b/Back-End/Subscriptions/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Back-End/Subscriptions/management/commands/test_email.py b/Back-End/Subscriptions/management/commands/test_email.py new file mode 100644 index 0000000..d938b23 --- /dev/null +++ b/Back-End/Subscriptions/management/commands/test_email.py @@ -0,0 +1,43 @@ +""" +Management command pour tester la configuration email Django +""" +from django.core.management.base import BaseCommand +from django.core.mail import send_mail +from django.conf import settings +from N3wtSchool.mailManager import getConnection, sendMail +import logging + +logger = logging.getLogger(__name__) + +class Command(BaseCommand): + help = 'Test de la configuration email' + + def add_arguments(self, parser): + parser.add_argument('--establishment-id', type=int, help='ID de l\'établissement pour test') + parser.add_argument('--email', type=str, default='test@example.com', help='Email de destination') + + def handle(self, *args, **options): + self.stdout.write("=== Test de configuration email ===") + + # Affichage de la configuration + self.stdout.write(f"EMAIL_HOST: {settings.EMAIL_HOST}") + self.stdout.write(f"EMAIL_PORT: {settings.EMAIL_PORT}") + self.stdout.write(f"EMAIL_HOST_USER: {settings.EMAIL_HOST_USER}") + self.stdout.write(f"EMAIL_HOST_PASSWORD: {settings.EMAIL_HOST_PASSWORD}") + self.stdout.write(f"EMAIL_USE_TLS: {settings.EMAIL_USE_TLS}") + self.stdout.write(f"EMAIL_USE_SSL: {settings.EMAIL_USE_SSL}") + self.stdout.write(f"EMAIL_BACKEND: {settings.EMAIL_BACKEND}") + + # Test 1: Configuration par défaut Django + self.stdout.write("\n--- Test : Configuration EMAIL par défaut ---") + try: + result = send_mail( + 'Test Django Email', + 'Ceci est un test de la configuration email par défaut.', + settings.EMAIL_HOST_USER, + [options['email']], + fail_silently=False, + ) + self.stdout.write(self.style.SUCCESS(f"✅ Email envoyé avec succès (résultat: {result})")) + except Exception as e: + self.stdout.write(self.style.ERROR(f"❌ Erreur: {e}")) \ No newline at end of file diff --git a/Back-End/Subscriptions/migrations/0001_initial.py b/Back-End/Subscriptions/migrations/0001_initial.py index afd9c5c..d74fbcb 100644 --- a/Back-End/Subscriptions/migrations/0001_initial.py +++ b/Back-End/Subscriptions/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.3 on 2025-05-28 11:14 +# Generated by Django 5.1.3 on 2025-11-30 11:02 import Subscriptions.models import django.db.models.deletion @@ -46,10 +46,11 @@ class Migration(migrations.Migration): migrations.CreateModel( name='RegistrationSchoolFileTemplate', fields=[ - ('id', models.IntegerField(primary_key=True, serialize=False)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('slug', models.CharField(default='', max_length=255)), ('name', models.CharField(default='', max_length=255)), ('file', models.FileField(blank=True, null=True, upload_to=Subscriptions.models.registration_school_file_upload_to)), + ('formTemplateData', models.JSONField(blank=True, default=list, null=True)), ], ), migrations.CreateModel( @@ -153,7 +154,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(default='', max_length=255)), - ('description', models.CharField(blank=True, null=True)), + ('description', models.CharField(blank=True, max_length=500, null=True)), ('is_required', models.BooleanField(default=False)), ('groups', models.ManyToManyField(blank=True, related_name='parent_file_masters', to='Subscriptions.registrationfilegroup')), ], @@ -161,9 +162,10 @@ class Migration(migrations.Migration): migrations.CreateModel( name='RegistrationSchoolFileMaster', fields=[ - ('id', models.IntegerField(primary_key=True, serialize=False)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(default='', max_length=255)), ('is_required', models.BooleanField(default=False)), + ('formMasterData', models.JSONField(blank=True, default=list, null=True)), ('groups', models.ManyToManyField(blank=True, related_name='school_file_masters', to='Subscriptions.registrationfilegroup')), ], ), diff --git a/Back-End/Subscriptions/migrations/0002_alter_registrationparentfilemaster_description.py b/Back-End/Subscriptions/migrations/0002_alter_registrationparentfilemaster_description.py deleted file mode 100644 index 82d5627..0000000 --- a/Back-End/Subscriptions/migrations/0002_alter_registrationparentfilemaster_description.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.1.3 on 2025-05-30 07:39 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('Subscriptions', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='registrationparentfilemaster', - name='description', - field=models.CharField(blank=True, max_length=500, null=True), - ), - ] diff --git a/Back-End/Subscriptions/serializers.py b/Back-End/Subscriptions/serializers.py index e3aeabd..e9d4ee5 100644 --- a/Back-End/Subscriptions/serializers.py +++ b/Back-End/Subscriptions/serializers.py @@ -1,15 +1,15 @@ from rest_framework import serializers from .models import ( - RegistrationFileGroup, - RegistrationForm, - Student, - Guardian, - Sibling, + RegistrationFileGroup, + RegistrationForm, + Student, + Guardian, + Sibling, Language, - RegistrationSchoolFileMaster, - RegistrationSchoolFileTemplate, - RegistrationParentFileMaster, - RegistrationParentFileTemplate, + RegistrationSchoolFileMaster, + RegistrationSchoolFileTemplate, + RegistrationParentFileMaster, + RegistrationParentFileTemplate, AbsenceManagement, BilanCompetence ) @@ -95,7 +95,7 @@ class RegistrationFormSimpleSerializer(serializers.ModelSerializer): class Meta: model = RegistrationForm fields = ['student_id', 'last_name', 'first_name', 'guardians'] - + def get_last_name(self, obj): return obj.student.last_name @@ -164,12 +164,20 @@ class StudentSerializer(serializers.ModelSerializer): if guardian_id: # Si un ID est fourni, récupérer ou mettre à jour le Guardian existant - guardian_instance, created = Guardian.objects.update_or_create( - id=guardian_id, - defaults=guardian_data - ) - guardians_ids.append(guardian_instance.id) - continue + try: + guardian_instance = Guardian.objects.get(id=guardian_id) + # Mettre à jour explicitement tous les champs y compris birth_date, profession, address + for field, value in guardian_data.items(): + if field != 'id': # Ne pas mettre à jour l'ID + setattr(guardian_instance, field, value) + guardian_instance.save() + guardians_ids.append(guardian_instance.id) + continue + except Guardian.DoesNotExist: + # Si le guardian n'existe pas, créer un nouveau + guardian_instance = Guardian.objects.create(**guardian_data) + guardians_ids.append(guardian_instance.id) + continue if profile_role_data: # Vérifiez si 'profile_data' est fourni pour créer un nouveau profil diff --git a/Back-End/Subscriptions/tasks.py b/Back-End/Subscriptions/tasks.py index cae3930..14f8778 100644 --- a/Back-End/Subscriptions/tasks.py +++ b/Back-End/Subscriptions/tasks.py @@ -5,6 +5,8 @@ from Subscriptions.automate import Automate_RF_Register, updateStateMachine from .models import RegistrationForm from GestionMessagerie.models import Messagerie from N3wtSchool import settings, bdd +from N3wtSchool.mailManager import sendMail, getConnection +from django.template.loader import render_to_string import requests import logging logger = logging.getLogger(__name__) @@ -26,17 +28,82 @@ def send_notification(dossier): # Changer l'état de l'automate updateStateMachine(dossier, 'EVENT_FOLLOW_UP') - url = settings.URL_DJANGO + 'GestionMessagerie/message' + # Envoyer un email de relance aux responsables + try: + # Récupérer l'établissement du dossier + establishment_id = dossier.establishment.id - destinataires = dossier.eleve.profiles.all() - for destinataire in destinataires: - message = { - "objet": "[RELANCE]", - "destinataire" : destinataire.id, - "corpus": "RELANCE pour le dossier d'inscription" + # Obtenir la connexion SMTP pour cet établissement + connection = getConnection(establishment_id) + + # Préparer le contenu de l'email + subject = f"[RELANCE] Dossier d'inscription en attente - {dossier.eleve.first_name} {dossier.eleve.last_name}" + + context = { + 'student_name': f"{dossier.eleve.first_name} {dossier.eleve.last_name}", + 'deadline_date': (timezone.now() - timezone.timedelta(days=settings.EXPIRATION_DI_NB_DAYS)).strftime('%d/%m/%Y'), + 'establishment_name': dossier.establishment.name, + 'base_url': settings.BASE_URL } - response = requests.post(url, json=message) + # Utiliser un template HTML pour l'email (si disponible) + try: + html_message = render_to_string('emails/relance_signature.html', context) + except: + # Si pas de template, message simple + html_message = f""" + + +

Relance - Dossier d'inscription en attente

+

Bonjour,

+

Le dossier d'inscription de {context['student_name']} est en attente de signature depuis plus de {settings.EXPIRATION_DI_NB_DAYS} jours.

+

Merci de vous connecter à votre espace pour finaliser l'inscription.

+

Cordialement,
L'équipe {context['establishment_name']}

+ + + """ + + # Récupérer les emails des responsables + destinataires = [] + profiles = dossier.eleve.profiles.all() + for profile in profiles: + if profile.email: + destinataires.append(profile.email) + + if destinataires: + # Envoyer l'email + result = sendMail( + subject=subject, + message=html_message, + recipients=destinataires, + connection=connection + ) + logger.info(f"Email de relance envoyé pour le dossier {dossier.id} à {destinataires}") + else: + logger.warning(f"Aucun email trouvé pour les responsables du dossier {dossier.id}") + + except Exception as e: + logger.error(f"Erreur lors de l'envoi de l'email de relance pour le dossier {dossier.id}: {str(e)}") + + # En cas d'erreur email, utiliser la messagerie interne comme fallback + try: + url = settings.URL_DJANGO + 'GestionMessagerie/send-message/' + + # Créer ou récupérer une conversation avec chaque responsable + destinataires = dossier.eleve.profiles.all() + for destinataire in destinataires: + message_data = { + "conversation_id": None, # Sera géré par l'API + "sender_id": 1, # ID du système ou admin + "content": f"RELANCE pour le dossier d'inscription de {dossier.eleve.first_name} {dossier.eleve.last_name}" + } + + response = requests.post(url, json=message_data) + if response.status_code != 201: + logger.error(f"Erreur lors de l'envoi du message interne: {response.text}") + + except Exception as inner_e: + logger.error(f"Erreur lors de l'envoi du message interne de fallback: {str(inner_e)}") # subject = f"Dossier d'inscription non signé - {dossier.objet}" # message = f"Le dossier d'inscription avec l'objet '{dossier.objet}' n'a pas été signé depuis {dossier.created_at}." diff --git a/Back-End/Subscriptions/templates/emails/relance_signature.html b/Back-End/Subscriptions/templates/emails/relance_signature.html new file mode 100644 index 0000000..411920f --- /dev/null +++ b/Back-End/Subscriptions/templates/emails/relance_signature.html @@ -0,0 +1,121 @@ + + + + + + Relance - Dossier d'inscription + + + +
+
+

{{ establishment_name }}

+

Relance - Dossier d'inscription

+
+ +
+ ⚠️ + Attention : Votre dossier d'inscription nécessite votre attention +
+ +
+

Bonjour,

+ +
+

Dossier d'inscription de : {{ student_name }}

+

En attente depuis le : {{ deadline_date }}

+
+ +

Nous vous informons que le dossier d'inscription mentionné ci-dessus est en attente de finalisation depuis plus de {{ deadline_date }}.

+ +

Action requise :

+ + +
+ Accéder à mon espace +
+ +

Si vous rencontrez des difficultés ou avez des questions concernant ce dossier, n'hésitez pas à nous contacter.

+
+ + +
+ + \ No newline at end of file diff --git a/Back-End/Subscriptions/util.py b/Back-End/Subscriptions/util.py index 16f2d33..f4e0a1e 100644 --- a/Back-End/Subscriptions/util.py +++ b/Back-End/Subscriptions/util.py @@ -35,6 +35,18 @@ def build_payload_from_request(request): - supporte application/json ou form-data simple Retour: (payload_dict, None) ou (None, Response erreur) """ + # Si c'est du JSON pur (Content-Type: application/json) + if hasattr(request, 'content_type') and 'application/json' in request.content_type: + try: + # request.data contient déjà le JSON parsé par Django REST + payload = dict(request.data) if hasattr(request.data, 'items') else request.data + logger.info(f"JSON payload extracted: {payload}") + return payload, None + except Exception as e: + logger.error(f'Error processing JSON: {e}') + return None, Response({'error': "Invalid JSON", 'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + # Cas multipart/form-data avec champ 'data' data_field = request.data.get('data') if hasattr(request.data, 'get') else None if data_field: try: diff --git a/Back-End/Subscriptions/views/register_form_views.py b/Back-End/Subscriptions/views/register_form_views.py index 18479f5..d7e6e93 100644 --- a/Back-End/Subscriptions/views/register_form_views.py +++ b/Back-End/Subscriptions/views/register_form_views.py @@ -17,10 +17,10 @@ import Subscriptions.util as util from Subscriptions.serializers import RegistrationFormSerializer, RegistrationSchoolFileTemplateSerializer, RegistrationParentFileTemplateSerializer from Subscriptions.pagination import CustomSubscriptionPagination from Subscriptions.models import ( - Guardian, - RegistrationForm, - RegistrationSchoolFileTemplate, - RegistrationFileGroup, + Guardian, + RegistrationForm, + RegistrationSchoolFileTemplate, + RegistrationFileGroup, RegistrationParentFileTemplate, StudentCompetency ) @@ -431,6 +431,262 @@ class RegisterFormWithIdView(APIView): # Retourner les données mises à jour return JsonResponse(studentForm_serializer.data, safe=False) + @swagger_auto_schema( + request_body=openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'student_data': openapi.Schema(type=openapi.TYPE_STRING, description='JSON string des données étudiant'), + 'guardians_data': openapi.Schema(type=openapi.TYPE_STRING, description='JSON string des données responsables'), + 'siblings_data': openapi.Schema(type=openapi.TYPE_STRING, description='JSON string des données fratrie'), + 'payment_data': openapi.Schema(type=openapi.TYPE_STRING, description='JSON string des données de paiement'), + 'current_page': openapi.Schema(type=openapi.TYPE_INTEGER, description='Page actuelle du formulaire'), + 'auto_save': openapi.Schema(type=openapi.TYPE_BOOLEAN, description='Indicateur auto-save'), + } + ), + responses={200: RegistrationFormSerializer()}, + operation_description="Auto-sauvegarde partielle d'un dossier d'inscription.", + operation_summary="Auto-sauvegarder un dossier d'inscription" + ) + @method_decorator(csrf_protect, name='dispatch') + @method_decorator(ensure_csrf_cookie, name='dispatch') + def patch(self, request, id): + """ + Auto-sauvegarde partielle d'un dossier d'inscription. + Cette méthode est optimisée pour les sauvegardes automatiques périodiques. + """ + try: + # Récupérer le dossier d'inscription + registerForm = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id) + if not registerForm: + return JsonResponse({"error": "Dossier d'inscription introuvable"}, status=status.HTTP_404_NOT_FOUND) + + # Préparer les données à mettre à jour + update_data = {} + + # Traiter les données étudiant si présentes + if 'student_data' in request.data: + try: + student_data = json.loads(request.data['student_data']) + + # Extraire les données de paiement des données étudiant + payment_fields = ['registration_payment', 'tuition_payment', 'registration_payment_plan', 'tuition_payment_plan'] + payment_data = {} + + for field in payment_fields: + if field in student_data: + payment_data[field] = student_data.pop(field) + + # Si nous avons des données de paiement, les traiter + if payment_data: + logger.debug(f"Auto-save: extracted payment_data from student_data = {payment_data}") + + # Traiter les données de paiement + payment_updates = {} + + # Gestion du mode de paiement d'inscription + if 'registration_payment' in payment_data and payment_data['registration_payment']: + try: + from School.models import PaymentMode + payment_mode = PaymentMode.objects.get(id=payment_data['registration_payment']) + registerForm.registration_payment = payment_mode + payment_updates['registration_payment'] = payment_mode.id + except PaymentMode.DoesNotExist: + logger.warning(f"Auto-save: PaymentMode with id {payment_data['registration_payment']} not found") + + # Gestion du mode de paiement de scolarité + if 'tuition_payment' in payment_data and payment_data['tuition_payment']: + try: + from School.models import PaymentMode + payment_mode = PaymentMode.objects.get(id=payment_data['tuition_payment']) + registerForm.tuition_payment = payment_mode + payment_updates['tuition_payment'] = payment_mode.id + except PaymentMode.DoesNotExist: + logger.warning(f"Auto-save: PaymentMode with id {payment_data['tuition_payment']} not found") + + # Gestion du plan de paiement d'inscription + if 'registration_payment_plan' in payment_data and payment_data['registration_payment_plan']: + try: + from School.models import PaymentPlan + payment_plan = PaymentPlan.objects.get(id=payment_data['registration_payment_plan']) + registerForm.registration_payment_plan = payment_plan + payment_updates['registration_payment_plan'] = payment_plan.id + except PaymentPlan.DoesNotExist: + logger.warning(f"Auto-save: PaymentPlan with id {payment_data['registration_payment_plan']} not found") + + # Gestion du plan de paiement de scolarité + if 'tuition_payment_plan' in payment_data and payment_data['tuition_payment_plan']: + try: + from School.models import PaymentPlan + payment_plan = PaymentPlan.objects.get(id=payment_data['tuition_payment_plan']) + registerForm.tuition_payment_plan = payment_plan + payment_updates['tuition_payment_plan'] = payment_plan.id + except PaymentPlan.DoesNotExist: + logger.warning(f"Auto-save: PaymentPlan with id {payment_data['tuition_payment_plan']} not found") + + # Sauvegarder les modifications de paiement + if payment_updates: + registerForm.save() + logger.debug(f"Auto-save: Payment data updated - {payment_updates}") + + update_data['student'] = student_data + except json.JSONDecodeError: + logger.warning("Auto-save: Invalid JSON in student_data") + + # Traiter les données des responsables si présentes + if 'guardians_data' in request.data: + try: + guardians_data = json.loads(request.data['guardians_data']) + logger.debug(f"Auto-save: guardians_data = {guardians_data}") + + # Enregistrer directement chaque guardian avec le modèle + for i, guardian_data in enumerate(guardians_data): + guardian_id = guardian_data.get('id') + if guardian_id: + try: + # Récupérer le guardian existant et mettre à jour ses champs + guardian = Guardian.objects.get(id=guardian_id) + + # Mettre à jour les champs si ils sont présents + if 'birth_date' in guardian_data and guardian_data['birth_date']: + guardian.birth_date = guardian_data['birth_date'] + if 'profession' in guardian_data: + guardian.profession = guardian_data['profession'] + if 'address' in guardian_data: + guardian.address = guardian_data['address'] + if 'phone' in guardian_data: + guardian.phone = guardian_data['phone'] + if 'first_name' in guardian_data: + guardian.first_name = guardian_data['first_name'] + if 'last_name' in guardian_data: + guardian.last_name = guardian_data['last_name'] + + guardian.save() + logger.debug(f"Guardian {i}: Updated birth_date={guardian.birth_date}, profession={guardian.profession}, address={guardian.address}") + + except Guardian.DoesNotExist: + logger.warning(f"Auto-save: Guardian with id {guardian_id} not found") + + except json.JSONDecodeError: + logger.warning("Auto-save: Invalid JSON in guardians_data") + + # Traiter les données de la fratrie si présentes + if 'siblings_data' in request.data: + try: + siblings_data = json.loads(request.data['siblings_data']) + logger.debug(f"Auto-save: siblings_data = {siblings_data}") + + # Enregistrer directement chaque sibling avec le modèle + for i, sibling_data in enumerate(siblings_data): + sibling_id = sibling_data.get('id') + if sibling_id: + try: + # Récupérer le sibling existant et mettre à jour ses champs + from Subscriptions.models import Sibling + sibling = Sibling.objects.get(id=sibling_id) + + # Mettre à jour les champs si ils sont présents + if 'first_name' in sibling_data: + sibling.first_name = sibling_data['first_name'] + if 'last_name' in sibling_data: + sibling.last_name = sibling_data['last_name'] + if 'birth_date' in sibling_data and sibling_data['birth_date']: + sibling.birth_date = sibling_data['birth_date'] + + sibling.save() + logger.debug(f"Sibling {i}: Updated first_name={sibling.first_name}, last_name={sibling.last_name}, birth_date={sibling.birth_date}") + + except Sibling.DoesNotExist: + logger.warning(f"Auto-save: Sibling with id {sibling_id} not found") + + except json.JSONDecodeError: + logger.warning("Auto-save: Invalid JSON in siblings_data") + + # Traiter les données de paiement si présentes + if 'payment_data' in request.data: + try: + payment_data = json.loads(request.data['payment_data']) + logger.debug(f"Auto-save: payment_data = {payment_data}") + + # Mettre à jour directement les champs de paiement du formulaire + payment_updates = {} + + # Gestion du mode de paiement d'inscription + if 'registration_payment' in payment_data and payment_data['registration_payment']: + try: + from School.models import PaymentMode + payment_mode = PaymentMode.objects.get(id=payment_data['registration_payment']) + registerForm.registration_payment = payment_mode + payment_updates['registration_payment'] = payment_mode.id + except PaymentMode.DoesNotExist: + logger.warning(f"Auto-save: PaymentMode with id {payment_data['registration_payment']} not found") + + # Gestion du mode de paiement de scolarité + if 'tuition_payment' in payment_data and payment_data['tuition_payment']: + try: + from School.models import PaymentMode + payment_mode = PaymentMode.objects.get(id=payment_data['tuition_payment']) + registerForm.tuition_payment = payment_mode + payment_updates['tuition_payment'] = payment_mode.id + except PaymentMode.DoesNotExist: + logger.warning(f"Auto-save: PaymentMode with id {payment_data['tuition_payment']} not found") + + # Gestion du plan de paiement d'inscription + if 'registration_payment_plan' in payment_data and payment_data['registration_payment_plan']: + try: + from School.models import PaymentPlan + payment_plan = PaymentPlan.objects.get(id=payment_data['registration_payment_plan']) + registerForm.registration_payment_plan = payment_plan + payment_updates['registration_payment_plan'] = payment_plan.id + except PaymentPlan.DoesNotExist: + logger.warning(f"Auto-save: PaymentPlan with id {payment_data['registration_payment_plan']} not found") + + # Gestion du plan de paiement de scolarité + if 'tuition_payment_plan' in payment_data and payment_data['tuition_payment_plan']: + try: + from School.models import PaymentPlan + payment_plan = PaymentPlan.objects.get(id=payment_data['tuition_payment_plan']) + registerForm.tuition_payment_plan = payment_plan + payment_updates['tuition_payment_plan'] = payment_plan.id + except PaymentPlan.DoesNotExist: + logger.warning(f"Auto-save: PaymentPlan with id {payment_data['tuition_payment_plan']} not found") + + # Sauvegarder les modifications de paiement + if payment_updates: + registerForm.save() + logger.debug(f"Auto-save: Payment data updated - {payment_updates}") + + except json.JSONDecodeError: + logger.warning("Auto-save: Invalid JSON in payment_data") + + # Mettre à jour la page actuelle si présente + if 'current_page' in request.data: + try: + current_page = int(request.data['current_page']) + # Vous pouvez sauvegarder cette info dans un champ du modèle si nécessaire + logger.debug(f"Auto-save: current_page = {current_page}") + except (ValueError, TypeError): + logger.warning("Auto-save: Invalid current_page value") + + # Effectuer la mise à jour partielle seulement si nous avons des données + if update_data: + serializer = RegistrationFormSerializer(registerForm, data=update_data, partial=True) + if serializer.is_valid(): + serializer.save() + logger.debug(f"Auto-save successful for student {id}") + return JsonResponse({"status": "auto_save_success", "timestamp": util._now().isoformat()}, safe=False) + else: + logger.warning(f"Auto-save validation errors: {serializer.errors}") + # Pour l'auto-save, on retourne un succès même en cas d'erreur de validation + return JsonResponse({"status": "auto_save_partial", "errors": serializer.errors}, safe=False) + else: + # Pas de données à sauvegarder, mais on retourne un succès + return JsonResponse({"status": "auto_save_no_data"}, safe=False) + + except Exception as e: + logger.error(f"Auto-save error for student {id}: {str(e)}") + # Pour l'auto-save, on ne retourne pas d'erreur HTTP pour éviter d'interrompre l'UX + return JsonResponse({"status": "auto_save_failed", "error": str(e)}, safe=False) + @swagger_auto_schema( responses={204: 'No Content'}, operation_description="Supprime un dossier d'inscription donné.", diff --git a/Back-End/Subscriptions/views/registration_school_file_masters_views.py b/Back-End/Subscriptions/views/registration_school_file_masters_views.py index f91afd9..5dc2d81 100644 --- a/Back-End/Subscriptions/views/registration_school_file_masters_views.py +++ b/Back-End/Subscriptions/views/registration_school_file_masters_views.py @@ -1,19 +1,18 @@ from django.http.response import JsonResponse from drf_yasg.utils import swagger_auto_schema from drf_yasg import openapi -from rest_framework.parsers import MultiPartParser, FormParser +from rest_framework.parsers import MultiPartParser, FormParser, JSONParser from rest_framework.response import Response from rest_framework.views import APIView from rest_framework import status import json from django.http import QueryDict -from Subscriptions.serializers import RegistrationSchoolFileMasterSerializer, RegistrationSchoolFileTemplateSerializer, RegistrationParentFileMasterSerializer, RegistrationParentFileTemplateSerializer +from Subscriptions.serializers import RegistrationSchoolFileMasterSerializer, RegistrationParentFileMasterSerializer, RegistrationParentFileTemplateSerializer from Subscriptions.models import ( RegistrationForm, - RegistrationSchoolFileMaster, - RegistrationSchoolFileTemplate, - RegistrationParentFileMaster, + RegistrationSchoolFileMaster, + RegistrationParentFileMaster, RegistrationParentFileTemplate ) from N3wtSchool import bdd @@ -23,7 +22,8 @@ import Subscriptions.util as util logger = logging.getLogger(__name__) class RegistrationSchoolFileMasterView(APIView): - parser_classes = [MultiPartParser, FormParser] + parser_classes = [MultiPartParser, FormParser, JSONParser] + @swagger_auto_schema( operation_description="Récupère tous les masters de templates d'inscription pour un établissement donné", manual_parameters=[ @@ -64,6 +64,7 @@ class RegistrationSchoolFileMasterView(APIView): if resp: return resp + logger.info(f"payload for serializer: {payload}") serializer = RegistrationSchoolFileMasterSerializer(data=payload, partial=True) if serializer.is_valid(): @@ -90,6 +91,7 @@ class RegistrationSchoolFileMasterView(APIView): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class RegistrationSchoolFileMasterSimpleView(APIView): + parser_classes = [MultiPartParser, FormParser, JSONParser] @swagger_auto_schema( operation_description="Récupère un master de template d'inscription spécifique", responses={ @@ -126,6 +128,7 @@ class RegistrationSchoolFileMasterSimpleView(APIView): if resp: return resp + logger.info(f"payload for update serializer: {payload}") serializer = RegistrationSchoolFileMasterSerializer(master, data=payload, partial=True) if serializer.is_valid(): diff --git a/Back-End/start.py b/Back-End/start.py index c957899..c265a97 100644 --- a/Back-End/start.py +++ b/Back-End/start.py @@ -12,21 +12,32 @@ def run_command(command): return process.returncode test_mode = os.getenv('test_mode', 'false').lower() == 'true' +flush_data = os.getenv('flush_data', 'false').lower() == 'true' +migrate_data = os.getenv('migrate_data', 'false').lower() == 'true' watch_mode = os.getenv('DJANGO_WATCH', 'false').lower() == 'true' +collect_static_cmd = [ + ["python", "manage.py", "collectstatic", "--noinput"] +] + +flush_data_cmd = [ + ["python", "manage.py", "flush", "--noinput"] +] + +migrate_commands = [ + ["python", "manage.py", "makemigrations", "Common", "--noinput"], + ["python", "manage.py", "makemigrations", "Establishment", "--noinput"], + ["python", "manage.py", "makemigrations", "Settings", "--noinput"], + ["python", "manage.py", "makemigrations", "Subscriptions", "--noinput"], + ["python", "manage.py", "makemigrations", "Planning", "--noinput"], + ["python", "manage.py", "makemigrations", "GestionNotification", "--noinput"], + ["python", "manage.py", "makemigrations", "GestionEmail", "--noinput"], + ["python", "manage.py", "makemigrations", "GestionMessagerie", "--noinput"], + ["python", "manage.py", "makemigrations", "Auth", "--noinput"], + ["python", "manage.py", "makemigrations", "School", "--noinput"] +] + commands = [ - ["python", "manage.py", "collectstatic", "--noinput"], - #["python", "manage.py", "flush", "--noinput"], - # ["python", "manage.py", "makemigrations", "Common", "--noinput"], - # ["python", "manage.py", "makemigrations", "Establishment", "--noinput"], - # ["python", "manage.py", "makemigrations", "Settings", "--noinput"], - # ["python", "manage.py", "makemigrations", "Subscriptions", "--noinput"], - # ["python", "manage.py", "makemigrations", "Planning", "--noinput"], - # ["python", "manage.py", "makemigrations", "GestionNotification", "--noinput"], - # ["python", "manage.py", "makemigrations", "GestionEmail", "--noinput"], - # ["python", "manage.py", "makemigrations", "GestionMessagerie", "--noinput"], - # ["python", "manage.py", "makemigrations", "Auth", "--noinput"], - # ["python", "manage.py", "makemigrations", "School", "--noinput"], ["python", "manage.py", "migrate", "--noinput"] ] @@ -45,14 +56,29 @@ def run_daphne(): return 0 if __name__ == "__main__": + + for command in collect_static_cmd: + if run_command(command) != 0: + exit(1) + + if flush_data: + for command in flush_data_cmd: + if run_command(command) != 0: + exit(1) + + if migrate_data: + for command in migrate_commands: + if run_command(command) != 0: + exit(1) + for command in commands: if run_command(command) != 0: exit(1) - #if test_mode: - # for test_command in test_commands: - # if run_command(test_command) != 0: - # exit(1) + if test_mode: + for test_command in test_commands: + if run_command(test_command) != 0: + exit(1) if watch_mode: celery_worker = subprocess.Popen(["celery", "-A", "N3wtSchool", "worker", "--loglevel=info"]) diff --git a/Front-End/src/app/[locale]/page.js b/Front-End/src/app/[locale]/page.js index 831066e..0e97ae7 100644 --- a/Front-End/src/app/[locale]/page.js +++ b/Front-End/src/app/[locale]/page.js @@ -15,7 +15,6 @@ export default function Home() {

{t('welcomeParents')}

{t('pleaseLogin')}