# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # Gestion scolarite IUT # # Copyright (c) 1999 - 2022 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@gmail.com # ############################################################################## """Formulaire ajout/édition d'une évaluation """ import time import flask from flask import url_for, render_template from flask import g from flask_login import current_user from flask import request from app import db from app import log from app import models from app.models.formsemestre import FormSemestre from app.models.moduleimpls import ModuleImpl import app.scodoc.sco_utils as scu from app.scodoc.sco_utils import ModuleType from app.scodoc.sco_exceptions import AccessDenied, ScoValueError from app.scodoc.TrivialFormulator import TrivialFormulator from app.scodoc import html_sco_header from app.scodoc import sco_evaluations from app.scodoc import sco_evaluation_db from app.scodoc import sco_moduleimpl from app.scodoc import sco_permissions_check def evaluation_create_form( moduleimpl_id=None, evaluation_id=None, edit=False, page_title="Évaluation", ): "Formulaire création/édition d'une évaluation (pas de ses notes)" if evaluation_id is not None: evaluation = models.Evaluation.query.get(evaluation_id) moduleimpl_id = evaluation.moduleimpl_id # modimpl_o = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[ 0 ] mod = modimpl_o["module"] formsemestre_id = modimpl_o["formsemestre_id"] sem = FormSemestre.query.get(formsemestre_id) sem_ues = sem.query_ues(with_sport=False).all() is_malus = mod["module_type"] == ModuleType.MALUS is_apc = mod["module_type"] in (ModuleType.RESSOURCE, ModuleType.SAE) min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible # if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id): return ( html_sco_header.sco_header() + "<h2>Opération non autorisée</h2><p>" + "Modification évaluation impossible pour %s" % current_user.get_nomplogin() + "</p>" + '<p><a href="moduleimpl_status?moduleimpl_id=%s">Revenir</a></p>' % (moduleimpl_id,) + html_sco_header.sco_footer() ) if not edit: # création nouvel if moduleimpl_id is None: raise ValueError("missing moduleimpl_id parameter") initvalues = { "note_max": 20, "jour": time.strftime("%d/%m/%Y", time.localtime()), "publish_incomplete": is_malus, } submitlabel = "Créer cette évaluation" action = "Création d'une évaluation" link = "" else: # édition données existantes # setup form init values if evaluation_id is None: raise ValueError("missing evaluation_id parameter") initvalues = evaluation.to_dict() moduleimpl_id = initvalues["moduleimpl_id"] submitlabel = "Modifier les données" action = "Modification d'une évaluation" link = "" # Note maximale actuelle dans cette éval ? etat = sco_evaluations.do_evaluation_etat(evaluation_id) if etat["maxi_num"] is not None: min_note_max = max(scu.NOTES_PRECISION, etat["maxi_num"]) else: min_note_max = scu.NOTES_PRECISION # if min_note_max > scu.NOTES_PRECISION: min_note_max_str = scu.fmt_note(min_note_max) else: min_note_max_str = "0" # mod_descr = '<a href="moduleimpl_status?moduleimpl_id=%s">%s %s</a> %s' % ( moduleimpl_id, mod["code"] or "module sans code", mod["titre"], link, ) H = [ f"""<h3>{action} en {scu.MODULE_TYPE_NAMES[mod["module_type"]]} {mod_descr}</h3> """ ] heures = ["%02dh%02d" % (h, m) for h in range(8, 19) for m in (0, 30)] # initvalues["visibulletin"] = initvalues.get("visibulletin", True) if initvalues["visibulletin"]: initvalues["visibulletinlist"] = ["X"] else: initvalues["visibulletinlist"] = [] initvalues["coefficient"] = initvalues.get("coefficient", 1.0) vals = scu.get_request_args() if vals.get("tf_submitted", False) and "visibulletinlist" not in vals: vals["visibulletinlist"] = [] # ue_coef_dict = {} if is_apc: # BUT: poids vers les UE ue_coef_dict = ModuleImpl.query.get(moduleimpl_id).module.get_ue_coef_dict() for ue in sem_ues: if edit: existing_poids = models.EvaluationUEPoids.query.filter_by( ue=ue, evaluation=evaluation ).first() else: existing_poids = None if existing_poids: poids = existing_poids.poids else: coef_ue = ue_coef_dict.get(ue.id, 0.0) or 0.0 if coef_ue > 0: poids = 1.0 # par défaut au départ else: poids = 0.0 initvalues[f"poids_{ue.id}"] = poids # form = [ ("evaluation_id", {"default": evaluation_id, "input_type": "hidden"}), ("formsemestre_id", {"default": formsemestre_id, "input_type": "hidden"}), ("moduleimpl_id", {"default": moduleimpl_id, "input_type": "hidden"}), # ('jour', { 'title' : 'Date (j/m/a)', 'size' : 12, 'explanation' : 'date de l\'examen, devoir ou contrôle' }), ( "jour", { "input_type": "datedmy", "title": "Date", "size": 12, "explanation": "date de l'examen, devoir ou contrôle", }, ), ( "heure_debut", { "title": "Heure de début", "explanation": "heure du début de l'épreuve", "input_type": "menu", "allowed_values": heures, "labels": heures, }, ), ( "heure_fin", { "title": "Heure de fin", "explanation": "heure de fin de l'épreuve", "input_type": "menu", "allowed_values": heures, "labels": heures, }, ), ] if is_malus: # pas de coefficient form.append(("coefficient", {"input_type": "hidden", "default": "1."})) elif not is_apc: # modules standard hors BUT form.append( ( "coefficient", { "size": 6, "type": "float", "explanation": "coef. dans le module (choisi librement par l'enseignant, non utilisé pour rattrapage et 2ème session)", "allow_null": False, }, ) ) form += [ ( "note_max", { "size": 4, "type": "float", "title": "Notes de 0 à", "explanation": "barème (note max actuelle: %s)" % min_note_max_str, "allow_null": False, "max_value": scu.NOTES_MAX, "min_value": min_note_max, }, ), ( "description", { "size": 36, "type": "text", "explanation": 'type d\'évaluation, apparait sur le bulletins longs. Exemples: "contrôle court", "examen de TP", "examen final".', }, ), ( "visibulletinlist", { "input_type": "checkbox", "allowed_values": ["X"], "labels": [""], "title": "Visible sur bulletins", "explanation": "(pour les bulletins en version intermédiaire)", }, ), ( "publish_incomplete", { "input_type": "boolcheckbox", "title": "Prise en compte immédiate", "explanation": "notes utilisées même si incomplètes", }, ), ( "evaluation_type", { "input_type": "menu", "title": "Modalité", "allowed_values": ( scu.EVALUATION_NORMALE, scu.EVALUATION_RATTRAPAGE, scu.EVALUATION_SESSION2, ), "type": "int", "labels": ( "Normale", "Rattrapage (remplace si meilleure note)", "Deuxième session (remplace toujours)", ), }, ), ] if is_apc: # ressources et SAÉs form += [ ( "coefficient", { "size": 6, "type": "float", "explanation": "importance de l'évaluation (multiplie les poids ci-dessous)", "allow_null": False, }, ), ] # Liste des UE utilisées dans des modules de ce semestre: for ue in sem_ues: coef_ue = ue_coef_dict.get(ue.id, 0.0) form.append( ( f"poids_{ue.id}", { "title": f"Poids {ue.acronyme}", "size": 2, "type": "float", "explanation": f""" <span class="eval_coef_ue" title="coef. du module dans cette UE">({"coef. mod.:" +str(coef_ue) if coef_ue else "ce module n'a pas de coef. dans cette UE"})</span> <span class="eval_coef_ue_titre">{ue.titre}</span> """, "allow_null": False, # ok si poids nul ou coef vers l'UE nul: "validator": lambda val, field: (not val) or ue_coef_dict.get(int(field[len("poids_") :]), 0.0) != 0, "enabled": coef_ue != 0 or initvalues[f"poids_{ue.id}"] != 0.0, }, ), ) tf = TrivialFormulator( request.base_url, vals, form, cancelbutton="Annuler", submitlabel=submitlabel, initvalues=initvalues, readonly=False, ) dest_url = "moduleimpl_status?moduleimpl_id=%s" % modimpl_o["moduleimpl_id"] if tf[0] == 0: head = html_sco_header.sco_header(page_title=page_title) return ( head + "\n".join(H) + "\n" + tf[1] + render_template("scodoc/help/evaluations.html", is_apc=is_apc) + html_sco_header.sco_footer() ) elif tf[0] == -1: return flask.redirect(dest_url) else: # form submission if tf[2]["visibulletinlist"]: tf[2]["visibulletin"] = True else: tf[2]["visibulletin"] = False if edit: sco_evaluation_db.do_evaluation_edit(tf[2]) else: # création d'une evaluation evaluation_id = sco_evaluation_db.do_evaluation_create(**tf[2]) if is_apc: # Set poids evaluation = models.Evaluation.query.get(evaluation_id) for ue in sem_ues: evaluation.set_ue_poids(ue, tf[2][f"poids_{ue.id}"]) db.session.add(evaluation) db.session.commit() return flask.redirect(dest_url)