# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # Gestion scolarite IUT # # Copyright (c) 1999 - 2023 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 # ############################################################################## """Liste des notes d'une évaluation """ from collections import defaultdict import numpy as np import flask from flask import url_for, g, request from app import db, log from app import models from app.comp import res_sem from app.comp import moy_mod from app.comp.moy_mod import ModuleImplResults from app.comp.res_compat import NotesTableCompat from app.comp.res_but import ResultatsSemestreBUT from app.models import FormSemestre, Module from app.models.etudiants import Identite from app.models.evaluations import Evaluation from app.models.moduleimpls import ModuleImpl import app.scodoc.notesdb as ndb from app.scodoc.TrivialFormulator import TrivialFormulator 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 import sco_version from app.scodoc.gen_tables import GenTable from app.scodoc.htmlutils import histogram_notes def do_evaluation_listenotes( evaluation_id=None, moduleimpl_id=None, fmt="html" ) -> tuple[str, str]: """ Affichage des notes d'une évaluation (si evaluation_id) ou de toutes les évaluations d'un module (si moduleimpl_id) """ mode = None if moduleimpl_id: mode = "module" evals = sco_evaluation_db.get_evaluations_dict({"moduleimpl_id": moduleimpl_id}) elif evaluation_id: mode = "eval" evals = sco_evaluation_db.get_evaluations_dict({"evaluation_id": evaluation_id}) else: raise ValueError("missing argument: evaluation or module") if not evals: return "
Aucune évaluation !
", "ScoDoc" eval_dict = evals[0] # il y a au moins une evaluation modimpl = db.session.get(ModuleImpl, eval_dict["moduleimpl_id"]) # description de l'evaluation if mode == "eval": H = [sco_evaluations.evaluation_describe(evaluation_id=evaluation_id)] page_title = f"Notes {eval_dict['description'] or modimpl.module.code}" else: H = [] page_title = f"Notes {modimpl.module.code}" # groupes groups = sco_groups.do_evaluation_listegroupes( eval_dict["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(evals) > 1: descr = [ ( "moduleimpl_id", {"default": eval_dict["moduleimpl_id"], "input_type": "hidden"}, ) ] else: descr = [ ( "evaluation_id", {"default": eval_dict["evaluation_id"], "input_type": "hidden"}, ) ] if len(grnams) > 1: descr += [ ( "s", { "input_type": "separator", "title": "Choix du ou des groupes d'étudiants:", }, ), ( "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", { "input_type": "checkbox", "title": "", "allowed_values": ("yes",), "labels": ('listing "anonyme"',), "attributes": ('onclick="document.tf.submit();"',), "template": 'Aucune évaluation !
" E = evals[0] moduleimpl_id = E["moduleimpl_id"] modimpl = ModuleImpl.query.get_or_404(moduleimpl_id) module: Module = modimpl.module formsemestre: FormSemestre = modimpl.formsemestre is_apc = module.formation.get_cursus().APC_SAE if is_apc: res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre) is_conforme = modimpl.check_apc_conformity(res) evals_poids, ues = moy_mod.load_evaluations_poids(moduleimpl_id) if not ues: is_apc = False else: evals_poids, ues = None, None is_conforme = True # (debug) check that all evals are in same module: for e in evals: if e["moduleimpl_id"] != moduleimpl_id: raise ValueError("invalid evaluations list") if fmt == "xls": 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) gr_title = sco_groups.listgroups_abbrev(groups) gr_title_filename = sco_groups.listgroups_filename(groups) if anonymous_listing: columns_ids = ["code"] # cols in table else: if fmt == "xls" or fmt == "xml": columns_ids = ["nom", "prenom"] else: columns_ids = ["nomprenom"] if not hide_groups: columns_ids.append("group") titles = { "code": "Code", "group": "Groupe", "nom": "Nom", "prenom": "Prénom", "nomprenom": "Nom", "expl_key": "Rem.", "email": "e-mail", "emailperso": "e-mail perso", "signatures": "Signatures", } rows = [] class KeyManager(dict): # comment : key (pour regrouper les comments a la fin) def __init__(self): self.lastkey = 1 def nextkey(self): r = self.lastkey self.lastkey += 1 # self.lastkey = chr(ord(self.lastkey)+1) return str(r) key_mgr = KeyManager() # code pour listings anonyme, à la place du nom if sco_preferences.get_preference("anonymous_lst_code") == "INE": anonymous_lst_key = "code_ine" elif sco_preferences.get_preference("anonymous_lst_code") == "NIP": anonymous_lst_key = "code_nip" else: anonymous_lst_key = "etudid" etudid_etats = sco_groups.do_evaluation_listeetuds_groups( E["evaluation_id"], groups, include_demdef=True ) for etudid, etat in etudid_etats: css_row_class = None # infos identite etudiant etud: Identite = Identite.query.filter_by( id=etudid, dept_id=g.scodoc_dept_id ).first() if etud is None: continue if etat == scu.INSCRIT: # si inscrit, indique groupe groups = sco_groups.get_etud_groups(etudid, formsemestre.id) grc = sco_groups.listgroups_abbrev(groups) else: if etat == scu.DEMISSION: grc = "DEM" # attention: ce code est re-ecrit plus bas, ne pas le changer (?) css_row_class = "etuddem" else: grc = etat code = getattr(etud, anonymous_lst_key) if not code: # laisser le code vide n'aurait aucun sens, prenons l'etudid code = etudid rows.append( { "code": str(code), # INE, NIP ou etudid "_code_td_attrs": 'style="padding-left: 1em; padding-right: 2em;"', "etudid": etudid, "nom": etud.nom.upper(), "_nomprenom_target": url_for( "notes.formsemestre_bulletinetud", scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id, etudid=etudid, ), "_nomprenom_td_attrs": f"""id="{etudid}" class="etudinfo" data-sort="{etud.sort_key}" """, "prenom": etud.prenom.lower().capitalize(), "nom_usuel": etud.nom_usuel, "nomprenom": etud.nomprenom, "group": grc, "_group_td_attrs": 'class="group"', "email": etud.get_first_email(), "emailperso": etud.get_first_email("emailperso"), "_css_row_class": css_row_class or "", } ) # Lignes en tête: row_coefs = { "nom": "", "prenom": "", "nomprenom": "", "group": "", "code": "", "_css_row_class": "sorttop fontitalic", "_table_part": "head", } row_poids = { "nom": "", "prenom": "", "nomprenom": "", "group": "", "code": "", "_css_row_class": "sorttop poids", "_table_part": "head", } row_note_max = { "nom": "", "prenom": "", "nomprenom": "", "group": "", "code": "", "_css_row_class": "sorttop fontitalic", "_table_part": "head", } row_moys = { "_css_row_class": "moyenne sortbottom", "_table_part": "foot", #'_nomprenom_td_attrs' : 'colspan="2" ', "nomprenom": "Moyenne :", "comment": "", } # Ajoute les notes de chaque évaluation: for e in evals: e["eval_state"] = sco_evaluations.do_evaluation_etat(e["evaluation_id"]) notes, nb_abs, nb_att = _add_eval_columns( e, evals_poids, ues, rows, titles, row_coefs, row_poids, row_note_max, row_moys, is_apc, key_mgr, note_sur_20, keep_numeric, fmt=fmt, ) columns_ids.append(e["evaluation_id"]) # if anonymous_listing: rows.sort(key=lambda x: x["code"] or "") else: # sort by nom, prenom, sans accents rows.sort(key=etud_sort_key) # Si module, ajoute la (les) "moyenne(s) du module: if mode == "module": if len(evals) > 1: # Moyenne de l'étudiant dans le module # Affichée même en APC à titre indicatif _add_moymod_column( formsemestre.id, moduleimpl_id, rows, columns_ids, titles, row_coefs, row_poids, row_note_max, row_moys, is_apc, keep_numeric, ) if is_apc: # Ajoute une colonne par UE _add_apc_columns( modimpl, evals_poids, ues, rows, columns_ids, titles, is_conforme, row_coefs, row_poids, row_note_max, row_moys, keep_numeric, ) # Ajoute colonnes emails tout à droite: if with_emails: columns_ids += ["email", "emailperso"] # Ajoute lignes en tête et moyennes if len(evals) > 0 and fmt != "bordereau": rows_head = [row_coefs] if is_apc: rows_head.append(row_poids) rows_head.append(row_note_max) rows = rows_head + rows rows.append(row_moys) # ajout liens HTMl vers affichage une evaluation: if fmt == "html" and len(evals) > 1: rlinks = {"_table_part": "head"} for e in evals: rlinks[e["evaluation_id"]] = "afficher" rlinks[ "_" + str(e["evaluation_id"]) + "_help" ] = "afficher seulement les notes de cette évaluation" rlinks["_" + str(e["evaluation_id"]) + "_target"] = url_for( "notes.evaluation_listenotes", scodoc_dept=g.scodoc_dept, evaluation_id=e["evaluation_id"], ) rlinks["_" + str(e["evaluation_id"]) + "_td_attrs"] = ' class="tdlink" ' rows.append(rlinks) if len(evals) == 1: # colonne "Rem." seulement si une eval if fmt == "html": # pas d'indication d'origine en pdf (pour affichage) columns_ids.append("expl_key") elif fmt == "xls" or fmt == "xml": columns_ids.append("comment") elif fmt == "bordereau": columns_ids.append("signatures") # titres divers: gl = "".join(["&group_ids%3Alist=" + str(g) for g in group_ids]) if note_sur_20: gl = "¬e_sur_20%3Alist=yes" + gl if anonymous_listing: gl = "&anonymous_listing%3Alist=yes" + gl if hide_groups: gl = "&hide_groups%3Alist=yes" + gl if with_emails: gl = "&with_emails%3Alist=yes" + gl if len(evals) == 1: evalname = "%s-%s" % (module.code, ndb.DateDMYtoISO(E["jour"])) hh = "%s, %s (%d étudiants)" % (E["description"], gr_title, len(etudid_etats)) filename = scu.make_filename("notes_%s_%s" % (evalname, gr_title_filename)) if fmt == "bordereau": hh = " %d étudiants" % (len(etudid_etats)) hh += " %d absent" % (nb_abs) if nb_abs > 1: hh += "s" hh += ", %d en attente." % (nb_att) # Attention: ReportLab supporte seulement 'Répartition des notes:" + histo + " | \n",
'',
]
commentkeys = list(key_mgr.items()) # [ (comment, key), ... ]
commentkeys.sort(key=lambda x: int(x[1]))
for comment, key in commentkeys:
C.append(
'(%s) %s
|