1
0
forked from ScoDoc/ScoDoc

Amélioration evaluation_listenotes

This commit is contained in:
Emmanuel Viennet 2024-08-26 12:03:37 +02:00
parent 0c3216e432
commit 6c6d1103e6
5 changed files with 130 additions and 124 deletions

View File

@ -47,6 +47,7 @@ def TrivialFormulator(
title="",
after_table="",
before_table="{title}",
hidden_args: list[tuple] | None = None,
):
"""
form_url : URL for this form
@ -124,6 +125,7 @@ def TrivialFormulator(
title=title,
after_table=after_table,
before_table=before_table,
hidden_args=hidden_args,
)
form = t.getform()
if t.canceled():
@ -161,6 +163,7 @@ class TF(object):
title="",
after_table="",
before_table="{title}",
hidden_args: list[tuple] | None = None,
):
self.form_url = form_url
self.values = values.copy()
@ -186,6 +189,7 @@ class TF(object):
self.title = title
self.after_table = after_table
self.before_table = before_table
self.hidden_args = hidden_args or []
self.readonly = readonly
self.result = None
self.is_submitted = is_submitted
@ -470,6 +474,8 @@ class TF(object):
}"/>"""
)
R.append(f"""<input type="hidden" name="{self.formid}_submitted" value="1"/>""")
for k, v in self.hidden_args:
R.append(f"""<input type="hidden" name="{k}" value="{v}"/>""")
if self.top_buttons:
R.append(buttons_markup + "<p></p>")
R.append(self.before_table.format(title=self.title))

View File

