Accelerate resync data ident with Apo

This commit is contained in:
viennet 2020-10-14 12:36:18 +02:00
parent 1c1e157761
commit 0ddf1faed4
3 changed files with 42 additions and 22 deletions

View File

@ -99,8 +99,7 @@ class PortalInterface:
return photo_url
def get_maquette_url(self, context):
"""Full URL of service giving Apogee maquette pour une étape (fichier "CSV")
"""
"""Full URL of service giving Apogee maquette pour une étape (fichier "CSV")"""
maquette_url = context.get_preference("maquette_url")
if not maquette_url:
# Default:
@ -128,9 +127,10 @@ get_maquette_url = _PI.get_maquette_url
get_portal_api_version = _PI.get_portal_api_version
def get_inscrits_etape(context, code_etape, anneeapogee=None):
def get_inscrits_etape(context, code_etape, anneeapogee=None, ntrials=2):
"""Liste des inscrits à une étape Apogée
Result = list of dicts
ntrials: try several time the same request, useful for some bad web services
"""
log("get_inscrits_etape: code=%s anneeapogee=%s" % (code_etape, anneeapogee))
if anneeapogee is None:
@ -149,7 +149,13 @@ def get_inscrits_etape(context, code_etape, anneeapogee=None):
)
else:
req = etud_url + "?" + urllib.urlencode((("etape", code_etape),))
doc = query_portal(req, timeout=portal_timeout)
actual_timeout = float(portal_timeout) / ntrials
if portal_timeout > 0:
actual_timeout = max(1, actual_timeout)
for _ntrial in range(ntrials):
doc = query_portal(req, timeout=actual_timeout)
if doc:
break
if not doc:
raise ScoValueError("pas de réponse du portail ! (timeout=%s)" % portal_timeout)
etuds = _normalize_apo_fields(xml_to_list_of_dicts(doc, req=req))
@ -197,30 +203,31 @@ def query_apogee_portal(context, **args):
def xml_to_list_of_dicts(doc, req=None):
"""Convert an XML 1.0 str to a list of dicts.
"""
"""Convert an XML 1.0 str to a list of dicts."""
if not doc:
return []
# Fix for buggy XML returned by some APIs (eg USPN)
invalid_entities = {
'Ç' : 'Ç',
'& ' : '& ', # only when followed by a space (avoid affecting entities)
"Ç": "Ç",
"& ": "& ", # only when followed by a space (avoid affecting entities)
# to be completed...
}
for k in invalid_entities:
doc = doc.replace(k,invalid_entities[k])
doc = doc.replace(k, invalid_entities[k])
#
try:
dom = xml.dom.minidom.parseString(doc)
except xml.parsers.expat.ExpatError as e:
# Find faulty part
err_zone = doc.splitlines()[e.lineno-1][e.offset:e.offset+20]
err_zone = doc.splitlines()[e.lineno - 1][e.offset : e.offset + 20]
# catch bug: log and re-raise exception
log(
"xml_to_list_of_dicts: exception in XML parseString\ndoc:\n%s\n(end xml doc)\n"
% doc
)
raise ScoValueError("erreur dans la réponse reçue du portail ! (peut être : \"%s\")" % err_zone)
raise ScoValueError(
'erreur dans la réponse reçue du portail ! (peut être : "%s")' % err_zone
)
infos = []
try:
if dom.childNodes[0].nodeName != u"etudiants":
@ -275,8 +282,7 @@ def get_infos_apogee_allaccents(context, nom, prenom):
def get_infos_apogee(context, nom, prenom):
"""recupere les codes Apogee en utilisant le web service CRIT
"""
"""recupere les codes Apogee en utilisant le web service CRIT"""
if (not nom) and (not prenom):
return []
# essaie plusieurs codages: tirets, accents
@ -322,8 +328,7 @@ def get_etud_apogee(context, code_nip):
def get_default_etapes(context):
"""Liste par défaut: devrait etre lue d'un fichier de config
"""
"""Liste par défaut: devrait etre lue d'un fichier de config"""
filename = context.file_path + "/config/default-etapes.txt"
log("get_default_etapes: reading %s" % filename)
f = open(filename)
@ -417,7 +422,7 @@ def get_etapes_apogee_dept(context):
Si xml_etapes_by_dept est faux (nouveau format XML depuis sept 2014),
le departement n'est pas utilisé: toutes les étapes sont présentées.
Returns [ ( code, intitule) ], ordonnée
"""
xml_etapes_by_dept = context.get_preference("xml_etapes_by_dept")
@ -466,7 +471,7 @@ def _normalize_apo_fields(infolist):
infolist: liste de dict renvoyés par le portail Apogee
recode les champs: paiementinscription (-> booleen), datefinalisationinscription (date)
ajoute le champs 'paiementinscription_str' : 'ok', 'Non' ou '?'
ajoute le champs 'paiementinscription_str' : 'ok', 'Non' ou '?'
ajuoute le champs 'etape' (= None) s'il n'est pas présent
"""
for infos in infolist:
@ -503,7 +508,7 @@ def check_paiement_etuds(context, etuds):
"""Interroge le portail pour vérifier l'état de "paiement" et l'étape d'inscription.
Seuls les etudiants avec code NIP sont renseignés.
Renseigne l'attribut booleen 'paiementinscription' dans chaque etud.
En sortie: modif les champs de chaque etud
@ -539,8 +544,7 @@ def check_paiement_etuds(context, etuds):
def get_maquette_apogee(context, etape="", annee_scolaire=""):
"""Maquette CSV Apogee pour une étape et une annee scolaire
"""
"""Maquette CSV Apogee pour une étape et une annee scolaire"""
maquette_url = get_maquette_url(context)
if not maquette_url:
return None

View File

@ -778,6 +778,17 @@ def formsemestre_import_etud_admission(
changed_mails = [] # modification d'adresse mails
cnx = context.GetDBConnexion()
# Essaie de recuperer les etudiants des étapes, car
# la requete get_inscrits_etape est en général beaucoup plus
# rapide que les requetes individuelles get_etud_apogee
anneeapogee = str(annee_scolaire_debut(sem["annee_debut"], sem["mois_debut_ord"]))
apo_etuds = {} # nip : etud apo
for etape in sem["etapes"]:
etudsapo = sco_portal_apogee.get_inscrits_etape(
context, etape, anneeapogee=anneeapogee
)
apo_etuds.update({e["nip"]: e for e in etudsapo})
for i in ins:
etudid = i["etudid"]
info = context.getEtudInfo(etudid=etudid, filled=1)[0]
@ -785,7 +796,10 @@ def formsemestre_import_etud_admission(
if not code_nip:
no_nip.append(etudid)
else:
etud = sco_portal_apogee.get_etud_apogee(context, code_nip)
etud = apo_etuds.get(code_nip)
if not etud:
# pas vu dans les etudiants de l'étape, tente en individuel
etud = sco_portal_apogee.get_etud_apogee(context, code_nip)
if etud:
do_import_etud_admission(
context,
@ -818,6 +832,7 @@ def formsemestre_import_etud_admission(
changed_mails.append((info, etud["mail"]))
else:
unknowns.append(code_nip)
context._inval_cache(formsemestre_id=sem["formsemestre_id"])
return no_nip, unknowns, changed_mails

View File

@ -836,8 +836,9 @@ def sort_dates(L, reverse=False):
def query_portal(req, msg="Portail Apogee", timeout=3):
"""retreive external data using http request
"""Retreives external data using HTTP request
(used to connect to Apogee portal, or ScoDoc server)
returns a string, "" on error
"""
log("query_portal: %s" % req)