diff --git a/app/models/formations.py b/app/models/formations.py
index 5bd4a8d96..d4aac9ad2 100644
--- a/app/models/formations.py
+++ b/app/models/formations.py
@@ -64,7 +64,7 @@ class Formation(db.Model):
return f"""Formation {self.titre} ({self.acronyme}) [version {self.version}] code {self.formation_code}"""
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.
"""
e = dict(self.__dict__)
diff --git a/app/scodoc/sco_apogee_compare.py b/app/scodoc/sco_apogee_compare.py
index 6c9676049..0c93c6652 100644
--- a/app/scodoc/sco_apogee_compare.py
+++ b/app/scodoc/sco_apogee_compare.py
@@ -43,6 +43,7 @@ Pour chaque étudiant commun:
comparer les résultats
"""
+from flask import g, url_for
from app import log
from app.scodoc import sco_apogee_csv
@@ -72,11 +73,11 @@ def apo_compare_csv_form():
"""
@@ -88,17 +89,36 @@ def apo_compare_csv_form():
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"""
- A = _load_apo_data(A_file, autodetect=autodetect)
- B = _load_apo_data(B_file, autodetect=autodetect)
-
+ try:
+ 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 = [
html_sco_header.sco_header(page_title="Comparaison de fichiers Apogée"),
"
Comparaison de fichiers Apogée
",
_help_txt,
'
',
- _apo_compare_csv(A, B),
+ _apo_compare_csv(apo_data_a, apo_data_b),
"
",
"""
Autre comparaison
""",
html_sco_header.sco_footer(),
@@ -112,9 +132,9 @@ def _load_apo_data(csvfile, autodetect=True):
if autodetect:
data_b, message = sco_apogee_csv.fix_data_encoding(data_b)
if message:
- log("apo_compare_csv: %s" % message)
+ log(f"apo_compare_csv: {message}")
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)
apo_data = sco_apogee_csv.ApoData(data, orig_filename=csvfile.filename)
return apo_data
diff --git a/app/scodoc/sco_apogee_csv.py b/app/scodoc/sco_apogee_csv.py
index 212bb133b..8d21d579b 100644
--- a/app/scodoc/sco_apogee_csv.py
+++ b/app/scodoc/sco_apogee_csv.py
@@ -155,28 +155,25 @@ def fix_data_encoding(
text: bytes,
default_source_encoding=APO_INPUT_ENCODING,
dest_encoding=APO_INPUT_ENCODING,
-) -> bytes:
+) -> tuple[bytes, str]:
"""Try to ensure that text is using dest_encoding
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 = ""
detected_encoding = guess_data_encoding(text)
if not detected_encoding:
if default_source_encoding != dest_encoding:
- message = "converting from %s to %s" % (
- default_source_encoding,
- dest_encoding,
- )
- text = text.decode(default_source_encoding).encode(
- dest_encoding
- ) # XXX #py3 #sco8 à tester
+ message = f"converting from {default_source_encoding} to {dest_encoding}"
+ text = text.decode(default_source_encoding).encode(dest_encoding)
else:
if detected_encoding != dest_encoding:
- message = "converting from detected %s to %s" % (
- detected_encoding,
- dest_encoding,
+ message = (
+ f"converting from detected {default_source_encoding} to {dest_encoding}"
)
- text = text.decode(detected_encoding).encode(dest_encoding) # XXX
+ text = text.decode(detected_encoding).encode(dest_encoding)
return text, message
diff --git a/app/scodoc/sco_etape_apogee_view.py b/app/scodoc/sco_etape_apogee_view.py
index e37b0fd84..ac6028736 100644
--- a/app/scodoc/sco_etape_apogee_view.py
+++ b/app/scodoc/sco_etape_apogee_view.py
@@ -591,19 +591,45 @@ def view_apo_csv_store(semset_id="", csvfile=None, data: bytes = "", autodetect=
if not semset_id:
raise ValueError("invalid null semset_id")
semset = sco_semset.SemSet(semset_id=semset_id)
- if csvfile:
- data = csvfile.read() # bytes
+ try:
+ if csvfile:
+ data = csvfile.read() # bytes
+ if autodetect:
+ # check encoding (although documentation states that users SHOULD upload LATIN1)
+
+ data, message = sco_apogee_csv.fix_data_encoding(data)
+ if message:
+ log(f"view_apo_csv_store: {message}")
+ else:
+ log("view_apo_csv_store: autodetection of encoding disabled by user")
+ if not data:
+ raise ScoValueError("view_apo_csv_store: no data")
+ # data est du bytes, encodé en 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:
- # check encoding (although documentation states that users SHOULD upload LATIN1)
- data, message = sco_apogee_csv.fix_data_encoding(data)
- if message:
- log("view_apo_csv_store: %s" % message)
+ 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:
- log("view_apo_csv_store: autodetection of encoding disabled by user")
- if not data:
- raise ScoValueError("view_apo_csv_store: no data")
- # data est du bytes, encodé en APO_INPUT_ENCODING
- data_str = data.decode(APO_INPUT_ENCODING)
+ 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
apo_data = sco_apogee_csv.ApoData(
data_str, periode=semset["sem_id"]
diff --git a/app/scodoc/sco_formations.py b/app/scodoc/sco_formations.py
index 9be52db4b..93f647346 100644
--- a/app/scodoc/sco_formations.py
+++ b/app/scodoc/sco_formations.py
@@ -119,6 +119,7 @@ def formation_export(
formation: Formation = Formation.query.get_or_404(formation_id)
f_dict = formation.to_dict(with_refcomp_attrs=True)
if not export_ids:
+ del f_dict["id"]
del f_dict["formation_id"]
del f_dict["dept_id"]
ues = formation.ues
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index d1b5fb793..cb5e0344e 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -326,9 +326,9 @@ div.logo-logo img {
box-sizing: content-box;
margin-top: 10px;
/* -10px */
- width: 80px;
+ width: 130px;
/* adapter suivant image */
- padding-right: 5px;
+ /* padding-right: 5px; */
}
div.sidebar-bottom {
diff --git a/app/static/icons/scologo_img.png b/app/static/icons/scologo_img.png
index 04a2c5c1c..9bf587a80 100644
Binary files a/app/static/icons/scologo_img.png and b/app/static/icons/scologo_img.png differ
diff --git a/app/templates/about.j2 b/app/templates/about.j2
index 23dc1ce5b..3dff1edee 100644
--- a/app/templates/about.j2
+++ b/app/templates/about.j2
@@ -6,7 +6,7 @@
Système de gestion scolarité
-
© Emmanuel Viennet 2021
+
© Emmanuel Viennet 2023
Version {{ version }}
diff --git a/sco_version.py b/sco_version.py
index c42cd066c..16ec61569 100644
--- a/sco_version.py
+++ b/sco_version.py
@@ -1,7 +1,7 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
-SCOVERSION = "9.4.35"
+SCOVERSION = "9.4.36"
SCONAME = "ScoDoc"
diff --git a/tests/api/test_api_formations.py b/tests/api/test_api_formations.py
index 1869fc985..d4202f922 100644
--- a/tests/api/test_api_formations.py
+++ b/tests/api/test_api_formations.py
@@ -114,21 +114,18 @@ def test_formation_export(api_headers):
assert r.status_code == 200
export_formation = r.json()
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["titre_officiel"], str)
assert isinstance(export_formation["formation_code"], str)
assert export_formation["code_specialite"] is None or isinstance(
export_formation["code_specialite"], str
)
- assert isinstance(export_formation["id"], int)
assert isinstance(export_formation["titre"], str)
assert isinstance(export_formation["version"], int)
assert isinstance(export_formation["type_parcours"], int)
assert export_formation["referentiel_competence_id"] is None or isinstance(
export_formation["referentiel_competence_id"], int
)
- assert isinstance(export_formation["formation_id"], int)
assert isinstance(export_formation["ue"], list)
ues = export_formation["ue"]
@@ -192,6 +189,23 @@ def test_formation_export(api_headers):
assert r_error.status_code == 404
+def test_formation_export_with_ids(api_headers):
+ """
+ Route: /formation/
/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):
"""
Route: /formation/moduleimpl/
diff --git a/tests/api/test_api_users.py b/tests/api/test_api_users.py
index 8a347700b..e0e0e579c 100644
--- a/tests/api/test_api_users.py
+++ b/tests/api/test_api_users.py
@@ -78,10 +78,10 @@ def test_edit_users(api_admin_headers):
nb_users = len(GET("/users/query", headers=admin_h))
user = POST_JSON(
"/user/create",
- {"user_name": "toto", "nom": "Toto"},
+ {"user_name": "test_edit_users", "nom": "Toto"},
headers=admin_h,
)
- assert user["user_name"] == "toto"
+ assert user["user_name"] == "test_edit_users"
assert user["dept"] is None
assert user["active"] is True
assert (nb_users + 1) == len(GET("/users/query", headers=admin_h))
diff --git a/tests/api/tools_test_api.py b/tests/api/tools_test_api.py
index 7201031bf..b277dd281 100644
--- a/tests/api/tools_test_api.py
+++ b/tests/api/tools_test_api.py
@@ -77,18 +77,16 @@ FORMATION_FIELDS = {
}
FORMATION_EXPORT_FIELDS = {
- "dept_id",
+ # "dept_id" "id" "formation_id", pas présents sauf si export_with_ids
"acronyme",
- "titre_officiel",
- "formation_code",
"code_specialite",
- "id",
- "titre",
- "version",
- "type_parcours",
+ "formation_code",
"referentiel_competence_id",
- "formation_id",
+ "titre_officiel",
+ "titre",
+ "type_parcours",
"ue",
+ "version",
}
FORMATION_EXPORT_UE_FIELDS = {
diff --git a/tests/unit/test_formations.py b/tests/unit/test_formations.py
index c91a4cf87..38a40378d 100644
--- a/tests/unit/test_formations.py
+++ b/tests/unit/test_formations.py
@@ -178,7 +178,7 @@ def test_formations(test_client):
# --- Export de formation_id
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)
assert isinstance(exp, str)
load_exp = json.loads(exp)