mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-04-03 16:51:26 +00:00
feat: Envoi mail d'inscription aux enseignants [N3WTS-1]
This commit is contained in:
@ -25,7 +25,7 @@ class ProfileRole(models.Model):
|
|||||||
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)
|
role_type = models.IntegerField(choices=RoleType.choices, default=RoleType.PROFIL_UNDEFINED)
|
||||||
establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='profile_roles')
|
establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='profile_roles')
|
||||||
is_active = models.BooleanField(default=False)
|
is_active = models.BooleanField(default=False, blank=True)
|
||||||
updated_date = models.DateTimeField(auto_now=True)
|
updated_date = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from django.core.mail import send_mail, get_connection, EmailMultiAlternatives, EmailMessage
|
from django.core.mail import get_connection, EmailMultiAlternatives, EmailMessage
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.html import strip_tags
|
from django.utils.html import strip_tags
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -207,4 +207,22 @@ def isValid(message, fiche_inscription):
|
|||||||
responsable = eleve.getMainGuardian()
|
responsable = eleve.getMainGuardian()
|
||||||
mailReponsableAVerifier = responsable.mail
|
mailReponsableAVerifier = responsable.mail
|
||||||
|
|
||||||
return responsableMail == mailReponsableAVerifier and str(idMail) == str(fiche_inscription.eleve.id)
|
return responsableMail == mailReponsableAVerifier and str(idMail) == str(fiche_inscription.eleve.id)
|
||||||
|
|
||||||
|
def sendRegisterTeacher(recipients, establishment_id):
|
||||||
|
errorMessage = ''
|
||||||
|
try:
|
||||||
|
EMAIL_INSCRIPTION_SUBJECT = '[N3WT-SCHOOL] Bienvenue sur N3wt School (Enseignant)'
|
||||||
|
context = {
|
||||||
|
'BASE_URL': settings.BASE_URL,
|
||||||
|
'URL_DJANGO': settings.URL_DJANGO,
|
||||||
|
'email': recipients,
|
||||||
|
'establishment': establishment_id
|
||||||
|
}
|
||||||
|
connection = getConnection(establishment_id)
|
||||||
|
subject = EMAIL_INSCRIPTION_SUBJECT
|
||||||
|
html_message = render_to_string('emails/inscription_teacher.html', context)
|
||||||
|
sendMail(subject=subject, message=html_message, recipients=recipients, connection=connection)
|
||||||
|
except Exception as e:
|
||||||
|
errorMessage = str(e)
|
||||||
|
return errorMessage
|
||||||
@ -35,6 +35,7 @@ from collections import defaultdict
|
|||||||
from Subscriptions.models import Student, StudentCompetency
|
from Subscriptions.models import Student, StudentCompetency
|
||||||
from Subscriptions.util import getCurrentSchoolYear
|
from Subscriptions.util import getCurrentSchoolYear
|
||||||
import logging
|
import logging
|
||||||
|
from N3wtSchool.mailManager import sendRegisterForm, sendRegisterTeacher
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -102,8 +103,17 @@ class TeacherListCreateView(APIView):
|
|||||||
teacher_serializer = TeacherSerializer(data=teacher_data)
|
teacher_serializer = TeacherSerializer(data=teacher_data)
|
||||||
|
|
||||||
if teacher_serializer.is_valid():
|
if teacher_serializer.is_valid():
|
||||||
teacher_serializer.save()
|
teacher_instance = teacher_serializer.save()
|
||||||
|
# Envoi du mail d'inscription enseignant uniquement à la création
|
||||||
|
email = None
|
||||||
|
establishment_id = None
|
||||||
|
if hasattr(teacher_instance, "profile_role") and teacher_instance.profile_role:
|
||||||
|
if hasattr(teacher_instance.profile_role, "profile") and teacher_instance.profile_role.profile:
|
||||||
|
email = teacher_instance.profile_role.profile.email
|
||||||
|
if hasattr(teacher_instance.profile_role, "establishment") and teacher_instance.profile_role.establishment:
|
||||||
|
establishment_id = teacher_instance.profile_role.establishment.id
|
||||||
|
if email and establishment_id:
|
||||||
|
sendRegisterTeacher(email, establishment_id)
|
||||||
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)
|
||||||
|
|||||||
@ -0,0 +1,63 @@
|
|||||||
|
<!-- Nouveau template pour l'inscription d'un enseignant -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Bienvenue sur N3wt School</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 30px;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
width: 120px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<!-- Utilisation d'un lien absolu pour le logo -->
|
||||||
|
<img src="{{URL_DJANGO}}/static/img/logo_min.svg" alt="Logo N3wt School" class="logo" style="display:block;margin:auto;" />
|
||||||
|
<h1>Bienvenue sur N3wt School</h1>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<p>Bonjour,</p>
|
||||||
|
<p>Votre compte enseignant a été créé sur la plateforme N3wt School.</p>
|
||||||
|
<p>Pour accéder à votre espace personnel, veuillez vous connecter à l'adresse suivante :<br>
|
||||||
|
<a href="{{BASE_URL}}/users/login">{{BASE_URL}}/users/login</a>
|
||||||
|
</p>
|
||||||
|
<p>Votre identifiant est : <b>{{ email }}</b></p>
|
||||||
|
<p>Si c'est votre première connexion, veuillez activer votre compte ici :<br>
|
||||||
|
<a href="{{BASE_URL}}/users/subscribe?establishment_id={{establishment}}">{{BASE_URL}}/users/subscribe</a>
|
||||||
|
</p>
|
||||||
|
<p>Nous vous souhaitons une excellente prise en main de l'outil.<br>
|
||||||
|
L'équipe N3wt School reste à votre disposition pour toute question.</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p>Ce message est généré automatiquement, merci de ne pas y répondre.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -140,38 +140,19 @@ const TeachersSection = ({
|
|||||||
const [removePopupMessage, setRemovePopupMessage] = useState('');
|
const [removePopupMessage, setRemovePopupMessage] = useState('');
|
||||||
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
|
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
|
||||||
|
|
||||||
const [confirmPopupVisible, setConfirmPopupVisible] = useState(false);
|
|
||||||
const [confirmPopupMessage, setConfirmPopupMessage] = useState('');
|
|
||||||
const [confirmPopupOnConfirm, setConfirmPopupOnConfirm] = useState(() => {});
|
|
||||||
|
|
||||||
const { selectedEstablishmentId } = useEstablishment();
|
const { selectedEstablishmentId } = useEstablishment();
|
||||||
|
|
||||||
// --- UTILS ---
|
// --- UTILS ---
|
||||||
|
|
||||||
// Retourne le profil existant pour un email, utilisé par un teacher actif ou le teacher en cours d'édition
|
// Retourne le profil existant pour un email
|
||||||
const getUsedProfileForEmail = (email, teacherId = null) => {
|
const getUsedProfileForEmail = (email) => {
|
||||||
const usedProfileIds = new Set(
|
// On cherche tous les profils dont l'email correspond
|
||||||
teachers.map(t => t.profile_role && t.profile).filter(Boolean)
|
const matchingProfiles = profiles.filter(p => p.email === email);
|
||||||
);
|
|
||||||
// Ajoute le profil du teacher en cours d'édition si besoin
|
// On retourne le premier profil correspondant (ou undefined)
|
||||||
if (teacherId) {
|
const result = matchingProfiles.length > 0 ? matchingProfiles[0] : undefined;
|
||||||
const currentTeacher = teachers.find(t => t.id === teacherId);
|
|
||||||
if (currentTeacher && currentTeacher.profile_role && currentTeacher.profile) {
|
return result;
|
||||||
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)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Met à jour le formData et newTeacher si besoin
|
// Met à jour le formData et newTeacher si besoin
|
||||||
@ -189,7 +170,7 @@ const TeachersSection = ({
|
|||||||
|
|
||||||
const handleEmailChange = (e) => {
|
const handleEmailChange = (e) => {
|
||||||
const email = e.target.value;
|
const email = e.target.value;
|
||||||
const existingProfile = getUsedProfileForEmail(email, editingTeacher);
|
const existingProfile = getUsedProfileForEmail(email);
|
||||||
|
|
||||||
if (existingProfile) {
|
if (existingProfile) {
|
||||||
logger.info(`Adresse email déjà utilisée pour le profil ${existingProfile.id}`);
|
logger.info(`Adresse email déjà utilisée pour le profil ${existingProfile.id}`);
|
||||||
@ -290,9 +271,6 @@ const TeachersSection = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdateTeacher = (id, updatedData) => {
|
const handleUpdateTeacher = (id, updatedData) => {
|
||||||
// Simplification : le profil est forcément existant, on utilise directement existingProfileId du formData
|
|
||||||
const currentTeacher = teachers.find((teacher) => teacher.id === id);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
updatedData.last_name &&
|
updatedData.last_name &&
|
||||||
updatedData.first_name &&
|
updatedData.first_name &&
|
||||||
@ -302,7 +280,6 @@ const TeachersSection = ({
|
|||||||
id: updatedData.profile_role,
|
id: updatedData.profile_role,
|
||||||
establishment: selectedEstablishmentId,
|
establishment: selectedEstablishmentId,
|
||||||
role_type: updatedData.role_type || 0,
|
role_type: updatedData.role_type || 0,
|
||||||
is_active: true,
|
|
||||||
profile: updatedData.existingProfileId,
|
profile: updatedData.existingProfileId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user