From 34fe649d515265e191f35d1594b430e9c09bb0bb Mon Sep 17 00:00:00 2001
From: Emmanuel Viennet <emmanuel.viennet@gmail.com>
Date: Mon, 8 Jul 2024 23:13:45 +0200
Subject: [PATCH] Log etud: code & check

---
 app/api/jury.py                             |  3 +-
 app/api/justificatifs.py                    |  8 ++-
 app/models/events.py                        | 22 ++++++-
 app/scodoc/sco_cursus_dut.py                | 29 ++++-----
 app/scodoc/sco_debouche.py                  |  9 ++-
 app/scodoc/sco_etud.py                      | 19 +-----
 app/scodoc/sco_formsemestre_inscriptions.py | 11 ++--
 app/scodoc/sco_formsemestre_validation.py   | 10 ++-
 app/scodoc/sco_groups.py                    |  6 +-
 app/scodoc/sco_moduleimpl.py                |  7 +--
 app/scodoc/sco_moduleimpl_inscriptions.py   |  7 +--
 app/scodoc/sco_page_etud.py                 |  2 +-
 app/scodoc/sco_photos.py                    |  7 +--
 app/scodoc/scolog.py                        | 68 ---------------------
 app/views/notes.py                          |  8 ++-
 app/views/scolar.py                         | 41 ++++++-------
 16 files changed, 91 insertions(+), 166 deletions(-)
 delete mode 100644 app/scodoc/scolog.py

diff --git a/app/api/jury.py b/app/api/jury.py
index e2e29b7d6..4fce0bfa0 100644
--- a/app/api/jury.py
+++ b/app/api/jury.py
@@ -290,13 +290,12 @@ def validation_rcue_record(etudid: int):
     db.session.add(validation)
     # invalider bulletins (les autres résultats ne dépendent pas des RCUEs):
     sco_cache.invalidate_formsemestre_etud(etud)
-    db.session.commit()
     Scolog.logdb(
         method="validation_rcue_record",
         etudid=etudid,
         msg=f"Enregistrement {validation}",
-        commit=True,
     )
+    db.session.commit()
     log(f"{operation} {validation}")
     return validation.to_dict()
 
diff --git a/app/api/justificatifs.py b/app/api/justificatifs.py
index 28063d059..79c05d8ef 100644
--- a/app/api/justificatifs.py
+++ b/app/api/justificatifs.py
@@ -533,13 +533,12 @@ def justif_edit(justif_id: int):
     # Mise à jour du justificatif
     justificatif_unique.dejustifier_assiduites()
     db.session.add(justificatif_unique)
-    db.session.commit()
-
     Scolog.logdb(
         method="edit_justificatif",
         etudid=justificatif_unique.etudiant.id,
         msg=f"justificatif modif: {justificatif_unique}",
     )
+    db.session.commit()
 
     # Génération du dictionnaire de retour
     # La couverture correspond
@@ -627,6 +626,11 @@ def _delete_one(justif_id: int) -> tuple[int, str]:
     scass.simple_invalidate_cache(justificatif_unique.to_dict())
     # On actualise les assiduités justifiées de l'étudiant concerné
     justificatif_unique.dejustifier_assiduites()
+    Scolog.logdb(
+        method="justificatif/delete",
+        etudid=justificatif_unique.etudiant.id,
+        msg="suppression justificatif",
+    )
     # On supprime le justificatif
     db.session.delete(justificatif_unique)
 
diff --git a/app/models/events.py b/app/models/events.py
index 659bf2600..3e6c2bf7a 100644
--- a/app/models/events.py
+++ b/app/models/events.py
@@ -12,12 +12,12 @@ from app import db
 from app import email
 from app import log
 from app.auth.models import User
-from app.models import SHORT_STR_LEN
+from app.models import ScoDocModel, SHORT_STR_LEN
 import app.scodoc.sco_utils as scu
 from app.scodoc import sco_preferences
 
 
-class Scolog(db.Model):
+class Scolog(ScoDocModel):
     """Log des actions (journal modif etudiants)"""
 
     __tablename__ = "scolog"
