mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
feat: Mise à jour des Teacher
This commit is contained in:
@ -601,4 +601,12 @@ class ProfileRoleSimpleView(APIView):
|
|||||||
responses={200: 'Suppression réussie'}
|
responses={200: 'Suppression réussie'}
|
||||||
)
|
)
|
||||||
def delete(self, request, id):
|
def delete(self, request, id):
|
||||||
return bdd.delete_object(ProfileRole, id)
|
profile_role = ProfileRole.objects.get(id=id)
|
||||||
|
profile = profile_role.profile
|
||||||
|
profile_role.delete()
|
||||||
|
|
||||||
|
# Vérifier si le profil n'a plus de rôles associés
|
||||||
|
if not ProfileRole.objects.filter(profile=profile).exists():
|
||||||
|
profile.delete()
|
||||||
|
|
||||||
|
return JsonResponse({'message': 'Suppression réussie'}, safe=False)
|
||||||
@ -33,34 +33,49 @@ class TeacherSerializer(serializers.ModelSerializer):
|
|||||||
specialities = serializers.PrimaryKeyRelatedField(queryset=Speciality.objects.all(), many=True, required=False)
|
specialities = serializers.PrimaryKeyRelatedField(queryset=Speciality.objects.all(), many=True, required=False)
|
||||||
specialities_details = serializers.SerializerMethodField()
|
specialities_details = serializers.SerializerMethodField()
|
||||||
updated_date_formatted = serializers.SerializerMethodField()
|
updated_date_formatted = serializers.SerializerMethodField()
|
||||||
role_type = serializers.SerializerMethodField()
|
role_type_display = serializers.SerializerMethodField()
|
||||||
associated_profile_email = serializers.SerializerMethodField()
|
role_type = serializers.IntegerField(write_only=True)
|
||||||
|
associated_profile_email = serializers.EmailField(write_only=True)
|
||||||
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)
|
associated_profile_email_display = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Teacher
|
model = Teacher
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
def create_or_update_profile_role(self, profile, associated_profile_email, establishment_id, role_type):
|
||||||
|
# Mettre à jour l'email du profil si nécessaire
|
||||||
|
if profile.email != associated_profile_email:
|
||||||
|
profile.email = associated_profile_email
|
||||||
|
profile.username = associated_profile_email
|
||||||
|
profile.save()
|
||||||
|
|
||||||
|
profile_role, created = ProfileRole.objects.update_or_create(
|
||||||
|
profile=profile,
|
||||||
|
establishment_id=establishment_id,
|
||||||
|
defaults={'role_type': role_type, 'is_active': True}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not created:
|
||||||
|
profile_role.role_type = role_type
|
||||||
|
profile_role.establishment_id = establishment_id
|
||||||
|
profile_role.save()
|
||||||
|
|
||||||
|
return profile_role
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
specialities_data = validated_data.pop('specialities', None)
|
specialities_data = validated_data.pop('specialities', None)
|
||||||
profile_role_data = validated_data.pop('profile_role_data', None)
|
associated_profile_email = validated_data.pop('associated_profile_email')
|
||||||
profile_role = validated_data.pop('profile_role', None)
|
establishment_id = validated_data.pop('establishment')
|
||||||
|
role_type = validated_data.pop('role_type')
|
||||||
|
|
||||||
if profile_role_data:
|
profile, created = Profile.objects.get_or_create(
|
||||||
establishment_id = profile_role_data.pop('establishment').id
|
email=associated_profile_email,
|
||||||
profile_id = profile_role_data.pop('profile').id
|
defaults={'username': associated_profile_email}
|
||||||
profile_role_data['establishment'] = establishment_id
|
)
|
||||||
profile_role_data['profile'] = profile_id
|
|
||||||
|
|
||||||
# Créer l'instance de ProfileRole
|
profile_role = self.create_or_update_profile_role(profile, associated_profile_email, establishment_id, role_type)
|
||||||
profile_role_serializer = ProfileRoleSerializer(data=profile_role_data)
|
|
||||||
profile_role_serializer.is_valid(raise_exception=True)
|
|
||||||
profile_role = profile_role_serializer.save()
|
|
||||||
elif profile_role:
|
|
||||||
profile_role = ProfileRole.objects.get(id=profile_role.id)
|
|
||||||
|
|
||||||
# Créer l'enseignant avec l'instance de ProfileRole
|
|
||||||
teacher = Teacher.objects.create(profile_role=profile_role, **validated_data)
|
teacher = Teacher.objects.create(profile_role=profile_role, **validated_data)
|
||||||
if specialities_data:
|
if specialities_data:
|
||||||
teacher.specialities.set(specialities_data)
|
teacher.specialities.set(specialities_data)
|
||||||
@ -69,21 +84,17 @@ class TeacherSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
specialities_data = validated_data.pop('specialities', [])
|
specialities_data = validated_data.pop('specialities', [])
|
||||||
profile_role_data = validated_data.pop('profile_role_data', None)
|
associated_profile_email = validated_data.pop('associated_profile_email', instance.profile_role.profile.email)
|
||||||
profile_role = validated_data.pop('profile_role', None)
|
establishment_id = validated_data.get('establishment', instance.profile_role.establishment.id)
|
||||||
|
role_type = validated_data.get('role_type', instance.profile_role.role_type)
|
||||||
|
|
||||||
if profile_role_data:
|
profile = instance.profile_role.profile
|
||||||
establishment_id = profile_role_data.pop('establishment').id
|
|
||||||
profile_role_data['establishment'] = establishment_id
|
profile_role = self.create_or_update_profile_role(profile, associated_profile_email, establishment_id, role_type)
|
||||||
profile_role_serializer = ProfileRoleSerializer(instance.profile_role, data=profile_role_data)
|
instance.profile_role = profile_role
|
||||||
profile_role_serializer.is_valid(raise_exception=True)
|
|
||||||
profile_role_serializer.save()
|
|
||||||
elif profile_role:
|
|
||||||
instance.profile_role = ProfileRole.objects.get(id=profile_role.id)
|
|
||||||
|
|
||||||
instance.last_name = validated_data.get('last_name', instance.last_name)
|
instance.last_name = validated_data.get('last_name', instance.last_name)
|
||||||
instance.first_name = validated_data.get('first_name', instance.first_name)
|
instance.first_name = validated_data.get('first_name', instance.first_name)
|
||||||
instance.email = validated_data.get('email', instance.email)
|
|
||||||
instance.save()
|
instance.save()
|
||||||
if specialities_data:
|
if specialities_data:
|
||||||
instance.specialities.set(specialities_data)
|
instance.specialities.set(specialities_data)
|
||||||
@ -95,12 +106,6 @@ class TeacherSerializer(serializers.ModelSerializer):
|
|||||||
local_time = utc_time.astimezone(local_tz)
|
local_time = utc_time.astimezone(local_tz)
|
||||||
return local_time.strftime("%d-%m-%Y %H:%M")
|
return local_time.strftime("%d-%m-%Y %H:%M")
|
||||||
|
|
||||||
def get_role_type(self, obj):
|
|
||||||
profile_role = obj.profile_role
|
|
||||||
if profile_role:
|
|
||||||
return {'role_type': profile_role.role_type, 'establishment': profile_role.establishment.name}
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_specialities_details(self, obj):
|
def get_specialities_details(self, obj):
|
||||||
return [{'id': speciality.id, 'name': speciality.name, 'color_code': speciality.color_code} for speciality in obj.specialities.all()]
|
return [{'id': speciality.id, 'name': speciality.name, 'color_code': speciality.color_code} for speciality in obj.specialities.all()]
|
||||||
|
|
||||||
@ -109,6 +114,14 @@ class TeacherSerializer(serializers.ModelSerializer):
|
|||||||
return obj.profile_role.profile.email
|
return obj.profile_role.profile.email
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_role_type_display(self, obj):
|
||||||
|
if obj.profile_role:
|
||||||
|
return obj.profile_role.role_type
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_associated_profile_email_display(self, obj):
|
||||||
|
return self.get_associated_profile_email(obj)
|
||||||
|
|
||||||
class PlanningSerializer(serializers.ModelSerializer):
|
class PlanningSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Planning
|
model = Planning
|
||||||
|
|||||||
@ -111,22 +111,6 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
|
|
||||||
const { selectedEstablishmentId } = useEstablishment();
|
const { selectedEstablishmentId } = useEstablishment();
|
||||||
|
|
||||||
const handleSelectProfile = (profile) => {
|
|
||||||
setNewTeacher((prevData) => ({
|
|
||||||
...prevData,
|
|
||||||
selectedProfile: profile,
|
|
||||||
}));
|
|
||||||
setFormData((prevData) => ({
|
|
||||||
...prevData,
|
|
||||||
selectedProfile: profile
|
|
||||||
}));
|
|
||||||
setConfirmPopupMessage(`Vous êtes sur le point de rattacher l'enseignant ${newTeacher?.first_name} ${newTeacher?.last_name} au profil ${profile.email} ID = ${profile.id}.`);
|
|
||||||
setConfirmPopupOnConfirm(() => () => {
|
|
||||||
setConfirmPopupVisible(false);
|
|
||||||
});
|
|
||||||
setConfirmPopupVisible(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCancelConfirmation = () => {
|
const handleCancelConfirmation = () => {
|
||||||
setConfirmPopupVisible(false);
|
setConfirmPopupVisible(false);
|
||||||
};
|
};
|
||||||
@ -137,8 +121,8 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleAddTeacher = () => {
|
const handleAddTeacher = () => {
|
||||||
setNewTeacher({ id: Date.now(), last_name: '', first_name: '', selectedProfile: null, specialities: [], droit: 0 });
|
setNewTeacher({ id: Date.now(), last_name: '', first_name: '', associated_profile_email: '', specialities: [], role_type: 0 });
|
||||||
setFormData({ last_name: '', first_name: '', selectedProfile: null, specialities: [], droit: 0});
|
setFormData({ last_name: '', first_name: '', associated_profile_email: '', specialities: [], role_type: 0});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveTeacher = (id) => {
|
const handleRemoveTeacher = (id) => {
|
||||||
@ -152,16 +136,13 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveNewTeacher = () => {
|
const handleSaveNewTeacher = () => {
|
||||||
if (formData.last_name && formData.first_name && formData.selectedProfile) {
|
if (formData.last_name && formData.first_name && formData.associated_profile_email) {
|
||||||
const data = {
|
const data = {
|
||||||
last_name: formData.last_name,
|
last_name: formData.last_name,
|
||||||
first_name: formData.first_name,
|
first_name: formData.first_name,
|
||||||
profile_role_data: {
|
associated_profile_email: formData.associated_profile_email,
|
||||||
role_type: formData.droit,
|
establishment: selectedEstablishmentId,
|
||||||
establishment: selectedEstablishmentId,
|
role_type: formData.role_type,
|
||||||
is_active: true,
|
|
||||||
profile: formData.selectedProfile.id
|
|
||||||
},
|
|
||||||
specialities: formData.specialities
|
specialities: formData.specialities
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -185,28 +166,20 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdateTeacher = (id, updatedData) => {
|
const handleUpdateTeacher = (id, updatedData) => {
|
||||||
if (updatedData.last_name && updatedData.first_name && updatedData.email) {
|
if (updatedData.last_name && updatedData.first_name && updatedData.associated_profile_email_display) {
|
||||||
const data = {
|
const data = {
|
||||||
email: updatedData.email,
|
last_name: formData.last_name,
|
||||||
username: updatedData.email,
|
first_name: formData.first_name,
|
||||||
droit: updatedData.droit,
|
associated_profile_email: formData.associated_profile_email || formData.associated_profile_email_display,
|
||||||
|
establishment: selectedEstablishmentId,
|
||||||
|
role_type: formData.role_type,
|
||||||
|
specialities: formData.specialities
|
||||||
};
|
};
|
||||||
updateProfile(updatedData.associated_profile, data, csrfToken)
|
handleEdit(id, data)
|
||||||
.then(response => {
|
.then((updatedTeacher) => {
|
||||||
logger.debug('Success:', response);
|
setTeachers(prevTeachers => prevTeachers.map(teacher => teacher.id === id ? { ...teacher, ...updatedTeacher } : teacher));
|
||||||
handleEdit(id, updatedData)
|
setEditingTeacher(null);
|
||||||
.then((updatedTeacher) => {
|
setFormData({});
|
||||||
setTeachers(prevTeachers => prevTeachers.map(teacher => teacher.id === id ? { ...teacher, ...updatedTeacher } : teacher));
|
|
||||||
setEditingTeacher(null);
|
|
||||||
setFormData({});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
logger.error('Error:', error.message);
|
|
||||||
if (error.details) {
|
|
||||||
logger.error('Form errors:', error.details);
|
|
||||||
setLocalErrors(error.details);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
logger.error('Error:', error.message);
|
logger.error('Error:', error.message);
|
||||||
@ -265,6 +238,15 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleEditTeacher = (teacher) => {
|
||||||
|
setEditingTeacher(teacher.id);
|
||||||
|
setFormData({
|
||||||
|
...teacher,
|
||||||
|
associated_profile_email: teacher.associated_profile_email_display,
|
||||||
|
role_type: teacher.role_type_display,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const renderTeacherCell = (teacher, column) => {
|
const renderTeacherCell = (teacher, column) => {
|
||||||
const isEditing = editingTeacher === teacher.id;
|
const isEditing = editingTeacher === teacher.id;
|
||||||
const isCreating = newTeacher && newTeacher.id === teacher.id;
|
const isCreating = newTeacher && newTeacher.id === teacher.id;
|
||||||
@ -291,26 +273,17 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
case 'EMAIL':
|
case 'EMAIL':
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center space-x-2">
|
<InputText
|
||||||
{currentData.selectedProfile ? (
|
name="associated_profile_email"
|
||||||
<span className="text-gray-900">
|
type="email"
|
||||||
{currentData.selectedProfile.email}
|
value={currentData.associated_profile_email || teacher.associated_profile_email_display || ''}
|
||||||
</span>
|
onChange={handleChange}
|
||||||
) : (
|
placeholder="Adresse email de l'enseignant"
|
||||||
<span className="text-gray-500 italic">
|
errorMsg={getError('email')}
|
||||||
Rechercher un profil existant
|
/>
|
||||||
</span>
|
);
|
||||||
)}
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setDirectoryPopupVisible(true)}
|
|
||||||
>
|
|
||||||
<Search className="w-5 h-5 text-emerald-500 hover:text-emerald-700"/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case 'SPECIALITES':
|
case 'SPECIALITES':
|
||||||
return (
|
return (
|
||||||
<SpecialitiesDropZone teacher={currentData} handleSpecialitiesChange={handleSpecialitiesChange} specialities={specialities} isEditing={isEditing || isCreating} />
|
<SpecialitiesDropZone teacher={currentData} handleSpecialitiesChange={handleSpecialitiesChange} specialities={specialities} isEditing={isEditing || isCreating} />
|
||||||
@ -319,8 +292,8 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
return (
|
return (
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
name="droit"
|
name="role_type"
|
||||||
checked={currentData.droit === 1}
|
checked={currentData.role_type === 1}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -354,7 +327,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
<TeacherItem key={teacher.id} teacher={teacher} />
|
<TeacherItem key={teacher.id} teacher={teacher} />
|
||||||
);
|
);
|
||||||
case 'EMAIL':
|
case 'EMAIL':
|
||||||
return teacher.associated_profile_email;
|
return teacher.associated_profile_email_display;
|
||||||
case 'SPECIALITES':
|
case 'SPECIALITES':
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center space-x-2 flex-wrap">
|
<div className="flex justify-center space-x-2 flex-wrap">
|
||||||
@ -364,9 +337,9 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
case 'ADMINISTRATEUR':
|
case 'ADMINISTRATEUR':
|
||||||
if (teacher.associated_profile_email) {
|
if (teacher.associated_profile_email_display) {
|
||||||
const badgeClass = teacher.role_type.role_type === 1 ? 'bg-red-100 text-red-600' : 'bg-blue-100 text-blue-600';
|
const badgeClass = teacher.role_type_display === 1 ? 'bg-red-100 text-red-600' : 'bg-blue-100 text-blue-600';
|
||||||
const label = teacher.role_type.role_type === 1 ? 'OUI' : 'NON';
|
const label = teacher.role_type_display === 1 ? 'OUI' : 'NON';
|
||||||
return (
|
return (
|
||||||
<div key={teacher.id} className="flex justify-center items-center space-x-2">
|
<div key={teacher.id} className="flex justify-center items-center space-x-2">
|
||||||
<span className={`px-3 py-1 rounded-full font-bold ${badgeClass}`}>
|
<span className={`px-3 py-1 rounded-full font-bold ${badgeClass}`}>
|
||||||
@ -384,7 +357,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
<div className="flex justify-center space-x-2">
|
<div className="flex justify-center space-x-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setEditingTeacher(teacher.id) || setFormData(teacher)}
|
onClick={() => handleEditTeacher(teacher)}
|
||||||
className="text-blue-500 hover:text-blue-700"
|
className="text-blue-500 hover:text-blue-700"
|
||||||
>
|
>
|
||||||
<Edit3 className="w-5 h-5" />
|
<Edit3 className="w-5 h-5" />
|
||||||
|
|||||||
Reference in New Issue
Block a user