Adaptation fonctions export Apogée pour ScoDoc 9

This commit is contained in:
Emmanuel Viennet 2021-08-31 19:32:12 +02:00
parent 2fbce89edd
commit a52de101b6
3 changed files with 69 additions and 77 deletions

View File

@ -82,14 +82,15 @@ XXX A vérifier:
import collections
import datetime
from functools import reduce
import io
import os
import pprint
import re
import time
from zipfile import ZipFile
import pprint
from functools import reduce
from flask import send_file
# Pour la détection auto de l'encodage des fichiers Apogée:
from chardet import detect as chardet_detect
@ -500,7 +501,7 @@ class ApoEtud(dict):
# print 'comp_elt_annuel cur_sem=%s autre_sem=%s' % (cur_sem['formsemestre_id'], autre_sem['formsemestre_id'])
if not cur_sem:
# l'étudiant n'a pas de semestre courant ?!
log("comp_elt_annuel: %s no cur_sem" % etudid)
log("comp_elt_annuel: etudid %s has no cur_sem" % etudid)
return VOID_APO_RES
cur_nt = sco_cache.NotesTableCache.get(cur_sem["formsemestre_id"])
cur_decision = cur_nt.get_etud_decision_sem(etudid)
@ -756,22 +757,19 @@ class ApoData(object):
else:
self.sems_periode = None
def read_csv(self, data):
def read_csv(self, data: str):
if not data:
raise FormatError("Fichier Apogée vide !")
data_utf8 = data.decode(APO_INPUT_ENCODING).encode(
scu.SCO_ENCODING
) # XXX #sco8
f = StringIOFileLineWrapper(data_utf8) # pour traiter comme un fichier
f = StringIOFileLineWrapper(data) # pour traiter comme un fichier
# check that we are at the begining of Apogee CSV
line = f.readline().strip()
if line != "XX-APO_TITRES-XX":
raise FormatError("format incorrect: pas de XX-APO_TITRES-XX")
# 1-- En-tête: du début jusqu'à la balise XX-APO_VALEURS-XX
idx = data_utf8.index("XX-APO_VALEURS-XX")
self.header = data_utf8[:idx] # en codage ScoDoc (utf8)
idx = data.index("XX-APO_VALEURS-XX")
self.header = data[:idx]
# 2-- Titres:
# on va y chercher apoC_Fichier_Exp qui donnera le nom du fichier
@ -1236,7 +1234,7 @@ def export_csv_to_apogee(
# Create ZIP
if not dest_zip:
data = io.StringIO()
data = io.BytesIO()
dest_zip = ZipFile(data, "w")
my_zip = True
else:
@ -1293,7 +1291,7 @@ def export_csv_to_apogee(
)
log(logf.getvalue()) # sortie aussi sur le log ScoDoc
csv_data = f.getvalue().decode(scu.SCO_ENCODING).encode(APO_OUTPUT_ENCODING) # XXX
csv_data = f.getvalue().encode(APO_OUTPUT_ENCODING)
# Write data to ZIP
dest_zip.writestr(csv_filename, csv_data)
@ -1304,13 +1302,12 @@ def export_csv_to_apogee(
if my_zip:
dest_zip.close()
size = data.tell()
content_type = "application/zip"
REQUEST.RESPONSE.setHeader(
"content-disposition", 'attachement; filename="%s-scodoc.zip"' % basename
data.seek(0)
return send_file(
data,
mimetype="application/zip",
download_name=basename + "-scodoc.zip",
as_attachment=True,
)
REQUEST.RESPONSE.setHeader("content-type", content_type)
REQUEST.RESPONSE.setHeader("content-length", size)
return data.getvalue()
else:
return None # zip modified in place

View File

@ -99,12 +99,14 @@ ApoCSVArchive = ApoCSVArchiver()
# return archive_id
def apo_csv_store(csv_data, annee_scolaire, sem_id):
def apo_csv_store(csv_data: str, annee_scolaire, sem_id):
"""
csv_data: maquette content, as a string, encoding given by APO_INPUT_ENCODING (latin-1, not utf8)
csv_data: maquette content (string)
annee_scolaire: int (2016)
sem_id: 0 (année ?), 1 (premier semestre de l'année) ou 2 (deuxième semestre)
:return: etape_apo du fichier CSV stocké
Note: le fichier CSV est stocké encodé en APO_OUTPUT_ENCODING
"""
# sanity check
filesize = len(csv_data)
@ -128,7 +130,8 @@ def apo_csv_store(csv_data, annee_scolaire, sem_id):
oid = "%d-%d" % (annee_scolaire, sem_id)
description = "%s;%s;%s" % (str(apo_data.etape), annee_scolaire, sem_id)
archive_id = ApoCSVArchive.create_obj_archive(oid, description)
ApoCSVArchive.store(archive_id, filename, csv_data)
csv_data_bytes = csv_data.encode(sco_apogee_csv.APO_OUTPUT_ENCODING)
ApoCSVArchive.store(archive_id, filename, csv_data_bytes)
return apo_data.etape
@ -199,7 +202,7 @@ def apo_csv_get_archive(etape_apo, annee_scolaire="", sem_id=""):
return None
def apo_csv_get(etape_apo="", annee_scolaire="", sem_id=""):
def apo_csv_get(etape_apo="", annee_scolaire="", sem_id="") -> str:
"""Get CSV data for given etape_apo
:return: CSV, as a data string
"""
@ -210,7 +213,9 @@ def apo_csv_get(etape_apo="", annee_scolaire="", sem_id=""):
)
archive_id = info["archive_id"]
data = ApoCSVArchive.get(archive_id, etape_apo + ".csv")
return data
# ce fichier a été archivé donc généré par ScoDoc
# son encodage est donc APO_OUTPUT_ENCODING
return data.decode(sco_apogee_csv.APO_OUTPUT_ENCODING)
# ------------------------------------------------------------------------

View File

@ -28,22 +28,21 @@
"""ScoDoc : formulaires gestion maquettes Apogee / export resultats
"""
from io import StringIO
import io
from zipfile import ZipFile
import flask
from flask import url_for, g
from flask import url_for, g, send_file
# from werkzeug.utils import send_file
import app.scodoc.sco_utils as scu
from app import log
from app.scodoc import html_sco_header
from app.scodoc import notes_table
from app.scodoc import sco_apogee_csv
from app.scodoc import sco_archives
from app.scodoc import sco_etape_apogee
from app.scodoc import sco_formations
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_status
from app.scodoc import sco_portal_apogee
from app.scodoc import sco_preferences
from app.scodoc import sco_semset
@ -180,15 +179,6 @@ def apo_semset_maq_status(
H.append('<div class="apo_csv_problems"><ul>')
if len(semset.annees_scolaires()) > 1:
H.append("""<li>Il y a plusieurs années scolaires !</li>""")
if nips_no_sco: # seulement un warning
url_list = (
"view_apo_etuds?semset_id=%s&title=Etudiants%%20presents%%20dans%%20maquettes%%20Apogee%%20mais%%20pas%%20dans%%20les%%20semestres%%20ScoDoc:&nips=%s"
% (semset_id, "&nips=".join(nips_no_sco))
)
H.append(
'<li class="apo_csv_warning">Attention: il y a <a href="%s">%d étudiant(s)</a> dans les maquettes Apogée chargées non inscrit(s) dans ce semestre ScoDoc;</li>'
% (url_list, len(nips_no_sco))
)
if etapes_missing_csv:
H.append(
@ -200,9 +190,12 @@ def apo_semset_maq_status(
H.append("<li>%d étudiants ScoDoc sans code NIP</li>" % len(etuds_without_nip))
if nips_no_apo:
url_list = (
"view_scodoc_etuds?semset_id=%s&title=Etudiants%%20ScoDoc%%20non%%20listés%%20dans%%20les%%20maquettes%%20Apogée%%20chargées&nips=%s"
% (semset_id, "&nips=".join(nips_no_apo))
url_list = url_for(
"notes.view_scodoc_etuds",
scodoc_dept=g.scodoc_dept,
semset_id=semset_id,
title="Etudiants ScoDoc non listés dans les maquettes Apogée chargées",
nip_list=",".join(nips_no_apo),
)
H.append(
'<li><a href="%s">%d étudiants</a> dans ce semestre non présents dans les maquettes Apogée chargées</li>'
@ -210,9 +203,12 @@ def apo_semset_maq_status(
)
if nips_no_sco: # seulement un warning
url_list = (
"view_apo_etuds?semset_id=%s&title=Etudiants%%20presents%%20dans%%20maquettes%%20Apogee%%20mais%%20pas%%20dans%%20les%%20semestres%%20ScoDoc:&nips=%s"
% (semset_id, "&nips=".join(nips_no_sco))
url_list = url_for(
"notes.view_apo_etuds",
scodoc_dept=g.scodoc_dept,
semset_id=semset_id,
title="Etudiants présents dans maquettes Apogée mais pas dans les semestres ScoDoc",
nip_list=",".join(nips_no_sco),
)
H.append(
'<li class="apo_csv_warning">Attention: il reste <a href="%s">%d étudiants</a> dans les maquettes Apogée chargées mais pas inscrits dans ce semestre ScoDoc</li>'
@ -220,9 +216,12 @@ def apo_semset_maq_status(
)
if apo_dups:
url_list = "view_apo_etuds?semset_id=%s&title=Doublons%%20Apogee&nips=%s" % (
semset_id,
"&nips=".join(apo_dups),
url_list = url_for(
"notes.view_apo_etuds",
scodoc_dept=g.scodoc_dept,
semset_id=semset_id,
title="Doublons%%20Apogée",
nip_list=",".join(apo_dups),
)
H.append(
'<li><a href="%s">%d étudiants</a> présents dans les <em>plusieurs</em> maquettes Apogée chargées</li>'
@ -485,16 +484,18 @@ def table_apo_csv_list(semset, REQUEST=None):
return tab
def view_apo_etuds(semset_id, title="", nips=[], format="html", REQUEST=None):
"""Table des étudiants Apogée par nips"""
def view_apo_etuds(semset_id, title="", nip_list="", format="html", REQUEST=None):
"""Table des étudiants Apogée par nips
nip_list est une chaine, codes nip séparés par des ,
"""
if not semset_id:
raise ValueError("invalid null semset_id")
semset = sco_semset.SemSet(semset_id=semset_id)
# annee_scolaire = semset["annee_scolaire"]
# sem_id = semset["sem_id"]
if nips and type(nips) != type([]):
nips = [nips]
if not isinstance(nip_list, str):
nip_list = str(nip_list)
nips = nip_list.split(",")
etuds = sco_etape_apogee.apo_csv_retreive_etuds_by_nip(semset, nips)
# Ils sont parfois dans ScoDoc même si pas dans le semestre: essaie de les retrouver
for etud in etuds.values():
@ -520,22 +521,12 @@ def view_apo_etuds(semset_id, title="", nips=[], format="html", REQUEST=None):
)
def view_scodoc_etuds(
semset_id, title="", etudids=None, nips=None, format="html", REQUEST=None
):
def view_scodoc_etuds(semset_id, title="", nip_list="", format="html", REQUEST=None):
"""Table des étudiants ScoDoc par nips ou etudids"""
if etudids is not None:
if type(etudids) != type([]):
etudids = [etudids]
etuds = [
sco_etud.get_etud_info(etudid=etudid, filled=True)[0] for etudid in etudids
]
elif nips is not None:
if type(nips) != type([]):
nips = [nips]
etuds = [sco_etud.get_etud_info(code_nip=nip, filled=True)[0] for nip in nips]
else:
raise ValueError("etudid or NIP must be specified")
if not isinstance(nip_list, str):
nip_list = str(nip_list)
nips = nip_list.split(",")
etuds = [sco_etud.get_etud_info(code_nip=nip, filled=True)[0] for nip in nips]
for e in etuds:
tgt = url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=e["etudid"])
@ -809,7 +800,7 @@ def apo_csv_export_results(
annee_scolaire = semset["annee_scolaire"]
periode = semset["sem_id"]
data = StringIO()
data = io.BytesIO()
dest_zip = ZipFile(data, "w")
etapes_apo = sco_etape_apogee.apo_csv_list_stored_etapes(
@ -830,6 +821,8 @@ def apo_csv_export_results(
REQUEST=REQUEST,
)
dest_zip.close()
data.seek(0)
basename = (
sco_preferences.get_preference("DeptName")
+ str(annee_scolaire)
@ -838,12 +831,9 @@ def apo_csv_export_results(
)
basename = scu.sanitize_filename(scu.unescape_html(basename))
dest_zip.close()
size = data.tell()
content_type = "application/zip"
REQUEST.RESPONSE.setHeader(
"content-disposition", 'attachement; filename="%s.zip"' % basename
return send_file(
data,
mimetype="application/zip",
download_name=basename + ".zip",
as_attachment=True,
)
REQUEST.RESPONSE.setHeader("content-type", content_type)
REQUEST.RESPONSE.setHeader("content-length", size)
return data.getvalue()