From af1e46ba82c886f1cb7aa8dbc7cd4582f1d28af3 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 29 May 2023 16:04:41 +0200 Subject: [PATCH] Nettoyage code + exception save note --- app/comp/res_but.py | 4 +- app/comp/res_compat.py | 4 +- app/models/evaluations.py | 12 ++ app/scodoc/sco_evaluation_db.py | 5 +- app/scodoc/sco_excel.py | 10 +- app/scodoc/sco_saisie_notes.py | 240 +++++++++++++++----------------- 6 files changed, 135 insertions(+), 140 deletions(-) diff --git a/app/comp/res_but.py b/app/comp/res_but.py index a7af9565..7e866a56 100644 --- a/app/comp/res_but.py +++ b/app/comp/res_but.py @@ -306,12 +306,12 @@ class ResultatsSemestreBUT(NotesTableCompat): return ues_ids - def etud_has_decision(self, etudid): + def etud_has_decision(self, etudid) -> bool: """True s'il y a une décision de jury pour cet étudiant émanant de ce formsemestre. prend aussi en compte les autorisations de passage. Sous-classée en BUT pour les RCUEs et années. """ - return ( + return bool( super().etud_has_decision(etudid) or ApcValidationAnnee.query.filter_by( formsemestre_id=self.formsemestre.id, etudid=etudid diff --git a/app/comp/res_compat.py b/app/comp/res_compat.py index cbebb835..d5e85d99 100644 --- a/app/comp/res_compat.py +++ b/app/comp/res_compat.py @@ -283,12 +283,12 @@ class NotesTableCompat(ResultatsSemestre): ] return etudids - def etud_has_decision(self, etudid): + def etud_has_decision(self, etudid) -> bool: """True s'il y a une décision de jury pour cet étudiant émanant de ce formsemestre. prend aussi en compte les autorisations de passage. Sous-classée en BUT pour les RCUEs et années. """ - return ( + return bool( self.get_etud_decisions_ue(etudid) or self.get_etud_decision_sem(etudid) or ScolarAutorisationInscription.query.filter_by( diff --git a/app/models/evaluations.py b/app/models/evaluations.py index 3e3cd07c..fd777b1c 100644 --- a/app/models/evaluations.py +++ b/app/models/evaluations.py @@ -145,6 +145,18 @@ class Evaluation(db.Model): db.session.add(copy) return copy + def is_matin(self) -> bool: + "Evaluation ayant lieu le matin (faux si pas de date)" + heure_debut_dt = self.heure_debut or datetime.time(8, 00) + # 8:00 au cas ou pas d'heure (note externe?) + return bool(self.jour) and heure_debut_dt < datetime.time(12, 00) + + def is_apresmidi(self) -> bool: + "Evaluation ayant lieu l'après midi (faux si pas de date)" + heure_debut_dt = self.heure_debut or datetime.time(8, 00) + # 8:00 au cas ou pas d'heure (note externe?) + return bool(self.jour) and heure_debut_dt >= datetime.time(12, 00) + def set_default_poids(self) -> bool: """Initialize les poids bvers les UE à leurs valeurs par défaut C'est à dire à 1 si le coef. module/UE est non nul, 0 sinon. diff --git a/app/scodoc/sco_evaluation_db.py b/app/scodoc/sco_evaluation_db.py index b99af2cc..44ec6a76 100644 --- a/app/scodoc/sco_evaluation_db.py +++ b/app/scodoc/sco_evaluation_db.py @@ -255,9 +255,8 @@ def do_evaluation_get_all_notes( """Toutes les notes pour une evaluation: { etudid : { 'value' : value, 'date' : date ... }} Attention: inclut aussi les notes des étudiants qui ne sont plus inscrits au module. """ - do_cache = ( - filter_suppressed and table == "notes_notes" and (by_uid is None) - ) # pas de cache pour (rares) appels via undo_notes ou specifiant un enseignant + # pas de cache pour (rares) appels via undo_notes ou specifiant un enseignant + do_cache = filter_suppressed and table == "notes_notes" and (by_uid is None) if do_cache: r = sco_cache.EvaluationCache.get(evaluation_id) if r is not None: diff --git a/app/scodoc/sco_excel.py b/app/scodoc/sco_excel.py index 2f2c93b5..92295137 100644 --- a/app/scodoc/sco_excel.py +++ b/app/scodoc/sco_excel.py @@ -433,7 +433,7 @@ def excel_simple_table( return ws.generate() -def excel_feuille_saisie(e, titreannee, description, lines): +def excel_feuille_saisie(evaluation: "Evaluation", titreannee, description, lines): """Genere feuille excel pour saisie des notes. E: evaluation (dict) lines: liste de tuples @@ -512,18 +512,20 @@ def excel_feuille_saisie(e, titreannee, description, lines): # description evaluation ws.append_single_cell_row(scu.unescape_html(description), style_titres) ws.append_single_cell_row( - "Evaluation du %s (coef. %g)" % (e["jour"], e["coefficient"]), style + "Evaluation du %s (coef. %g)" + % (evaluation.jour or "sans date", evaluation.coefficient or 0.0), + style, ) # ligne blanche ws.append_blank_row() # code et titres colonnes ws.append_row( [ - ws.make_cell("!%s" % e["evaluation_id"], style_ro), + ws.make_cell("!%s" % evaluation.id, style_ro), ws.make_cell("Nom", style_titres), ws.make_cell("Prénom", style_titres), ws.make_cell("Groupe", style_titres), - ws.make_cell("Note sur %g" % e["note_max"], style_titres), + ws.make_cell("Note sur %g" % (evaluation.note_max or 0.0), style_titres), ws.make_cell("Remarque", style_titres), ] ) diff --git a/app/scodoc/sco_saisie_notes.py b/app/scodoc/sco_saisie_notes.py index 14a10380..f9f39bf3 100644 --- a/app/scodoc/sco_saisie_notes.py +++ b/app/scodoc/sco_saisie_notes.py @@ -40,7 +40,7 @@ from app.auth.models import User from app.comp import res_sem from app.comp.res_compat import NotesTableCompat from app.models import Evaluation, FormSemestre -from app.models import ModuleImpl, ScolarNews +from app.models import ModuleImpl, NotesNotes, ScolarNews from app.models.etudiants import Identite import app.scodoc.sco_utils as scu from app.scodoc.sco_utils import ModuleType @@ -50,7 +50,8 @@ from app.scodoc.sco_exceptions import ( AccessDenied, InvalidNoteValue, NoteProcessError, - ScoGenError, + ScoBugCatcher, + ScoException, ScoInvalidParamError, ScoValueError, ) @@ -63,7 +64,6 @@ from app.scodoc import sco_edit_module from app.scodoc import sco_evaluations from app.scodoc import sco_evaluation_db from app.scodoc import sco_excel -from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre_inscriptions from app.scodoc import sco_groups from app.scodoc import sco_groups_view @@ -526,9 +526,8 @@ def notes_add( - si la note existe deja avec valeur distincte, ajoute une entree au log (notes_notes_log) Return tuple (nb_changed, nb_suppress, existing_decisions) """ - now = psycopg2.Timestamp( - *time.localtime()[:6] - ) # datetime.datetime.now().isoformat() + now = psycopg2.Timestamp(*time.localtime()[:6]) + # Verifie inscription et valeur note inscrits = { x[0] @@ -550,11 +549,11 @@ def notes_add( cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) nb_changed = 0 nb_suppress = 0 - E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0] - M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0] - existing_decisions = ( - [] - ) # etudids pour lesquels il y a une decision de jury et que la note change + evaluation: Evaluation = Evaluation.query.get_or_404(evaluation_id) + formsemestre: FormSemestre = evaluation.moduleimpl.formsemestre + res: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) + # etudids pour lesquels il y a une decision de jury et que la note change: + etudids_with_existing_decision = [] try: for etudid, value in notes: changed = False @@ -571,20 +570,29 @@ def notes_add( "date": now, } ndb.quote_dict(aa) - cursor.execute( - """INSERT INTO notes_notes - (etudid, evaluation_id, value, comment, date, uid) - VALUES (%(etudid)s,%(evaluation_id)s,%(value)s,%(comment)s,%(date)s,%(uid)s) - """, - aa, - ) + try: + cursor.execute( + """INSERT INTO notes_notes + (etudid, evaluation_id, value, comment, date, uid) + VALUES (%(etudid)s,%(evaluation_id)s,%(value)s,%(comment)s,%(date)s,%(uid)s) + """, + aa, + ) + except psycopg2.errors.UniqueViolation as exc: + # XXX ne devrait pas arriver mais bug possible ici (non reproductible) + existing_note = NotesNotes.query.filter_by( + evaluation_id=evaluation_id, etudid=etudid + ).first() + raise ScoBugCatcher( + f"dup: existing={existing_note}" + ) from exc changed = True else: # il y a deja une note oldval = notes_db[etudid]["value"] if type(value) != type(oldval): changed = True - elif type(value) == float and ( + elif isinstance(value, float) and ( abs(value - oldval) > scu.NOTES_PRECISION ): changed = True @@ -646,26 +654,21 @@ def notes_add( nb_suppress += 1 if changed: nb_changed += 1 - if has_existing_decision(M, E, etudid): - existing_decisions.append(etudid) + if res.etud_has_decision(etudid): + etudids_with_existing_decision.append(etudid) except Exception as exc: log("*** exception in notes_add") if do_it: cnx.rollback() # abort # inval cache - sco_cache.invalidate_formsemestre( - formsemestre_id=M["formsemestre_id"] - ) # > modif notes (exception) + sco_cache.invalidate_formsemestre(formsemestre_id=formsemestre.id) sco_cache.EvaluationCache.delete(evaluation_id) - raise # XXX - raise ScoGenError("Erreur enregistrement note: merci de ré-essayer") from exc + raise ScoException from exc if do_it: cnx.commit() - sco_cache.invalidate_formsemestre( - formsemestre_id=M["formsemestre_id"] - ) # > modif notes + sco_cache.invalidate_formsemestre(formsemestre_id=formsemestre.id) sco_cache.EvaluationCache.delete(evaluation_id) - return nb_changed, nb_suppress, existing_decisions + return nb_changed, nb_suppress, etudids_with_existing_decision def saisie_notes_tableur(evaluation_id, group_ids=()): @@ -868,35 +871,35 @@ def saisie_notes_tableur(evaluation_id, group_ids=()): def feuille_saisie_notes(evaluation_id, group_ids=[]): """Document Excel pour saisie notes dans l'évaluation et les groupes indiqués""" - evals = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id}) - if not evals: + evaluation: Evaluation = Evaluation.query.get(evaluation_id) + if not evaluation: raise ScoValueError("invalid evaluation_id") - eval_dict = evals[0] - M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=eval_dict["moduleimpl_id"])[0] - formsemestre_id = M["formsemestre_id"] - Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0] - sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"]) - mod_responsable = sco_users.user_info(M["responsable_id"]) - if eval_dict["jour"]: - indication_date = ndb.DateDMYtoISO(eval_dict["jour"]) + modimpl = evaluation.moduleimpl + formsemestre = modimpl.formsemestre + mod_responsable = sco_users.user_info(modimpl.responsable_id) + if evaluation.jour: + indication_date = evaluation.jour.isoformat() else: - indication_date = scu.sanitize_filename(eval_dict["description"])[:12] - eval_name = "%s-%s" % (Mod["code"], indication_date) + indication_date = scu.sanitize_filename(evaluation.description or "")[:12] + eval_name = "%s-%s" % (evaluation.moduleimpl.module.code, indication_date) - if eval_dict["description"]: - evaltitre = "%s du %s" % (eval_dict["description"], eval_dict["jour"]) + if evaluation.description: + evaltitre = "%s du %s" % ( + evaluation.description, + evaluation.jour.strftime("%d/%m/%Y"), + ) else: - evaltitre = "évaluation du %s" % eval_dict["jour"] + evaltitre = "évaluation du %s" % evaluation.jour.strftime("%d/%m/%Y") description = "%s en %s (%s) resp. %s" % ( evaltitre, - Mod["abbrev"] or "", - Mod["code"] or "", + evaluation.moduleimpl.module.abbrev or "", + evaluation.moduleimpl.module.code, mod_responsable["prenomnom"], ) groups_infos = sco_groups_view.DisplayedGroupsInfos( group_ids=group_ids, - formsemestre_id=formsemestre_id, + formsemestre_id=formsemestre.id, select_all_when_unspecified=True, etat=None, ) @@ -919,15 +922,15 @@ def feuille_saisie_notes(evaluation_id, group_ids=[]): # une liste de liste de chaines: lignes de la feuille de calcul L = [] - etuds = _get_sorted_etuds(eval_dict, etudids, formsemestre_id) + etuds = _get_sorted_etuds(evaluation, etudids, formsemestre.id) for e in etuds: etudid = e["etudid"] - groups = sco_groups.get_etud_groups(etudid, formsemestre_id) + groups = sco_groups.get_etud_groups(etudid, formsemestre.id) grc = sco_groups.listgroups_abbrev(groups) L.append( [ - "%s" % etudid, + str(etudid), e["nom"].upper(), e["prenom"].lower().capitalize(), e["inscr"]["etat"], @@ -939,29 +942,9 @@ def feuille_saisie_notes(evaluation_id, group_ids=[]): filename = "notes_%s_%s" % (eval_name, gr_title_filename) xls = sco_excel.excel_feuille_saisie( - eval_dict, sem["titreannee"], description, lines=L + evaluation, formsemestre.titre_annee(), description, lines=L ) return scu.send_file(xls, filename, scu.XLSX_SUFFIX, mime=scu.XLSX_MIMETYPE) - # return sco_excel.send_excel_file(xls, filename) - - -def has_existing_decision(M, E, etudid): - """Verifie s'il y a une validation pour cet etudiant dans ce semestre ou UE - Si oui, return True - """ - formsemestre_id = M["formsemestre_id"] - formsemestre = FormSemestre.get_formsemestre(formsemestre_id) - nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) - if nt.get_etud_decision_sem(etudid): - return True - dec_ues = nt.get_etud_decisions_ue(etudid) - if dec_ues: - mod = sco_edit_module.module_list({"module_id": M["module_id"]})[0] - ue_id = mod["ue_id"] - if ue_id in dec_ues: - return True # decision pour l'UE a laquelle appartient cette evaluation - - return False # pas de decision de jury affectee par cette note # ----------------------------- @@ -973,20 +956,18 @@ def saisie_notes(evaluation_id: int, group_ids: list = None): if not isinstance(evaluation_id, int): raise ScoInvalidParamError() group_ids = [int(group_id) for group_id in (group_ids or [])] - evals = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id}) - if not evals: + evaluation: Evaluation = Evaluation.query.get(evaluation_id) + if evaluation is None: raise ScoValueError("évaluation inexistante") - E = evals[0] - M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[0] - formsemestre_id = M["formsemestre_id"] + modimpl = evaluation.moduleimpl moduleimpl_status_url = url_for( "notes.moduleimpl_status", scodoc_dept=g.scodoc_dept, - moduleimpl_id=E["moduleimpl_id"], + moduleimpl_id=evaluation.moduleimpl_id, ) # Check access # (admin, respformation, and responsable_id) - if not sco_permissions_check.can_edit_notes(current_user, E["moduleimpl_id"]): + if not sco_permissions_check.can_edit_notes(current_user, evaluation.moduleimpl_id): return f""" {html_sco_header.sco_header()}

Modification des notes impossible pour {current_user.user_name}

@@ -1001,16 +982,16 @@ def saisie_notes(evaluation_id: int, group_ids: list = None): # Informations sur les groupes à afficher: groups_infos = sco_groups_view.DisplayedGroupsInfos( group_ids=group_ids, - formsemestre_id=formsemestre_id, + formsemestre_id=modimpl.formsemestre_id, select_all_when_unspecified=True, etat=None, ) - if E["description"]: - page_title = 'Saisie "%s"' % E["description"] - else: - page_title = "Saisie des notes" - + page_title = ( + f'Saisie "{evaluation.description}"' + if evaluation.description + else "Saisie des notes" + ) # HTML page: H = [ html_sco_header.sco_header( @@ -1036,19 +1017,19 @@ def saisie_notes(evaluation_id: int, group_ids: list = None): "id": "menu_saisie_tableur", "endpoint": "notes.saisie_notes_tableur", "args": { - "evaluation_id": E["evaluation_id"], + "evaluation_id": evaluation.id, "group_ids": groups_infos.group_ids, }, }, { "title": "Voir toutes les notes du module", "endpoint": "notes.evaluation_listenotes", - "args": {"moduleimpl_id": E["moduleimpl_id"]}, + "args": {"moduleimpl_id": evaluation.moduleimpl_id}, }, { "title": "Effacer toutes les notes de cette évaluation", "endpoint": "notes.evaluation_suppress_alln", - "args": {"evaluation_id": E["evaluation_id"]}, + "args": {"evaluation_id": evaluation.id}, }, ], alone=True, @@ -1077,7 +1058,9 @@ def saisie_notes(evaluation_id: int, group_ids: list = None): ) # Le formulaire de saisie des notes: - form = _form_saisie_notes(E, M, groups_infos, destination=moduleimpl_status_url) + form = _form_saisie_notes( + evaluation, modimpl, groups_infos, destination=moduleimpl_status_url + ) if form is None: return flask.redirect(moduleimpl_status_url) H.append(form) @@ -1101,10 +1084,9 @@ def saisie_notes(evaluation_id: int, group_ids: list = None): return "\n".join(H) -def _get_sorted_etuds(eval_dict: dict, etudids: list, formsemestre_id: int): - notes_db = sco_evaluation_db.do_evaluation_get_all_notes( - eval_dict["evaluation_id"] - ) # Notes existantes +def _get_sorted_etuds(evaluation: Evaluation, etudids: list, formsemestre_id: int): + # Notes existantes + notes_db = sco_evaluation_db.do_evaluation_get_all_notes(evaluation.id) cnx = ndb.GetDBConnexion() etuds = [] for etudid in etudids: @@ -1123,17 +1105,17 @@ def _get_sorted_etuds(eval_dict: dict, etudids: list, formsemestre_id: int): e["groups"] = sco_groups.get_etud_groups(etudid, formsemestre_id) # Information sur absence (tenant compte de la demi-journée) - jour_iso = ndb.DateDMYtoISO(eval_dict["jour"]) + jour_iso = evaluation.jour.isoformat() if evaluation.jour else "" warn_abs_lst = [] - if eval_dict["matin"]: - nbabs = sco_abs.count_abs(etudid, jour_iso, jour_iso, matin=1) - nbabsjust = sco_abs.count_abs_just(etudid, jour_iso, jour_iso, matin=1) + if evaluation.is_matin(): + nbabs = sco_abs.count_abs(etudid, jour_iso, jour_iso, matin=True) + nbabsjust = sco_abs.count_abs_just(etudid, jour_iso, jour_iso, matin=True) if nbabs: if nbabsjust: warn_abs_lst.append("absent justifié le matin !") else: warn_abs_lst.append("absent le matin !") - if eval_dict["apresmidi"]: + if evaluation.is_apresmidi(): nbabs = sco_abs.count_abs(etudid, jour_iso, jour_iso, matin=0) nbabsjust = sco_abs.count_abs_just(etudid, jour_iso, jour_iso, matin=0) if nbabs: @@ -1169,35 +1151,38 @@ def _get_sorted_etuds(eval_dict: dict, etudids: list, formsemestre_id: int): return etuds -def _form_saisie_notes(E, M, groups_infos, destination=""): +def _form_saisie_notes( + evaluation: Evaluation, modimpl: ModuleImpl, groups_infos, destination="" +): """Formulaire HTML saisie des notes dans l'évaluation E du moduleimpl M pour les groupes indiqués. On charge tous les étudiants, ne seront montrés que ceux des groupes sélectionnés grace a un filtre en javascript. """ - evaluation_id = E["evaluation_id"] - formsemestre_id = M["formsemestre_id"] - + formsemestre_id = modimpl.formsemestre_id + formsemestre: FormSemestre = evaluation.moduleimpl.formsemestre + res: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) etudids = [ x[0] for x in sco_groups.do_evaluation_listeetuds_groups( - evaluation_id, getallstudents=True, include_demdef=True + evaluation.id, getallstudents=True, include_demdef=True ) ] if not etudids: return '
Aucun étudiant sélectionné !
' - # Decisions de jury existantes ? - decisions_jury = {etudid: has_existing_decision(M, E, etudid) for etudid in etudids} - # Nb de decisions de jury (pour les inscrits à l'évaluation): + # Décisions de jury existantes ? + decisions_jury = {etudid: res.etud_has_decision(etudid) for etudid in etudids} + + # Nb de décisions de jury (pour les inscrits à l'évaluation): nb_decisions = sum(decisions_jury.values()) - etuds = _get_sorted_etuds(E, etudids, formsemestre_id) + etuds = _get_sorted_etuds(evaluation, etudids, formsemestre_id) # Build form: descr = [ - ("evaluation_id", {"default": evaluation_id, "input_type": "hidden"}), + ("evaluation_id", {"default": evaluation.id, "input_type": "hidden"}), ("formsemestre_id", {"default": formsemestre_id, "input_type": "hidden"}), ( "group_ids", @@ -1207,7 +1192,7 @@ def _form_saisie_notes(E, M, groups_infos, destination=""): ("comment", {"size": 44, "title": "Commentaire", "return_focus_next": True}), ("changed", {"default": "0", "input_type": "hidden"}), # changed in JS ] - if M["module"]["module_type"] in ( + if modimpl.module.module_type in ( ModuleType.STANDARD, ModuleType.RESSOURCE, ModuleType.SAE, @@ -1220,11 +1205,11 @@ def _form_saisie_notes(E, M, groups_infos, destination=""): "title": "Notes ", "cssclass": "formnote_bareme", "readonly": True, - "default": " / %g" % E["note_max"], + "default": " / %g" % evaluation.note_max, }, ) ) - elif M["module"]["module_type"] == ModuleType.MALUS: + elif modimpl.module.module_type == ModuleType.MALUS: descr.append( ( "s3", @@ -1238,7 +1223,7 @@ def _form_saisie_notes(E, M, groups_infos, destination=""): ) ) else: - raise ValueError("invalid module type (%s)" % M["module"]["module_type"]) # bug + raise ValueError(f"invalid module type ({modimpl.module.module_type})") # bug initvalues = {} for e in etuds: @@ -1248,7 +1233,7 @@ def _form_saisie_notes(E, M, groups_infos, destination=""): if disabled: classdem = " etud_dem" etud_classes.append("etud_dem") - disabled_attr = 'disabled="%d"' % disabled + disabled_attr = f'disabled="{disabled}"' else: classdem = "" disabled_attr = "" @@ -1265,18 +1250,17 @@ def _form_saisie_notes(E, M, groups_infos, destination=""): ) # Historique des saisies de notes: - if not disabled: - explanation = ( - '' % etudid - + get_note_history_menu(evaluation_id, etudid) - + "" - ) - else: - explanation = "" + explanation = ( + "" + if disabled + else f"""{ + get_note_history_menu(evaluation.id, etudid) + }""" + ) explanation = e["absinfo"] + explanation # Lien modif decision de jury: - explanation += '' % etudid + explanation += f'' # Valeur actuelle du champ: initvalues["note_" + str(etudid)] = e["val"] @@ -1330,7 +1314,7 @@ def _form_saisie_notes(E, M, groups_infos, destination=""): H.append(tf.getform()) # check and init H.append( f"""Terminer """ ) @@ -1345,7 +1329,7 @@ def _form_saisie_notes(E, M, groups_infos, destination=""): Mettre les notes manquantes à - + @@ -1364,10 +1348,8 @@ def _form_saisie_notes(E, M, groups_infos, destination=""): def save_note(etudid=None, evaluation_id=None, value=None, comment=""): """Enregistre une note (ajax)""" - authuser = current_user log( - "save_note: evaluation_id=%s etudid=%s uid=%s value=%s" - % (evaluation_id, etudid, authuser, value) + f"save_note: evaluation_id={evaluation_id} etudid={etudid} uid={current_user} value={value}" ) E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0] M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0] @@ -1380,13 +1362,13 @@ def save_note(etudid=None, evaluation_id=None, value=None, comment=""): ) result = {"nbchanged": 0} # JSON # Check access: admin, respformation, or responsable_id - if not sco_permissions_check.can_edit_notes(authuser, E["moduleimpl_id"]): + if not sco_permissions_check.can_edit_notes(current_user, E["moduleimpl_id"]): result["status"] = "unauthorized" else: L, _, _, _, _ = _check_notes([(etudid, value)], E, Mod) if L: nbchanged, _, existing_decisions = notes_add( - authuser, evaluation_id, L, comment=comment, do_it=True + current_user, evaluation_id, L, comment=comment, do_it=True ) ScolarNews.add( typ=ScolarNews.NEWS_NOTE,