intégration (non testée) du code de P.-A. J.
This commit is contained in:
parent
e943e7f283
commit
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_recapcomplet
|
||||||
import sco_liste_notes
|
import sco_liste_notes
|
||||||
import sco_saisie_notes
|
import sco_saisie_notes
|
||||||
|
import sco_saisie_notes_moodle
|
||||||
import sco_placement
|
import sco_placement
|
||||||
import sco_undo_notes
|
import sco_undo_notes
|
||||||
import sco_formations
|
import sco_formations
|
||||||
@ -2460,6 +2461,9 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
|
|||||||
security.declareProtected(ScoEnsView, "saisie_notes_tableur")
|
security.declareProtected(ScoEnsView, "saisie_notes_tableur")
|
||||||
saisie_notes_tableur = sco_saisie_notes.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")
|
security.declareProtected(ScoEnsView, "feuille_saisie_notes")
|
||||||
feuille_saisie_notes = sco_saisie_notes.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",
|
"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])
|
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("""<div id="group-tabs"><table><tr><td>""")
|
||||||
H.append(sco_groups_view.form_groups_choice(context, groups_infos))
|
H.append(sco_groups_view.form_groups_choice(context, groups_infos))
|
||||||
H.append('</td><td style="padding-left: 35px;">')
|
H.append('</td><td style="padding-left: 35px;">')
|
||||||
H.append(
|
|
||||||
htmlutils.make_menu(
|
# Pour savoir si l'interface Moodle est configurée:
|
||||||
"Autres opérations",
|
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",
|
"title": "Saisie par fichier tableur",
|
||||||
"id": "menu_saisie_tableur",
|
"id": "menu_saisie_tableur",
|
||||||
"url": "/saisie_notes_tableur?evaluation_id=%s&%s"
|
"url": "/saisie_notes_tableur?evaluation_id=%s&%s"
|
||||||
% (E["evaluation_id"], groups_infos.groups_query_args),
|
% (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",
|
"title": "Voir toutes les notes du module",
|
||||||
"url": "/evaluation_listenotes?moduleimpl_id=%s"
|
"url": "/evaluation_listenotes?moduleimpl_id=%s" % E["moduleimpl_id"],
|
||||||
% E["moduleimpl_id"],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Effacer toutes les notes de cette évaluation",
|
"title": "Effacer toutes les notes de cette évaluation",
|
||||||
"url": "/evaluation_suppress_alln?evaluation_id=%s"
|
"url": "/evaluation_suppress_alln?evaluation_id=%s" % (E["evaluation_id"],),
|
||||||
% (E["evaluation_id"],),
|
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
|
|
||||||
|
H.append(
|
||||||
|
htmlutils.make_menu(
|
||||||
|
"Autres opérations",
|
||||||
|
menu_items,
|
||||||
base_url=context.absolute_url(),
|
base_url=context.absolute_url(),
|
||||||
alone=True,
|
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