@ -42,7 +42,6 @@ from flask_login import current_user
from app import db, log
from app.models import FormSemestre, Identite, ScolarEvent
import app.scodoc.sco_utils as scu
from app.scodoc import html_sco_header
from app.scodoc import sco_assiduites as scass
from app.scodoc import sco_excel
from app.scodoc import sco_formsemestre
@ -170,11 +169,10 @@ def form_groups_choice(
with_deselect_butt=False,
submit_on_change=False,
default_deselect_others=True,
args: dict | None = None,
title="Groupes&nbsp;:",
):
"""form pour selection groupes
group_ids est la liste des groupes actuellement sélectionnés
et doit comporter au moins un élément, sauf si formsemestre_id est spécifié.
(utilisé pour retrouver le semestre et proposer la liste des autres groupes)
"""Formulaire complet pour choix de groupe.
Si submit_on_change, soumet (recharge la page) à chaque modif.
Si default_deselect_others, désélectionne le groupe "Tous" quand on sélectionne un autre groupe.
@ -182,7 +180,14 @@ def form_groups_choice(
Ces deux options ajoutent des classes utilisées en JS pour la gestion du formulaire.
"""
default_group_id = sco_groups.get_default_group(groups_infos.formsemestre_id)
args = args or {}
args_wdg = "\n".join(
[
f"""<input type="hidden" name="{k}" value="{v}"/>"""
for k, v in args.items()
if k not in ("formsemestre_id", "group_ids")
]
)
H = [
f"""
<form id="group_selector" method="get">
@ -190,7 +195,8 @@ def form_groups_choice(
value="{groups_infos.formsemestre_id}"/>
<input type="hidden" name="default_group_id" id="default_group_id"
value="{default_group_id}"/>
Groupes:
{args_wdg}
{title}
{
menu_groups_choice(
groups_infos,
@ -480,6 +486,7 @@ class DisplayedGroupsInfos:
return "\n".join(H)
def get_formsemestre(self) -> FormSemestre:
"le formsemestre"
return (
db.session.get(FormSemestre, self.formsemestre_id)
if self.formsemestre_id

View File

@ -43,17 +43,21 @@ from app.models import FormSemestre, Module
from app.models.etudiants import Identite
from app.models.evaluations import Evaluation
from app.models.moduleimpls import ModuleImpl
from app.scodoc.TrivialFormulator import TrivialFormulator
from app.scodoc import (
sco_evaluations,
sco_evaluation_db,
sco_groups,
sco_groups_view,
sco_preferences,
sco_users,
)
from app.scodoc.sco_groups_view import DisplayedGroupsInfos
from app.scodoc.sco_etud import etud_sort_key
from app.scodoc import sco_evaluations
from app.scodoc import sco_evaluation_db
from app.scodoc import sco_groups
from app.scodoc import sco_preferences
from app.scodoc import sco_users
import app.scodoc.sco_utils as scu
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc.gen_tables import GenTable
from app.scodoc.htmlutils import histogram_notes
from app.scodoc.TrivialFormulator import TrivialFormulator
import app.scodoc.sco_utils as scu
import sco_version
@ -82,18 +86,23 @@ def do_evaluation_listenotes(
return "<p>Aucune évaluation !</p>", "ScoDoc"
evaluation = evaluations[0]
modimpl = evaluation.moduleimpl # il y a au moins une evaluation
# Argument groupes:
group_ids = request.args.getlist("group_ids")
try:
group_ids = [int(gid) for gid in group_ids]
except ValueError as exc:
raise ScoValueError("group_ids invalide") from exc
groups_infos = DisplayedGroupsInfos(
group_ids,
formsemestre_id=modimpl.formsemestre.id,
select_all_when_unspecified=True,
)
# description de l'évaluation
if evaluation_id is not None:
H = [sco_evaluations.evaluation_describe(evaluation_id=evaluation_id)]
page_title = f"Notes {evaluation.description or modimpl.module.code}"
else:
H = []
page_title = f"Notes {modimpl.module.code}"
# groupes
groups = sco_groups.do_evaluation_listegroupes(evaluation.id, include_default=True)
grlabs = [g["group_name"] or "tous" for g in groups] # legendes des boutons
grnams = [str(g["group_id"]) for g in groups] # noms des checkbox
if len(evaluations) > 1:
descr = [
@ -109,37 +118,6 @@ def do_evaluation_listenotes(
{"default": evaluation.id, "input_type": "hidden"},
)
]
if len(grnams) > 1:
descr += [
(
"s",
{
"input_type": "separator",
"title": "<b>Choix du ou des groupes d'étudiants:</b>",
},
),
(
"group_ids",
{
"input_type": "checkbox",
"title": "",
"allowed_values": grnams,
"labels": grlabs,
"attributes": ('onclick="document.tf.submit();"',),
},
),
]
else:
if grnams:
def_nam = grnams[0]
else:
def_nam = ""
descr += [
(
"group_ids",
{"input_type": "hidden", "type": "list", "default": [def_nam]},
)
]
descr += [
(
"anonymous_listing",
@ -202,17 +180,16 @@ def do_evaluation_listenotes(
request.base_url,
scu.get_request_args(),
descr,
hidden_args=[("group_ids", gid) for gid in group_ids],
cancelbutton=None,
submitbutton=None,
bottom_buttons=False,
method="GET", # consultation
cssclass="noprint",
cssclass="noprint tf-liste-notes",
name="tf",
is_submitted=True, # toujours "soumis" (démarre avec liste complète)
)
if tf[0] == 0:
return "\n".join(H) + "\n" + tf[1], page_title
elif tf[0] == -1:
if tf[0] == -1:
return (
flask.redirect(
url_for(
@ -223,44 +200,43 @@ def do_evaluation_listenotes(
),
"",
)
else:
anonymous_listing = tf[2]["anonymous_listing"]
note_sur_20 = tf[2]["note_sur_20"]
hide_groups = tf[2]["hide_groups"]
split_groups = tf[2]["split_groups"]
with_emails = tf[2]["with_emails"]
group_ids = [x for x in tf[2]["group_ids"] if x != ""]
return (
_make_table_notes(
tf[1],
evaluations,
fmt=fmt,
note_sur_20=note_sur_20,
anonymous_listing=anonymous_listing,
group_ids=group_ids,
hide_groups=hide_groups,
split_groups=split_groups,
with_emails=with_emails,
mode=mode,
),
page_title,
)
return (
_make_table_notes(
tf[1],
evaluations,
fmt=fmt,
groups_infos=groups_infos,
args={
"note_sur_20": tf[2]["note_sur_20"],
"anonymous_listing": tf[2]["anonymous_listing"],
"group_ids": group_ids,
"hide_groups": tf[2]["hide_groups"],
"split_groups": tf[2]["split_groups"],
"with_emails": tf[2]["with_emails"],
},
mode=mode,
),
page_title,
)
def _make_table_notes(
html_form,
evaluations: list[Evaluation],
fmt: str = "",
note_sur_20=False,
anonymous_listing=False,
hide_groups=False,
split_groups=False,
with_emails=False,
group_ids: list[int] | None = None,
groups_infos: DisplayedGroupsInfos = None,
args: dict = None,
mode="module", # "eval" or "module"
) -> str:
"""Table liste notes (une seule évaluation ou toutes celles d'un module)"""
group_ids = group_ids or []
"""Table liste notes (une seule évaluation ou toutes celles d'un module)
args doit contenir:
note_sur_20=False,
anonymous_listing=False,
hide_groups=False,
split_groups=False,
with_emails=False
"""
args = args or {}
if not evaluations:
return "<p>Aucune évaluation !</p>"
evaluation = evaluations[0]
@ -286,15 +262,25 @@ def _make_table_notes(
keep_numeric = True # pas de conversion des notes en strings
else:
keep_numeric = False
# Si pas de groupe, affiche tout
if not group_ids:
group_ids = [sco_groups.get_default_group(formsemestre.id)]
groups = sco_groups.listgroups(group_ids)
# Menu groupes
group_selector = (
sco_groups_view.form_groups_choice(
groups_infos, submit_on_change=True, args=args
)
if groups_infos
else ""
)
gr_title = sco_groups.listgroups_abbrev(groups)
gr_title_filename = sco_groups.listgroups_filename(groups)
# Si pas de groupe, affiche tout XXX TODO
# if not groups_infos.group_ids:
# groups_infos.group_ids = [sco_groups.get_default_group(formsemestre.id)]
if anonymous_listing:
groups = sco_groups.listgroups(groups_infos.group_ids)
gr_title = groups_infos.groups_titles
gr_title_filename = groups_infos.groups_filename
if args["anonymous_listing"]:
columns_ids = ["code"] # cols in table
else:
if fmt in {"xls", "xml", "json"}:
@ -302,14 +288,15 @@ def _make_table_notes(
else:
columns_ids = ["nomprenom"]
partitions = []
if split_groups:
partitions = formsemestre.get_partitions_list(
with_default=False, only_listed=True
)
columns_ids += [f"partition_{p.id}" for p in partitions]
elif not hide_groups and fmt not in {"xml", "json"}:
# n'indique pas les groupes en xml et json car notation "humaine" ici
columns_ids.append("group")
if not args["hide_groups"]:
if args["split_groups"]:
partitions = formsemestre.get_partitions_list(
with_default=False, only_listed=True
)
columns_ids += [f"partition_{p.id}" for p in partitions]
elif fmt not in {"xml", "json"}:
# n'indique pas les groupes en xml et json car notation "humaine" ici
columns_ids.append("group")
titles = {
"code": "Code",
@ -456,13 +443,13 @@ def _make_table_notes(
row_moys,
is_apc,
key_mgr,
note_sur_20,
args["note_sur_20"],
keep_numeric,
fmt=fmt,
)
columns_ids.append(e.id)
#
if anonymous_listing:
if args["anonymous_listing"]:
rows.sort(key=lambda x: x["code"] or "")
else:
# sort by nom, prenom, sans accents
@ -504,7 +491,7 @@ def _make_table_notes(
)
# Ajoute colonnes emails tout à droite:
if with_emails:
if args["with_emails"]:
columns_ids += ["email", "emailperso"]
# Ajoute lignes en tête et moyennes
if len(evaluations) > 0 and fmt != "bordereau" and fmt != "json":
@ -539,17 +526,10 @@ def _make_table_notes(
columns_ids.append("signatures")
# titres divers:
gl = "".join(["&group_ids%3Alist=" + str(g) for g in group_ids])
if note_sur_20:
gl = "&note_sur_20%3Alist=yes" + gl
if anonymous_listing:
gl = "&anonymous_listing%3Alist=yes" + gl
if hide_groups:
gl = "&hide_groups%3Alist=yes" + gl
if split_groups:
gl = "&split_groups%3Alist=yes" + gl
if with_emails:
gl = "&with_emails%3Alist=yes" + gl
gl = "".join(["&group_ids=" + str(g) for g in groups_infos.group_ids])
for k, v in args.items():
gl += f"&{k}%3Alist=yes" if v else ""
if len(evaluations) == 1:
evalname = f"""{module.code}-{
evaluation.date_debut.replace(tzinfo=None).isoformat()
@ -582,7 +562,8 @@ def _make_table_notes(
len(etudid_etats),
)
if evaluation.date_debut:
pdf_title = f"{evaluation.description} ({evaluation.date_debut.strftime('%d/%m/%Y')})"
pdf_title = f"""{evaluation.description} ({
evaluation.date_debut.strftime('%d/%m/%Y')})"""
else:
pdf_title = evaluation.description or f"évaluation dans {module.code}"
@ -671,12 +652,14 @@ def _make_table_notes(
Les moyennes sur le groupe sont estimées sans les absents
(sauf pour les moyennes des moyennes d'UE) ni les démissionnaires.</span>"""
eval_info += """</span>"""
return html_form + eval_info + t + "<p></p>"
return group_selector + html_form + eval_info + t + "<p></p>"
# Une seule evaluation: ajoute histogramme
histo = histogram_notes(notes)
# 2 colonnes: histo, comments
C = [
f"""<br><a class="stdlink" href="{base_url}&fmt=bordereau">Bordereau de Signatures (version PDF)</a>
section_basse_html = [
f"""<br><a class="stdlink" href="{base_url}&fmt=bordereau"
>Bordereau de Signatures (version PDF)</a>
<table>
<tr><td>
<div><h4>Répartition des notes:</h4>
@ -689,15 +672,17 @@ def _make_table_notes(
commentkeys = list(key_mgr.items()) # [ (comment, key), ... ]
commentkeys.sort(key=lambda x: int(x[1]))
for comment, key in commentkeys:
C.append(f"""<span class="colcomment">({key})</span> <em>{comment}</em><br>""")
section_basse_html.append(
f"""<span class="colcomment">({key})</span> <em>{comment}</em><br>"""
)
if commentkeys:
C.append(
section_basse_html.append(
f"""<span><a class=stdlink" href="{ url_for(
'notes.evaluation_list_operations', scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id )
}">Gérer les opérations</a></span><br>
"""
)
eval_info = "xxx"
eval_info = ""
if evals_state[evaluation.id]["evalcomplete"]:
eval_info = '<span class="eval_info eval_complete">Evaluation prise en compte dans les moyennes</span>'
elif evals_state[evaluation.id]["evalattente"]:
@ -708,9 +693,10 @@ def _make_table_notes(
return (
sco_evaluations.evaluation_describe(evaluation_id=evaluation.id)
+ eval_info
+ group_selector
+ html_form
+ t
+ "\n".join(C)
+ "\n".join(section_basse_html)
)

View File

@ -1536,6 +1536,10 @@ span.eval_title {
padding-top: 24px;
}
.tf-liste-notes td.tf-field {
max-width: var(--sco-content-max-width);
}
/* #saisie_notes span.eval_title {
border-bottom: 1px solid rgb(100,100,100);
}
@ -1581,8 +1585,10 @@ div.jury_footer>span {
color: red;
}
span.eval_info {
.eval_info {
font-style: italic;
max-width: var(--sco-content-max-width);
margin: 16px 0 16px 0;
}
span.eval_complete {

View File

@ -1787,6 +1787,7 @@ def evaluation_listenotes():
content=content,
title=page_title,
cssstyles=["css/verticalhisto.css"],
javascripts=["js/groups_view.js"],
)
return content