forked from ScoDoc/ScoDoc
Merge branch 'master' of https://scodoc.org/git/viennet/ScoDoc into table
This commit is contained in:
commit
27b98be125
@ -64,7 +64,7 @@ class Formation(db.Model):
|
|||||||
return f"""Formation {self.titre} ({self.acronyme}) [version {self.version}] code {self.formation_code}"""
|
return f"""Formation {self.titre} ({self.acronyme}) [version {self.version}] code {self.formation_code}"""
|
||||||
|
|
||||||
def to_dict(self, with_refcomp_attrs=False):
|
def to_dict(self, with_refcomp_attrs=False):
|
||||||
""" "as a dict.
|
"""As a dict.
|
||||||
Si with_refcomp_attrs, ajoute attributs permettant de retrouver le ref. de comp.
|
Si with_refcomp_attrs, ajoute attributs permettant de retrouver le ref. de comp.
|
||||||
"""
|
"""
|
||||||
e = dict(self.__dict__)
|
e = dict(self.__dict__)
|
||||||
|
@ -43,6 +43,7 @@ Pour chaque étudiant commun:
|
|||||||
comparer les résultats
|
comparer les résultats
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from flask import g, url_for
|
||||||
|
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc import sco_apogee_csv
|
from app.scodoc import sco_apogee_csv
|
||||||
@ -72,11 +73,11 @@ def apo_compare_csv_form():
|
|||||||
"""
|
"""
|
||||||
<div class="apo_compare_csv_form_but">
|
<div class="apo_compare_csv_form_but">
|
||||||
Fichier Apogée A:
|
Fichier Apogée A:
|
||||||
<input type="file" size="30" name="A_file"/>
|
<input type="file" size="30" name="file_a"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="apo_compare_csv_form_but">
|
<div class="apo_compare_csv_form_but">
|
||||||
Fichier Apogée B:
|
Fichier Apogée B:
|
||||||
<input type="file" size="30" name="B_file"/>
|
<input type="file" size="30" name="file_b"/>
|
||||||
</div>
|
</div>
|
||||||
<input type="checkbox" name="autodetect" checked/>autodétecter encodage</input>
|
<input type="checkbox" name="autodetect" checked/>autodétecter encodage</input>
|
||||||
<div class="apo_compare_csv_form_submit">
|
<div class="apo_compare_csv_form_submit">
|
||||||
@ -88,17 +89,36 @@ def apo_compare_csv_form():
|
|||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
def apo_compare_csv(A_file, B_file, autodetect=True):
|
def apo_compare_csv(file_a, file_b, autodetect=True):
|
||||||
"""Page comparing 2 Apogee CSV files"""
|
"""Page comparing 2 Apogee CSV files"""
|
||||||
A = _load_apo_data(A_file, autodetect=autodetect)
|
try:
|
||||||
B = _load_apo_data(B_file, autodetect=autodetect)
|
apo_data_a = _load_apo_data(file_a, autodetect=autodetect)
|
||||||
|
apo_data_b = _load_apo_data(file_b, autodetect=autodetect)
|
||||||
|
except (UnicodeDecodeError, UnicodeEncodeError) as exc:
|
||||||
|
dest_url = url_for("notes.semset_page", scodoc_dept=g.scodoc_dept)
|
||||||
|
if autodetect:
|
||||||
|
raise ScoValueError(
|
||||||
|
"""
|
||||||
|
Erreur: l'encodage de l'un des fichiers est mal détecté.
|
||||||
|
Essayez sans auto-détection, ou vérifiez le codage et le contenu
|
||||||
|
des fichiers.
|
||||||
|
""",
|
||||||
|
dest_url=dest_url,
|
||||||
|
) from exc
|
||||||
|
else:
|
||||||
|
raise ScoValueError(
|
||||||
|
f"""
|
||||||
|
Erreur: l'encodage de l'un des fichiers est incorrect.
|
||||||
|
Vérifiez qu'il est bien en {sco_apogee_csv.APO_INPUT_ENCODING}
|
||||||
|
""",
|
||||||
|
dest_url=dest_url,
|
||||||
|
) from exc
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(page_title="Comparaison de fichiers Apogée"),
|
html_sco_header.sco_header(page_title="Comparaison de fichiers Apogée"),
|
||||||
"<h2>Comparaison de fichiers Apogée</h2>",
|
"<h2>Comparaison de fichiers Apogée</h2>",
|
||||||
_help_txt,
|
_help_txt,
|
||||||
'<div class="apo_compare_csv">',
|
'<div class="apo_compare_csv">',
|
||||||
_apo_compare_csv(A, B),
|
_apo_compare_csv(apo_data_a, apo_data_b),
|
||||||
"</div>",
|
"</div>",
|
||||||
"""<p><a href="apo_compare_csv_form" class="stdlink">Autre comparaison</a></p>""",
|
"""<p><a href="apo_compare_csv_form" class="stdlink">Autre comparaison</a></p>""",
|
||||||
html_sco_header.sco_footer(),
|
html_sco_header.sco_footer(),
|
||||||
@ -112,9 +132,9 @@ def _load_apo_data(csvfile, autodetect=True):
|
|||||||
if autodetect:
|
if autodetect:
|
||||||
data_b, message = sco_apogee_csv.fix_data_encoding(data_b)
|
data_b, message = sco_apogee_csv.fix_data_encoding(data_b)
|
||||||
if message:
|
if message:
|
||||||
log("apo_compare_csv: %s" % message)
|
log(f"apo_compare_csv: {message}")
|
||||||
if not data_b:
|
if not data_b:
|
||||||
raise ScoValueError("apo_compare_csv: no data")
|
raise ScoValueError("fichier vide ? (apo_compare_csv: no data)")
|
||||||
data = data_b.decode(sco_apogee_csv.APO_INPUT_ENCODING)
|
data = data_b.decode(sco_apogee_csv.APO_INPUT_ENCODING)
|
||||||
apo_data = sco_apogee_csv.ApoData(data, orig_filename=csvfile.filename)
|
apo_data = sco_apogee_csv.ApoData(data, orig_filename=csvfile.filename)
|
||||||
return apo_data
|
return apo_data
|
||||||
|
@ -155,28 +155,25 @@ def fix_data_encoding(
|
|||||||
text: bytes,
|
text: bytes,
|
||||||
default_source_encoding=APO_INPUT_ENCODING,
|
default_source_encoding=APO_INPUT_ENCODING,
|
||||||
dest_encoding=APO_INPUT_ENCODING,
|
dest_encoding=APO_INPUT_ENCODING,
|
||||||
) -> bytes:
|
) -> tuple[bytes, str]:
|
||||||
"""Try to ensure that text is using dest_encoding
|
"""Try to ensure that text is using dest_encoding
|
||||||
returns converted text, and a message describing the conversion.
|
returns converted text, and a message describing the conversion.
|
||||||
|
|
||||||
|
Raises UnicodeEncodeError en cas de problème, en général liée à
|
||||||
|
une auto-détection errornée.
|
||||||
"""
|
"""
|
||||||
message = ""
|
message = ""
|
||||||
detected_encoding = guess_data_encoding(text)
|
detected_encoding = guess_data_encoding(text)
|
||||||
if not detected_encoding:
|
if not detected_encoding:
|
||||||
if default_source_encoding != dest_encoding:
|
if default_source_encoding != dest_encoding:
|
||||||
message = "converting from %s to %s" % (
|
message = f"converting from {default_source_encoding} to {dest_encoding}"
|
||||||
default_source_encoding,
|
text = text.decode(default_source_encoding).encode(dest_encoding)
|
||||||
dest_encoding,
|
|
||||||
)
|
|
||||||
text = text.decode(default_source_encoding).encode(
|
|
||||||
dest_encoding
|
|
||||||
) # XXX #py3 #sco8 à tester
|
|
||||||
else:
|
else:
|
||||||
if detected_encoding != dest_encoding:
|
if detected_encoding != dest_encoding:
|
||||||
message = "converting from detected %s to %s" % (
|
message = (
|
||||||
detected_encoding,
|
f"converting from detected {default_source_encoding} to {dest_encoding}"
|
||||||
dest_encoding,
|
|
||||||
)
|
)
|
||||||
text = text.decode(detected_encoding).encode(dest_encoding) # XXX
|
text = text.decode(detected_encoding).encode(dest_encoding)
|
||||||
return text, message
|
return text, message
|
||||||
|
|
||||||
|
|
||||||
|
@ -591,19 +591,45 @@ def view_apo_csv_store(semset_id="", csvfile=None, data: bytes = "", autodetect=
|
|||||||
if not semset_id:
|
if not semset_id:
|
||||||
raise ValueError("invalid null semset_id")
|
raise ValueError("invalid null semset_id")
|
||||||
semset = sco_semset.SemSet(semset_id=semset_id)
|
semset = sco_semset.SemSet(semset_id=semset_id)
|
||||||
|
try:
|
||||||
if csvfile:
|
if csvfile:
|
||||||
data = csvfile.read() # bytes
|
data = csvfile.read() # bytes
|
||||||
if autodetect:
|
if autodetect:
|
||||||
# check encoding (although documentation states that users SHOULD upload LATIN1)
|
# check encoding (although documentation states that users SHOULD upload LATIN1)
|
||||||
|
|
||||||
data, message = sco_apogee_csv.fix_data_encoding(data)
|
data, message = sco_apogee_csv.fix_data_encoding(data)
|
||||||
if message:
|
if message:
|
||||||
log("view_apo_csv_store: %s" % message)
|
log(f"view_apo_csv_store: {message}")
|
||||||
else:
|
else:
|
||||||
log("view_apo_csv_store: autodetection of encoding disabled by user")
|
log("view_apo_csv_store: autodetection of encoding disabled by user")
|
||||||
if not data:
|
if not data:
|
||||||
raise ScoValueError("view_apo_csv_store: no data")
|
raise ScoValueError("view_apo_csv_store: no data")
|
||||||
# data est du bytes, encodé en APO_INPUT_ENCODING
|
# data est du bytes, encodé en APO_INPUT_ENCODING
|
||||||
data_str = data.decode(APO_INPUT_ENCODING)
|
data_str = data.decode(APO_INPUT_ENCODING)
|
||||||
|
except (UnicodeDecodeError, UnicodeEncodeError) as exc:
|
||||||
|
dest_url = url_for(
|
||||||
|
"notes.apo_semset_maq_status",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
semset_id=semset_id,
|
||||||
|
)
|
||||||
|
if autodetect:
|
||||||
|
raise ScoValueError(
|
||||||
|
f"""
|
||||||
|
Erreur: l'encodage du fichier est mal détecté.
|
||||||
|
Essayez sans auto-détection, ou vérifiez le codage et le contenu
|
||||||
|
du fichier (qui doit être en {sco_apogee_csv.APO_INPUT_ENCODING}).
|
||||||
|
""",
|
||||||
|
dest_url=dest_url,
|
||||||
|
) from exc
|
||||||
|
else:
|
||||||
|
raise ScoValueError(
|
||||||
|
f"""
|
||||||
|
Erreur: l'encodage du fichier est incorrect.
|
||||||
|
Vérifiez qu'il est bien en {sco_apogee_csv.APO_INPUT_ENCODING}
|
||||||
|
""",
|
||||||
|
dest_url=dest_url,
|
||||||
|
) from exc
|
||||||
|
|
||||||
# check si etape maquette appartient bien au semset
|
# check si etape maquette appartient bien au semset
|
||||||
apo_data = sco_apogee_csv.ApoData(
|
apo_data = sco_apogee_csv.ApoData(
|
||||||
data_str, periode=semset["sem_id"]
|
data_str, periode=semset["sem_id"]
|
||||||
|
@ -119,6 +119,7 @@ def formation_export(
|
|||||||
formation: Formation = Formation.query.get_or_404(formation_id)
|
formation: Formation = Formation.query.get_or_404(formation_id)
|
||||||
f_dict = formation.to_dict(with_refcomp_attrs=True)
|
f_dict = formation.to_dict(with_refcomp_attrs=True)
|
||||||
if not export_ids:
|
if not export_ids:
|
||||||
|
del f_dict["id"]
|
||||||
del f_dict["formation_id"]
|
del f_dict["formation_id"]
|
||||||
del f_dict["dept_id"]
|
del f_dict["dept_id"]
|
||||||
ues = formation.ues
|
ues = formation.ues
|
||||||
|
@ -326,9 +326,9 @@ div.logo-logo img {
|
|||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
/* -10px */
|
/* -10px */
|
||||||
width: 80px;
|
width: 130px;
|
||||||
/* adapter suivant image */
|
/* adapter suivant image */
|
||||||
padding-right: 5px;
|
/* padding-right: 5px; */
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sidebar-bottom {
|
div.sidebar-bottom {
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 69 KiB |
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<h2>Système de gestion scolarité</h2>
|
<h2>Système de gestion scolarité</h2>
|
||||||
|
|
||||||
<p>© Emmanuel Viennet 2021</p>
|
<p>© Emmanuel Viennet 2023</p>
|
||||||
|
|
||||||
<p>Version {{ version }}</p>
|
<p>Version {{ version }}</p>
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.4.35"
|
SCOVERSION = "9.4.36"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
@ -114,21 +114,18 @@ def test_formation_export(api_headers):
|
|||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
export_formation = r.json()
|
export_formation = r.json()
|
||||||
assert verify_fields(export_formation, FORMATION_EXPORT_FIELDS) is True
|
assert verify_fields(export_formation, FORMATION_EXPORT_FIELDS) is True
|
||||||
assert isinstance(export_formation["dept_id"], int)
|
|
||||||
assert isinstance(export_formation["acronyme"], str)
|
assert isinstance(export_formation["acronyme"], str)
|
||||||
assert isinstance(export_formation["titre_officiel"], str)
|
assert isinstance(export_formation["titre_officiel"], str)
|
||||||
assert isinstance(export_formation["formation_code"], str)
|
assert isinstance(export_formation["formation_code"], str)
|
||||||
assert export_formation["code_specialite"] is None or isinstance(
|
assert export_formation["code_specialite"] is None or isinstance(
|
||||||
export_formation["code_specialite"], str
|
export_formation["code_specialite"], str
|
||||||
)
|
)
|
||||||
assert isinstance(export_formation["id"], int)
|
|
||||||
assert isinstance(export_formation["titre"], str)
|
assert isinstance(export_formation["titre"], str)
|
||||||
assert isinstance(export_formation["version"], int)
|
assert isinstance(export_formation["version"], int)
|
||||||
assert isinstance(export_formation["type_parcours"], int)
|
assert isinstance(export_formation["type_parcours"], int)
|
||||||
assert export_formation["referentiel_competence_id"] is None or isinstance(
|
assert export_formation["referentiel_competence_id"] is None or isinstance(
|
||||||
export_formation["referentiel_competence_id"], int
|
export_formation["referentiel_competence_id"], int
|
||||||
)
|
)
|
||||||
assert isinstance(export_formation["formation_id"], int)
|
|
||||||
assert isinstance(export_formation["ue"], list)
|
assert isinstance(export_formation["ue"], list)
|
||||||
|
|
||||||
ues = export_formation["ue"]
|
ues = export_formation["ue"]
|
||||||
@ -192,6 +189,23 @@ def test_formation_export(api_headers):
|
|||||||
assert r_error.status_code == 404
|
assert r_error.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
def test_formation_export_with_ids(api_headers):
|
||||||
|
"""
|
||||||
|
Route: /formation/<int:formation_id>/export_with_ids
|
||||||
|
"""
|
||||||
|
r = requests.get(
|
||||||
|
API_URL + "/formation/1/export_with_ids",
|
||||||
|
headers=api_headers,
|
||||||
|
verify=CHECK_CERTIFICATE,
|
||||||
|
)
|
||||||
|
assert r.status_code == 200
|
||||||
|
export_formation = r.json()
|
||||||
|
assert verify_fields(export_formation, FORMATION_EXPORT_FIELDS) is True
|
||||||
|
assert isinstance(export_formation["id"], int)
|
||||||
|
assert isinstance(export_formation["dept_id"], int)
|
||||||
|
assert isinstance(export_formation["formation_id"], int)
|
||||||
|
|
||||||
|
|
||||||
def test_moduleimpl(api_headers):
|
def test_moduleimpl(api_headers):
|
||||||
"""
|
"""
|
||||||
Route: /formation/moduleimpl/<int:moduleimpl_id>
|
Route: /formation/moduleimpl/<int:moduleimpl_id>
|
||||||
|
@ -78,10 +78,10 @@ def test_edit_users(api_admin_headers):
|
|||||||
nb_users = len(GET("/users/query", headers=admin_h))
|
nb_users = len(GET("/users/query", headers=admin_h))
|
||||||
user = POST_JSON(
|
user = POST_JSON(
|
||||||
"/user/create",
|
"/user/create",
|
||||||
{"user_name": "toto", "nom": "Toto"},
|
{"user_name": "test_edit_users", "nom": "Toto"},
|
||||||
headers=admin_h,
|
headers=admin_h,
|
||||||
)
|
)
|
||||||
assert user["user_name"] == "toto"
|
assert user["user_name"] == "test_edit_users"
|
||||||
assert user["dept"] is None
|
assert user["dept"] is None
|
||||||
assert user["active"] is True
|
assert user["active"] is True
|
||||||
assert (nb_users + 1) == len(GET("/users/query", headers=admin_h))
|
assert (nb_users + 1) == len(GET("/users/query", headers=admin_h))
|
||||||
|
@ -77,18 +77,16 @@ FORMATION_FIELDS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FORMATION_EXPORT_FIELDS = {
|
FORMATION_EXPORT_FIELDS = {
|
||||||
"dept_id",
|
# "dept_id" "id" "formation_id", pas présents sauf si export_with_ids
|
||||||
"acronyme",
|
"acronyme",
|
||||||
"titre_officiel",
|
|
||||||
"formation_code",
|
|
||||||
"code_specialite",
|
"code_specialite",
|
||||||
"id",
|
"formation_code",
|
||||||
"titre",
|
|
||||||
"version",
|
|
||||||
"type_parcours",
|
|
||||||
"referentiel_competence_id",
|
"referentiel_competence_id",
|
||||||
"formation_id",
|
"titre_officiel",
|
||||||
|
"titre",
|
||||||
|
"type_parcours",
|
||||||
"ue",
|
"ue",
|
||||||
|
"version",
|
||||||
}
|
}
|
||||||
|
|
||||||
FORMATION_EXPORT_UE_FIELDS = {
|
FORMATION_EXPORT_UE_FIELDS = {
|
||||||
|
@ -178,7 +178,7 @@ def test_formations(test_client):
|
|||||||
# --- Export de formation_id
|
# --- Export de formation_id
|
||||||
|
|
||||||
exp = sco_formations.formation_export(
|
exp = sco_formations.formation_export(
|
||||||
formation_id=formation_id, format="json"
|
formation_id=formation_id, format="json", export_ids=True
|
||||||
).get_data(as_text=True)
|
).get_data(as_text=True)
|
||||||
assert isinstance(exp, str)
|
assert isinstance(exp, str)
|
||||||
load_exp = json.loads(exp)
|
load_exp = json.loads(exp)
|
||||||
|
Loading…
Reference in New Issue
Block a user