From 3b436fa0f3df47952976df60f9ba920239064997 Mon Sep 17 00:00:00 2001
From: Emmanuel Viennet <emmanuel.viennet@gmail.com>
Date: Mon, 20 May 2024 10:46:36 +0200
Subject: [PATCH] =?UTF-8?q?Enhance=20ScoValueError=20messages=20(li=C3=A9?=
 =?UTF-8?q?=20=C3=A0=2087aaf12d27)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/but/bulletin_but_court.py    |  4 +++-
 app/comp/res_classic.py          |  3 ++-
 app/comp/res_common.py           |  3 ++-
 app/scodoc/sco_bulletins_pdf.py  |  3 ++-
 app/scodoc/sco_dump_db.py        | 10 +++++-----
 app/scodoc/sco_edit_formation.py |  1 +
 app/scodoc/sco_exceptions.py     |  8 ++++++--
 app/scodoc/sco_synchro_etuds.py  |  3 ++-
 app/templates/sco_value_error.j2 | 12 ++++++++----
 app/views/notes.py               | 10 +++++-----
 10 files changed, 36 insertions(+), 21 deletions(-)

diff --git a/app/but/bulletin_but_court.py b/app/but/bulletin_but_court.py
index a4fc6ec13..41f989a11 100644
--- a/app/but/bulletin_but_court.py
+++ b/app/but/bulletin_but_court.py
@@ -124,7 +124,9 @@ def _build_bulletin_but_infos(
         formsemestre, bulletins_sem.res
     )
     if warn_html:
-        raise ScoValueError("<b>Formation mal configurée pour le BUT</b>" + warn_html)
+        raise ScoValueError(
+            "<b>Formation mal configurée pour le BUT</b>" + warn_html, safe=True
+        )
     ue_validation_by_niveau = validations_view.get_ue_validation_by_niveau(
         refcomp, etud
     )
diff --git a/app/comp/res_classic.py b/app/comp/res_classic.py
index 113faa0b2..59f3790e4 100644
--- a/app/comp/res_classic.py
+++ b/app/comp/res_classic.py
@@ -242,7 +242,8 @@ class ResultatsSemestreClassic(NotesTableCompat):
             )
             }">saisir le coefficient de cette UE avant de continuer</a></p>
             </div>
-            """
+            """,
+            safe=True,
         )
 
 
diff --git a/app/comp/res_common.py b/app/comp/res_common.py
index 9915c6162..267f5e7fa 100644
--- a/app/comp/res_common.py
+++ b/app/comp/res_common.py
@@ -518,7 +518,8 @@ class ResultatsSemestre(ResultatsCache):
                     Corrigez ou faite corriger le programme
                     <a href="{url_for('notes.ue_table', scodoc_dept=g.scodoc_dept,
                     formation_id=ue_capitalized.formation_id)}">via cette page</a>.
-                    """
+                    """,
+                        safe=True,
                     )
             else:
                 # Coefs de l'UE capitalisée en formation classique:
diff --git a/app/scodoc/sco_bulletins_pdf.py b/app/scodoc/sco_bulletins_pdf.py
index 80cee3a4d..dddd4430e 100644
--- a/app/scodoc/sco_bulletins_pdf.py
+++ b/app/scodoc/sco_bulletins_pdf.py
@@ -122,7 +122,8 @@ def replacement_function(match) -> str:
         return r'<img %s src="%s"%s/>' % (match.group(2), logo.filepath, match.group(4))
     raise ScoValueError(
         'balise "%s": logo "%s" introuvable'
-        % (pydoc.html.escape(balise), pydoc.html.escape(name))
+        % (pydoc.html.escape(balise), pydoc.html.escape(name)),
+        safe=True,
     )
 
 
diff --git a/app/scodoc/sco_dump_db.py b/app/scodoc/sco_dump_db.py
index a74fab8d3..1bef54391 100644
--- a/app/scodoc/sco_dump_db.py
+++ b/app/scodoc/sco_dump_db.py
@@ -216,11 +216,11 @@ def _drop_ano_db(ano_db_name):
         log("_drop_ano_db: no temp db, nothing to drop")
         return
     cmd = ["dropdb", ano_db_name]
-    log("sco_dump_and_send_db: {}".format(cmd))
+    log(f"sco_dump_and_send_db: {cmd}")
     try:
         _ = subprocess.check_output(cmd)
