344 lines
12 KiB
Python
344 lines
12 KiB
Python
# -*- 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"],
|
|
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"] = []
|
|
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 defaut 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:
|
|
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">{ue_coef_dict.get(ue.id, 0.)}</span>
|
|
<span class="eval_coef_ue_titre">{ue.titre}</span>
|
|
""",
|
|
"allow_null": False,
|
|
},
|
|
),
|
|
)
|
|
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:
|
|
# creation 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)
|