From 176edc5c452fa7b03da266f5a227c730ff4ad525 Mon Sep 17 00:00:00 2001 From: N3WT DE COMPET Date: Sun, 15 Feb 2026 15:47:51 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20Edition=20d'un=20teacher,=20champ=20emai?= =?UTF-8?q?l=20d=C3=A9sactiv=C3=A9=20[N3WTS-1]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Back-End/School/serializers.py | 7 + Back-End/School/views.py | 14 +- .../Configuration/TeachersSection.js | 197 ++++++++---------- 3 files changed, 105 insertions(+), 113 deletions(-) diff --git a/Back-End/School/serializers.py b/Back-End/School/serializers.py index 801b1c5..c23af9d 100644 --- a/Back-End/School/serializers.py +++ b/Back-End/School/serializers.py @@ -60,6 +60,7 @@ class TeacherSerializer(serializers.ModelSerializer): profile_role = serializers.PrimaryKeyRelatedField(queryset=ProfileRole.objects.all(), required=False) profile_role_data = ProfileRoleSerializer(write_only=True, required=False) associated_profile_email = serializers.SerializerMethodField() + profile = serializers.SerializerMethodField() class Meta: model = Teacher @@ -155,6 +156,12 @@ class TeacherSerializer(serializers.ModelSerializer): return obj.profile_role.role_type return None + def get_profile(self, obj): + # Retourne l'id du profile associé via profile_role + if obj.profile_role and obj.profile_role.profile: + return obj.profile_role.profile.id + return None + class PlanningSerializer(serializers.ModelSerializer): class Meta: model = Planning diff --git a/Back-End/School/views.py b/Back-End/School/views.py index bd5cc1e..97b0cc3 100644 --- a/Back-End/School/views.py +++ b/Back-End/School/views.py @@ -118,11 +118,23 @@ class TeacherDetailView(APIView): return JsonResponse(teacher_serializer.data, safe=False) def put(self, request, id): - teacher_data=JSONParser().parse(request) + teacher_data = JSONParser().parse(request) teacher = getObject(_objectName=Teacher, _columnName='id', _value=id) + + # Récupérer l'ancien profile avant modification + old_profile_role = getattr(teacher, 'profile_role', None) + old_profile = getattr(old_profile_role, 'profile', None) if old_profile_role else None + teacher_serializer = TeacherSerializer(teacher, data=teacher_data) if teacher_serializer.is_valid(): teacher_serializer.save() + + # Après modification, vérifier si l'ancien profile n'a plus de ProfileRole + if old_profile: + from Auth.models import ProfileRole # import local pour éviter les imports circulaires + if not ProfileRole.objects.filter(profile=old_profile).exists(): + old_profile.delete() + return JsonResponse(teacher_serializer.data, safe=False) return JsonResponse(teacher_serializer.errors, safe=False) diff --git a/Front-End/src/components/Structure/Configuration/TeachersSection.js b/Front-End/src/components/Structure/Configuration/TeachersSection.js index 326166c..9cffc51 100644 --- a/Front-End/src/components/Structure/Configuration/TeachersSection.js +++ b/Front-End/src/components/Structure/Configuration/TeachersSection.js @@ -146,43 +146,61 @@ const TeachersSection = ({ const { selectedEstablishmentId } = useEstablishment(); - const handleEmailChange = (e) => { - const email = e.target.value; + // --- UTILS --- - // Vérifier si l'email correspond à un profil existant - const existingProfile = profiles.find((profile) => profile.email === email); - - // Ajout du log si l'adresse email est déjà utilisée pour un profil existant - if (existingProfile) { - logger.info( - `Adresse email déjà utilisée pour le profil ${existingProfile.id}` - ); - } - - setFormData((prevData) => ({ - ...prevData, - associated_profile_email: email, - existingProfileId: existingProfile ? existingProfile.id : null, - })); - - if (newTeacher) { - setNewTeacher((prevData) => ({ - ...prevData, - associated_profile_email: email, - existingProfileId: existingProfile ? existingProfile.id : null, - })); + // Retourne le profil existant pour un email, utilisé par un teacher actif ou le teacher en cours d'édition + const getUsedProfileForEmail = (email, teacherId = null) => { + const usedProfileIds = new Set( + teachers.map(t => t.profile_role && t.profile).filter(Boolean) + ); + // Ajoute le profil du teacher en cours d'édition si besoin + if (teacherId) { + const currentTeacher = teachers.find(t => t.id === teacherId); + if (currentTeacher && currentTeacher.profile_role && currentTeacher.profile) { + const profileObj = profiles.find(p => p.id === currentTeacher.profile); + if (profileObj && profileObj.email === email) { + usedProfileIds.add(profileObj.id); + } + } else { + // Cas création immédiate : on cherche le profil par email dans profiles + const profileObj = profiles.find(p => p.email === email); + if (profileObj) { + usedProfileIds.add(profileObj.id); + } + } } + return profiles.find( + (profile) => profile.email === email && usedProfileIds.has(profile.id) + ); }; - const handleCancelConfirmation = () => { - setConfirmPopupVisible(false); + // Met à jour le formData et newTeacher si besoin + const updateFormData = (data) => { + setFormData(prev => ({ ...prev, ...data })); + if (newTeacher) setNewTeacher(prev => ({ ...prev, ...data })); }; - // Récupération des messages d'erreur + // Récupération des messages d'erreur pour un champ donné const getError = (field) => { return localErrors?.[field]?.[0]; }; + // --- HANDLERS --- + + const handleEmailChange = (e) => { + const email = e.target.value; + const existingProfile = getUsedProfileForEmail(email, editingTeacher); + + if (existingProfile) { + logger.info(`Adresse email déjà utilisée pour le profil ${existingProfile.id}`); + } + + updateFormData({ + associated_profile_email: email, + existingProfileId: existingProfile ? existingProfile.id : null, + }); + }; + const handleAddTeacher = () => { setNewTeacher({ id: Date.now(), @@ -202,15 +220,15 @@ const TeachersSection = ({ }; const handleRemoveTeacher = (id) => { + logger.debug('[DELETE] Suppression teacher id:', id); return handleDelete(id) .then(() => { - setTeachers((prevTeachers) => - prevTeachers.filter((teacher) => teacher.id !== id) + setTeachers(prevTeachers => + prevTeachers.filter(teacher => teacher.id !== id) ); + logger.debug('[DELETE] Teacher supprimé:', id); }) - .catch((error) => { - logger.error(error); - }); + .catch(logger.error); }; const handleSaveNewTeacher = () => { @@ -241,16 +259,29 @@ const TeachersSection = ({ handleCreate(data) .then((createdTeacher) => { + // Recherche du profile associé dans profiles + let newProfileId = undefined; + let foundProfile = undefined; + if ( + createdTeacher && + createdTeacher.profile_role && + createdTeacher.profile + ) { + newProfileId = createdTeacher.profile; + foundProfile = profiles.find(p => p.id === newProfileId); + } + setTeachers([createdTeacher, ...teachers]); setNewTeacher(null); setLocalErrors({}); + setFormData(prev => ({ + ...prev, + existingProfileId: newProfileId, + })); }) .catch((error) => { logger.error('Error:', error.message); - if (error.details) { - logger.error('Form errors:', error.details); - setLocalErrors(error.details); - } + if (error.details) setLocalErrors(error.details); }); } else { setPopupMessage('Tous les champs doivent être remplis et valides'); @@ -259,51 +290,28 @@ const TeachersSection = ({ }; const handleUpdateTeacher = (id, updatedData) => { - // Récupérer l'enseignant actuel à partir de la liste des enseignants + // Simplification : le profil est forcément existant, on utilise directement existingProfileId du formData const currentTeacher = teachers.find((teacher) => teacher.id === id); - // Vérifier si l'email correspond à un profil existant - const existingProfile = profiles.find( - (profile) => profile.email === currentTeacher.associated_profile_email - ); - - // Vérifier si l'email a été modifié - const isEmailModified = currentTeacher - ? currentTeacher.associated_profile_email !== - updatedData.associated_profile_email - : true; - - // Mettre à jour existingProfileId en fonction de l'email - updatedData.existingProfileId = existingProfile ? existingProfile.id : null; - if ( updatedData.last_name && updatedData.first_name && updatedData.associated_profile_email ) { - const data = { - last_name: updatedData.last_name, - first_name: updatedData.first_name, - profile_role_data: { - id: updatedData.profile_role, - establishment: selectedEstablishmentId, - role_type: updatedData.role_type || 0, - is_active: true, - ...(isEmailModified - ? { - profile_data: { - id: updatedData.existingProfileId, - email: updatedData.associated_profile_email, - username: updatedData.associated_profile_email, - password: 'Provisoire01!', - }, - } - : { profile: updatedData.existingProfileId }), - }, - specialities: updatedData.specialities || [], + const profileRoleData = { + id: updatedData.profile_role, + establishment: selectedEstablishmentId, + role_type: updatedData.role_type || 0, + is_active: true, + profile: updatedData.existingProfileId, }; - handleEdit(id, data) + handleEdit(id, { + last_name: updatedData.last_name, + first_name: updatedData.first_name, + profile_role_data: profileRoleData, + specialities: updatedData.specialities || [], + }) .then((updatedTeacher) => { setTeachers((prevTeachers) => prevTeachers.map((teacher) => @@ -315,10 +323,7 @@ const TeachersSection = ({ }) .catch((error) => { logger.error('Error:', error.message); - if (error.details) { - logger.error('Form errors:', error.details); - setLocalErrors(error.details); - } + if (error.details) setLocalErrors(error.details); }); } else { setPopupMessage('Tous les champs doivent être remplis et valides'); @@ -328,45 +333,12 @@ const TeachersSection = ({ const handleChange = (e) => { const { name, value, type, checked } = e.target; - let parsedValue = value; - - if (type === 'checkbox') { - parsedValue = checked ? 1 : 0; - } - - if (editingTeacher) { - setFormData((prevData) => ({ - ...prevData, - [name]: parsedValue, - })); - } else if (newTeacher) { - setNewTeacher((prevData) => ({ - ...prevData, - [name]: parsedValue, - })); - setFormData((prevData) => ({ - ...prevData, - [name]: parsedValue, - })); - } + let parsedValue = type === 'checkbox' ? (checked ? 1 : 0) : value; + updateFormData({ [name]: parsedValue }); }; const handleSpecialitiesChange = (selectedSpecialities) => { - if (editingTeacher) { - setFormData((prevData) => ({ - ...prevData, - specialities: selectedSpecialities, - })); - } else if (newTeacher) { - setNewTeacher((prevData) => ({ - ...prevData, - specialities: selectedSpecialities, - })); - setFormData((prevData) => ({ - ...prevData, - specialities: selectedSpecialities, - })); - } + updateFormData({ specialities: selectedSpecialities }); }; const handleEditTeacher = (teacher) => { @@ -413,6 +385,7 @@ const TeachersSection = ({ onChange={handleEmailChange} placeholder="Adresse email de l'enseignant" errorMsg={getError('email')} + enable={!isEditing} /> ); case 'SPECIALITES':