1
0
forked from ScoDoc/ScoDoc

Assiduité : Désactivation du module (préférence semestre) closes #67

This commit is contained in:
Iziram 2024-07-09 14:31:15 +02:00
parent d4fd6527e5
commit d4f206cc3e
4 changed files with 98 additions and 5 deletions

View File

@ -21,6 +21,7 @@ from app.scodoc import sco_abs_notification
from app.scodoc.sco_archives_justificatifs import JustificatifArchiver from app.scodoc.sco_archives_justificatifs import JustificatifArchiver
from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
from app.scodoc import sco_preferences
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
from app.scodoc.sco_utils import ( from app.scodoc.sco_utils import (
EtatAssiduite, EtatAssiduite,
@ -188,6 +189,12 @@ class Assiduite(ScoDocModel):
): ):
raise ScoValueError("La date de fin n'est pas un jour travaillé") raise ScoValueError("La date de fin n'est pas un jour travaillé")
# Vérification de l'activation du module
if (err_msg := has_assiduites_disable_pref(formsemestre_date_debut)) or (
err_msg := has_assiduites_disable_pref(formsemestre_date_fin)
):
raise ScoValueError(err_msg)
# 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):
@ -817,3 +824,29 @@ def get_formsemestre_from_data(data: dict[str, datetime | int]) -> FormSemestre:
) )
.first() .first()
) )
def has_assiduites_disable_pref(formsemestre: FormSemestre) -> str | bool:
"""
Vérifie si le semestre possède la préférence "assiduites_disable"
et renvoie le message d'erreur associé.
La préférence est un text field. Il est considéré comme vide si :
- la chaine de caractère est vide
- si elle n'est composée que de caractères d'espacement (espace, tabulation, retour à la ligne)
Si la chaine est vide, la fonction renvoie False
"""
# Si pas de formsemestre, on ne peut pas vérifier la préférence
# On considère que la préférence n'est pas activée
if formsemestre is None:
return False
pref: str = (
sco_preferences.get_preference("assiduites_disable", formsemestre.id) or ""
)
pref = pref.strip()
return pref if pref else False

View File

@ -3,9 +3,10 @@ Ecrit par Matthias Hartmann.
""" """
from datetime import date, datetime, time, timedelta from datetime import date, datetime, time, timedelta
from functools import wraps
from pytz import UTC from pytz import UTC
from flask import g from flask import g, request
from flask_sqlalchemy.query import Query from flask_sqlalchemy.query import Query
from app import log, db, set_sco_dept from app import log, db, set_sco_dept
@ -18,12 +19,13 @@ from app.models import (
ModuleImplInscription, ModuleImplInscription,
ScoDocSiteConfig, ScoDocSiteConfig,
) )
from app.models.assiduites import Assiduite, Justificatif from app.models.assiduites import Assiduite, Justificatif, has_assiduites_disable_pref
from app.scodoc import sco_formsemestre_inscriptions from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app.scodoc import sco_cache from app.scodoc import sco_cache
from app.scodoc import sco_etud from app.scodoc import sco_etud
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc.sco_exceptions import ScoValueError
class CountCalculator: class CountCalculator:
@ -819,6 +821,38 @@ def get_etud_evaluations_assiduites(etud: Identite) -> list[dict]:
return etud_evaluations_assiduites return etud_evaluations_assiduites
# --- Décorateur ---
def check_disabled(func):
"""
Vérifie sur le module a été désactivé dans les préférences du semestre.
Récupère le formsemestre depuis l'url (formsemestre_id)
Si le formsemestre est trouvé :
- Vérifie si le module a été désactivé dans les préférences du semestre
- Si le module a été désactivé, une ScoValueError est levée
Sinon :
Il ne se passe rien
"""
@wraps(func)
def decorated_function(*args, **kwargs):
# Récupération du formsemestre depuis l'url
formsemestre_id = request.args.get("formsemestre_id")
# Si on a un formsemestre_id
if formsemestre_id:
# Récupération du formsemestre
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
# Vériication si le module a été désactivé (avec la préférence)
pref: str | bool = has_assiduites_disable_pref(formsemestre)
# Le module est désactivé si on récupère un message d'erreur (str)
if pref:
raise ScoValueError(pref, dest_url=request.referrer)
return func(*args, **kwargs)
return decorated_function
# Gestion du cache # Gestion du cache
def get_assiduites_count(etudid: int, sem: dict) -> tuple[int, int, int]: def get_assiduites_count(etudid: int, sem: dict) -> tuple[int, int, int]:
"""Les comptes d'absences de cet étudiant dans ce semestre: """Les comptes d'absences de cet étudiant dans ce semestre:

View File

