Optimisation de la synchro inscription

This commit is contained in:
Emmanuel Viennet 2021-09-02 18:05:22 +02:00
parent ca4d9817e6
commit afaab2d5e0
10 changed files with 87 additions and 86 deletions

View File

@ -251,6 +251,9 @@ def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=Fa
"""
from app.scodoc import sco_parcours_dut
if g.defer_cache_invalidation:
g.sem_to_invalidate.add(formsemestre_id)
return
log("inval_cache, formsemestre_id=%s pdfonly=%s" % (formsemestre_id, pdfonly))
if formsemestre_id is None:
# clear all caches
@ -286,3 +289,25 @@ def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=Fa
SemInscriptionsCache.delete_many(formsemestre_ids)
SemBulletinsPDFCache.invalidate_sems(formsemestre_ids)
class DefferedSemCacheManager:
"""Experimental: pour effectuer des opérations indépendantes dans la
même requete qui invalident le cache. Par exemple, quand on inscrit
des étudiants un par un à un semestre, chaque inscription va invalider
le cache, et la suivante va le reconstruire... pour l'invalider juste après.
Ce context manager permet de grouper les invalidations.
"""
def __enter__(self):
assert not hasattr(g, "defer_cache_invalidation")
g.defer_cache_invalidation = True
g.sem_to_invalidate = set()
return True
def __exit__(self, exc_type, exc_value, exc_traceback):
assert g.defer_cache_invalidation
g.defer_cache_invalidation = False
while g.sem_to_invalidate:
formsemestre_id = g.sem_to_invalidate.pop()
invalidate_formsemestre(formsemestre_id)

View File

@ -74,7 +74,6 @@ def formsemestre_ext_create(etudid, sem_params, REQUEST=None):
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
formsemestre_id,
etudid,
REQUEST=REQUEST,
method="formsemestre_ext_create",
)
return formsemestre_id

View File

@ -135,7 +135,7 @@ def do_formsemestre_inscription_edit(args=None, formsemestre_id=None):
) # > modif inscription semestre (demission ?)
def do_formsemestre_desinscription(etudid, formsemestre_id, REQUEST=None):
def do_formsemestre_desinscription(etudid, formsemestre_id):
"""Désinscription d'un étudiant.
Si semestre extérieur et dernier inscrit, suppression de ce semestre.
"""
@ -194,14 +194,13 @@ def do_formsemestre_desinscription(etudid, formsemestre_id, REQUEST=None):
)
sco_formsemestre_edit.do_formsemestre_delete(formsemestre_id)
if REQUEST:
logdb(
cnx,
method="formsemestre_desinscription",
etudid=etudid,
msg="desinscription semestre %s" % formsemestre_id,
commit=False,
)
logdb(
cnx,
method="formsemestre_desinscription",
etudid=etudid,
msg="desinscription semestre %s" % formsemestre_id,
commit=False,
)
def do_formsemestre_inscription_with_modules(
@ -210,7 +209,6 @@ def do_formsemestre_inscription_with_modules(
group_ids=[],
etat="I",
etape=None,
REQUEST=None,
method="inscription_with_modules",
):
"""Inscrit cet etudiant à ce semestre et TOUS ses modules STANDARDS
@ -245,7 +243,6 @@ def do_formsemestre_inscription_with_modules(
if mod["ue"]["type"] != UE_SPORT:
sco_moduleimpl.do_moduleimpl_inscription_create(
{"moduleimpl_id": mod["moduleimpl_id"], "etudid": etudid},
REQUEST=REQUEST,
formsemestre_id=formsemestre_id,
)
@ -406,7 +403,6 @@ def formsemestre_inscription_with_modules(
etudid,
group_ids=group_ids,
etat="I",
REQUEST=REQUEST,
method="formsemestre_inscription_with_modules",
)
return flask.redirect(
@ -691,7 +687,6 @@ def do_moduleimpl_incription_options(
mod = mods[0]
sco_moduleimpl.do_moduleimpl_inscription_create(
{"moduleimpl_id": moduleimpl_id, "etudid": etudid},
REQUEST=REQUEST,
formsemestre_id=mod["formsemestre_id"],
)
# desinscriptions

View File

@ -601,7 +601,7 @@ def set_group(etudid, group_id):
return True
def change_etud_group_in_partition(etudid, group_id, partition=None, REQUEST=None):
def change_etud_group_in_partition(etudid, group_id, partition=None):
"""Inscrit etud au groupe de cette partition, et le desinscrit d'autres groupes de cette partition."""
log("change_etud_group_in_partition: etudid=%s group_id=%s" % (etudid, group_id))
@ -632,16 +632,15 @@ def change_etud_group_in_partition(etudid, group_id, partition=None, REQUEST=Non
# 3- log
formsemestre_id = partition["formsemestre_id"]
if REQUEST:
cnx = ndb.GetDBConnexion()
logdb(
cnx,
method="changeGroup",
etudid=etudid,
msg="formsemestre_id=%s,partition_name=%s, group_name=%s"
% (formsemestre_id, partition["partition_name"], group["group_name"]),
)
cnx.commit()
cnx = ndb.GetDBConnexion()
logdb(
cnx,
method="changeGroup",
etudid=etudid,
msg="formsemestre_id=%s,partition_name=%s, group_name=%s"
% (formsemestre_id, partition["partition_name"], group["group_name"]),
)
cnx.commit()
# 4- invalidate cache
sco_cache.invalidate_formsemestre(
formsemestre_id=formsemestre_id
@ -696,9 +695,7 @@ def setGroups(
if (etudid not in etud_groups) or (
group_id != etud_groups[etudid].get(partition_id, "")
): # pas le meme groupe qu'actuel
change_etud_group_in_partition(
etudid, group_id, partition, REQUEST=REQUEST
)
change_etud_group_in_partition(etudid, group_id, partition)
# Retire les anciens membres:
cnx = ndb.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
@ -734,7 +731,7 @@ def setGroups(
group_id = createGroup(partition_id, group_name)
# Place dans ce groupe les etudiants indiqués:
for etudid in fs[1:-1]:
change_etud_group_in_partition(etudid, group_id, partition, REQUEST=REQUEST)
change_etud_group_in_partition(etudid, group_id, partition)
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
return (
@ -1329,9 +1326,7 @@ def groups_auto_repartition(partition_id=None, REQUEST=None):
etudid = listes[civilite].pop()[1]
group_id = group_ids[igroup]
igroup = (igroup + 1) % nbgroups
change_etud_group_in_partition(
etudid, group_id, partition, REQUEST=REQUEST
)
change_etud_group_in_partition(etudid, group_id, partition)
log("%s in group %s" % (etudid, group_id))
return flask.redirect(dest_url)

View File

@ -572,7 +572,6 @@ def _import_one_student(
etudid,
group_ids,
etat="I",
REQUEST=REQUEST,
method="import_csv_file",
)
return args["formsemestre_id"]
@ -716,7 +715,7 @@ def scolars_import_admission(
for group_id in group_ids:
sco_groups.change_etud_group_in_partition(
args["etudid"], group_id, REQUEST=REQUEST
args["etudid"], group_id
)
#
diag.append("import de %s" % (etud["nomprenom"]))

View File

@ -157,7 +157,7 @@ def list_inscrits_date(sem):
return [x[0] for x in cursor.fetchall()]
def do_inscrit(sem, etudids, REQUEST=None, inscrit_groupes=False):
def do_inscrit(sem, etudids, inscrit_groupes=False):
"""Inscrit ces etudiants dans ce semestre
(la liste doit avoir été vérifiée au préalable)
En option: inscrit aux mêmes groupes que dans le semestre origine
@ -168,7 +168,6 @@ def do_inscrit(sem, etudids, REQUEST=None, inscrit_groupes=False):
sem["formsemestre_id"],
etudid,
etat="I",
REQUEST=REQUEST,
method="formsemestre_inscr_passage",
)
if inscrit_groupes:
@ -208,15 +207,14 @@ def do_inscrit(sem, etudids, REQUEST=None, inscrit_groupes=False):
etudid,
partition_group["group_id"],
partition_group,
REQUEST=REQUEST,
)
def do_desinscrit(sem, etudids, REQUEST):
def do_desinscrit(sem, etudids):
log("do_desinscrit: %s" % etudids)
for etudid in etudids:
sco_formsemestre_inscriptions.do_formsemestre_desinscription(
etudid, sem["formsemestre_id"], REQUEST=REQUEST
etudid, sem["formsemestre_id"]
)
@ -361,12 +359,11 @@ def formsemestre_inscr_passage(
do_inscrit(
sem,
a_inscrire,
REQUEST=REQUEST,
inscrit_groupes=inscrit_groupes,
)
# Desincriptions:
do_desinscrit(sem, a_desinscrire, REQUEST)
do_desinscrit(sem, a_desinscrire)
H.append(
"""<h3>Opération effectuée</h3>

View File

@ -218,7 +218,7 @@ _moduleimpl_inscriptionEditor = ndb.EditableTable(
)
def do_moduleimpl_inscription_create(args, REQUEST=None, formsemestre_id=None):
def do_moduleimpl_inscription_create(args, formsemestre_id=None):
"create a moduleimpl_inscription"
cnx = ndb.GetDBConnexion()
log("do_moduleimpl_inscription_create: " + str(args))
@ -226,14 +226,13 @@ def do_moduleimpl_inscription_create(args, REQUEST=None, formsemestre_id=None):
sco_cache.invalidate_formsemestre(
formsemestre_id=formsemestre_id
) # > moduleimpl_inscription
if REQUEST:
scolog.logdb(
cnx,
method="moduleimpl_inscription",
etudid=args["etudid"],
msg="inscription module %s" % args["moduleimpl_id"],
commit=False,
)
scolog.logdb(
cnx,
method="moduleimpl_inscription",
etudid=args["etudid"],
msg="inscription module %s" % args["moduleimpl_id"],
commit=False,
)
return r
@ -283,7 +282,6 @@ def do_moduleimpl_inscrit_etuds(
if not etudid in inmod_set:
do_moduleimpl_inscription_create(
{"moduleimpl_id": moduleimpl_id, "etudid": etudid},
REQUEST=REQUEST,
formsemestre_id=formsemestre_id,
)

View File

@ -582,6 +582,5 @@ def do_etud_inscrit_ue(etudid, formsemestre_id, ue_id, REQUEST=None):
for moduleimpl_id in [x["moduleimpl_id"] for x in res]:
sco_moduleimpl.do_moduleimpl_inscription_create(
{"moduleimpl_id": moduleimpl_id, "etudid": etudid},
REQUEST=REQUEST,
formsemestre_id=formsemestre_id,
)

View File

@ -32,7 +32,8 @@ import time
import pprint
from operator import itemgetter
from flask import g, url_for
from flask import g, url_for, send_file
from flask_login import current_user
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
@ -55,7 +56,7 @@ EKEY_APO = "nip"
EKEY_SCO = "code_nip"
EKEY_NAME = "code NIP"
# view:
def formsemestre_synchro_etuds(
formsemestre_id,
etuds=[], # liste des codes NIP des etudiants a inscrire (ou deja inscrits)
@ -65,7 +66,6 @@ def formsemestre_synchro_etuds(
dialog_confirmed=False,
export_cat_xls=None,
read_only=False, # Affiche sans permettre modifications
REQUEST=None,
):
"""Synchronise les étudiants de ce semestre avec ceux d'Apogée.
On a plusieurs cas de figure: L'étudiant peut être
@ -85,15 +85,14 @@ def formsemestre_synchro_etuds(
- l'utilisateur valide (cocher les étudiants à importer/inscrire)
- go
etuds: apres selection par utilisateur, la liste des etudiants selectionnes
etuds: apres sélection par l'utilisateur, la liste des étudiants selectionnés
que l'on va importer/inscrire
"""
log("formsemestre_synchro_etuds: formsemestre_id=%s" % formsemestre_id)
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
sem["etape_apo_str"] = sco_formsemestre.formsemestre_etape_apo_str(sem)
# Write access ?
authuser = REQUEST.AUTHENTICATED_USER
if not authuser.has_permission(Permission.ScoEtudInscrit):
if not current_user.has_permission(Permission.ScoEtudInscrit):
read_only = True
if read_only:
submitted = False
@ -110,9 +109,11 @@ def formsemestre_synchro_etuds(
)
header = html_sco_header.sco_header(page_title="Synchronisation étudiants")
footer = html_sco_header.sco_footer()
base_url = "%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id)
if anneeapogee:
base_url += "&anneeapogee=%s" % anneeapogee
base_url = url_for(
"notes.formsemestre_synchro_etuds",
scodoc_dept=g.scodoc_dept,
anneeapogee=anneeapogee or None, # si None, le param n'est pas dans l'URL
)
if anneeapogee is None: # année d'inscription par défaut
anneeapogee = scu.annee_scolaire_debut(
@ -145,7 +146,12 @@ def formsemestre_synchro_etuds(
base_url=base_url,
read_only=read_only,
)
return sco_excel.send_excel_file(REQUEST, xls, filename + scu.XLSX_SUFFIX)
return send_file(
xls,
mimetype=scu.XLS_MIMETYPE,
download_name=scu.sanitize_filename(filename + scu.XLSX_SUFFIX),
as_attachment=True,
)
H = [header]
if not submitted:
@ -235,9 +241,10 @@ def formsemestre_synchro_etuds(
etudids_a_desinscrire = [nip2etudid(x) for x in a_desinscrire]
etudids_a_desinscrire += a_desinscrire_without_key
#
do_import_etuds_from_portal(sem, a_importer, etudsapo_ident, REQUEST)
sco_inscr_passage.do_inscrit(sem, etudids_a_inscrire, REQUEST)
sco_inscr_passage.do_desinscrit(sem, etudids_a_desinscrire, REQUEST)
with sco_cache.DefferedSemCacheManager():
do_import_etuds_from_portal(sem, a_importer, etudsapo_ident)
sco_inscr_passage.do_inscrit(sem, etudids_a_inscrire)
sco_inscr_passage.do_desinscrit(sem, etudids_a_desinscrire)
H.append(
"""<h3>Opération effectuée</h3>
@ -522,9 +529,9 @@ def formsemestre_synchro_etuds_help(sem):
href="formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titreannee)s</a>
les étudiants inscrits dans l'étape Apogée correspondante (<b><tt>%(etape_apo_str)s</tt></b>)
</p>
<p>Au départ, tous les étudiants d'Apogée sont sélectionnés; vous pouvez
en déselectionner certains. Tous les étudiants cochés seront inscrits au semestre ScoDoc,
les autres seront si besoin désinscrits. Aucune modification n'est effectuée avant
<p>Au départ, tous les étudiants d'Apogée sont sélectionnés; vous pouvez
en déselectionner certains. Tous les étudiants cochés seront inscrits au semestre ScoDoc,
les autres seront si besoin désinscrits. Aucune modification n'est effectuée avant
d'appuyer sur le bouton "Appliquer les modifications".</p>
<h4>Autres fonctions utiles</h4>
@ -557,16 +564,17 @@ def get_opt_str(etud, k):
return v.strip()
def get_annee_naissance(ddmmyyyyy): # stokee en dd/mm/yyyy dans le XML portail
def get_annee_naissance(ddmmyyyyy: str) -> int:
"""Extrait l'année de la date stockée en dd/mm/yyyy dans le XML portail"""
if not ddmmyyyyy:
return None
try:
return int(ddmmyyyyy.split("/")[2])
except:
except (ValueError, IndexError):
return None
def do_import_etuds_from_portal(sem, a_importer, etudsapo_ident, REQUEST):
def do_import_etuds_from_portal(sem, a_importer, etudsapo_ident):
"""Inscrit les etudiants Apogee dans ce semestre."""
log("do_import_etuds_from_portal: a_importer=%s" % a_importer)
if not a_importer:
@ -623,7 +631,6 @@ def do_import_etuds_from_portal(sem, a_importer, etudsapo_ident, REQUEST):
args["etudid"],
etat="I",
etape=args["etape"],
REQUEST=REQUEST,
method="synchro_apogee",
)
except:
@ -838,16 +845,3 @@ def formsemestre_import_etud_admission(
unknowns.append(code_nip)
sco_cache.invalidate_formsemestre(formsemestre_id=sem["formsemestre_id"])
return no_nip, unknowns, changed_mails
def do_synch_inscrits_etuds(sem, etuds, REQUEST=None): # unused ?
"""inscrits ces etudiants (déja dans ScoDoc) au semestre"""
log("do_synch_inscrits_etuds: inscription de %d etudiants" % len(etuds))
for etud in etuds:
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
sem["formsemestre_id"],
etud["etudid"],
etat="I",
REQUEST=REQUEST,
method="synchro_apogee",
)

View File

@ -1358,7 +1358,7 @@ def formsemestre_desinscription(
)
sco_formsemestre_inscriptions.do_formsemestre_desinscription(
etudid, formsemestre_id, REQUEST=REQUEST
etudid, formsemestre_id
)
return (