Assiduite: notifications mail. Fix #789

This commit is contained in:
Emmanuel Viennet 2023-10-09 23:01:19 +02:00
parent 3ecbe5128e
commit 6c3d13b3e1
3 changed files with 63 additions and 44 deletions

View File

@ -559,7 +559,7 @@ def _create_singular(
data: dict, data: dict,
etud: Identite, etud: Identite,
) -> tuple[int, object]: ) -> tuple[int, object]:
"""TODO: documenter""" """TODO @iziram: documenter"""
errors: list[str] = [] errors: list[str] = []
# -- vérifications de l'objet json -- # -- vérifications de l'objet json --
@ -630,6 +630,7 @@ def _create_singular(
description=desc, description=desc,
user_id=current_user.id, user_id=current_user.id,
external_data=external_data, external_data=external_data,
notify_mail=True,
) )
db.session.add(nouv_assiduite) db.session.add(nouv_assiduite)

View File

@ -7,6 +7,7 @@ from app import db, log
from app.models import ModuleImpl, Scolog from app.models import ModuleImpl, Scolog
from app.models.etudiants import Identite from app.models.etudiants import Identite
from app.auth.models import User from app.auth.models import User
from app.scodoc import sco_abs_notification
from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc.sco_utils import ( from app.scodoc.sco_utils import (
EtatAssiduite, EtatAssiduite,
@ -130,13 +131,14 @@ class Assiduite(db.Model):
user_id: int = None, user_id: int = None,
est_just: bool = False, est_just: bool = False,
external_data: dict = None, external_data: dict = None,
notify_mail=False,
) -> "Assiduite": ) -> "Assiduite":
"""Créer une nouvelle assiduité pour l'étudiant""" """Créer une nouvelle assiduité pour l'étudiant"""
# Vérification de non duplication des périodes # Vérification de non duplication des périodes
assiduites: Query = etud.assiduites assiduites: Query = etud.assiduites
if is_period_conflicting(date_debut, date_fin, assiduites, Assiduite): if is_period_conflicting(date_debut, date_fin, assiduites, Assiduite):
raise ScoValueError( raise ScoValueError(
"Duplication des assiduités (la période rentrée rentre en conflit avec une assiduité enregistrée)" "Duplication: la période rentre en conflit avec une plage enregistrée"
) )
if not est_just: if not est_just:
@ -147,35 +149,25 @@ class Assiduite(db.Model):
> 0 > 0
) )
moduleimpl_id = None
if moduleimpl is not None: if moduleimpl is not None:
# Vérification de l'existence du module pour l'étudiant # Vérification de l'inscription de l'étudiant
if moduleimpl.est_inscrit(etud): if moduleimpl.est_inscrit(etud):
nouv_assiduite = Assiduite( moduleimpl_id = moduleimpl.id
date_debut=date_debut,
date_fin=date_fin,
etat=etat,
etudiant=etud,
moduleimpl_id=moduleimpl.id,
description=description,
entry_date=entry_date,
user_id=user_id,
est_just=est_just,
external_data=external_data,
)
else: else:
raise ScoValueError("L'étudiant n'est pas inscrit au module") raise ScoValueError("L'étudiant n'est pas inscrit au module")
else: nouv_assiduite = Assiduite(
nouv_assiduite = Assiduite( date_debut=date_debut,
date_debut=date_debut, date_fin=date_fin,
date_fin=date_fin, description=description,
etat=etat, entry_date=entry_date,
etudiant=etud, est_just=est_just,
description=description, etat=etat,
entry_date=entry_date, etudiant=etud,
user_id=user_id, external_data=external_data,
est_just=est_just, moduleimpl_id=moduleimpl_id,
external_data=external_data, user_id=user_id,
) )
db.session.add(nouv_assiduite) db.session.add(nouv_assiduite)
log(f"create_assiduite: {etud.id} {nouv_assiduite}") log(f"create_assiduite: {etud.id} {nouv_assiduite}")
Scolog.logdb( Scolog.logdb(
@ -183,6 +175,8 @@ class Assiduite(db.Model):
etudid=etud.id, etudid=etud.id,
msg=f"assiduité: {nouv_assiduite}", msg=f"assiduité: {nouv_assiduite}",
) )
if notify_mail and etat == EtatAssiduite.ABSENT:
sco_abs_notification.abs_notify(etud.id, nouv_assiduite.date_debut)
return nouv_assiduite return nouv_assiduite

View File

