forked from ScoDoc/ScoDoc
news pour opérations jury. Implements #668
This commit is contained in:
parent
d57b6638ea
commit
c9babcd8c2
@ -5,9 +5,10 @@
|
||||
##############################################################################
|
||||
|
||||
"""
|
||||
ScoDoc 9 API : jury WIP
|
||||
ScoDoc 9 API : jury WIP à compléter avec enregistrement décisions
|
||||
"""
|
||||
|
||||
from flask import g, url_for
|
||||
from flask_json import as_json
|
||||
from flask_login import login_required
|
||||
|
||||
@ -24,6 +25,7 @@ from app.models import (
|
||||
Identite,
|
||||
ScolarAutorisationInscription,
|
||||
ScolarFormSemestreValidation,
|
||||
ScolarNews,
|
||||
)
|
||||
from app.scodoc import sco_cache
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
@ -47,6 +49,20 @@ def decisions_jury(formsemestre_id: int):
|
||||
raise ScoException("non implemente")
|
||||
|
||||
|
||||
def _news_delete_jury_etud(etud: Identite):
|
||||
"génère news sur effacement décision"
|
||||
# n'utilise pas g.scodoc_dept, pas toujours dispo en mode API
|
||||
url = url_for(
|
||||
"scolar.ficheEtud", scodoc_dept=etud.departement.acronym, etudid=etud.id
|
||||
)
|
||||
ScolarNews.add(
|
||||
typ=ScolarNews.NEWS_JURY,
|
||||
obj=etud.id,
|
||||
text=f"""Suppression décision jury pour <a href="{url}">{etud.nomprenom}</a>""",
|
||||
url=url,
|
||||
)
|
||||
|
||||
|
||||
@bp.route(
|
||||
"/etudiant/<int:etudid>/jury/validation_ue/<int:validation_id>/delete",
|
||||
methods=["POST"],
|
||||
@ -94,6 +110,7 @@ def _validation_ue_delete(etudid: int, validation_id: int):
|
||||
db.session.delete(validation)
|
||||
sco_cache.invalidate_formsemestre_etud(etud)
|
||||
db.session.commit()
|
||||
_news_delete_jury_etud(etud)
|
||||
return "ok"
|
||||
|
||||
|
||||
@ -121,6 +138,7 @@ def autorisation_inscription_delete(etudid: int, validation_id: int):
|
||||
db.session.delete(validation)
|
||||
sco_cache.invalidate_formsemestre_etud(etud)
|
||||
db.session.commit()
|
||||
_news_delete_jury_etud(etud)
|
||||
return "ok"
|
||||
|
||||
|
||||
@ -148,6 +166,7 @@ def validation_rcue_delete(etudid: int, validation_id: int):
|
||||
db.session.delete(validation)
|
||||
sco_cache.invalidate_formsemestre_etud(etud)
|
||||
db.session.commit()
|
||||
_news_delete_jury_etud(etud)
|
||||
return "ok"
|
||||
|
||||
|
||||
@ -175,4 +194,5 @@ def validation_annee_but_delete(etudid: int, validation_id: int):
|
||||
db.session.delete(validation)
|
||||
sco_cache.invalidate_formsemestre_etud(etud)
|
||||
db.session.commit()
|
||||
_news_delete_jury_etud(etud)
|
||||
return "ok"
|
||||
|
@ -459,10 +459,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
"""informations, for debugging purpose."""
|
||||
text = f"""<b>DecisionsProposeesAnnee</b>
|
||||
<ul>
|
||||
<li>Etudiant: <a href="{url_for("scolar.ficheEtud",
|
||||
scodoc_dept=g.scodoc_dept, etudid=self.etud.id)
|
||||
}">{self.etud.nomprenom}</a>
|
||||
</li>
|
||||
<li>Étudiant: {self.etud.html_link_fiche()}</li>
|
||||
"""
|
||||
for formsemestre, title in (
|
||||
(self.formsemestre_impair, "formsemestre_impair"),
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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:
|
||||
|
@ -671,6 +671,7 @@ def create_etud(cnx, args: dict = None):
|
||||
typ=ScolarNews.NEWS_INSCR,
|
||||
text='Nouvel étudiant <a href="%(url)s">%(nomprenom)s</a>' % etud,
|
||||
url=etud["url"],
|
||||
max_frequency=0,
|
||||
)
|
||||
return etud
|
||||
|
||||
|
@ -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 !")
|
||||
|
@ -261,6 +261,7 @@ def do_formsemestre_create(args, silent=False):
|
||||
typ=ScolarNews.NEWS_SEM,
|
||||
text='Création du semestre <a href="%(url)s">%(titre)s</a>' % args,
|
||||
url=args["url"],
|
||||
max_frequency=0,
|
||||
)
|
||||
return formsemestre_id
|
||||
|
||||
|
@ -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,
|
||||
)
|
||||
|
||||
|
||||
|
@ -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(
|
||||
"""<h2>Saisie automatique des décisions du semestre %s</h2>
|
||||
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")}
|
||||
<h2>Saisie automatique des décisions du semestre {formsemestre.titre_annee()}</h2>
|
||||
<p>Opération effectuée.</p>
|
||||
<p>%d étudiants validés (sur %s)</p>"""
|
||||
% (sem["titreannee"], nb_valid, len(etudids))
|
||||
)
|
||||
<p>{nb_valid} étudiants validés sur {len(etudids)}</p>
|
||||
"""
|
||||
]
|
||||
if conflicts:
|
||||
H.append(
|
||||
f"""<p><b>Attention:</b> {len(conflicts)} étudiants non modifiés
|
||||
|
@ -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")
|
||||
|
@ -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'
|
||||
)
|
||||
|
||||
|
||||
|
@ -629,7 +629,7 @@ div.news {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
div.news a {
|
||||
div.news a, div.news a.stdlink {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
SCOVERSION = "9.4.90"
|
||||
SCOVERSION = "9.4.91"
|
||||
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user