@@ -34,7 +34,8 @@ class Scolog(db.Model):
     def logdb(
         cls, method: str = None, etudid: int = None, msg: str = None, commit=False
     ):
-        """Add entry in student's log (replacement for old scolog.logdb)"""
+        """Add entry in student's log (replacement for old scolog.logdb).
+        Par défaut ne commite pas."""
         entry = Scolog(
             method=method,
             msg=msg,
@@ -45,6 +46,21 @@ class Scolog(db.Model):
         if commit:
             db.session.commit()
 
+    def to_dict(self, convert_date=False) -> dict:
+        "convert to dict"
+        return {
+            "etudid": self.etudid,
+            "date": (
+                (self.date.strftime(scu.DATETIME_FMT) if convert_date else self.date)
+                if self.date
+                else ""
+            ),
+            "_date_order": self.date.isoformat() if self.date else "",
+            "authenticated_user": self.authenticated_user or "",
+            "msg": self.msg or "",
+            "method": self.method or "",
+        }
+
 
 class ScolarNews(db.Model):
     """Nouvelles pour page d'accueil"""
diff --git a/app/scodoc/sco_cursus_dut.py b/app/scodoc/sco_cursus_dut.py
index 7cb14eb1c..06c64b214 100644
--- a/app/scodoc/sco_cursus_dut.py
+++ b/app/scodoc/sco_cursus_dut.py
@@ -31,13 +31,18 @@
 from app import db
 from app.comp import res_sem
 from app.comp.res_compat import NotesTableCompat
-from app.models import FormSemestre, Identite, ScolarAutorisationInscription, UniteEns
+from app.models import (
+    FormSemestre,
+    Identite,
+    ScolarAutorisationInscription,
+    Scolog,
+    UniteEns,
+)
 
 import app.scodoc.sco_utils as scu
 import app.scodoc.notesdb as ndb
 from app import log
-from app.scodoc.scolog import logdb
-from app.scodoc import sco_cache, sco_etud
+from app.scodoc import sco_cache
 from app.scodoc import sco_formsemestre
 from app.scodoc.codes_cursus import (
     CMP,
@@ -586,13 +591,11 @@ class SituationEtudCursusClassic(SituationEtudCursus):
                 decision.assiduite,
                 decision.formsemestre_id_utilise_pour_compenser,
             )
-        logdb(
-            cnx,
+        Scolog.logdb(
             method="validate_sem",
             etudid=self.etudid,
             commit=False,
-            msg="formsemestre_id=%s code=%s"
-            % (self.formsemestre_id, decision.code_etat),
+            msg=f"formsemestre_id={self.formsemestre_id} code={decision.code_etat}",
         )
         # -- decisions UEs
         formsemestre_validate_ues(
@@ -616,13 +619,11 @@ class SituationEtudCursusClassic(SituationEtudCursus):
                 assidu=True,
                 formsemestre_id_utilise_pour_compenser=fsid,
             )
-            logdb(
-                cnx,
+            Scolog.logdb(
                 method="validate_sem",
                 etudid=self.etudid,
                 commit=False,
-                msg="formsemestre_id=%s code=%s"
-                % (self.prev_formsemestre.id, decision.new_code_prev),
+                msg=f"formsemestre_id={self.prev_formsemestre.id} code={decision.new_code_prev}",
             )
             # modifs des codes d'UE (pourraient passer de ADM a CMP, meme sans modif des notes)
             formsemestre_validate_ues(
@@ -937,13 +938,13 @@ def formsemestre_validate_ues(formsemestre_id, etudid, code_etat_sem, assiduite)
                 cnx, nt, formsemestre_id, etudid, ue_id, code_ue
             )
 
-        logdb(
-            cnx,
+        Scolog.logdb(
             method="validate_ue",
             etudid=etudid,
-            msg="ue_id=%s code=%s" % (ue_id, code_ue),
+            msg=f"ue_id={ue_id} code={code_ue}",
             commit=False,
         )
+    db.session.commit()
     cnx.commit()
 
 
diff --git a/app/scodoc/sco_debouche.py b/app/scodoc/sco_debouche.py
index 8c0eb2875..18b62e899 100644
--- a/app/scodoc/sco_debouche.py
+++ b/app/scodoc/sco_debouche.py
@@ -34,11 +34,10 @@ from flask import url_for, g, request
 from app import log
 from app.comp import res_sem
 from app.comp.res_compat import NotesTableCompat
-from app.models import FormSemestre
+from app.models import FormSemestre, Scolog
 import app.scodoc.sco_utils as scu
 import app.scodoc.notesdb as ndb
 from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
-from app.scodoc.scolog import logdb
 from app.scodoc.gen_tables import GenTable
 from app.scodoc import safehtml
 from app.scodoc import html_sco_header
@@ -291,8 +290,8 @@ def itemsuivi_suppress(itemsuivi_id):
     item = itemsuivi_get(cnx, itemsuivi_id, ignore_errors=True)
     if item:
         _itemsuivi_delete(cnx, itemsuivi_id)
-        logdb(cnx, method="itemsuivi_suppress", etudid=item["etudid"])
-        log("suppressed itemsuivi %s" % (itemsuivi_id,))
+        Scolog.logdb(method="itemsuivi_suppress", etudid=item["etudid"], commit=True)
+        log(f"suppressed itemsuivi {itemsuivi_id}")
     return ("", 204)
 
 
@@ -304,7 +303,7 @@ def itemsuivi_create(etudid, item_date=None, situation="", fmt=None):
     itemsuivi_id = _itemsuivi_create(
         cnx, args={"etudid": etudid, "item_date": item_date, "situation": situation}
     )
-    logdb(cnx, method="itemsuivi_create", etudid=etudid)
+    Scolog.logdb(method="itemsuivi_create", etudid=etudid, commit=True)
     log("created itemsuivi %s for %s" % (itemsuivi_id, etudid))
     item = itemsuivi_get(cnx, itemsuivi_id)
     if fmt == "json":
diff --git a/app/scodoc/sco_etud.py b/app/scodoc/sco_etud.py
index 5ad690687..fde983703 100644
--- a/app/scodoc/sco_etud.py
+++ b/app/scodoc/sco_etud.py
@@ -37,7 +37,7 @@ from flask import url_for, g
 
 from app import db, email
 from app import log
-from app.models import Admission, Identite
+from app.models import Admission, Identite, Scolog
 from app.models.etudiants import (
     check_etud_duplicate_code,
     input_civilite,
@@ -53,10 +53,9 @@ from app.scodoc.sco_utils import (
     format_prenom,
 )
 import app.scodoc.notesdb as ndb
-from app.scodoc.sco_exceptions import ScoGenError, ScoValueError
+from app.scodoc.sco_exceptions import ScoValueError
 from app.scodoc import safehtml
 from app.scodoc import sco_preferences
-from app.scodoc.scolog import logdb
 
 
 def format_etud_ident(etud: dict):
@@ -511,8 +510,7 @@ def create_etud(cnx, args: dict = None):
     etudid = etud.id
 
     # log
-    logdb(
-        cnx,
+    Scolog.logdb(
         method="etudident_edit_form",
         etudid=etudid,
         msg="creation initiale",
@@ -681,17 +679,6 @@ o.close()
 """
 
 
-def list_scolog(etudid):
-    "liste des operations effectuees sur cet etudiant"
-    cnx = ndb.GetDBConnexion()
-    cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
-    cursor.execute(
-        "SELECT * FROM scolog WHERE etudid=%(etudid)s ORDER BY DATE DESC",
-        {"etudid": etudid},
-    )
-    return cursor.dictfetchall()
-
-
 def fill_etuds_info(etuds: list[dict], add_admission=True):
     """etuds est une liste d'etudiants (mappings)
     Pour chaque etudiant, ajoute ou formatte les champs
diff --git a/app/scodoc/sco_formsemestre_inscriptions.py b/app/scodoc/sco_formsemestre_inscriptions.py
index 15995e11e..217a096e5 100644
--- a/app/scodoc/sco_formsemestre_inscriptions.py
+++ b/app/scodoc/sco_formsemestre_inscriptions.py
@@ -42,7 +42,6 @@ from app.models.groups import Partition, GroupDescr
 from app.models.scolar_event import ScolarEvent
 import app.scodoc.sco_utils as scu
 from app import log
-from app.scodoc.scolog import logdb
 from app.scodoc.sco_exceptions import ScoValueError
 from app.scodoc.codes_cursus import UE_STANDARD, UE_SPORT, UE_TYPE_NAME
 import app.scodoc.notesdb as ndb
@@ -112,12 +111,11 @@ def do_formsemestre_inscription_create(args, method=None):
         },
     )
     # Log etudiant
-    logdb(
-        cnx,
+    Scolog.logdb(
         method=method,
         etudid=args["etudid"],
         msg=f"inscription en semestre {args['formsemestre_id']}",
-        commit=False,
+        commit=True,
     )
     #
     sco_cache.invalidate_formsemestre(formsemestre_id=args["formsemestre_id"])
@@ -265,12 +263,11 @@ def do_formsemestre_desinscription(
             db.session.commit()
             flash(f"Semestre extérieur supprimé: {formsemestre.titre_annee()}")
 
-    logdb(
-        cnx,
+    Scolog.logdb(
         method="formsemestre_desinscription",
         etudid=etudid,
         msg=f"desinscription semestre {formsemestre_id}",
-        commit=False,
+        commit=True,
     )
 
 
diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py
index 3b3fa3b54..1598abc55 100644
--- a/app/scodoc/sco_formsemestre_validation.py
+++ b/app/scodoc/sco_formsemestre_validation.py
@@ -41,7 +41,7 @@ from app import db, log
 
 from app.comp import res_sem
 from app.comp.res_compat import NotesTableCompat
-from app.models import Formation, FormSemestre, UniteEns, ScolarNews
+from app.models import Formation, FormSemestre, UniteEns, ScolarNews, Scolog
 from app.models.notes import etud_has_notes_attente
 from app.models.validations import (
     ScolarAutorisationInscription,
@@ -49,7 +49,6 @@ from app.models.validations import (
 )
 from app.models.but_validations import ApcValidationRCUE, ApcValidationAnnee
 from app.scodoc.sco_exceptions import ScoValueError
-from app.scodoc.scolog import logdb
 from app.scodoc.codes_cursus import *
 from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
 
@@ -1077,7 +1076,7 @@ def do_formsemestre_validation_auto(formsemestre_id):
                     url_for('notes.formsemestre_validation_etud_form',
                     scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id,
                     etudid=etud.id, check=1)
-                }">{etud_d["nomprenom"]}</li>"""
+                }">{etud.nom_prenom()}</li>"""
             )
         H.append("</ul>")
     H.append(
@@ -1392,12 +1391,11 @@ def do_formsemestre_validate_previous_ue(
         is_external=True,
     )
 
-    logdb(
-        cnx,
+    Scolog.logdb(
         method="formsemestre_validate_previous_ue",
         etudid=etudid,
         msg=f"Validation UE prec. {ue_id} {ue.acronyme}: {code}",
-        commit=False,
+        commit=True,
     )
     _invalidate_etud_formation_caches(etudid, formsemestre.formation_id)
     cnx.commit()
diff --git a/app/scodoc/sco_groups.py b/app/scodoc/sco_groups.py
index 8609c6234..6faf1cea7 100644
--- a/app/scodoc/sco_groups.py
+++ b/app/scodoc/sco_groups.py
@@ -44,9 +44,7 @@ from app.comp.res_compat import NotesTableCompat
 from app.models import FormSemestre, Identite, Scolog
 from app.models import SHORT_STR_LEN
 from app.models.groups import GroupDescr, Partition
-import app.scodoc.sco_utils as scu
 import app.scodoc.notesdb as ndb
-from app.scodoc.scolog import logdb
 from app.scodoc import html_sco_header
 from app.scodoc import sco_cache
 from app.scodoc import codes_cursus
@@ -769,12 +767,12 @@ groupsToDelete={groupsToDelete}
                 {"etudid": etudid, "group_id": group_id},
                 cursor=cursor,
             )
-            logdb(
-                cnx,
+            Scolog.logdb(
                 method="removeFromGroup",
                 etudid=etudid,
                 msg=f"""formsemestre_id={partition.formsemestre.id},partition_name={
                     partition.partition_name}, group_name={group.group_name}""",
+                commit=True,
             )
 
     # Supprime les groupes indiqués comme supprimés:
diff --git a/app/scodoc/sco_moduleimpl.py b/app/scodoc/sco_moduleimpl.py
index 86c4dfe97..c315477c8 100644
--- a/app/scodoc/sco_moduleimpl.py
+++ b/app/scodoc/sco_moduleimpl.py
@@ -30,7 +30,7 @@
 
 import psycopg2
 
-from app.scodoc import scolog
+from app.models import Scolog
 from app.scodoc import sco_cache
 import app.scodoc.notesdb as ndb
 from app.scodoc.sco_exceptions import ScoValueError
@@ -182,12 +182,11 @@ def do_moduleimpl_inscription_create(args, formsemestre_id=None, cnx=None):
     sco_cache.invalidate_formsemestre(
         formsemestre_id=formsemestre_id
     )  # > moduleimpl_inscription
-    scolog.logdb(
-        cnx,
+    Scolog.logdb(
         method="moduleimpl_inscription",
         etudid=args["etudid"],
         msg=f"inscription module {args['moduleimpl_id']}",
-        commit=False,
+        commit=True,
     )
     return r
 
diff --git a/app/scodoc/sco_moduleimpl_inscriptions.py b/app/scodoc/sco_moduleimpl_inscriptions.py
index 7b5eaa2e1..2e5968b69 100644
--- a/app/scodoc/sco_moduleimpl_inscriptions.py
+++ b/app/scodoc/sco_moduleimpl_inscriptions.py
@@ -44,8 +44,8 @@ from app.models import (
     Partition,
     ScolarFormSemestreValidation,
     UniteEns,
+    Scolog,
 )
-from app.scodoc.scolog import logdb
 from app.scodoc import html_sco_header
 from app.scodoc import htmlutils
 from app.scodoc import sco_cache
@@ -774,12 +774,11 @@ def do_etud_desinscrit_ue_classic(etudid, formsemestre_id, ue_id):
     """,
         {"etudid": etudid, "formsemestre_id": formsemestre_id, "ue_id": ue_id},
     )
-    logdb(
-        cnx,
+    Scolog.logdb(
         method="etud_desinscrit_ue",
         etudid=etudid,
         msg=f"desinscription UE {ue_id}",
-        commit=False,
+        commit=True,
     )
     sco_cache.invalidate_formsemestre(
         formsemestre_id=formsemestre_id
diff --git a/app/scodoc/sco_page_etud.py b/app/scodoc/sco_page_etud.py
index 0177cf483..a04c845d8 100644
--- a/app/scodoc/sco_page_etud.py
+++ b/app/scodoc/sco_page_etud.py
@@ -800,7 +800,7 @@ def menus_etud(etudid):
         },
         {
             "title": "Voir le journal...",
-            "endpoint": "scolar.showEtudLog",
+            "endpoint": "scolar.show_etud_log",
             "args": {"etudid": etud["etudid"]},
             "enabled": True,
         },
diff --git a/app/scodoc/sco_photos.py b/app/scodoc/sco_photos.py
index 35b2ea128..0e69214be 100755
--- a/app/scodoc/sco_photos.py
+++ b/app/scodoc/sco_photos.py
@@ -64,8 +64,6 @@ from app.scodoc import sco_etud
 from app.scodoc import sco_portal_apogee
 from app.scodoc import sco_preferences
 from app.scodoc.sco_exceptions import ScoValueError
-from app.scodoc.scolog import logdb
-import app.scodoc.notesdb as ndb
 import app.scodoc.sco_utils as scu
 from config import Config
 
@@ -304,10 +302,9 @@ def suppress_photo(etud: Identite) -> None:
         for filename in filenames:
             log(f"removing file {filename}")
             os.remove(filename)
-    db.session.commit()
     # 3- log
-    cnx = ndb.GetDBConnexion()
-    logdb(cnx, method="changePhoto", msg="suppression", etudid=etud.id)
+    Scolog.logdb(method="changePhoto", msg="suppression", etudid=etud.id)
+    db.session.commit()
 
 
 # ---------------------------------------------------------------------------
diff --git a/app/scodoc/scolog.py b/app/scodoc/scolog.py
deleted file mode 100644
index f972d3b4b..000000000
--- a/app/scodoc/scolog.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# -*- mode: python -*-
-# -*- coding: utf-8 -*-
-
-##############################################################################
-#
-# Gestion scolarite IUT
-#
-# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#
-#   Emmanuel Viennet      emmanuel.viennet@viennet.net
-#
-##############################################################################
-
-"""Logging des opérations en base de données
-"""
-
-from flask import request
-from flask_login import current_user
-import app.scodoc.notesdb as ndb
-
-
-def logdb(cnx=None, method=None, etudid=None, msg=None, commit=True):
-    "Add entry"
-    if not cnx:
-        raise ValueError("logdb: cnx is None")
-
-    args = {
-        "authenticated_user": current_user.user_name,
-    }
-
-    args.update({"method": method, "etudid": etudid, "msg": msg})
-    ndb.quote_dict(args)
-    cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
-    cursor.execute(
-        """INSERT INTO scolog
-        (authenticated_user,method,etudid,msg)
-        VALUES
-        (%(authenticated_user)s,%(method)s,%(etudid)s,%(msg)s)""",
-        args,
-    )
-    if commit:
-        cnx.commit()
-
-
-def loglist(cnx, method=None, authenticated_user=None):
-    """List of events logged for these method and user"""
-    cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
-    cursor.execute(
-        """SELECT * FROM scolog
-        WHERE method=%(method)s
-        AND authenticated_user=%(authenticated_user)s""",
-        {"method": method, "authenticated_user": authenticated_user},
-    )
-    return cursor.dictfetchall()
diff --git a/app/views/notes.py b/app/views/notes.py
index 9157af762..482b6c48f 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -2909,7 +2909,7 @@ def formsemestre_saisie_jury(formsemestre_id: int, selected_etudid: int = None):
 @scodoc
 @permission_required(Permission.ScoView)
 def formsemestre_jury_erase(formsemestre_id: int, etudid: int = None):
-    """Supprime la décision de jury (classique ou BUT) pour cette année.
+    """Supprime toutes les décisions de jury (classique ou BUT) pour cette année.
     Si l'étudiant n'est pas spécifié, efface les décisions de tous les inscrits.
     En BUT, si only_one_sem n'efface que pour le formsemestre indiqué, pas les deux de l'année.
     En classique, n'affecte que les décisions issues de ce formsemestre.
@@ -2992,8 +2992,10 @@ def formsemestre_jury_erase(formsemestre_id: int, etudid: int = None):
         """
             + """
         <p>Efface aussi toutes les validations concernant l'année BUT de ce semestre,
-        même si elles ont été acquises ailleurs.
-        </p>"""
+        même si elles ont été acquises ailleurs, ainsi que les validations de DUT en 120 ECTS
+        obtenues après BUT1/BUT2.
+        </p>
+        """
             if is_apc
             else ""
             + """
diff --git a/app/views/scolar.py b/app/views/scolar.py
index 8355fcef5..161ac4863 100644
--- a/app/views/scolar.py
+++ b/app/views/scolar.py
@@ -70,7 +70,6 @@ from app.views import ScoData
 
 import app.scodoc.sco_utils as scu
 import app.scodoc.notesdb as ndb
-from app.scodoc.scolog import logdb
 from app.scodoc.sco_permissions import Permission
 from app.scodoc.sco_exceptions import (
     AccessDenied,
@@ -78,7 +77,7 @@ from app.scodoc.sco_exceptions import (
     ScoValueError,
 )
 
-from app.scodoc.TrivialFormulator import DMY_REGEXP, TrivialFormulator, tf_error_message
+from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
 from app.scodoc.gen_tables import GenTable
 from app.scodoc import (
     codes_cursus,
@@ -302,39 +301,37 @@ class DeptLogosConfigurationForm(FlaskForm):
 # --------------------------------------------------------------------
 
 
-@bp.route("/showEtudLog")
+@bp.route("/show_etud_log")
 @scodoc
 @permission_required(Permission.ScoView)
 @scodoc7func
-def showEtudLog(etudid, fmt="html"):
+def show_etud_log(etudid, fmt="html"):
     """Display log of operations on this student"""
-    etud = sco_etud.get_etud_info(filled=True)[0]
-
-    ops = sco_etud.list_scolog(etudid)
+    etud = Identite.get_etud(etudid)
 
+    operations = Scolog.query.filter_by(etudid=etud.id).order_by(Scolog.date.desc())
     tab = GenTable(
         titles={
             "date": "Date",
             "authenticated_user": "Utilisateur",
-            "remote_addr": "IP",
             "method": "Opération",
             "msg": "Message",
         },
-        columns_ids=("date", "authenticated_user", "remote_addr", "method", "msg"),
-        rows=ops,
+        columns_ids=("date", "authenticated_user", "method", "msg"),
+        rows=[op.to_dict(convert_date=True) for op in operations],
         html_sortable=True,
         html_class="table_leftalign",
-        base_url="%s?etudid=%s" % (request.base_url, etudid),
-        page_title="Opérations sur %(nomprenom)s" % etud,
-        html_title="<h2>Opérations effectuées sur l'étudiant %(nomprenom)s</h2>" % etud,
-        filename="log_" + scu.make_filename(etud["nomprenom"]),
+        base_url="%s?etudid=%s" % (request.base_url, etud.id),
+        page_title=f"Opérations sur {etud.nom_prenom()}",
+        html_title=f"""<h2>Opérations effectuées sur l'étudiant{etud.e} {
+                etud.html_link_fiche()}</h2>""",
+        filename="log_" + scu.make_filename(etud.nom_prenom()),
         html_next_section=f"""
-        <ul><li>
-        <a href="{url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid)}">
-        fiche de {etud['nomprenom']}</a></li>
+        <ul>
+            <li>Fiche de {etud.html_link_fiche()}</li>
         </ul>""",
         preferences=sco_preferences.SemPreferences(),
-        table_id="showEtudLog",
+        table_id="show_etud_log",
     )
 
     return tab.make_page(fmt=fmt)
@@ -738,7 +735,7 @@ def doAddAnnotation(etudid, comment):
                 "author": current_user.user_name,
             },
         )
-        logdb(cnx, method="addAnnotation", etudid=etudid)
+        Scolog.logdb(method="addAnnotation", etudid=etudid, commit=True)
     return flask.redirect(
         url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid)
     )
@@ -758,8 +755,8 @@ def doSuppressAnnotation(etudid, annotation_id):
     if len(annos) != 1:
         raise ScoValueError("annotation inexistante !")
     anno = annos[0]
-    log("suppress annotation: %s" % str(anno))
-    logdb(cnx, method="SuppressAnnotation", etudid=etudid)
+    log(f"suppress annotation: {anno}")
+    Scolog.logdb(method="SuppressAnnotation", etudid=etudid)
     sco_etud.etud_annotations_delete(cnx, annotation_id)
 
     flash("Annotation supprimée")
@@ -842,7 +839,7 @@ def form_change_coordonnees(etudid):
             sco_etud.adresse_edit(cnx, args=tf[2])
         else:
             sco_etud.adresse_create(cnx, args=tf[2])
-        logdb(cnx, method="changeCoordonnees", etudid=etudid)
+        Scolog.logdb(method="changeCoordonnees", etudid=etudid, commit=True)
         return flask.redirect(dest_url)
 
 
-- 
GitLab