- - Etudiant: {self.etud.nomprenom}
-
+ - Étudiant: {self.etud.html_link_fiche()}
"""
for formsemestre, title in (
(self.formsemestre_impair, "formsemestre_impair"),
diff --git a/app/but/jury_but_validation_auto.py b/app/but/jury_but_validation_auto.py
index e698b5dd4..a061b42f1 100644
--- a/app/but/jury_but_validation_auto.py
+++ b/app/but/jury_but_validation_auto.py
@@ -6,11 +6,11 @@
"""Jury BUT: calcul des décisions de jury annuelles "automatiques"
"""
+from flask import g, url_for
from app import db
from app.but import jury_but
-from app.models.etudiants import Identite
-from app.models.formsemestre import FormSemestre
+from app.models import Identite, FormSemestre, ScolarNews
from app.scodoc import sco_cache
from app.scodoc.sco_exceptions import ScoValueError
@@ -39,4 +39,14 @@ def formsemestre_validation_auto_but(
nb_etud_modif += deca.record_all(only_validantes=only_adm)
db.session.commit()
+ ScolarNews.add(
+ typ=ScolarNews.NEWS_JURY,
+ obj=formsemestre.id,
+ text=f"""Calcul jury automatique du semestre {formsemestre.html_link_status()}""",
+ url=url_for(
+ "notes.formsemestre_status",
+ scodoc_dept=g.scodoc_dept,
+ formsemestre_id=formsemestre.id,
+ ),
+ )
return nb_etud_modif
diff --git a/app/but/jury_but_view.py b/app/but/jury_but_view.py
index 87321684e..275d93b1e 100644
--- a/app/but/jury_but_view.py
+++ b/app/but/jury_but_view.py
@@ -31,6 +31,7 @@ from app.models import (
UniteEns,
ScolarAutorisationInscription,
ScolarFormSemestreValidation,
+ ScolarNews,
)
from app.models.config import ScoDocSiteConfig
from app.scodoc import html_sco_header
@@ -369,6 +370,16 @@ def jury_but_semestriel(
flash(
f"autorisation de passage en S{formsemestre.semestre_id + 1} annulée"
)
+ ScolarNews.add(
+ typ=ScolarNews.NEWS_JURY,
+ obj=formsemestre.id,
+ text=f"""Saisie décision jury dans {formsemestre.html_link_status()}""",
+ url=url_for(
+ "notes.formsemestre_status",
+ scodoc_dept=g.scodoc_dept,
+ formsemestre_id=formsemestre.id,
+ ),
+ )
return flask.redirect(
url_for(
"notes.formsemestre_validation_but",
diff --git a/app/models/events.py b/app/models/events.py
index 6555948d6..d3e770976 100644
--- a/app/models/events.py
+++ b/app/models/events.py
@@ -54,14 +54,17 @@ class ScolarNews(db.Model):
NEWS_APO = "APO" # changements de codes APO
NEWS_FORM = "FORM" # modification formation (object=formation_id)
NEWS_INSCR = "INSCR" # inscription d'étudiants (object=None ou formsemestre_id)
+ NEWS_JURY = "JURY" # saisie jury
NEWS_MISC = "MISC" # unused
NEWS_NOTE = "NOTES" # saisie note (object=moduleimpl_id)
NEWS_SEM = "SEM" # creation semestre (object=None)
+
NEWS_MAP = {
NEWS_ABS: "saisie absence",
NEWS_APO: "modif. code Apogée",
NEWS_FORM: "modification formation",
NEWS_INSCR: "inscription d'étudiants",
+ NEWS_JURY: "saisie jury",
NEWS_MISC: "opération", # unused
NEWS_NOTE: "saisie note",
NEWS_SEM: "création semestre",
@@ -130,10 +133,10 @@ class ScolarNews(db.Model):
return query.order_by(cls.date.desc()).limit(n).all()
@classmethod
- def add(cls, typ, obj=None, text="", url=None, max_frequency=0):
+ def add(cls, typ, obj=None, text="", url=None, max_frequency=600):
"""Enregistre une nouvelle
Si max_frequency, ne génère pas 2 nouvelles "identiques"
- à moins de max_frequency secondes d'intervalle.
+ à moins de max_frequency secondes d'intervalle (10 minutes par défaut).
Deux nouvelles sont considérées comme "identiques" si elles ont
même (obj, typ, user).
La nouvelle enregistrée est aussi envoyée par mail.
@@ -153,7 +156,10 @@ class ScolarNews(db.Model):
if last_news:
now = datetime.datetime.now(tz=last_news.date.tzinfo)
if (now - last_news.date) < datetime.timedelta(seconds=max_frequency):
- # on n'enregistre pas
+ # pas de nouvel event, mais met à jour l'heure
+ last_news.date = datetime.datetime.now()
+ db.session.add(last_news)
+ db.session.commit()
return
news = ScolarNews(
diff --git a/app/scodoc/sco_edit_formation.py b/app/scodoc/sco_edit_formation.py
index 384ec0650..a3ce002a0 100644
--- a/app/scodoc/sco_edit_formation.py
+++ b/app/scodoc/sco_edit_formation.py
@@ -132,6 +132,7 @@ def do_formation_delete(formation_id):
typ=ScolarNews.NEWS_FORM,
obj=formation_id,
text=f"Suppression de la formation {acronyme}",
+ max_frequency=0,
)
@@ -329,6 +330,7 @@ def do_formation_create(args: dict) -> Formation:
typ=ScolarNews.NEWS_FORM,
text=f"""Création de la formation {
formation.titre} ({formation.acronyme}) version {formation.version}""",
+ max_frequency=0,
)
return formation
diff --git a/app/scodoc/sco_edit_matiere.py b/app/scodoc/sco_edit_matiere.py
index 312f01ec1..ef425b493 100644
--- a/app/scodoc/sco_edit_matiere.py
+++ b/app/scodoc/sco_edit_matiere.py
@@ -93,7 +93,6 @@ def do_matiere_create(args):
typ=ScolarNews.NEWS_FORM,
obj=ue["formation_id"],
text=f"Modification de la formation {formation.acronyme}",
- max_frequency=10 * 60,
)
formation.invalidate_cached_sems()
return r
@@ -199,7 +198,6 @@ def do_matiere_delete(oid):
typ=ScolarNews.NEWS_FORM,
obj=ue["formation_id"],
text=f"Modification de la formation {formation.acronyme}",
- max_frequency=10 * 60,
)
formation.invalidate_cached_sems()
diff --git a/app/scodoc/sco_edit_module.py b/app/scodoc/sco_edit_module.py
index 4d963c6e4..139afa841 100644
--- a/app/scodoc/sco_edit_module.py
+++ b/app/scodoc/sco_edit_module.py
@@ -114,7 +114,6 @@ def do_module_create(args) -> int:
typ=ScolarNews.NEWS_FORM,
obj=formation.id,
text=f"Modification de la formation {formation.acronyme}",
- max_frequency=10 * 60,
)
formation.invalidate_cached_sems()
return module_id
@@ -186,7 +185,6 @@ def do_module_delete(oid):
typ=ScolarNews.NEWS_FORM,
obj=mod["formation_id"],
text=f"Modification de la formation {formation.acronyme}",
- max_frequency=10 * 60,
)
formation.invalidate_cached_sems()
diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py
index ba6cb918e..fbe8e2be9 100644
--- a/app/scodoc/sco_edit_ue.py
+++ b/app/scodoc/sco_edit_ue.py
@@ -145,7 +145,6 @@ def do_ue_create(args):
typ=ScolarNews.NEWS_FORM,
obj=args["formation_id"],
text=f"Modification de la formation {formation.acronyme}",
- max_frequency=10 * 60,
)
formation.invalidate_cached_sems()
return ue_id
@@ -230,7 +229,6 @@ def do_ue_delete(ue: UniteEns, delete_validations=False, force=False):
typ=ScolarNews.NEWS_FORM,
obj=formation.id,
text=f"Modification de la formation {formation.acronyme}",
- max_frequency=10 * 60,
)
#
if not force:
diff --git a/app/scodoc/sco_etud.py b/app/scodoc/sco_etud.py
index 7bbf12b5f..827363c89 100644
--- a/app/scodoc/sco_etud.py
+++ b/app/scodoc/sco_etud.py
@@ -671,6 +671,7 @@ def create_etud(cnx, args: dict = None):
typ=ScolarNews.NEWS_INSCR,
text='Nouvel étudiant %(nomprenom)s' % etud,
url=etud["url"],
+ max_frequency=0,
)
return etud
diff --git a/app/scodoc/sco_formations.py b/app/scodoc/sco_formations.py
index 981908c97..398ed7d47 100644
--- a/app/scodoc/sco_formations.py
+++ b/app/scodoc/sco_formations.py
@@ -638,6 +638,7 @@ def formation_create_new_version(formation_id, redirect=True):
typ=ScolarNews.NEWS_FORM,
obj=new_id,
text=f"Nouvelle version de la formation {formation.acronyme}",
+ max_frequency=0,
)
if redirect:
flash("Nouvelle version !")
diff --git a/app/scodoc/sco_formsemestre.py b/app/scodoc/sco_formsemestre.py
index 3d46b1de7..bac3352a7 100644
--- a/app/scodoc/sco_formsemestre.py
+++ b/app/scodoc/sco_formsemestre.py
@@ -261,6 +261,7 @@ def do_formsemestre_create(args, silent=False):
typ=ScolarNews.NEWS_SEM,
text='Création du semestre %(titre)s' % args,
url=args["url"],
+ max_frequency=0,
)
return formsemestre_id
diff --git a/app/scodoc/sco_formsemestre_edit.py b/app/scodoc/sco_formsemestre_edit.py
index 4961e8a21..4a94f0bde 100644
--- a/app/scodoc/sco_formsemestre_edit.py
+++ b/app/scodoc/sco_formsemestre_edit.py
@@ -1521,6 +1521,7 @@ def do_formsemestre_delete(formsemestre_id):
typ=ScolarNews.NEWS_SEM,
obj=formsemestre_id,
text="Suppression du semestre %(titre)s" % sem,
+ max_frequency=0,
)
diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py
index 1822e3a65..15254a0e5 100644
--- a/app/scodoc/sco_formsemestre_validation.py
+++ b/app/scodoc/sco_formsemestre_validation.py
@@ -39,7 +39,7 @@ from app import db, log
from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
-from app.models import Formation, FormSemestre, UniteEns
+from app.models import Formation, FormSemestre, UniteEns, ScolarNews
from app.models.notes import etud_has_notes_attente
from app.models.validations import (
ScolarAutorisationInscription,
@@ -992,16 +992,26 @@ def do_formsemestre_validation_auto(formsemestre_id):
)
nb_valid += 1
log(
- "do_formsemestre_validation_auto: %d validations, %d conflicts"
- % (nb_valid, len(conflicts))
+ f"do_formsemestre_validation_auto: {nb_valid} validations, {len(conflicts)} conflicts"
)
- H = [html_sco_header.sco_header(page_title="Saisie automatique")]
- H.append(
- """Saisie automatique des décisions du semestre %s
+ ScolarNews.add(
+ typ=ScolarNews.NEWS_JURY,
+ obj=formsemestre.id,
+ text=f"""Calcul jury automatique du semestre {formsemestre.html_link_status()
+ } ({nb_valid} décisions)""",
+ url=url_for(
+ "notes.formsemestre_status",
+ scodoc_dept=g.scodoc_dept,
+ formsemestre_id=formsemestre.id,
+ ),
+ )
+ H = [
+ f"""{html_sco_header.sco_header(page_title="Saisie automatique")}
+ Saisie automatique des décisions du semestre {formsemestre.titre_annee()}
Opération effectuée.
- %d étudiants validés (sur %s)
"""
- % (sem["titreannee"], nb_valid, len(etudids))
- )
+ {nb_valid} étudiants validés sur {len(etudids)}
+ """
+ ]
if conflicts:
H.append(
f"""Attention: {len(conflicts)} étudiants non modifiés
diff --git a/app/scodoc/sco_import_etuds.py b/app/scodoc/sco_import_etuds.py
index 736d60212..e7eb8dceb 100644
--- a/app/scodoc/sco_import_etuds.py
+++ b/app/scodoc/sco_import_etuds.py
@@ -480,6 +480,7 @@ def scolars_import_excel_file(
text="Inscription de %d étudiants" # peuvent avoir ete inscrits a des semestres differents
% len(created_etudids),
obj=formsemestre_id,
+ max_frequency=0,
)
log("scolars_import_excel_file: completing transaction")
diff --git a/app/scodoc/sco_synchro_etuds.py b/app/scodoc/sco_synchro_etuds.py
index 6685909c4..764d889f4 100644
--- a/app/scodoc/sco_synchro_etuds.py
+++ b/app/scodoc/sco_synchro_etuds.py
@@ -704,7 +704,6 @@ def do_import_etuds_from_portal(sem, a_importer, etudsapo_ident):
typ=ScolarNews.NEWS_INSCR,
text=f"Import Apogée de {len(created_etudids)} étudiants en ",
obj=sem["formsemestre_id"],
- max_frequency=10 * 60, # 10'
)
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index 0173a14e5..ca1b1f129 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -629,7 +629,7 @@ div.news {
border-radius: 8px;
}
-div.news a {
+div.news a, div.news a.stdlink {
color: black;
text-decoration: none;
}
diff --git a/app/views/notes.py b/app/views/notes.py
index c51571941..1ef706934 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -2410,6 +2410,16 @@ def formsemestre_validation_but(
if request.method == "POST":
if not read_only:
deca.record_form(request.form)
+ ScolarNews.add(
+ typ=ScolarNews.NEWS_JURY,
+ obj=formsemestre.id,
+ text=f"""Saisie décision jury dans {formsemestre.html_link_status()}""",
+ url=url_for(
+ "notes.formsemestre_status",
+ scodoc_dept=g.scodoc_dept,
+ formsemestre_id=formsemestre.id,
+ ),
+ )
flash("codes enregistrés")
return flask.redirect(
url_for(
@@ -3059,7 +3069,6 @@ def formsemestre_set_apo_etapes():
ScolarNews.add(
typ=ScolarNews.NEWS_APO,
text=f"Modification code Apogée du semestre {formsemestre.titre_annee()})",
- max_frequency=10 * 60,
)
return ("", 204)
@@ -3081,7 +3090,6 @@ def formsemestre_set_elt_annee_apo():
ScolarNews.add(
typ=ScolarNews.NEWS_APO,
text=f"Modification code Apogée du semestre {formsemestre.titre_annee()})",
- max_frequency=10 * 60,
)
return ("", 204)
@@ -3103,7 +3111,6 @@ def formsemestre_set_elt_sem_apo():
ScolarNews.add(
typ=ScolarNews.NEWS_APO,
text=f"Modification code Apogée du semestre {formsemestre.titre_annee()})",
- max_frequency=10 * 60,
)
return ("", 204)
@@ -3125,7 +3132,6 @@ def ue_set_apo():
ScolarNews.add(
typ=ScolarNews.NEWS_FORM,
text=f"Modification code Apogée d'UE dans la formation {ue.formation.titre} ({ue.formation.acronyme})",
- max_frequency=10 * 60,
)
return ("", 204)
@@ -3146,8 +3152,8 @@ def module_set_apo():
db.session.commit()
ScolarNews.add(
typ=ScolarNews.NEWS_FORM,
- text=f"Modification code Apogée d'UE dans la formation {mod.formation.titre} ({mod.formation.acronyme})",
- max_frequency=10 * 60,
+ text=f"""Modification code Apogée d'UE dans la formation {
+ mod.formation.titre} ({mod.formation.acronyme})""",
)
return ("", 204)
diff --git a/sco_version.py b/sco_version.py
index 7be8d568b..bd238565a 100644
--- a/sco_version.py
+++ b/sco_version.py
@@ -1,7 +1,7 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
-SCOVERSION = "9.4.90"
+SCOVERSION = "9.4.91"
SCONAME = "ScoDoc"