mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-04-03 16:51:26 +00:00
fix: Edition d'un teacher, champ email désactivé [N3WTS-1]
This commit is contained in:
@ -60,6 +60,7 @@ class TeacherSerializer(serializers.ModelSerializer):
|
|||||||
profile_role = serializers.PrimaryKeyRelatedField(queryset=ProfileRole.objects.all(), required=False)
|
profile_role = serializers.PrimaryKeyRelatedField(queryset=ProfileRole.objects.all(), required=False)
|
||||||
profile_role_data = ProfileRoleSerializer(write_only=True, required=False)
|
profile_role_data = ProfileRoleSerializer(write_only=True, required=False)
|
||||||
associated_profile_email = serializers.SerializerMethodField()
|
associated_profile_email = serializers.SerializerMethodField()
|
||||||
|
profile = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Teacher
|
model = Teacher
|
||||||
@ -155,6 +156,12 @@ class TeacherSerializer(serializers.ModelSerializer):
|
|||||||
return obj.profile_role.role_type
|
return obj.profile_role.role_type
|
||||||
return None
|
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 PlanningSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Planning
|
model = Planning
|
||||||
|
|||||||
@ -118,11 +118,23 @@ class TeacherDetailView(APIView):
|
|||||||
return JsonResponse(teacher_serializer.data, safe=False)
|
return JsonResponse(teacher_serializer.data, safe=False)
|
||||||
|
|
||||||
def put(self, request, id):
|
def put(self, request, id):
|
||||||
teacher_data=JSONParser().parse(request)
|
teacher_data = JSONParser().parse(request)
|
||||||
teacher = getObject(_objectName=Teacher, _columnName='id', _value=id)
|
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)
|
teacher_serializer = TeacherSerializer(teacher, data=teacher_data)
|
||||||
if teacher_serializer.is_valid():
|
if teacher_serializer.is_valid():
|
||||||
teacher_serializer.save()
|
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.data, safe=False)
|
||||||
|
|
||||||
return JsonResponse(teacher_serializer.errors, safe=False)
|
return JsonResponse(teacher_serializer.errors, safe=False)
|
||||||
|
|||||||
@ -146,43 +146,61 @@ const TeachersSection = ({
|
|||||||
|
|
||||||
const { selectedEstablishmentId } = useEstablishment();
|
const { selectedEstablishmentId } = useEstablishment();
|
||||||
|
|
||||||
const handleEmailChange = (e) => {
|
// --- UTILS ---
|
||||||
const email = e.target.value;
|
|
||||||
|
|
||||||
// Vérifier si l'email correspond à un profil existant
|
// Retourne le profil existant pour un email, utilisé par un teacher actif ou le teacher en cours d'édition
|
||||||
const existingProfile = profiles.find((profile) => profile.email === email);
|
const getUsedProfileForEmail = (email, teacherId = null) => {
|
||||||
|
const usedProfileIds = new Set(
|
||||||
// Ajout du log si l'adresse email est déjà utilisée pour un profil existant
|
teachers.map(t => t.profile_role && t.profile).filter(Boolean)
|
||||||
if (existingProfile) {
|
);
|
||||||
logger.info(
|
// Ajoute le profil du teacher en cours d'édition si besoin
|
||||||
`Adresse email déjà utilisée pour le profil ${existingProfile.id}`
|
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);
|
||||||
setFormData((prevData) => ({
|
if (profileObj && profileObj.email === email) {
|
||||||
...prevData,
|
usedProfileIds.add(profileObj.id);
|
||||||
associated_profile_email: email,
|
}
|
||||||
existingProfileId: existingProfile ? existingProfile.id : null,
|
} else {
|
||||||
}));
|
// Cas création immédiate : on cherche le profil par email dans profiles
|
||||||
|
const profileObj = profiles.find(p => p.email === email);
|
||||||
if (newTeacher) {
|
if (profileObj) {
|
||||||
setNewTeacher((prevData) => ({
|
usedProfileIds.add(profileObj.id);
|
||||||
...prevData,
|
}
|
||||||
associated_profile_email: email,
|
}
|
||||||
existingProfileId: existingProfile ? existingProfile.id : null,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
return profiles.find(
|
||||||
|
(profile) => profile.email === email && usedProfileIds.has(profile.id)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancelConfirmation = () => {
|
// Met à jour le formData et newTeacher si besoin
|
||||||
setConfirmPopupVisible(false);
|
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) => {
|
const getError = (field) => {
|
||||||
return localErrors?.[field]?.[0];
|
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 = () => {
|
const handleAddTeacher = () => {
|
||||||
setNewTeacher({
|
setNewTeacher({
|
||||||
id: Date.now(),
|
id: Date.now(),
|
||||||
@ -202,15 +220,15 @@ const TeachersSection = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveTeacher = (id) => {
|
const handleRemoveTeacher = (id) => {
|
||||||
|
logger.debug('[DELETE] Suppression teacher id:', id);
|
||||||
return handleDelete(id)
|
return handleDelete(id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setTeachers((prevTeachers) =>
|
setTeachers(prevTeachers =>
|
||||||
prevTeachers.filter((teacher) => teacher.id !== id)
|
prevTeachers.filter(teacher => teacher.id !== id)
|
||||||
);
|
);
|
||||||
|
logger.debug('[DELETE] Teacher supprimé:', id);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch(logger.error);
|
||||||
logger.error(error);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveNewTeacher = () => {
|
const handleSaveNewTeacher = () => {
|
||||||
@ -241,16 +259,29 @@ const TeachersSection = ({
|
|||||||
|
|
||||||
handleCreate(data)
|
handleCreate(data)
|
||||||
.then((createdTeacher) => {
|
.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]);
|
setTeachers([createdTeacher, ...teachers]);
|
||||||
setNewTeacher(null);
|
setNewTeacher(null);
|
||||||
setLocalErrors({});
|
setLocalErrors({});
|
||||||
|
setFormData(prev => ({
|
||||||
|
...prev,
|
||||||
|
existingProfileId: newProfileId,
|
||||||
|
}));
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
logger.error('Error:', error.message);
|
logger.error('Error:', error.message);
|
||||||
if (error.details) {
|
if (error.details) setLocalErrors(error.details);
|
||||||
logger.error('Form errors:', error.details);
|
|
||||||
setLocalErrors(error.details);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setPopupMessage('Tous les champs doivent être remplis et valides');
|
setPopupMessage('Tous les champs doivent être remplis et valides');
|
||||||
@ -259,51 +290,28 @@ const TeachersSection = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdateTeacher = (id, updatedData) => {
|
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);
|
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 (
|
if (
|
||||||
updatedData.last_name &&
|
updatedData.last_name &&
|
||||||
updatedData.first_name &&
|
updatedData.first_name &&
|
||||||
updatedData.associated_profile_email
|
updatedData.associated_profile_email
|
||||||
) {
|
) {
|
||||||
const data = {
|
const profileRoleData = {
|
||||||
last_name: updatedData.last_name,
|
id: updatedData.profile_role,
|
||||||
first_name: updatedData.first_name,
|
establishment: selectedEstablishmentId,
|
||||||
profile_role_data: {
|
role_type: updatedData.role_type || 0,
|
||||||
id: updatedData.profile_role,
|
is_active: true,
|
||||||
establishment: selectedEstablishmentId,
|
profile: updatedData.existingProfileId,
|
||||||
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 || [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
handleEdit(id, data)
|
handleEdit(id, {
|
||||||
|
last_name: updatedData.last_name,
|
||||||
|
first_name: updatedData.first_name,
|
||||||
|
profile_role_data: profileRoleData,
|
||||||
|
specialities: updatedData.specialities || [],
|
||||||
|
})
|
||||||
.then((updatedTeacher) => {
|
.then((updatedTeacher) => {
|
||||||
setTeachers((prevTeachers) =>
|
setTeachers((prevTeachers) =>
|
||||||
prevTeachers.map((teacher) =>
|
prevTeachers.map((teacher) =>
|
||||||
@ -315,10 +323,7 @@ const TeachersSection = ({
|
|||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
logger.error('Error:', error.message);
|
logger.error('Error:', error.message);
|
||||||
if (error.details) {
|
if (error.details) setLocalErrors(error.details);
|
||||||
logger.error('Form errors:', error.details);
|
|
||||||
setLocalErrors(error.details);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setPopupMessage('Tous les champs doivent être remplis et valides');
|
setPopupMessage('Tous les champs doivent être remplis et valides');
|
||||||
@ -328,45 +333,12 @@ const TeachersSection = ({
|
|||||||
|
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
const { name, value, type, checked } = e.target;
|
const { name, value, type, checked } = e.target;
|
||||||
let parsedValue = value;
|
let parsedValue = type === 'checkbox' ? (checked ? 1 : 0) : value;
|
||||||
|
updateFormData({ [name]: parsedValue });
|
||||||
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,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSpecialitiesChange = (selectedSpecialities) => {
|
const handleSpecialitiesChange = (selectedSpecialities) => {
|
||||||
if (editingTeacher) {
|
updateFormData({ specialities: selectedSpecialities });
|
||||||
setFormData((prevData) => ({
|
|
||||||
...prevData,
|
|
||||||
specialities: selectedSpecialities,
|
|
||||||
}));
|
|
||||||
} else if (newTeacher) {
|
|
||||||
setNewTeacher((prevData) => ({
|
|
||||||
...prevData,
|
|
||||||
specialities: selectedSpecialities,
|
|
||||||
}));
|
|
||||||
setFormData((prevData) => ({
|
|
||||||
...prevData,
|
|
||||||
specialities: selectedSpecialities,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditTeacher = (teacher) => {
|
const handleEditTeacher = (teacher) => {
|
||||||
@ -413,6 +385,7 @@ const TeachersSection = ({
|
|||||||
onChange={handleEmailChange}
|
onChange={handleEmailChange}
|
||||||
placeholder="Adresse email de l'enseignant"
|
placeholder="Adresse email de l'enseignant"
|
||||||
errorMsg={getError('email')}
|
errorMsg={getError('email')}
|
||||||
|
enable={!isEditing}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'SPECIALITES':
|
case 'SPECIALITES':
|
||||||
|
|||||||
Reference in New Issue
Block a user