@ -625,6 +625,16 @@ class BasePreferences:
"explanation": "Désactive la saisie et l'affichage des présences", "explanation": "Désactive la saisie et l'affichage des présences",
}, },
), ),
(
"assiduites_disable",
{
"initvalue": "",
"title": "Désactiver le module d'assiduité",
"size": 40,
"category": "assi",
"explanation": "Laisser vide pour ne pas désactiver. Sinon mettre un message à afficher",
},
),
( (
"nb_heures_par_jour", "nb_heures_par_jour",
{ {
@ -2293,9 +2303,7 @@ class BasePreferences:
if "explanation" in descr: if "explanation" in descr:
del descr["explanation"] del descr["explanation"]
if formsemestre_id: if formsemestre_id:
descr[ descr["explanation"] = f"""ou <span class="spanlink"
"explanation"
] = f"""ou <span class="spanlink"
onclick="set_global_pref(this, '{pref_name}');" onclick="set_global_pref(this, '{pref_name}');"
>utiliser paramètre global</span>""" >utiliser paramètre global</span>"""
if formsemestre_id and self.is_global(formsemestre_id, pref_name): if formsemestre_id and self.is_global(formsemestre_id, pref_name):

View File

@ -96,6 +96,7 @@ from app.scodoc.sco_archives_justificatifs import JustificatifArchiver
CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# #
# Assiduité (/ScoDoc/<dept>/Scolarite/Assiduites/...) # Assiduité (/ScoDoc/<dept>/Scolarite/Assiduites/...)
@ -106,6 +107,7 @@ CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS
@bp.route("/") @bp.route("/")
@bp.route("/bilan_dept") @bp.route("/bilan_dept")
@scodoc @scodoc
@scass.check_disabled
@permission_required(Permission.AbsChange) @permission_required(Permission.AbsChange)
def bilan_dept(): def bilan_dept():
"""Gestionnaire assiduités, page principale""" """Gestionnaire assiduités, page principale"""
@ -212,6 +214,7 @@ def bilan_dept():
@bp.route("/ajout_assiduite_etud", methods=["GET", "POST"]) @bp.route("/ajout_assiduite_etud", methods=["GET", "POST"])
@scodoc @scodoc
@scass.check_disabled
@permission_required(Permission.AbsChange) @permission_required(Permission.AbsChange)
def ajout_assiduite_etud() -> str | Response: def ajout_assiduite_etud() -> str | Response:
""" """
@ -1016,6 +1019,7 @@ def calendrier_assi_etud():
@bp.route("/signal_assiduites_group") @bp.route("/signal_assiduites_group")
@scodoc @scodoc
@scass.check_disabled
@permission_required(Permission.AbsChange) @permission_required(Permission.AbsChange)
def signal_assiduites_group(): def signal_assiduites_group():
""" """
@ -1324,6 +1328,11 @@ def visu_assi_group():
# Récupération des groupes, du semestre et des étudiants # Récupération des groupes, du semestre et des étudiants
groups_infos = sco_groups_view.DisplayedGroupsInfos(group_ids) groups_infos = sco_groups_view.DisplayedGroupsInfos(group_ids)
formsemestre = db.session.get(FormSemestre, groups_infos.formsemestre_id) formsemestre = db.session.get(FormSemestre, groups_infos.formsemestre_id)
# Vérification de la désactivation de l'assiduité
if err_msg := scass.has_assiduites_disable_pref(formsemestre):
raise ScoValueError(err_msg, request.referrer)
etuds = etuds_sorted_from_ids([m["etudid"] for m in groups_infos.members]) etuds = etuds_sorted_from_ids([m["etudid"] for m in groups_infos.members])
# Génération du tableau des assiduités # Génération du tableau des assiduités
@ -1795,6 +1804,7 @@ def signale_evaluation_abs(etudid: int = None, evaluation_id: int = None):
@scodoc @scodoc
@permission_required(Permission.JustifValidate) @permission_required(Permission.JustifValidate)
@permission_required(Permission.AbsJustifView) @permission_required(Permission.AbsJustifView)
@scass.check_disabled
def traitement_justificatifs(): def traitement_justificatifs():
"""Page de traitement des justificatifs """Page de traitement des justificatifs
On traite les justificatifs par formsemestre On traite les justificatifs par formsemestre
@ -1864,6 +1874,7 @@ def traitement_justificatifs():
@bp.route("signal_assiduites_hebdo") @bp.route("signal_assiduites_hebdo")
@scodoc @scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scass.check_disabled
def signal_assiduites_hebdo(): def signal_assiduites_hebdo():
""" """
signal_assiduites_hebdo signal_assiduites_hebdo
@ -2049,6 +2060,10 @@ def edit_assiduite_etud(assiduite_id: int):
etud: Identite = assi.etudiant etud: Identite = assi.etudiant
formsemestre: FormSemestre = assi.get_formsemestre() formsemestre: FormSemestre = assi.get_formsemestre()
# Vérification de la désactivation de l'assiduité
if err_msg := scass.has_assiduites_disable_pref(formsemestre):
raise ScoValueError(err_msg, request.referrer)
readonly: bool = not current_user.has_permission(Permission.AbsChange) readonly: bool = not current_user.has_permission(Permission.AbsChange)
form: EditAssiForm = EditAssiForm(request.form) form: EditAssiForm = EditAssiForm(request.form)
@ -2228,6 +2243,7 @@ def generate_bul_list(etud: Identite, semestre: FormSemestre) -> str:
@bp.route("feuille_abs_hebdo", methods=["GET", "POST"]) @bp.route("feuille_abs_hebdo", methods=["GET", "POST"])
@scodoc @scodoc
@permission_required(Permission.AbsChange) @permission_required(Permission.AbsChange)
@scass.check_disabled
def feuille_abs_hebdo(): def feuille_abs_hebdo():
""" """
GET : Renvoie un tableau excel pour permettre la saisie des absences GET : Renvoie un tableau excel pour permettre la saisie des absences
@ -2374,6 +2390,8 @@ def feuille_abs_hebdo():
@bp.route("feuille_abs_formsemestre", methods=["GET", "POST"]) @bp.route("feuille_abs_formsemestre", methods=["GET", "POST"])
@scodoc @scodoc
@permission_required(Permission.AbsChange)
@scass.check_disabled
def feuille_abs_formsemestre(): def feuille_abs_formsemestre():
""" """
Permet l'importation d'une liste d'assiduités depuis un fichier excel Permet l'importation d'une liste d'assiduités depuis un fichier excel