1
0
forked from ScoDoc/ScoDoc

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 return photo_url
def get_maquette_url(self, context): 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") maquette_url = context.get_preference("maquette_url")
if not maquette_url: if not maquette_url:
# Default: # Default:
@ -128,9 +127,10 @@ get_maquette_url = _PI.get_maquette_url
get_portal_api_version = _PI.get_portal_api_version 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 """Liste des inscrits à une étape Apogée
Result = list of dicts 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)) log("get_inscrits_etape: code=%s anneeapogee=%s" % (code_etape, anneeapogee))
if anneeapogee is None: if anneeapogee is None:
@ -149,7 +149,13 @@ def get_inscrits_etape(context, code_etape, anneeapogee=None):
) )
else: else:
req = etud_url + "?" + urllib.urlencode((("etape", code_etape),)) 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: if not doc:
raise ScoValueError("pas de réponse du portail ! (timeout=%s)" % portal_timeout) raise ScoValueError("pas de réponse du portail ! (timeout=%s)" % portal_timeout)
etuds = _normalize_apo_fields(xml_to_list_of_dicts(doc, req=req)) 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): 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: if not doc:
return [] return []
# Fix for buggy XML returned by some APIs (eg USPN) # Fix for buggy XML returned by some APIs (eg USPN)
invalid_entities = { invalid_entities = {
'Ç' : 'Ç', "Ç": "Ç",
'& ' : '& ', # only when followed by a space (avoid affecting entities) "& ": "& ", # only when followed by a space (avoid affecting entities)
# to be completed... # to be completed...
} }
for k in invalid_entities: for k in invalid_entities:
doc = doc.replace(k,invalid_entities[k]) doc = doc.replace(k, invalid_entities[k])
# #
try: try:
dom = xml.dom.minidom.parseString(doc) dom = xml.dom.minidom.parseString(doc)
except xml.parsers.expat.ExpatError as e: except xml.parsers.expat.ExpatError as e:
# Find faulty part # 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 # catch bug: log and re-raise exception
log( log(
"xml_to_list_of_dicts: exception in XML parseString\ndoc:\n%s\n(end xml doc)\n" "xml_to_list_of_dicts: exception in XML parseString\ndoc:\n%s\n(end xml doc)\n"
% doc % 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 = [] infos = []
try: try:
if dom.childNodes[0].nodeName != u"etudiants": 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): 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): if (not nom) and (not prenom):
return [] return []
# essaie plusieurs codages: tirets, accents # essaie plusieurs codages: tirets, accents
@ -322,8 +328,7 @@ def get_etud_apogee(context, code_nip):
def get_default_etapes(context): 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" filename = context.file_path + "/config/default-etapes.txt"
log("get_default_etapes: reading %s" % filename) log("get_default_etapes: reading %s" % filename)
f = open(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), 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. le departement n'est pas utilisé: toutes les étapes sont présentées.
Returns [ ( code, intitule) ], ordonnée Returns [ ( code, intitule) ], ordonnée
""" """
xml_etapes_by_dept = context.get_preference("xml_etapes_by_dept") 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 infolist: liste de dict renvoyés par le portail Apogee
recode les champs: paiementinscription (-> booleen), datefinalisationinscription (date) 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 ajuoute le champs 'etape' (= None) s'il n'est pas présent
""" """
for infos in infolist: 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. """Interroge le portail pour vérifier l'état de "paiement" et l'étape d'inscription.
Seuls les etudiants avec code NIP sont renseignés. Seuls les etudiants avec code NIP sont renseignés.
Renseigne l'attribut booleen 'paiementinscription' dans chaque etud. Renseigne l'attribut booleen 'paiementinscription' dans chaque etud.
En sortie: modif les champs de 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=""): 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) maquette_url = get_maquette_url(context)
if not maquette_url: if not maquette_url:
return None return None

View File

@ -778,6 +778,17 @@ def formsemestre_import_etud_admission(
changed_mails = [] # modification d'adresse mails changed_mails = [] # modification d'adresse mails
cnx = context.GetDBConnexion() 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: for i in ins:
etudid = i["etudid"] etudid = i["etudid"]
info = context.getEtudInfo(etudid=etudid, filled=1)[0] info = context.getEtudInfo(etudid=etudid, filled=1)[0]
@ -785,7 +796,10 @@ def formsemestre_import_etud_admission(
if not code_nip: if not code_nip:
no_nip.append(etudid) no_nip.append(etudid)
else: 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: if etud:
do_import_etud_admission( do_import_etud_admission(
context, context,
@ -818,6 +832,7 @@ def formsemestre_import_etud_admission(
changed_mails.append((info, etud["mail"])) changed_mails.append((info, etud["mail"]))
else: else:
unknowns.append(code_nip) unknowns.append(code_nip)
context._inval_cache(formsemestre_id=sem["formsemestre_id"])
return no_nip, unknowns, changed_mails 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): 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) (used to connect to Apogee portal, or ScoDoc server)
returns a string, "" on error
""" """
log("query_portal: %s" % req) log("query_portal: %s" % req)