@ -40,17 +40,17 @@ from flask_mail import Message
from app import db from app import db
from app import email from app import email
from app import log from app import log
from app.auth.models import User
from app.models.absences import AbsenceNotification from app.models.absences import AbsenceNotification
from app.models.events import Scolog from app.models.events import Scolog
from app.models.formsemestre import FormSemestre from app.models.formsemestre import FormSemestre
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app.scodoc import sco_users
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
def abs_notify(etudid, date): def abs_notify(etudid: int, date: str | datetime.datetime):
"""Check if notifications are requested and send them """Check if notifications are requested and send them
Considère le nombre d'absence dans le semestre courant Considère le nombre d'absence dans le semestre courant
(s'il n'y a pas de semestre courant, ne fait rien, (s'il n'y a pas de semestre courant, ne fait rien,
@ -64,18 +64,28 @@ def abs_notify(etudid, date):
nbabs, nbabsjust = sco_assiduites.get_assiduites_count_in_interval( nbabs, nbabsjust = sco_assiduites.get_assiduites_count_in_interval(
etudid, etudid,
formsemestre.date_debut.isoformat(), metrique=scu.translate_assiduites_metric(
formsemestre.date_fin.isoformat(),
scu.translate_assiduites_metric(
sco_preferences.get_preference( sco_preferences.get_preference(
"assi_metrique", formsemestre.formsemestre_id "assi_metrique", formsemestre.formsemestre_id
) )
), ),
date_debut=datetime.datetime.combine(
formsemestre.date_debut, datetime.datetime.min.time()
),
date_fin=datetime.datetime.combine(
formsemestre.date_fin, datetime.datetime.min.time()
),
) )
do_abs_notify(formsemestre, etudid, date, nbabs, nbabsjust) do_abs_notify(formsemestre, etudid, date, nbabs, nbabsjust)
def do_abs_notify(formsemestre: FormSemestre, etudid, date, nbabs, nbabsjust): def do_abs_notify(
formsemestre: FormSemestre,
etudid: int,
date: str | datetime.datetime,
nbabs: int,
nbabsjust: int,
):
"""Given new counts of absences, check if notifications are requested and send them.""" """Given new counts of absences, check if notifications are requested and send them."""
# prefs fallback to global pref if sem is None: # prefs fallback to global pref if sem is None:
if formsemestre: if formsemestre:
@ -138,8 +148,13 @@ def abs_notify_send(destinations, etudid, msg, nbabs, nbabsjust, formsemestre_id
def abs_notify_get_destinations( def abs_notify_get_destinations(
formsemestre: FormSemestre, prefs, etudid, date, nbabs, nbabsjust formsemestre: FormSemestre,
) -> set: prefs: dict,
etudid: int,
date: str | datetime.datetime,
nbabs: int,
nbabsjust: int,
) -> set[str]:
"""Returns set of destination emails to be notified""" """Returns set of destination emails to be notified"""
destinations = [] # list of email address to notify destinations = [] # list of email address to notify
@ -165,9 +180,9 @@ def abs_notify_get_destinations(
if prefs["abs_notify_respeval"]: if prefs["abs_notify_respeval"]:
mods = mod_with_evals_at_date(date, etudid) mods = mod_with_evals_at_date(date, etudid)
for mod in mods: for mod in mods:
u = sco_users.user_info(mod["responsable_id"]) u: User = db.session.get(User, mod["responsable_id"])
if u["email"]: if u is not None and u.is_active and u.email:
destinations.append(u["email"]) destinations.append(u.email)
# uniq # uniq
destinations = set(destinations) destinations = set(destinations)
@ -267,9 +282,11 @@ def abs_notification_message(
return msg return msg
def retreive_current_formsemestre(etudid: int, cur_date) -> Optional[FormSemestre]: def retreive_current_formsemestre(
etudid: int, cur_date: str | datetime.date
) -> Optional[FormSemestre]:
"""Get formsemestre dans lequel etudid est (ou était) inscrit a la date indiquée """Get formsemestre dans lequel etudid est (ou était) inscrit a la date indiquée
date est une chaine au format ISO (yyyy-mm-dd) date est une chaine au format ISO (yyyy-mm-dd) ou un datetime.date
Result: FormSemestre ou None si pas inscrit à la date indiquée Result: FormSemestre ou None si pas inscrit à la date indiquée
""" """
@ -287,10 +304,17 @@ def retreive_current_formsemestre(etudid: int, cur_date) -> Optional[FormSemestr
return formsemestre return formsemestre
def mod_with_evals_at_date(date_abs, etudid): def mod_with_evals_at_date(
date_abs: str | datetime.datetime, etudid: int
) -> list[dict]:
"""Liste des moduleimpls avec des evaluations à la date indiquée""" """Liste des moduleimpls avec des evaluations à la date indiquée"""
req = """SELECT m.id AS moduleimpl_id, m.* req = """
SELECT m.id AS moduleimpl_id, m.*
FROM notes_moduleimpl m, notes_evaluation e, notes_moduleimpl_inscription i FROM notes_moduleimpl m, notes_evaluation e, notes_moduleimpl_inscription i
WHERE m.id = e.moduleimpl_id AND e.moduleimpl_id = i.moduleimpl_id WHERE m.id = e.moduleimpl_id
AND i.etudid = %(etudid)s AND e.jour = %(date_abs)s""" AND e.moduleimpl_id = i.moduleimpl_id
AND i.etudid = %(etudid)s
AND e.date_debut <= %(date_abs)s
AND e.date_fin >= %(date_abs)s
"""
return ndb.SimpleDictFetch(req, {"etudid": etudid, "date_abs": date_abs}) return ndb.SimpleDictFetch(req, {"etudid": etudid, "date_abs": date_abs})