-    except subprocess.CalledProcessError as e:
-        log("sco_dump_and_send_db: exception dropdb {}".format(e))
+    except subprocess.CalledProcessError as exc:
+        log(f"sco_dump_and_send_db: exception dropdb {exc}")
         raise ScoValueError(
-            "erreur lors de la suppression de la base {}".format(ano_db_name)
-        )
+            f"erreur lors de la suppression de la base {ano_db_name}"
+        ) from exc
diff --git a/app/scodoc/sco_edit_formation.py b/app/scodoc/sco_edit_formation.py
index 1a951e996..6def9f0fa 100644
--- a/app/scodoc/sco_edit_formation.py
+++ b/app/scodoc/sco_edit_formation.py
@@ -326,6 +326,7 @@ def do_formation_create(args: dict) -> Formation:
                 scodoc_dept=g.scodoc_dept,
                 formation_id=formation.id,
             ),
+            safe=True,
         ) from exc
 
     ScolarNews.add(
diff --git a/app/scodoc/sco_exceptions.py b/app/scodoc/sco_exceptions.py
index aa2d04d0e..2e61608c3 100644
--- a/app/scodoc/sco_exceptions.py
+++ b/app/scodoc/sco_exceptions.py
@@ -45,13 +45,17 @@ class ScoInvalidCSRF(ScoException):
 
 
 class ScoValueError(ScoException):
-    "Exception avec page d'erreur utilisateur, et qui stoque dest_url"
+    """Exception avec page d'erreur utilisateur
+    - dest_url : url où aller après la page d'erreur
+    - safe (default False): si vrai, affiche le message non html quoté.
+    """
 
     # mal nommée: super classe de toutes les exceptions avec page
     # d'erreur gentille.
-    def __init__(self, msg, dest_url=None):
+    def __init__(self, msg, dest_url=None, safe=False):
         super().__init__(msg)
         self.dest_url = dest_url
+        self.safe = safe  # utilisé par template sco_value_error.j2
 
 
 class ScoPermissionDenied(ScoValueError):
diff --git a/app/scodoc/sco_synchro_etuds.py b/app/scodoc/sco_synchro_etuds.py
index 3f5008e3e..19c64367d 100644
--- a/app/scodoc/sco_synchro_etuds.py
+++ b/app/scodoc/sco_synchro_etuds.py
@@ -115,7 +115,8 @@ def formsemestre_synchro_etuds(
             url_for('notes.formsemestre_editwithmodules',
                 scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id)
         }">Modifier ce semestre</a>)
-        """
+        """,
+            safe=True,
         )
     footer = html_sco_header.sco_footer()
     base_url = url_for(
diff --git a/app/templates/sco_value_error.j2 b/app/templates/sco_value_error.j2
index 6fa329c7b..2a488c933 100644
--- a/app/templates/sco_value_error.j2
+++ b/app/templates/sco_value_error.j2
@@ -5,15 +5,19 @@
 
 <h2>Erreur !</h2>
 
-{{ exc }}
+{% if exc.safe %}
+    {{ exc | safe }}
+{% else %}
+    {{ exc }}
+{% endif %}
 
 <div style="margin-top: 16px;">
     {% if g.scodoc_dept %}
-    <a href="{{ exc.dest_url or url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}">continuer</a>
+    <a class="stdlink" href="{{ exc.dest_url or url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}">continuer</a>
     {% elif exc.dest_url %}
-        <a href="{{ exc.dest_url or url_for('scodoc.index') }}">continuer</a>
+        <a class="stdlink" href="{{ exc.dest_url or url_for('scodoc.index') }}">continuer</a>
     {% else %}
-        <a href="{{ exc.dest_url or url_for('scodoc.index') }}">retour page d'accueil</a>
+        <a class="stdlink" href="{{ exc.dest_url or url_for('scodoc.index') }}">retour page d'accueil</a>
     {% endif %}
 </div>
 
diff --git a/app/views/notes.py b/app/views/notes.py
index 1add286a9..51a74b3e7 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -1436,14 +1436,14 @@ def formsemestre_desinscription(etudid, formsemestre_id, dialog_confirmed=False)
     if nt.etud_has_decision(etudid):
         raise ScoValueError(
             f"""Désinscription impossible: l'étudiant a une décision de jury
-            (la supprimer avant si nécessaire:
-            <a href="{
+            (la supprimer avant si nécessaire avec
+            <a class="stdlink" href="{
                 url_for("notes.formsemestre_validation_suppress_etud",
                 scodoc_dept=g.scodoc_dept, etudid=etudid,
                 formsemestre_id=formsemestre_id)
-            }">supprimer décision jury</a>
-            )
-            """
+            }">supprimer décision jury</a>)
+            """,
+            safe=True,
         )
     if not dialog_confirmed:
         etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
-- 
GitLab