forked from ScoDoc/ScoDoc
Compare commits
1 Commits
master
...
moodle-not
Author | SHA1 | Date | |
---|---|---|---|
06d83cc691 |
4
ZNotes.py
Normal file → Executable file
4
ZNotes.py
Normal file → Executable file
@ -90,6 +90,7 @@ import sco_compute_moy
|
||||
import sco_recapcomplet
|
||||
import sco_liste_notes
|
||||
import sco_saisie_notes
|
||||
import sco_saisie_notes_moodle
|
||||
import sco_placement
|
||||
import sco_undo_notes
|
||||
import sco_formations
|
||||
@ -2460,6 +2461,9 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
|
||||
security.declareProtected(ScoEnsView, "saisie_notes_tableur")
|
||||
saisie_notes_tableur = sco_saisie_notes.saisie_notes_tableur
|
||||
|
||||
security.declareProtected(ScoEnsView, "import_eval_notes_from_moodle")
|
||||
import_eval_notes_from_moodle = sco_saisie_notes_moodle.import_from_moodle
|
||||
|
||||
security.declareProtected(ScoEnsView, "feuille_saisie_notes")
|
||||
feuille_saisie_notes = sco_saisie_notes.feuille_saisie_notes
|
||||
|
||||
|
20
sco_preferences.py
Normal file → Executable file
20
sco_preferences.py
Normal file → Executable file
@ -1744,6 +1744,26 @@ Année scolaire: %(anneescolaire)s
|
||||
"category": "edt",
|
||||
},
|
||||
),
|
||||
(
|
||||
"moodle_server_url",
|
||||
{
|
||||
"title": "URL pour accéder au service web de Moodle",
|
||||
"initvalue": "",
|
||||
"explanation": "cette URL est du type https://nom_du_serveur/moodle/webservice/rest/server.php",
|
||||
"size": 50,
|
||||
"category": "portal",
|
||||
},
|
||||
),
|
||||
(
|
||||
"moodle_ws_token",
|
||||
{
|
||||
"title": "jeton d'identification pour le service web de Moodle",
|
||||
"initvalue": "",
|
||||
"explanation": "ce jeton est créé par moodle dans la gestion du plugin service web: consultez l'administrateur de Moodle",
|
||||
"size": 30,
|
||||
"category": "portal",
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
PREFS_NAMES = set([x[0] for x in PREFS])
|
||||
|
@ -921,27 +921,37 @@ def saisie_notes(context, evaluation_id, group_ids=[], REQUEST=None):
|
||||
H.append("""<div id="group-tabs"><table><tr><td>""")
|
||||
H.append(sco_groups_view.form_groups_choice(context, groups_infos))
|
||||
H.append('</td><td style="padding-left: 35px;">')
|
||||
H.append(
|
||||
htmlutils.make_menu(
|
||||
"Autres opérations",
|
||||
[
|
||||
|
||||
# Pour savoir si l'interface Moodle est configurée:
|
||||
moodle_token = context.get_preference("moodle_ws_token", formsemestre_id)
|
||||
moodle_serveur = context.get_preference("moodle_server_url", formsemestre_id)
|
||||
menu_items = [
|
||||
{
|
||||
"title": "Saisie par fichier tableur",
|
||||
"id": "menu_saisie_tableur",
|
||||
"url": "/saisie_notes_tableur?evaluation_id=%s&%s"
|
||||
% (E["evaluation_id"], groups_infos.groups_query_args),
|
||||
},
|
||||
{
|
||||
"id": "import_moodle",
|
||||
"title": "Importer les notes depuis Moodle",
|
||||
"url": "/import_from_moodle?evaluation_id=%s" % (E["evaluation_id"],),
|
||||
"enabled": moodle_serveur and moodle_token,
|
||||
},
|
||||
{
|
||||
"title": "Voir toutes les notes du module",
|
||||
"url": "/evaluation_listenotes?moduleimpl_id=%s"
|
||||
% E["moduleimpl_id"],
|
||||
"url": "/evaluation_listenotes?moduleimpl_id=%s" % E["moduleimpl_id"],
|
||||
},
|
||||
{
|
||||
"title": "Effacer toutes les notes de cette évaluation",
|
||||
"url": "/evaluation_suppress_alln?evaluation_id=%s"
|
||||
% (E["evaluation_id"],),
|
||||
"url": "/evaluation_suppress_alln?evaluation_id=%s" % (E["evaluation_id"],),
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
H.append(
|
||||
htmlutils.make_menu(
|
||||
"Autres opérations",
|
||||
menu_items,
|
||||
base_url=context.absolute_url(),
|
||||
alone=True,
|
||||
)
|
||||
|
474
sco_saisie_notes_moodle.py
Normal file
474
sco_saisie_notes_moodle.py
Normal file
@ -0,0 +1,474 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2021 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
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
"""Importation de notes depuis Moodle
|
||||
Contrib. Pierre-Alain Jacquot, mai 2021
|
||||
"""
|
||||
|
||||
# QUESTION: un (long) commentaire expliquant le principe de base de ce module
|
||||
|
||||
import requests
|
||||
import re
|
||||
|
||||
|
||||
def cleanhtml(raw_html):
|
||||
cleanr = re.compile("<.*?>")
|
||||
cleantext = re.sub(cleanr, " ", raw_html)
|
||||
cleantext = cleantext.strip()
|
||||
cleantext = cleantext.encode("utf-8")
|
||||
return cleantext
|
||||
|
||||
|
||||
#
|
||||
def get_moodle_course_id(moodle_serveur, moodle_token, courses_short_name):
|
||||
param_cours = {
|
||||
"wstoken": moodle_token,
|
||||
"moodlewsrestformat": "json",
|
||||
"wsfunction": "core_course_get_courses_by_field",
|
||||
"field": "shortname",
|
||||
"value": courses_short_name,
|
||||
}
|
||||
try:
|
||||
r = requests.post(url=moodle_serveur, data=param_cours).json()
|
||||
except ValueError:
|
||||
raise ValueError("Erreur de connexion vérifiez l'URL de Moodle")
|
||||
if "exception" in r:
|
||||
raise ValueError(
|
||||
"Connexion au service web de Moodle impossible %s : Vérifiez votre paramétrage"
|
||||
% r["message"]
|
||||
)
|
||||
if len(r["courses"]) == 0:
|
||||
courseid = 0
|
||||
else:
|
||||
courseid = r["courses"][0]["id"]
|
||||
return courseid
|
||||
|
||||
|
||||
def has_student_role(user):
|
||||
"""
|
||||
Retourne vrai si l'utilisateur a le role 5 : «etudiant» ou «student» dans le cours
|
||||
i.e. il a des notes
|
||||
"""
|
||||
# QUESTION: ce nombre "5" est une constante universelle dans Moodle ?
|
||||
est_etudiant = False
|
||||
for role in user["roles"]:
|
||||
# print "role : "+str(role['roleid'] )
|
||||
if role["roleid"] == 5:
|
||||
# print "est_etudiant "+str(role['roleid'] )
|
||||
est_etudiant = 1
|
||||
return est_etudiant
|
||||
|
||||
|
||||
def get_etudiants_from_course(moodle_serveur, moodle_token, courses_short_name):
|
||||
"""
|
||||
Extrait la liste des étudiants des utilisateurs inscrit dans le cours.
|
||||
Cette liste contient les informations suivante :
|
||||
- id moodle
|
||||
- email
|
||||
- idnumber (numéro d'identification) s'il existe : celui ci peut servir a stocker le EID ou le nip
|
||||
"""
|
||||
courseid = get_moodle_course_id(moodle_serveur, moodle_token, courses_short_name)
|
||||
param_cours = {
|
||||
"wstoken": moodle_token,
|
||||
"moodlewsrestformat": "json",
|
||||
"wsfunction": "core_enrol_get_enrolled_users",
|
||||
"options[0][name]": "onlyactive",
|
||||
"options[0][value]": "1",
|
||||
"options[1][name]": "userfields",
|
||||
"options[1][value]": "id,email,idnumber,roles",
|
||||
"courseid": courseid,
|
||||
}
|
||||
r = requests.post(url=moodle_serveur, data=param_cours).json()
|
||||
etudiants = [user for user in r if has_student_role(user)]
|
||||
# le role n'est plus une information pertinente : suppression
|
||||
for etudiant in etudiants:
|
||||
del etudiant["roles"]
|
||||
etudiant["email"] = etudiant["email"].encode("ascii").lower()
|
||||
return etudiants
|
||||
|
||||
|
||||
def get_evaluation_list(moodle_serveur, moodle_token, courses_short_name):
|
||||
"""
|
||||
Récupère la liste des evaluations du cours Moodle
|
||||
On recherche les notes d'un seul etudiant pour gagner du temps.
|
||||
"""
|
||||
# QUESTION: documenter les valeurs résultats
|
||||
etudiants = get_etudiants_from_course(
|
||||
moodle_serveur, moodle_token, courses_short_name
|
||||
)
|
||||
a_userid = etudiants[0]["id"]
|
||||
courseid = get_moodle_course_id(moodle_serveur, moodle_token, courses_short_name)
|
||||
param_notes = {
|
||||
"wstoken": moodle_token,
|
||||
"moodlewsrestformat": "json",
|
||||
"wsfunction": "gradereport_user_get_grades_table",
|
||||
"courseid": courseid,
|
||||
"userid": a_userid,
|
||||
}
|
||||
r = requests.post(url=moodle_serveur, data=param_notes)
|
||||
notes = r.json()
|
||||
bareme = {}
|
||||
liste_evals = []
|
||||
for etu_notes in notes["tables"][0]["tabledata"]:
|
||||
if "grade" in etu_notes:
|
||||
nom_eval = cleanhtml(etu_notes["itemname"]["content"])
|
||||
liste_evals.append(nom_eval)
|
||||
bareme_min, bareme_max = etu_notes["range"]["content"].split("–")
|
||||
bareme[nom_eval] = {
|
||||
"min": float(bareme_min.replace(",", ".")),
|
||||
"max": float(bareme_max.replace(",", ".")),
|
||||
}
|
||||
return liste_evals, bareme
|
||||
|
||||
|
||||
def get_grades_from_moodle_course(moodle_serveur, moodle_token, courses_short_name):
|
||||
"""
|
||||
Récupère toutes les notes du cours et les remet en forme
|
||||
dans un dictionnaire indexé par le userid de moodle
|
||||
{userid: { nom_eval:note, ...}}
|
||||
"""
|
||||
courseid = get_moodle_course_id(moodle_serveur, moodle_token, courses_short_name)
|
||||
param_notes = {
|
||||
"wstoken": moodle_token,
|
||||
"moodlewsrestformat": "json",
|
||||
"wsfunction": "gradereport_user_get_grades_table",
|
||||
"courseid": courseid,
|
||||
}
|
||||
r = requests.post(url=moodle_serveur, data=param_notes)
|
||||
notes = r.json()
|
||||
notes_evals = {}
|
||||
for etudiant in notes["tables"]:
|
||||
# remise en forme des notes dans un dictionnaire indexe par le nom de la note
|
||||
tab_notes = {}
|
||||
|
||||
for etu_notes in etudiant["tabledata"]:
|
||||
if "grade" in etu_notes:
|
||||
if etu_notes["grade"]["content"] == "-":
|
||||
etu_notes["grade"]["content"] = "SUPR"
|
||||
tab_notes[cleanhtml(etu_notes["itemname"]["content"])] = etu_notes[
|
||||
"grade"
|
||||
]["content"]
|
||||
notes_evals[etudiant["userid"]] = tab_notes
|
||||
return notes_evals
|
||||
|
||||
|
||||
# QUESTION: j'ai l'impression qu'il y a trop de code en commun entre cette fonction et
|
||||
# sco_saisie_notes._form_saisie_notes
|
||||
|
||||
# QUESTION: manque vérification de la présence de décisions de jury ?? (qui devrait bloquer l'import amha)
|
||||
|
||||
|
||||
def import_eval_notes_from_moodle(context, evaluation_id, group_ids=[], REQUEST=None):
|
||||
"""Récuperation des notes sur moodle"""
|
||||
moodle_token = context.get_preference("moodle_ws_token", formsemestre_id)
|
||||
moodle_serveur = context.get_preference("moodle_server_url", formsemestre_id)
|
||||
# Désactive si l'interface n'est pas configurée:
|
||||
if not moodle_serveur or not moodle_token:
|
||||
return "Interface Moodle non paramétrée !"
|
||||
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
evals = context.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||
if not evals:
|
||||
raise ScoValueError("invalid evaluation_id")
|
||||
E = evals[0]
|
||||
M = context.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
# M = context.do_moduleimpl_list( args={ 'moduleimpl_id' : E['moduleimpl_id'] } )[0]
|
||||
formsemestre_id = M["formsemestre_id"]
|
||||
if not can_edit_notes(context, authuser, E["moduleimpl_id"]):
|
||||
return (
|
||||
context.sco_header(REQUEST)
|
||||
+ "<h2>Modification des notes impossible pour %s</h2>" % authusername
|
||||
+ """<p>(vérifiez que le semestre n'est pas verrouillé et que vous
|
||||
avez l'autorisation d'effectuer cette opération)</p>
|
||||
<p><a href="moduleimpl_status?moduleimpl_id=%s">Continuer</a></p>
|
||||
"""
|
||||
% E["moduleimpl_id"]
|
||||
+ context.sco_footer(REQUEST)
|
||||
)
|
||||
|
||||
if E["description"]:
|
||||
page_title = 'Saisie des notes de "%s"' % E["description"]
|
||||
else:
|
||||
page_title = "Saisie des notes"
|
||||
|
||||
# Informations sur les groupes à afficher:
|
||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||
context,
|
||||
group_ids=group_ids,
|
||||
formsemestre_id=formsemestre_id,
|
||||
select_all_when_unspecified=True,
|
||||
etat=None,
|
||||
REQUEST=REQUEST,
|
||||
)
|
||||
|
||||
H = [
|
||||
context.sco_header(
|
||||
REQUEST,
|
||||
page_title=page_title,
|
||||
javascripts=sco_groups_view.JAVASCRIPTS,
|
||||
cssstyles=sco_groups_view.CSSSTYLES,
|
||||
init_qtip=True,
|
||||
),
|
||||
sco_evaluations.evaluation_describe(
|
||||
context, evaluation_id=evaluation_id, REQUEST=REQUEST
|
||||
),
|
||||
"""<span class="eval_title">Import des notes depuis Moodle</span>""",
|
||||
]
|
||||
H.append(
|
||||
"""<div class="saisienote_etape1">
|
||||
<form action="import_from_moodle" method="post">
|
||||
Nom abrégé du cours sur Moodle <input type="text" size="20" name="course_short_name"/>
|
||||
<input type="submit" value="OK"/>
|
||||
<input type="hidden" name="evaluation_id" value="%s"/></form>
|
||||
</div>
|
||||
"""
|
||||
% (evaluation_id)
|
||||
)
|
||||
if "course_short_name" in REQUEST.form:
|
||||
course_short_name = REQUEST.form["course_short_name"]
|
||||
courseid = get_moodle_course_id(moodle_serveur, moodle_token, course_short_name)
|
||||
|
||||
if courseid == 0:
|
||||
H.append(
|
||||
"""
|
||||
<p class="warning">" %s " n'est pas un nom abrégé de cours connu sur ce Moodle</p>
|
||||
"""
|
||||
% course_short_name
|
||||
)
|
||||
else:
|
||||
list_evaluations, bareme = get_evaluation_list(
|
||||
moodle_serveur, moodle_token, course_short_name
|
||||
)
|
||||
|
||||
msg = "<p> <b>Remarque</b> : Si l'étudiant n'a pas de note sur Moodle la note dans cette évaluation sera supprimée</p>"
|
||||
if len(list_evaluations) > 5:
|
||||
msg += "<p>ATTENTION : Le chargement des notes peut prendre beaucoup de temps </p>"
|
||||
H.append(
|
||||
"""<div class="saisienote_etape2">
|
||||
<span class="eval_title"> liste des évaluations du cours %s </span>
|
||||
<form action="import_from_moodle" method="post">
|
||||
"""
|
||||
% course_short_name
|
||||
)
|
||||
pbplage = False
|
||||
for ev in range(0, len(list_evaluations)):
|
||||
# verification du bareme
|
||||
marque = ""
|
||||
if (
|
||||
bareme[list_evaluations[ev]]["min"] != scu.NOTES_MIN
|
||||
or bareme[list_evaluations[ev]]["max"] != E["note_max"]
|
||||
):
|
||||
marque = (
|
||||
"""<span class="redboldtext" >note entre %.2f et %.2f</span>"""
|
||||
% (
|
||||
bareme[list_evaluations[ev]]["min"],
|
||||
bareme[list_evaluations[ev]]["max"],
|
||||
)
|
||||
)
|
||||
pbplage = True
|
||||
H.append(
|
||||
"""
|
||||
<input type="radio" name="num_eval" value=%d > %s %s<br>
|
||||
"""
|
||||
% (ev, list_evaluations[ev], marque)
|
||||
)
|
||||
if pbplage:
|
||||
msg += (
|
||||
'<p><span class="redboldtext">ATTENTION </span>: certaines évaluations ne sont pas dans la plage %.2f - %.2f il faudrait modifier cette cette évaluation pour pouvoir les importer !</p> '
|
||||
% (scu.NOTES_MIN, E["note_max"])
|
||||
)
|
||||
H.append(
|
||||
"""
|
||||
<input type="submit" value="OK"/>
|
||||
<input type="hidden" name="course_short_name" value="%s"/>
|
||||
<input type="hidden" name="evaluation_id" value="%s"/></form>
|
||||
%s
|
||||
</div>
|
||||
"""
|
||||
% (course_short_name, evaluation_id, msg)
|
||||
)
|
||||
if "num_eval" in REQUEST.form:
|
||||
nom_eval = list_evaluations[int(REQUEST.form["num_eval"])]
|
||||
etudiant_info = get_etudiants_from_course(
|
||||
moodle_serveur, moodle_token, course_short_name
|
||||
)
|
||||
moodle_notes = get_grades_from_moodle_course(
|
||||
moodle_serveur, moodle_token, course_short_name
|
||||
)
|
||||
email_id = {}
|
||||
nip_id = {}
|
||||
for etu in groups_infos.members:
|
||||
email = str(etu["email"]).lower()
|
||||
email_id[email] = etu["etudid"]
|
||||
nip_id[etu["code_nip"]] = etu["etudid"]
|
||||
nouvelles_notes = []
|
||||
for etu in etudiant_info:
|
||||
# La présence d'un code nip est prioritaire sur l'adresse mail
|
||||
if "idnumber" in etu:
|
||||
nouvelles_notes.append(
|
||||
(nip_id[etu["idnumber"]], moodle_notes[etu["id"]][nom_eval])
|
||||
)
|
||||
elif etu["email"] in email_id:
|
||||
email = str(etu["email"]).lower()
|
||||
nouvelles_notes.append(
|
||||
(email_id[email], moodle_notes[etu["id"]][nom_eval])
|
||||
)
|
||||
updiag = do_moodle_import(
|
||||
context,
|
||||
REQUEST,
|
||||
nouvelles_notes,
|
||||
"Moodle/%s/%s" % (course_short_name, nom_eval),
|
||||
)
|
||||
# updiag=[0,"en test: merci de patienter"]
|
||||
if updiag[0]:
|
||||
H.append(updiag[1])
|
||||
H.append(
|
||||
"""<p>Notes chargées.
|
||||
<a class="stdlink" href="moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s">
|
||||
Revenir au tableau de bord du module</a>
|
||||
|
||||
<a class="stdlink" href="saisie_notes?evaluation_id=%(evaluation_id)s">Charger d'autres notes dans cette évaluation</a>
|
||||
</p>"""
|
||||
% E
|
||||
)
|
||||
else:
|
||||
H.append(
|
||||
"""<p class="redboldtext">Notes non chargées !</p>"""
|
||||
+ updiag[1]
|
||||
)
|
||||
H.append(
|
||||
"""
|
||||
<p><a class="stdlink" href="saisie_notes_tableur?evaluation_id=%(evaluation_id)s">
|
||||
Reprendre</a>
|
||||
</p>"""
|
||||
% E
|
||||
)
|
||||
#
|
||||
H.append("""<h3>Autres opérations</h3><ul>""")
|
||||
if can_edit_notes(
|
||||
context, REQUEST.AUTHENTICATED_USER, E["moduleimpl_id"], allow_ens=False
|
||||
):
|
||||
H.append(
|
||||
"""
|
||||
<li>
|
||||
<form action="do_evaluation_set_missing" method="get">
|
||||
Mettre toutes les notes manquantes à <input type="text" size="5" name="value"/>
|
||||
<input type="submit" value="OK"/>
|
||||
<input type="hidden" name="evaluation_id" value="%s"/>
|
||||
<em>ABS indique "absent" (zéro), EXC "excusé" (neutralisées), ATT "attente"</em>
|
||||
</form>
|
||||
</li>
|
||||
<li><a class="stdlink" href="evaluation_suppress_alln?evaluation_id=%s">Effacer toutes les notes de cette évaluation
|
||||
</a> (ceci permet ensuite de supprimer l'évaluation si besoin)
|
||||
</li>"""
|
||||
% (evaluation_id, evaluation_id)
|
||||
) #'
|
||||
H.append(
|
||||
"""<li><a class="stdlink" href="moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s">Revenir au module</a></li>
|
||||
<li><a class="stdlink" href="saisie_notes?evaluation_id=%(evaluation_id)s">Revenir au formulaire de saisie</a></li>
|
||||
</ul>"""
|
||||
% E
|
||||
)
|
||||
H.append(context.sco_footer(REQUEST))
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
# QUESTION: Beaucoup de code dupliqué de sco-saisie_notes => maintenance trop difficile à terme
|
||||
# => refactoring nécessaire
|
||||
def do_moodle_import(context, REQUEST, notes, comment):
|
||||
"""import moodle"""
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
evaluation_id = REQUEST.form["evaluation_id"]
|
||||
# comment = "Importée de moodle"#REQUEST.form['comment']
|
||||
E = context.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
M = context.do_moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
# M = context.do_moduleimpl_withmodule_list( args={ 'moduleimpl_id' : E['moduleimpl_id'] } )[0]
|
||||
# Check access
|
||||
# (admin, respformation, and responsable_id)
|
||||
# if not context.can_edit_notes( authuser, E['moduleimpl_id'] ):
|
||||
if not can_edit_notes(context, authuser, E["moduleimpl_id"]):
|
||||
# XXX imaginer un redirect + msg erreur
|
||||
raise AccessDenied("Modification des notes impossible pour %s" % authuser)
|
||||
#
|
||||
diag = []
|
||||
try:
|
||||
# -- check values
|
||||
L, invalids, withoutnotes, absents, tosuppress = _check_notes(
|
||||
notes, E, M["module"]
|
||||
)
|
||||
if len(invalids):
|
||||
diag.append(
|
||||
"Erreur: Moodle fournit %d notes invalides vérifiez que la note maximale est bien la même sur scodoc et sur Moodle</p>"
|
||||
% len(invalids)
|
||||
)
|
||||
if len(invalids) < 25:
|
||||
etudsnames = [
|
||||
context.getEtudInfo(etudid=etudid, filled=True)[0]["nomprenom"]
|
||||
for etudid in invalids
|
||||
]
|
||||
diag.append("Notes invalides pour: " + ", ".join(etudsnames))
|
||||
raise InvalidNoteValue()
|
||||
else:
|
||||
nb_changed, nb_suppress, existing_decisions = _notes_add(
|
||||
context, authuser, evaluation_id, L, comment
|
||||
)
|
||||
# news
|
||||
cnx = context.GetDBConnexion()
|
||||
E = context.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||
M = context.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
# M = context.do_moduleimpl_list( args={ 'moduleimpl_id':E['moduleimpl_id'] } )[0]
|
||||
mod = context.do_module_list(args={"module_id": M["module_id"]})[0]
|
||||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||
sco_news.add(
|
||||
context,
|
||||
REQUEST,
|
||||
typ=NEWS_NOTE,
|
||||
object=M["moduleimpl_id"],
|
||||
text='Chargement notes dans <a href="%(url)s">%(titre)s</a>' % mod,
|
||||
url=mod["url"],
|
||||
)
|
||||
|
||||
msg = (
|
||||
"<p>%d notes changées (%d sans notes, %d absents, %d note supprimées)</p>"
|
||||
% (nb_changed, len(withoutnotes), len(absents), nb_suppress)
|
||||
)
|
||||
if existing_decisions:
|
||||
msg += """<p class="warning">Important: il y avait déjà des décisions de jury enregistrées, qui sont potentiellement à revoir suite à cette modification !</p>"""
|
||||
# msg += '<p>' + str(notes) # debug
|
||||
return 1, msg
|
||||
|
||||
except InvalidNoteValue:
|
||||
if diag:
|
||||
msg = (
|
||||
'<ul class="tf-msg"><li class="tf_msg">'
|
||||
+ '</li><li class="tf_msg">'.join(diag)
|
||||
+ "</li></ul>"
|
||||
)
|
||||
else:
|
||||
msg = '<ul class="tf-msg"><li class="tf_msg">Une erreur est survenue</li></ul>'
|
||||
return 0, msg + "<p>(pas de notes modifiées)</p>"
|
Loading…
Reference in New Issue
Block a user