From 55cb20bf8cd4e198471937d337ee595df88ea969 Mon Sep 17 00:00:00 2001 From: N3WT DE COMPET Date: Wed, 28 May 2025 14:28:21 +0200 Subject: [PATCH] =?UTF-8?q?chore:=20Lors=20de=20la=20cr=C3=A9ation=20d'un?= =?UTF-8?q?=20=C3=A9tablissement,=20cr=C3=A9ation=20d'un=20directeur=20et?= =?UTF-8?q?=20d'un=20SMTP=20Settings=20(utilis=C3=A9=20pour=20les=20envois?= =?UTF-8?q?=20de=20dossiers)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Back-End/.gitignore | 2 +- Back-End/Auth/models.py | 12 +++++- Back-End/Establishment/models.py | 2 +- Back-End/Establishment/views.py | 66 +++++++++++++++++++++++++++--- Back-End/N3wtSchool/mailManager.py | 65 +++++++++++++++++------------ 5 files changed, 111 insertions(+), 36 deletions(-) diff --git a/Back-End/.gitignore b/Back-End/.gitignore index 636e5aa..4a10846 100644 --- a/Back-End/.gitignore +++ b/Back-End/.gitignore @@ -4,4 +4,4 @@ documents data *.dmp staticfiles -/*/Configuration/application.json \ No newline at end of file +/*/Configuration/application*.json \ No newline at end of file diff --git a/Back-End/Auth/models.py b/Back-End/Auth/models.py index 95b36ea..408d702 100644 --- a/Back-End/Auth/models.py +++ b/Back-End/Auth/models.py @@ -22,11 +22,19 @@ class ProfileRole(models.Model): PROFIL_ADMIN = 1, _('ADMIN') PROFIL_PARENT = 2, _('PARENT') - profile = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='roles') + profile = models.ForeignKey('Profile', on_delete=models.CASCADE, related_name='roles') role_type = models.IntegerField(choices=RoleType.choices, default=RoleType.PROFIL_UNDEFINED) establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='profile_roles') is_active = models.BooleanField(default=False) updated_date = models.DateTimeField(auto_now=True) def __str__(self): - return f"{self.profile.email} - {self.get_role_type_display()}" \ No newline at end of file + return f"{self.profile.email} - {self.get_role_type_display()}" + +class Directeur(models.Model): + profile_role = models.OneToOneField("ProfileRole", on_delete=models.CASCADE, related_name='directeur_profile') + last_name = models.CharField(max_length=100) + first_name = models.CharField(max_length=100) + + def __str__(self): + return f"{self.first_name} {self.last_name} ({self.profile_role.profile.email})" \ No newline at end of file diff --git a/Back-End/Establishment/models.py b/Back-End/Establishment/models.py index 0440e0c..cbeb4d5 100644 --- a/Back-End/Establishment/models.py +++ b/Back-End/Establishment/models.py @@ -13,7 +13,7 @@ class EvaluationFrequency(models.IntegerChoices): YEAR = 3, _("Année") class Establishment(models.Model): - name = models.CharField(max_length=255, unique=True) + name = models.CharField(max_length=255) address = models.CharField(max_length=255) total_capacity = models.IntegerField() establishment_type = ArrayField(models.IntegerField(choices=StructureType.choices)) diff --git a/Back-End/Establishment/views.py b/Back-End/Establishment/views.py index 052aa0b..2e0b23c 100644 --- a/Back-End/Establishment/views.py +++ b/Back-End/Establishment/views.py @@ -9,6 +9,8 @@ from .serializers import EstablishmentSerializer from N3wtSchool.bdd import delete_object, getAllObjects from School.models import EstablishmentCompetency, Competency from django.db.models import Q +from Auth.models import Profile, ProfileRole, Directeur +from Settings.models import SMTPSettings @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') @@ -20,9 +22,8 @@ class EstablishmentListCreateView(APIView): def post(self, request): establishment_data = JSONParser().parse(request) - establishment_serializer = EstablishmentSerializer(data=establishment_data) - if establishment_serializer.is_valid(): - establishment = establishment_serializer.save() + try: + establishment, data = create_establishment_with_directeur(establishment_data) # Création des EstablishmentCompetency pour chaque compétence existante competencies = Competency.objects.filter( Q(end_of_cycle=True) | ~Q(level=None) @@ -33,8 +34,9 @@ class EstablishmentListCreateView(APIView): competency=competency, defaults={'is_required': True} ) - return JsonResponse(establishment_serializer.data, safe=False, status=status.HTTP_201_CREATED) - return JsonResponse(establishment_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) + return JsonResponse(data, safe=False, status=status.HTTP_201_CREATED) + except Exception as e: + return JsonResponse({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) @method_decorator(csrf_protect, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch') @@ -60,4 +62,56 @@ class EstablishmentDetailView(APIView): return JsonResponse(establishment_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, id): - return delete_object(Establishment, id) \ No newline at end of file + return delete_object(Establishment, id) + +def create_establishment_with_directeur(establishment_data): + # Extraction des sous-objets + directeur_data = establishment_data.pop("directeur", None) + smtp_settings_data = establishment_data.pop("smtp_settings", {}) + + # Vérification de la présence du directeur + if not directeur_data or not directeur_data.get("email"): + raise ValueError("Le champ 'directeur.email' est obligatoire.") + + directeur_email = directeur_data.get("email") + last_name = directeur_data.get("last_name", "") + first_name = directeur_data.get("first_name", "") + password = directeur_data.get("password", "Provisoire01!") + + # Création ou récupération du profil utilisateur + profile, created = Profile.objects.get_or_create( + email=directeur_email, + defaults={"username": directeur_email} + ) + if created or not profile.has_usable_password(): + profile.set_password(password) + profile.save() + + # Création de l'établissement + establishment_serializer = EstablishmentSerializer(data=establishment_data) + establishment_serializer.is_valid(raise_exception=True) + establishment = establishment_serializer.save() + + # Création ou récupération du ProfileRole ADMIN pour ce profil et cet établissement + profile_role, _ = ProfileRole.objects.get_or_create( + profile=profile, + establishment=establishment, + role_type=ProfileRole.RoleType.PROFIL_ADMIN, + defaults={"is_active": True} + ) + + # Création ou mise à jour du Directeur lié à ce ProfileRole + Directeur.objects.update_or_create( + profile_role=profile_role, + defaults={ + "last_name": last_name, + "first_name": first_name + } + ) + + # Création du SMTPSettings rattaché à l'établissement si des données sont fournies + if smtp_settings_data: + smtp_settings_data["establishment"] = establishment + SMTPSettings.objects.create(**smtp_settings_data) + + return establishment, establishment_serializer.data \ No newline at end of file diff --git a/Back-End/N3wtSchool/mailManager.py b/Back-End/N3wtSchool/mailManager.py index aafe115..83108fd 100644 --- a/Back-End/N3wtSchool/mailManager.py +++ b/Back-End/N3wtSchool/mailManager.py @@ -13,33 +13,45 @@ def getConnection(id_establishement): try: # Récupérer l'instance de l'établissement establishment = Establishment.objects.get(id=id_establishement) + try: + # Récupérer les paramètres SMTP associés à l'établissement + smtp_settings = SMTPSettings.objects.get(establishment=establishment) - # Récupérer les paramètres SMTP associés à l'établissement - smtp_settings = SMTPSettings.objects.get(establishment=establishment) - - # Créer une connexion SMTP avec les paramètres récupérés - connection = get_connection( - host=smtp_settings.smtp_server, - port=smtp_settings.smtp_port, - username=smtp_settings.smtp_user, - password=smtp_settings.smtp_password, - use_tls=smtp_settings.use_tls, - use_ssl=smtp_settings.use_ssl - ) - return connection - + # Créer une connexion SMTP avec les paramètres récupérés + connection = get_connection( + host=smtp_settings.smtp_server, + port=smtp_settings.smtp_port, + username=smtp_settings.smtp_user, + password=smtp_settings.smtp_password, + use_tls=smtp_settings.use_tls, + use_ssl=smtp_settings.use_ssl + ) + return connection + except SMTPSettings.DoesNotExist: + # Aucun paramètre SMTP spécifique, retournera None + return None except Establishment.DoesNotExist: raise NotFound(f"Aucun établissement trouvé avec l'ID {id_establishement}") - except SMTPSettings.DoesNotExist: - raise NotFound(f"Aucun paramètre SMTP trouvé pour l'établissement {id_establishement}") - def sendMail(subject, message, recipients, cc=[], bcc=[], attachments=[], connection=None): try: + # S'assurer que recipients, cc, bcc sont des listes + if isinstance(recipients, str): + recipients = [recipients] + if isinstance(cc, str): + cc = [cc] + if isinstance(bcc, str): + bcc = [bcc] + + # Récupération robuste du username + username = getattr(connection, 'username', None) + plain_message = strip_tags(message) - from_email = settings.EMAIL_HOST_USER if connection is not None: - from_email = connection.username + from_email = username + else: + from_email = settings.EMAIL_HOST_USER + email = EmailMultiAlternatives( subject=subject, @@ -52,15 +64,13 @@ def sendMail(subject, message, recipients, cc=[], bcc=[], attachments=[], connec ) email.attach_alternative(message, "text/html") - # Ajout des pièces jointes for attachment in attachments: - # attachment doit être un tuple (filename, content, mimetype) - # ex: ("document.pdf", fichier.read(), "application/pdf") email.attach(*attachment) email.send(fail_silently=False) return Response({'message': 'Email envoyé avec succès.'}, status=status.HTTP_200_OK) except Exception as e: + print(f"[DEBUG] Erreur lors de l'envoi de l'email : {e}") return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) def envoieReinitMotDePasse(recipients, code): @@ -73,7 +83,7 @@ def envoieReinitMotDePasse(recipients, code): } subject = EMAIL_REINIT_SUBJECT html_message = render_to_string('emails/resetPassword.html', context) - sendMail(subject, html_message, recipients) + sendMail(subject=subject, message=html_message, recipients=recipients) except Exception as e: errorMessage = str(e) @@ -91,10 +101,11 @@ def sendRegisterForm(recipients, establishment_id): 'email': recipients, 'establishment': establishment_id } - + # Récupérer la connexion SMTP + connection = getConnection(establishment_id) subject = EMAIL_INSCRIPTION_SUBJECT html_message = render_to_string('emails/inscription.html', context) - sendMail(subject, html_message, recipients) + sendMail(subject=subject, message=html_message, recipients=recipients, connection=connection) except Exception as e: @@ -113,9 +124,11 @@ def sendMandatSEPA(recipients, establishment_id): 'establishment': establishment_id } + # Récupérer la connexion SMTP + connection = getConnection(establishment_id) subject = EMAIL_INSCRIPTION_SUBJECT html_message = render_to_string('emails/sepa.html', context) - sendMail(subject, html_message, recipients) + sendMail(subject=subject, message=html_message, recipients=recipients, connection=connection) except Exception as e: errorMessage = str(e)