ScoDoc/app/scodoc/sco_undo_notes.py

297 lines
9.5 KiB
Python
Raw Permalink Normal View History

2020-09-26 16:19:37 +02:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
2023-12-31 23:04:06 +01:00
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
2020-09-26 16:19:37 +02:00
#
# 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
#
##############################################################################
"""ScoDoc : annulation des saisies de notes
note = {evaluation_id, etudid, value, date, uid, comment}
Pour une évaluation:
- notes actuelles: table notes_notes
2023-12-31 23:04:06 +01:00
- historique: table notes_notes_log
2020-09-26 16:19:37 +02:00
saisie de notes == saisir ou supprimer une ou plusieurs notes (mêmes date et uid)
2021-02-04 20:02:44 +01:00
! tolérance sur les dates (200ms ?)
2020-09-26 16:19:37 +02:00
Chaque saisie affecte ou remplace une ou plusieurs notes.
Opérations:
- lister les saisies de notes
- annuler une saisie complète
- lister les modifs d'une seule note
- annuler une modif d'une note
"""
import datetime
from flask import request
from app.models import Evaluation, FormSemestre
from app.scodoc.intervals import intervalmap
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc import sco_evaluation_db
from app.scodoc import sco_preferences
from app.scodoc import sco_users
from app.scodoc.gen_tables import GenTable
import sco_version
2020-09-26 16:19:37 +02:00
# deux notes (de même uid) sont considérées comme de la même opération si
# elles sont séparées de moins de 2*tolerance:
OPERATION_DATE_TOLERANCE = datetime.timedelta(seconds=0.1)
class NotesOperation(dict):
"""Represents an operation on an evaluation
Keys: evaluation_id, date, uid, notes
"""
def get_comment(self):
if self["notes"]:
return self["notes"][0]["comment"]
else:
return ""
def comp_values(self):
"compute keys: comment, nb_notes"
self["comment"] = self.get_comment()
self["nb_notes"] = len(self["notes"])
self["datestr"] = self["date"].strftime("%a %d/%m/%y %Hh%M")
def undo(self):
2020-09-26 16:19:37 +02:00
"undo operation"
pass
# replace notes by last found in notes_log
# and suppress log entry
# select * from notes_notes_log where evaluation_id= and etudid= and date <
#
# verrouille tables notes, notes_log
# pour chaque note qui n'est pas plus recente que l'operation:
# recupere valeurs precedentes dans log
# affecte valeurs notes
# suppr log
# deverrouille tablesj
# for note in self['notes']:
# # il y a-t-il une modif plus recente ?
# if self['current_notes_by_etud']['date'] <= self['date'] + OPERATION_DATE_TOLERANCE:
#
2021-07-19 19:53:01 +02:00
# + invalider cache sco_cache.EvaluationCache.delete(evaluation_id)
2020-09-26 16:19:37 +02:00
def list_operations(evaluation_id):
2020-09-26 16:19:37 +02:00
"""returns list of NotesOperation for this evaluation"""
2021-07-19 19:53:01 +02:00
notes = list(
sco_evaluation_db.do_evaluation_get_all_notes(
evaluation_id, filter_suppressed=False
2021-07-19 19:53:01 +02:00
).values()
)
notes_log = list(
sco_evaluation_db.do_evaluation_get_all_notes(
evaluation_id, filter_suppressed=False, table="notes_notes_log"
2021-07-19 19:53:01 +02:00
).values()
)
2020-09-26 16:19:37 +02:00
dt = OPERATION_DATE_TOLERANCE
NotesDates = {} # { uid : intervalmap }
for note in notes + notes_log:
2021-07-09 17:47:06 +02:00
if note["uid"] not in NotesDates:
2020-09-26 16:19:37 +02:00
NotesDates[note["uid"]] = intervalmap()
nd = NotesDates[note["uid"]]
if nd[note["date"]] is None:
nd[note["date"] - dt : note["date"] + dt] = [note]
else:
nd[note["date"]].append(note)
current_notes_by_etud = {} # { etudid : note }
for note in notes:
current_notes_by_etud[note["etudid"]] = note
Ops = []
for uid in NotesDates.keys():
2021-12-12 21:48:26 +01:00
user_name = "{prenomnom} ({user_name})".format(**sco_users.user_info(uid))
2021-02-04 20:02:44 +01:00
for (t0, _), notes in NotesDates[uid].items():
2020-09-26 16:19:37 +02:00
Op = NotesOperation(
evaluation_id=evaluation_id,
date=t0,
uid=uid,
2021-12-12 21:48:26 +01:00
user_name=user_name,
2020-09-26 16:19:37 +02:00
notes=NotesDates[uid][t0],
current_notes_by_etud=current_notes_by_etud,
)
Op.comp_values()
Ops.append(Op)
return Ops
def evaluation_list_operations(evaluation_id):
2020-09-26 16:19:37 +02:00
"""Page listing operations on evaluation"""
evaluation = Evaluation.get_evaluation(evaluation_id)
operations = list_operations(evaluation_id)
2020-09-26 16:19:37 +02:00
2021-12-12 21:48:26 +01:00
columns_ids = ("datestr", "user_name", "nb_notes", "comment")
2020-09-26 16:19:37 +02:00
titles = {
"datestr": "Date",
2021-12-12 21:48:26 +01:00
"user_name": "Enseignant",
2020-09-26 16:19:37 +02:00
"nb_notes": "Nb de notes",
"comment": "Commentaire",
}
tab = GenTable(
titles=titles,
columns_ids=columns_ids,
rows=operations,
2020-09-26 16:19:37 +02:00
html_sortable=False,
html_title=f"""<h2>Opérations sur l'évaluation {evaluation.description} {
evaluation.date_debut.strftime("du %d/%m/%Y") if evaluation.date_debut else "(sans date)"
}</h2>""",
preferences=sco_preferences.SemPreferences(
evaluation.moduleimpl.formsemestre_id
),
table_id="evaluation_list_operations",
2020-09-26 16:19:37 +02:00
)
return tab.make_page()
2020-09-26 16:19:37 +02:00
def formsemestre_list_saisies_notes(formsemestre_id, fmt="html"):
"""Table listant toutes les opérations de saisies de notes, dans toutes
les évaluations du semestre.
"""
2022-09-07 17:40:40 +02:00
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
rows = ndb.SimpleDictFetch(
2023-12-31 23:04:06 +01:00
"""SELECT i.nom, i.prenom, code_nip, n.*, mod.titre, e.description, e.date_debut,
2022-09-07 17:40:40 +02:00
u.user_name, e.id as evaluation_id
2021-08-16 22:48:22 +02:00
FROM notes_notes n, notes_evaluation e, notes_moduleimpl mi,
2021-12-12 21:48:26 +01:00
notes_modules mod, identite i, "user" u
WHERE mi.id = e.moduleimpl_id
2021-08-16 22:48:22 +02:00
and mi.module_id = mod.id
and e.id = n.evaluation_id
and i.id = n.etudid
and u.id = n.uid
2021-08-16 22:48:22 +02:00
and mi.formsemestre_id = %(formsemestre_id)s
ORDER BY date desc
""",
2020-09-26 16:19:37 +02:00
{"formsemestre_id": formsemestre_id},
)
2022-09-07 17:40:40 +02:00
# Formate les notes
keep_numeric = fmt in scu.FORMATS_NUMERIQUES
for row in rows:
row["value"] = scu.fmt_note(row["value"], keep_numeric=keep_numeric)
2023-08-25 17:58:57 +02:00
row["date_evaluation"] = (
row["date_debut"].strftime("%d/%m/%Y %H:%M") if row["date_debut"] else ""
)
row["_date_evaluation_order"] = (
row["date_debut"].isoformat() if row["date_debut"] else ""
)
2020-09-26 16:19:37 +02:00
columns_ids = (
"date",
"code_nip",
2020-09-26 16:19:37 +02:00
"nom",
"prenom",
2020-09-26 16:19:37 +02:00
"value",
"user_name",
2020-09-26 16:19:37 +02:00
"titre",
"evaluation_id",
2020-09-26 16:19:37 +02:00
"description",
2023-08-25 17:58:57 +02:00
"date_evaluation",
2020-09-26 16:19:37 +02:00
"comment",
)
titles = {
"code_nip": "NIP",
"nom": "nom",
"prenom": "prenom",
2020-09-26 16:19:37 +02:00
"date": "Date",
"value": "Note",
"comment": "Remarque",
"user_name": "Enseignant",
"evaluation_id": "evaluation_id",
2020-09-26 16:19:37 +02:00
"titre": "Module",
"description": "Evaluation",
2023-08-25 17:58:57 +02:00
"date_evaluation": "Date éval.",
2020-09-26 16:19:37 +02:00
}
tab = GenTable(
titles=titles,
columns_ids=columns_ids,
rows=rows,
2022-09-08 09:46:16 +02:00
html_title=f"<h2>Saisies de notes dans {formsemestre.titre_annee()}</h2>",
html_class="table_leftalign table_coldate gt_table_searchable",
html_class_ignore_default=True,
2020-09-26 16:19:37 +02:00
html_sortable=True,
2022-09-08 09:46:16 +02:00
caption=f"Saisies de notes dans {formsemestre.titre_annee()}",
preferences=sco_preferences.SemPreferences(formsemestre_id),
base_url="%s?formsemestre_id=%s" % (request.base_url, formsemestre_id),
2022-09-07 17:40:40 +02:00
origin=f"Généré par {sco_version.SCONAME} le " + scu.timedate_human_repr() + "",
table_id="formsemestre_list_saisies_notes",
2020-09-26 16:19:37 +02:00
)
return tab.make_page(fmt=fmt)
2020-09-26 16:19:37 +02:00
def get_note_history(evaluation_id, etudid, fmt=""):
2020-09-26 16:19:37 +02:00
"""Historique d'une note
= liste chronologique d'opérations, la plus récente d'abord
[ { 'value', 'date', 'comment', 'uid' } ]
"""
2021-06-15 13:59:56 +02:00
cnx = ndb.GetDBConnexion()
2021-02-03 22:00:41 +01:00
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
2020-09-26 16:19:37 +02:00
# Valeur courante
cursor.execute(
"""
SELECT * FROM notes_notes
2023-12-31 23:04:06 +01:00
WHERE evaluation_id=%(evaluation_id)s AND etudid=%(etudid)s
2020-09-26 16:19:37 +02:00
""",
{"evaluation_id": evaluation_id, "etudid": etudid},
)
history = cursor.dictfetchall()
# Historique
cursor.execute(
"""
SELECT * FROM notes_notes_log
2023-12-31 23:04:06 +01:00
WHERE evaluation_id=%(evaluation_id)s AND etudid=%(etudid)s
2020-09-26 16:19:37 +02:00
ORDER BY date DESC""",
{"evaluation_id": evaluation_id, "etudid": etudid},
)
history += cursor.dictfetchall()
# Replace None comments by ''
# et cherche nom complet de l'enseignant:
for x in history:
x["comment"] = x["comment"] or ""
x["user_name"] = sco_users.user_info(x["uid"])["nomcomplet"]
2020-09-26 16:19:37 +02:00
if fmt == "json":
return scu.sendJSON(history)
2020-09-26 16:19:37 +02:00
else:
return history
"""
from debug import *
from app.scodoc.sco_undo_notes import *
_ = go_dept(app, 'RT').Notes
get_note_history( 'EVAL29740', 'EID28403')
2020-09-26 16:19:37 +02:00
"""