diff --git a/app/models/assiduites.py b/app/models/assiduites.py index 29b8b889..297a4014 100644 --- a/app/models/assiduites.py +++ b/app/models/assiduites.py @@ -21,6 +21,7 @@ from app.scodoc import sco_abs_notification from app.scodoc.sco_archives_justificatifs import JustificatifArchiver from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_permissions import Permission +from app.scodoc import sco_preferences from app.scodoc import sco_utils as scu from app.scodoc.sco_utils import ( EtatAssiduite, @@ -188,6 +189,12 @@ class Assiduite(ScoDocModel): ): 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 assiduites: Query = etud.assiduites 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() ) + + +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 diff --git a/app/scodoc/sco_assiduites.py b/app/scodoc/sco_assiduites.py index 6626c903..f085a83f 100644 --- a/app/scodoc/sco_assiduites.py +++ b/app/scodoc/sco_assiduites.py @@ -3,9 +3,10 @@ Ecrit par Matthias Hartmann. """ from datetime import date, datetime, time, timedelta +from functools import wraps from pytz import UTC -from flask import g +from flask import g, request from flask_sqlalchemy.query import Query from app import log, db, set_sco_dept @@ -18,12 +19,13 @@ from app.models import ( ModuleImplInscription, 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_preferences from app.scodoc import sco_cache from app.scodoc import sco_etud import app.scodoc.sco_utils as scu +from app.scodoc.sco_exceptions import ScoValueError class CountCalculator: @@ -819,6 +821,38 @@ def get_etud_evaluations_assiduites(etud: Identite) -> list[dict]: 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 def get_assiduites_count(etudid: int, sem: dict) -> tuple[int, int, int]: """Les comptes d'absences de cet étudiant dans ce semestre: diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index 4c3748f4..19ebe1fc 100755 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -61,6 +61,7 @@ from app.scodoc.sco_utils import ModuleType from app.scodoc import html_sco_header from app.scodoc import htmlutils from app.scodoc import sco_archives_formsemestre +from app.scodoc import sco_assiduites as scass from app.scodoc import sco_bulletins from app.scodoc import codes_cursus from app.scodoc import sco_compute_moy @@ -783,6 +784,10 @@ def _make_listes_sem(formsemestre: FormSemestre) -> str: ) # H.append('
")
+
+ if disable_abs:
+ H.append(
+ f"""
+ Assiduité
",
- '',
- "
",
+ "",
+ ]
+
+ if disable_abs:
+ liens_abs = [
+ f"""
+ Assiduité
",
+ *liens_abs,
"Feuilles
",
'',
"""
")
- H.append(
- f"""')
H.append(" Absences dans ce module"""
- )
+ )
# Adapté à partir d'une suggestion de DS (Le Havre)
# Liens saisies absences seulement si permission et date courante dans le semestre
- if current_user.has_permission(Permission.AbsChange) and formsemestre.est_courant():
+ if (
+ current_user.has_permission(Permission.AbsChange)
+ and formsemestre.est_courant()
+ and not disable_abs
+ ):
group_id = sco_groups.get_default_group(formsemestre_id)
H.append(
f"""
diff --git a/app/scodoc/sco_preferences.py b/app/scodoc/sco_preferences.py
index e581b6b4..6b940076 100644
--- a/app/scodoc/sco_preferences.py
+++ b/app/scodoc/sco_preferences.py
@@ -685,6 +685,19 @@ class BasePreferences:
"only_global": True,
},
),
+ (
+ "assiduites_disable",
+ {
+ "initvalue": "",
+ "title": "Désactiver le module d'assiduité",
+ "size": 40,
+ "category": "assi",
+ "explanation": """Désactive complètement le suivi de l'assiduité sur ScoDoc.
+ Indiquer un message à afficher pour orienter l'utilisateur.
+ Laisser ce champ est vide pour utiliser l'assiduité dans ScoDoc.
+ """,
+ },
+ ),
(
"abs_notify_max_freq",
{
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index b3cc3d96..4974a4e1 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -4931,4 +4931,8 @@ div.cas_etat_certif_ssl {
margin-bottom: 8px;
font-style: italic;
color: rgb(231, 0, 0);
+}
+
+.hidden {
+ visibility: hidden;
}
\ No newline at end of file
diff --git a/app/views/assiduites.py b/app/views/assiduites.py
index 8db1da15..10e092cb 100644
--- a/app/views/assiduites.py
+++ b/app/views/assiduites.py
@@ -96,6 +96,7 @@ from app.scodoc.sco_archives_justificatifs import JustificatifArchiver
CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS
+
# --------------------------------------------------------------------
#
# Assiduité (/ScoDoc/