Fixes - fiche utilisateur ok

This commit is contained in:
Emmanuel Viennet 2021-08-10 17:12:10 +02:00
parent 77fc1c7de2
commit 4a43e96fe9
24 changed files with 148 additions and 95 deletions

View File

@ -151,5 +151,5 @@ class EtudAnnotation(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
etudid = db.Column(db.Integer) # sans contrainte pour garder logs après suppression etudid = db.Column(db.Integer) # sans contrainte pour garder logs après suppression
authenticated_user = db.Column(db.Text) author = db.Column(db.Text) # le pseudo (user_name)
comment = db.Column(db.Text) comment = db.Column(db.Text)

View File

@ -114,7 +114,7 @@ class NotesAppreciations(db.Model):
db.Integer, db.Integer,
db.ForeignKey("notes_formsemestre.id"), db.ForeignKey("notes_formsemestre.id"),
) )
author = db.Column(db.Text) # login, sans contrainte author = db.Column(db.Text) # le pseudo (user_name), sans contrainte
comment = db.Column(db.Text) # texte libre comment = db.Column(db.Text) # texte libre

View File

@ -301,6 +301,8 @@ class EditableTable(object):
vals = dictfilter(args, self.dbfields, self.filter_nulls) vals = dictfilter(args, self.dbfields, self.filter_nulls)
if self.id_name in vals: if self.id_name in vals:
del vals[self.id_name] del vals[self.id_name]
if "id" in vals:
del vals["id"]
if self.html_quote: if self.html_quote:
quote_dict(vals) # quote all HTML markup quote_dict(vals) # quote all HTML markup
# format value # format value

View File

@ -393,7 +393,7 @@ def get_avis_poursuite_par_etudiant(
result: [ chaine unicode, chaine unicode ] result: [ chaine unicode, chaine unicode ]
""" """
if pe_tools.PE_DEBUG: if pe_tools.PE_DEBUG:
pe_tools.pe_print(jury.syntheseJury[etudid]["nom"] + " " + etudid) pe_tools.pe_print(jury.syntheseJury[etudid]["nom"] + " " + str(etudid))
civilite_str = jury.syntheseJury[etudid]["civilite_str"] civilite_str = jury.syntheseJury[etudid]["civilite_str"]
nom = jury.syntheseJury[etudid]["nom"].replace(" ", "-") nom = jury.syntheseJury[etudid]["nom"].replace(" ", "-")
@ -405,7 +405,7 @@ def get_avis_poursuite_par_etudiant(
+ "_" + "_"
+ pe_tools.remove_accents(prenom) + pe_tools.remove_accents(prenom)
+ "_" + "_"
+ etudid + str(etudid)
) )
if pe_tools.PE_DEBUG: if pe_tools.PE_DEBUG:
pe_tools.pe_print("fichier latex =" + nom_fichier, type(nom_fichier)) pe_tools.pe_print("fichier latex =" + nom_fichier, type(nom_fichier))

View File

@ -423,7 +423,7 @@ class JuryPE(object):
fid = sesFormsemestre_idValidants[i] fid = sesFormsemestre_idValidants[i]
self.PARCOURSINFO_DICT[etudid][nom_sem] = fid # ['formsemestre_id'] self.PARCOURSINFO_DICT[etudid][nom_sem] = fid # ['formsemestre_id']
if fid != None and pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 2: if fid != None and pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 2:
pe_tools.pe_print(nom_sem + "=" + fid, end="") pe_tools.pe_print(nom_sem + "=" + str(fid), end="")
# self.get_moyennesEtClassements_par_semestre_d_un_etudiant( etudid, fid ) # self.get_moyennesEtClassements_par_semestre_d_un_etudiant( etudid, fid )
# Quelles sont ses années validantes ('1A', '2A') et ses parcours (3S, 4S) validants ? # Quelles sont ses années validantes ('1A', '2A') et ses parcours (3S, 4S) validants ?
@ -1170,7 +1170,7 @@ class JuryPE(object):
nom_sem nom_sem
] # le formsemestre_id du semestre taggué de l'étudiant ] # le formsemestre_id du semestre taggué de l'étudiant
semtag = self.semTagDict[semtagid] semtag = self.semTagDict[semtagid]
chaine += "Semestre " + nom_sem + semtagid + "\n" chaine += "Semestre " + nom_sem + str(semtagid) + "\n"
# le détail du calcul tag par tag # le détail du calcul tag par tag
# chaine += "Détail du calcul du tag\n" # chaine += "Détail du calcul du tag\n"
# chaine += "-----------------------\n" # chaine += "-----------------------\n"

View File

@ -360,7 +360,12 @@ class SemestreTag(pe_tagtable.TableTag):
lesEtuds = [] lesEtuds = []
for etudid in lesEtuds: for etudid in lesEtuds:
descr = "%15s" % self.nt.get_nom_short(etudid)[:15] + delim + etudid + delim descr = (
"%15s" % self.nt.get_nom_short(etudid)[:15]
+ delim
+ str(etudid)
+ delim
)
if tag in taglist: if tag in taglist:
for modimpl_id in self.tagdict[tag]: for modimpl_id in self.tagdict[tag]:
(note, coeff) = self.get_noteEtCoeff_modimpl(modimpl_id, etudid) (note, coeff) = self.get_noteEtCoeff_modimpl(modimpl_id, etudid)
@ -433,7 +438,7 @@ class SemestreTag(pe_tagtable.TableTag):
+ "*" + "*"
+ str(mod["ponderation"]) + str(mod["ponderation"])
+ ") " + ") "
+ modid + str(modid)
+ ", " + ", "
) )
chaine += "\n" chaine += "\n"

View File

@ -101,7 +101,7 @@ class BaseArchiver(object):
if not os.path.isdir(dept_dir): if not os.path.isdir(dept_dir):
log("creating directory %s" % dept_dir) log("creating directory %s" % dept_dir)
os.mkdir(dept_dir) os.mkdir(dept_dir)
obj_dir = os.path.join(dept_dir, oid) obj_dir = os.path.join(dept_dir, str(oid))
if not os.path.isdir(obj_dir): if not os.path.isdir(obj_dir):
log("creating directory %s" % obj_dir) log("creating directory %s" % obj_dir)
os.mkdir(obj_dir) os.mkdir(obj_dir)
@ -144,7 +144,7 @@ class BaseArchiver(object):
dt = [int(x) for x in os.path.split(archive_id)[1].split("-")] dt = [int(x) for x in os.path.split(archive_id)[1].split("-")]
return datetime.datetime(*dt) return datetime.datetime(*dt)
def list_archive(self, archive_id): def list_archive(self, archive_id: str) -> str:
"""Return list of filenames (without path) in archive""" """Return list of filenames (without path) in archive"""
try: try:
scu.GSL.acquire() scu.GSL.acquire()
@ -152,9 +152,7 @@ class BaseArchiver(object):
finally: finally:
scu.GSL.release() scu.GSL.release()
files.sort() files.sort()
return [ return [f for f in files if f and f[0] != "_"]
f.encode(scu.SCO_ENCODING) for f in files if f and f[0] != "_"
] # sco8 XXX
def get_archive_name(self, archive_id): def get_archive_name(self, archive_id):
"""name identifying archive, to be used in web URLs""" """name identifying archive, to be used in web URLs"""
@ -183,7 +181,7 @@ class BaseArchiver(object):
"""Return description of archive""" """Return description of archive"""
return open(os.path.join(archive_id, "_description.txt")).read() return open(os.path.join(archive_id, "_description.txt")).read()
def create_obj_archive(self, context, oid, description): def create_obj_archive(self, context, oid: int, description: str):
"""Creates a new archive for this object and returns its id.""" """Creates a new archive for this object and returns its id."""
archive_id = ( archive_id = (
self.get_obj_dir(context, oid) self.get_obj_dir(context, oid)
@ -196,10 +194,10 @@ class BaseArchiver(object):
os.mkdir(archive_id) # if exists, raises an OSError os.mkdir(archive_id) # if exists, raises an OSError
finally: finally:
scu.GSL.release() scu.GSL.release()
self.store(archive_id, "_description.txt", description) self.store(archive_id, "_description.txt", description.encode("utf-8"))
return archive_id return archive_id
def store(self, archive_id, filename, data): def store(self, archive_id: str, filename: str, data: bytes):
"""Store data in archive, under given filename. """Store data in archive, under given filename.
Filename may be modified (sanitized): return used filename Filename may be modified (sanitized): return used filename
The file is created or replaced. The file is created or replaced.
@ -209,21 +207,21 @@ class BaseArchiver(object):
try: try:
scu.GSL.acquire() scu.GSL.acquire()
fname = os.path.join(archive_id, filename) fname = os.path.join(archive_id, filename)
f = open(fname, "w") f = open(fname, "wb")
f.write(data) f.write(data)
f.close() f.close()
finally: finally:
scu.GSL.release() scu.GSL.release()
return filename return filename
def get(self, archive_id, filename): def get(self, archive_id: str, filename: str):
"""Retreive data""" """Retreive data"""
if not scu.is_valid_filename(filename): if not scu.is_valid_filename(filename):
log('Archiver.get: invalid filename "%s"' % filename) log('Archiver.get: invalid filename "%s"' % filename)
raise ValueError("invalid filename") raise ValueError("invalid filename")
fname = os.path.join(archive_id, filename) fname = os.path.join(archive_id, filename)
log("reading archive file %s" % fname) log("reading archive file %s" % fname)
return open(fname).read() return open(fname, "rb").read()
def get_archived_file(self, context, REQUEST, oid, archive_name, filename): def get_archived_file(self, context, REQUEST, oid, archive_name, filename):
"""Recupere donnees du fichier indiqué et envoie au client""" """Recupere donnees du fichier indiqué et envoie au client"""
@ -242,8 +240,8 @@ class BaseArchiver(object):
return scu.sendCSVFile(REQUEST, data, filename) return scu.sendCSVFile(REQUEST, data, filename)
elif ext == ".pdf": elif ext == ".pdf":
return scu.sendPDFFile(REQUEST, data, filename) return scu.sendPDFFile(REQUEST, data, filename)
REQUEST.RESPONSE.setHeader("content-type", "application/octet-stream")
return data # should set mimetype... return data # should set mimetype for known files like images
class SemsArchiver(BaseArchiver): class SemsArchiver(BaseArchiver):

View File

@ -169,9 +169,9 @@ def etud_upload_file_form(context, REQUEST, etudid):
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
) )
else: else:
data = tf[2]["datafile"][0].read() data = tf[2]["datafile"].read()
descr = tf[2]["description"] descr = tf[2]["description"]
filename = tf[2]["datafile"][0].filename filename = tf[2]["datafile"].filename
_store_etud_file_to_new_archive( _store_etud_file_to_new_archive(
context, REQUEST, etudid, data, filename, description=descr context, REQUEST, etudid, data, filename, description=descr
) )

View File

@ -28,7 +28,7 @@
""" """
Rapport (table) avec dernier semestre fréquenté et débouché de chaque étudiant Rapport (table) avec dernier semestre fréquenté et débouché de chaque étudiant
""" """
import http
from flask import url_for, g from flask import url_for, g
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
@ -372,3 +372,4 @@ def itemsuivi_tag_set(context, itemsuivi_id="", taglist=[], REQUEST=None):
for tagname in to_del: for tagname in to_del:
t = ItemSuiviTag(context, tagname) t = ItemSuiviTag(context, tagname)
t.remove_tag_from_object(itemsuivi_id) t.remove_tag_from_object(itemsuivi_id)
return "", http.HTTPStatus.NO_CONTENT

View File

@ -307,9 +307,13 @@ def check_nom_prenom(cnx, nom="", prenom="", etudid=None):
return False, 0 return False, 0
# Now count homonyms: # Now count homonyms:
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
req = "select etudid from identite where lower(nom) ~ %(nom)s and lower(prenom) ~ %(prenom)s" req = """SELECT id
FROM identite
WHERE lower(nom) ~ %(nom)s
and lower(prenom) ~ %(prenom)s
"""
if etudid: if etudid:
req += " and etudid <> %(etudid)s" req += " and id <> %(etudid)s"
cursor.execute(req, {"nom": nom, "prenom": prenom, "etudid": etudid}) cursor.execute(req, {"nom": nom, "prenom": prenom, "etudid": etudid})
res = cursor.dictfetchall() res = cursor.dictfetchall()
return True, len(res) return True, len(res)
@ -559,6 +563,7 @@ _admissionEditor = ndb.EditableTable(
"annee_bac": pivot_year, "annee_bac": pivot_year,
"classement": ndb.int_null_is_null, "classement": ndb.int_null_is_null,
"apb_classement_gr": ndb.int_null_is_null, "apb_classement_gr": ndb.int_null_is_null,
"boursier_prec": bool,
}, },
output_formators={"type_admission": lambda x: x or scu.TYPE_ADMISSION_DEFAULT}, output_formators={"type_admission": lambda x: x or scu.TYPE_ADMISSION_DEFAULT},
convert_null_outputs_to_empty=True, convert_null_outputs_to_empty=True,
@ -747,8 +752,7 @@ _etud_annotationsEditor = ndb.EditableTable(
"etudid", "etudid",
"author", "author",
"comment", "comment",
"zope_authenticated_user", "author",
"zope_remote_addr",
), ),
sortkey="date desc", sortkey="date desc",
convert_null_outputs_to_empty=True, convert_null_outputs_to_empty=True,
@ -786,8 +790,7 @@ _appreciationsEditor = ndb.EditableTable(
"formsemestre_id", "formsemestre_id",
"author", "author",
"comment", "comment",
"zope_authenticated_user", "author",
"zope_remote_addr",
), ),
sortkey="date desc", sortkey="date desc",
convert_null_outputs_to_empty=True, convert_null_outputs_to_empty=True,

View File

@ -137,7 +137,7 @@ def formation_export(
) )
def formation_import_xml(context, doc, import_tags=True): def formation_import_xml(context, doc: str, import_tags=True):
"""Create a formation from XML representation """Create a formation from XML representation
(format dumped by formation_export( format='xml' )) (format dumped by formation_export( format='xml' ))
XML may contain object (UE, modules) ids: this function returns two XML may contain object (UE, modules) ids: this function returns two

View File

@ -1319,10 +1319,14 @@ def formsemestre_delete(context, formsemestre_id, REQUEST=None):
return "\n".join(H) + html_sco_header.sco_footer() return "\n".join(H) + html_sco_header.sco_footer()
elif tf[0] == -1: # cancel elif tf[0] == -1: # cancel
return flask.redirect( return flask.redirect(
scu.NotesURL() + "/formsemestre_status?formsemestre_id=" + formsemestre_id scu.NotesURL()
+ "/formsemestre_status?formsemestre_id="
+ str(formsemestre_id)
) )
else: else:
return flask.redirect("formsemestre_delete2?formsemestre_id=" + formsemestre_id) return flask.redirect(
"formsemestre_delete2?formsemestre_id=" + str(formsemestre_id)
)
def formsemestre_delete2( def formsemestre_delete2(

View File

@ -181,7 +181,7 @@ def formsemestre_validation_etud_form(
if not desturl: if not desturl:
desturl = ( desturl = (
"formsemestre_recapcomplet?modejury=1&hidemodules=1&hidebac=1&pref_override=0&formsemestre_id=" "formsemestre_recapcomplet?modejury=1&hidemodules=1&hidebac=1&pref_override=0&formsemestre_id="
+ formsemestre_id + str(formsemestre_id)
) )
if sortcol: if sortcol:
desturl += ( desturl += (
@ -427,7 +427,7 @@ def _redirect_valid_choice(
# flask.redirect( 'formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1&desturl=%s' % (formsemestre_id, etudid, desturl) ) # flask.redirect( 'formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1&desturl=%s' % (formsemestre_id, etudid, desturl) )
# else: # else:
# if not desturl: # if not desturl:
# desturl = 'formsemestre_recapcomplet?modejury=1&hidemodules=1&formsemestre_id=' + formsemestre_id # desturl = 'formsemestre_recapcomplet?modejury=1&hidemodules=1&formsemestre_id=' + str(formsemestre_id)
# flask.redirect(desturl) # flask.redirect(desturl)
@ -1082,7 +1082,7 @@ def formsemestre_validate_previous_ue(context, formsemestre_id, etudid, REQUEST=
return "\n".join(H) + tf[1] + X + warn + html_sco_header.sco_footer() return "\n".join(H) + tf[1] + X + warn + html_sco_header.sco_footer()
elif tf[0] == -1: elif tf[0] == -1:
return flask.redirect( return flask.redirect(
scu.NotesURL() + "/formsemestre_status?formsemestre_id=" + formsemestre_id scu.NotesURL() + "/formsemestre_status?formsemestre_id=" + str(formsemestre_id)
) )
else: else:
if tf[2]["semestre_id"]: if tf[2]["semestre_id"]:

View File

@ -1035,7 +1035,9 @@ def partition_delete(
# redirect to partition edit page: # redirect to partition edit page:
if redirect: if redirect:
return flask.redirect("editPartitionForm?formsemestre_id=" + formsemestre_id) return flask.redirect(
"editPartitionForm?formsemestre_id=" + str(formsemestre_id)
)
def partition_move(context, partition_id, after=0, REQUEST=None, redirect=1): def partition_move(context, partition_id, after=0, REQUEST=None, redirect=1):
@ -1068,7 +1070,9 @@ def partition_move(context, partition_id, after=0, REQUEST=None, redirect=1):
# redirect to partition edit page: # redirect to partition edit page:
if redirect: if redirect:
return flask.redirect("editPartitionForm?formsemestre_id=" + formsemestre_id) return flask.redirect(
"editPartitionForm?formsemestre_id=" + str(formsemestre_id)
)
def partition_rename(context, partition_id, REQUEST=None): def partition_rename(context, partition_id, REQUEST=None):
@ -1105,7 +1109,9 @@ def partition_rename(context, partition_id, REQUEST=None):
+ html_sco_header.sco_footer() + html_sco_header.sco_footer()
) )
elif tf[0] == -1: elif tf[0] == -1:
return flask.redirect("editPartitionForm?formsemestre_id=" + formsemestre_id) return flask.redirect(
"editPartitionForm?formsemestre_id=" + str(formsemestre_id)
)
else: else:
# form submission # form submission
return partition_set_name( return partition_set_name(
@ -1146,7 +1152,9 @@ def partition_set_name(context, partition_id, partition_name, REQUEST=None, redi
# redirect to partition edit page: # redirect to partition edit page:
if redirect: if redirect:
return flask.redirect("editPartitionForm?formsemestre_id=" + formsemestre_id) return flask.redirect(
"editPartitionForm?formsemestre_id=" + str(formsemestre_id)
)
def group_set_name(context, group_id, group_name, REQUEST=None, redirect=1): def group_set_name(context, group_id, group_name, REQUEST=None, redirect=1):
@ -1531,7 +1539,7 @@ def form_group_choice(
def make_query_groups(group_ids): def make_query_groups(group_ids):
if group_ids: if group_ids:
return "&".join(["group_ids%3Alist=" + group_id for group_id in group_ids]) return "&".join(["group_ids%3Alist=" + str(group_id) for group_id in group_ids])
else: else:
return "" return ""

View File

@ -353,7 +353,7 @@ def formsemestre_inscr_passage(
dest_url="formsemestre_inscr_passage", dest_url="formsemestre_inscr_passage",
add_headers=False, add_headers=False,
cancel_url="formsemestre_inscr_passage?formsemestre_id=" cancel_url="formsemestre_inscr_passage?formsemestre_id="
+ formsemestre_id, + str(formsemestre_id),
OK="Effectuer l'opération", OK="Effectuer l'opération",
parameters={ parameters={
"formsemestre_id": formsemestre_id, "formsemestre_id": formsemestre_id,

View File

@ -295,7 +295,7 @@ def ficheEtud(context, etudid=None, REQUEST=None):
), ),
) )
alist.append( alist.append(
'<tr><td><span class="annodate">Le %(date)s par %(zope_authenticated_user)s : </span><span class="annoc">%(comment)s</span></td>%(dellink)s</tr>' '<tr><td><span class="annodate">Le %(date)s par %(author)s : </span><span class="annoc">%(comment)s</span></td>%(dellink)s</tr>'
% a % a
) )
info["liste_annotations"] = "\n".join(alist) info["liste_annotations"] = "\n".join(alist)

View File

@ -95,9 +95,9 @@ def can_suppress_annotation(annotation_id):
if len(annos) != 1: if len(annos) != 1:
raise sco_exceptions.ScoValueError("annotation inexistante !") raise sco_exceptions.ScoValueError("annotation inexistante !")
anno = annos[0] anno = annos[0]
return ( return (current_user.user_name == anno["author"]) or current_user.has_permission(
current_user.user_name == anno["zope_authenticated_user"] Permission.ScoEtudAddAnnotations
) or current_user.has_permission(Permission.ScoEtudAddAnnotations) )
def can_edit_suivi(): def can_edit_suivi():

View File

@ -321,7 +321,7 @@ def get_new_filename(context, etudid):
The path is constructed as: Fxx/etudid The path is constructed as: Fxx/etudid
""" """
dept = scu.get_dept_id() dept = scu.get_dept_id()
return find_new_dir() + dept + "_" + etudid return find_new_dir() + dept + "_" + str(etudid)
def find_new_dir(): def find_new_dir():

View File

@ -1123,13 +1123,13 @@ def _form_saisie_notes(context, E, M, group_ids, destination="", REQUEST=None):
explanation += '<span id="jurylink_%s" class="jurylink"></span>' % etudid explanation += '<span id="jurylink_%s" class="jurylink"></span>' % etudid
# Valeur actuelle du champ: # Valeur actuelle du champ:
initvalues["note_" + etudid] = e["val"] initvalues["note_" + str(etudid)] = e["val"]
label_link = '<a class="etudinfo" id="%s">%s</a>' % (etudid, label) label_link = '<a class="etudinfo" id="%s">%s</a>' % (etudid, label)
# Element de formulaire: # Element de formulaire:
descr.append( descr.append(
( (
"note_" + etudid, "note_" + str(etudid),
{ {
"size": 5, "size": 5,
"title": label_link, "title": label_link,

View File

@ -211,7 +211,7 @@ def formsemestre_synchro_etuds(
dest_url="formsemestre_synchro_etuds", dest_url="formsemestre_synchro_etuds",
add_headers=False, add_headers=False,
cancel_url="formsemestre_synchro_etuds?formsemestre_id=" cancel_url="formsemestre_synchro_etuds?formsemestre_id="
+ formsemestre_id, + str(formsemestre_id),
OK="Effectuer l'opération", OK="Effectuer l'opération",
parameters={ parameters={
"formsemestre_id": formsemestre_id, "formsemestre_id": formsemestre_id,

View File

@ -1173,7 +1173,7 @@ def AddBilletAbsenceForm(context, etudid, REQUEST=None):
justified=tf[2]["justified"], justified=tf[2]["justified"],
) )
) )
return flask.redirect("listeBilletsEtud?etudid=" + etudid) return flask.redirect("listeBilletsEtud?etudid=" + str(etudid))
def _tableBillets(context, billets, etud=None, title=""): def _tableBillets(context, billets, etud=None, title=""):

View File

@ -40,6 +40,7 @@ from xml.etree import ElementTree
import flask import flask
from flask import url_for, g from flask import url_for, g
from flask import current_app from flask import current_app
from flask_login import current_user
from config import Config from config import Config
import scodoc_manager import scodoc_manager
@ -483,7 +484,7 @@ def formation_import_xml_form(context, REQUEST):
return flask.redirect(scu.NotesURL()) return flask.redirect(scu.NotesURL())
else: else:
formation_id, _, _ = sco_formations.formation_import_xml( formation_id, _, _ = sco_formations.formation_import_xml(
context, tf[2]["xmlfile"] context, tf[2]["xmlfile"].read()
) )
return ( return (
@ -1078,7 +1079,9 @@ def edit_ue_expr(context, REQUEST, formsemestre_id, ue_id):
if tf[0] == 0: if tf[0] == 0:
return "\n".join(H) + tf[1] + html_sco_header.sco_footer() return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
elif tf[0] == -1: elif tf[0] == -1:
return flask.redirect("formsemestre_status?formsemestre_id=" + formsemestre_id) return flask.redirect(
"formsemestre_status?formsemestre_id=" + str(formsemestre_id)
)
else: else:
if el: if el:
el[0]["computation_expr"] = tf[2]["computation_expr"] el[0]["computation_expr"] = tf[2]["computation_expr"]
@ -1091,7 +1094,7 @@ def edit_ue_expr(context, REQUEST, formsemestre_id, ue_id):
) # > modif regle calcul ) # > modif regle calcul
return flask.redirect( return flask.redirect(
"formsemestre_status?formsemestre_id=" "formsemestre_status?formsemestre_id="
+ formsemestre_id + str(formsemestre_id)
+ "&head_message=règle%20de%20calcul%20modifiée" + "&head_message=règle%20de%20calcul%20modifiée"
) )
@ -1329,7 +1332,7 @@ def etud_desinscrit_ue(context, etudid, formsemestre_id, ue_id, REQUEST=None):
return flask.redirect( return flask.redirect(
scu.ScoURL() scu.ScoURL()
+ "/Notes/moduleimpl_inscriptions_stats?formsemestre_id=" + "/Notes/moduleimpl_inscriptions_stats?formsemestre_id="
+ formsemestre_id + str(formsemestre_id)
) )
@ -1344,7 +1347,7 @@ def etud_inscrit_ue(context, etudid, formsemestre_id, ue_id, REQUEST=None):
return flask.redirect( return flask.redirect(
scu.ScoURL() scu.ScoURL()
+ "/Notes/moduleimpl_inscriptions_stats?formsemestre_id=" + "/Notes/moduleimpl_inscriptions_stats?formsemestre_id="
+ formsemestre_id + str(formsemestre_id)
) )
@ -1767,7 +1770,6 @@ def appreciation_add_form(
): ):
"form ajout ou edition d'une appreciation" "form ajout ou edition d'une appreciation"
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
authuser = REQUEST.AUTHENTICATED_USER
if id: # edit mode if id: # edit mode
apps = sco_etud.appreciations_list(cnx, args={"id": id}) apps = sco_etud.appreciations_list(cnx, args={"id": id})
if not apps: if not apps:
@ -1783,8 +1785,8 @@ def appreciation_add_form(
edit = 0 edit = 0
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
# check custom access permission # check custom access permission
can_edit_app = (str(authuser) in sem["responsables"]) or ( can_edit_app = (current_user.id in sem["responsables"]) or (
authuser.has_permission(Permission.ScoEtudInscrit) current_user.has_permission(Permission.ScoEtudInscrit)
) )
if not can_edit_app: if not can_edit_app:
raise AccessDenied("vous n'avez pas le droit d'ajouter une appreciation") raise AccessDenied("vous n'avez pas le droit d'ajouter une appreciation")
@ -1839,10 +1841,8 @@ def appreciation_add_form(
args = { args = {
"etudid": etudid, "etudid": etudid,
"formsemestre_id": formsemestre_id, "formsemestre_id": formsemestre_id,
"author": str(authuser), "author": current_user.user_name,
"comment": tf[2]["comment"], "comment": tf[2]["comment"],
"zope_authenticated_user": str(authuser),
"zope_remote_addr": REQUEST.REMOTE_ADDR,
} }
if edit: if edit:
args["id"] = id args["id"] = id

View File

@ -43,6 +43,7 @@ import psycopg2
import flask import flask
from flask import g, url_for from flask import g, url_for
from flask import current_app from flask import current_app
from flask_login import current_user
from config import Config from config import Config
import scodoc_manager import scodoc_manager
@ -454,18 +455,28 @@ sco_publish(
# Debouche / devenir etudiant # Debouche / devenir etudiant
sco_publish( sco_publish(
"/itemsuivi_suppress", sco_debouche.itemsuivi_suppress, Permission.ScoEtudChangeAdr "/itemsuivi_suppress",
sco_debouche.itemsuivi_suppress,
Permission.ScoEtudChangeAdr,
methods=["GET", "POST"],
) )
sco_publish( sco_publish(
"/itemsuivi_create", sco_debouche.itemsuivi_create, Permission.ScoEtudChangeAdr "/itemsuivi_create",
sco_debouche.itemsuivi_create,
Permission.ScoEtudChangeAdr,
methods=["GET", "POST"],
) )
sco_publish( sco_publish(
"/itemsuivi_set_date", sco_debouche.itemsuivi_set_date, Permission.ScoEtudChangeAdr "/itemsuivi_set_date",
sco_debouche.itemsuivi_set_date,
Permission.ScoEtudChangeAdr,
methods=["GET", "POST"],
) )
sco_publish( sco_publish(
"/itemsuivi_set_situation", "/itemsuivi_set_situation",
sco_debouche.itemsuivi_set_situation, sco_debouche.itemsuivi_set_situation,
Permission.ScoEtudChangeAdr, Permission.ScoEtudChangeAdr,
methods=["GET", "POST"],
) )
sco_publish( sco_publish(
"/itemsuivi_list_etud", sco_debouche.itemsuivi_list_etud, Permission.ScoView "/itemsuivi_list_etud", sco_debouche.itemsuivi_list_etud, Permission.ScoView
@ -475,24 +486,25 @@ sco_publish(
"/itemsuivi_tag_search", sco_debouche.itemsuivi_tag_search, Permission.ScoView "/itemsuivi_tag_search", sco_debouche.itemsuivi_tag_search, Permission.ScoView
) )
sco_publish( sco_publish(
"/itemsuivi_tag_set", sco_debouche.itemsuivi_tag_set, Permission.ScoEtudChangeAdr "/itemsuivi_tag_set",
sco_debouche.itemsuivi_tag_set,
Permission.ScoEtudChangeAdr,
methods=["GET", "POST"],
) )
@bp.route("/doAddAnnotation", methods=["GET", "POST"]) @bp.route("/doAddAnnotation", methods=["GET", "POST"])
@permission_required(Permission.ScoEtudAddAnnotations) @permission_required(Permission.ScoEtudAddAnnotations)
@scodoc7func(context) @scodoc7func(context)
def doAddAnnotation(context, etudid, comment, REQUEST): def doAddAnnotation(etudid, comment):
"ajoute annotation sur etudiant" "ajoute annotation sur etudiant"
authuser = REQUEST.AUTHENTICATED_USER
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
sco_etud.etud_annotations_create( sco_etud.etud_annotations_create(
cnx, cnx,
args={ args={
"etudid": etudid, "etudid": etudid,
"comment": comment, "comment": comment,
"zope_authenticated_user": str(authuser), "authenticated_user": current_user.user_name,
"zope_remote_addr": REQUEST.REMOTE_ADDR,
}, },
) )
logdb(cnx, method="addAnnotation", etudid=etudid) logdb(cnx, method="addAnnotation", etudid=etudid)
@ -1473,7 +1485,7 @@ def _etudident_create_or_edit_form(context, REQUEST, edit):
formsemestre_id=formsemestre_id formsemestre_id=formsemestre_id
) # > etudident_create_or_edit ) # > etudident_create_or_edit
# #
return flask.redirect("ficheEtud?etudid=" + etudid) return flask.redirect("ficheEtud?etudid=" + str(etudid))
@bp.route("/etudident_delete", methods=["GET", "POST"]) @bp.route("/etudident_delete", methods=["GET", "POST"])
@ -1968,7 +1980,9 @@ def form_students_import_infos_admissions(context, REQUEST, formsemestre_id=None
return "\n".join(H) + tf[1] + help_text + F return "\n".join(H) + tf[1] + help_text + F
elif tf[0] == -1: elif tf[0] == -1:
return flask.redirect( return flask.redirect(
scu.ScoURL() + "/formsemestre_status?formsemestre_id=" + formsemestre_id scu.ScoURL()
+ "/formsemestre_status?formsemestre_id="
+ str(formsemestre_id)
) )
else: else:
return sco_import_etuds.students_import_admission( return sco_import_etuds.students_import_admission(

View File

@ -15,9 +15,10 @@ BASEURL = "https://scodoc.xxx.net/ScoDoc/RT/Scolarite"
USER = "XXX" USER = "XXX"
PASSWORD = "XXX" PASSWORD = "XXX"
values = {'__ac_name' : USER, values = {
'__ac_password' : PASSWORD, "__ac_name": USER,
} "__ac_password": PASSWORD,
}
# Configure memorisation des cookies: # Configure memorisation des cookies:
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor()) opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
@ -25,57 +26,74 @@ urllib2.install_opener(opener)
data = urllib.urlencode(values) data = urllib.urlencode(values)
req = urllib2.Request(BASEURL, data) # this is a POST http request req = urllib2.Request(BASEURL, data) # this is a POST http request
response = urllib2.urlopen(req) response = urllib2.urlopen(req)
# --- Use API # --- Use API
# Affiche la liste des formations en format XML # Affiche la liste des formations en format XML
req = urllib2.Request(BASEURL+'/Notes/formation_list?format=xml' ) req = urllib2.Request(BASEURL + "/Notes/formation_list?format=xml")
response = urllib2.urlopen(req) response = urllib2.urlopen(req)
print response.read()[:100] # limite aux 100 premiers caracteres... print response.read()[:100] # limite aux 100 premiers caracteres...
# Recupere la liste de tous les semestres: # Recupere la liste de tous les semestres:
req = urllib2.Request(BASEURL+'/Notes/formsemestre_list?format=json') # format json req = urllib2.Request(BASEURL + "/Notes/formsemestre_list?format=json") # format json
response = urllib2.urlopen(req) response = urllib2.urlopen(req)
js_data = response.read() js_data = response.read()
# Plus amusant: va retrouver le bulletin de notes du premier etudiant (au hasard donc) du premier semestre (au hasard aussi) # Plus amusant: va retrouver le bulletin de notes du premier etudiant (au hasard donc) du premier semestre (au hasard aussi)
try: try:
import json # Attention: ceci demande Python >= 2.6 import json # Attention: ceci demande Python >= 2.6
except: except:
import simplejson as json # python2.4 with simplejson installed import simplejson as json # python2.4 with simplejson installed
data = json.loads(js_data) # decode la reponse JSON data = json.loads(js_data) # decode la reponse JSON
if not data: if not data:
print "Aucun semestre !" print "Aucun semestre !"
else: else:
formsemestre_id = str(data[0]['formsemestre_id']) formsemestre_id = str(data[0]["formsemestre_id"])
# Obtient la liste des groupes: # Obtient la liste des groupes:
req = urllib2.Request(BASEURL+'/Notes/formsemestre_partition_list?format=json&formsemestre_id='+formsemestre_id) # format json req = urllib2.Request(
response = urllib2.urlopen(req) BASEURL
+ "/Notes/formsemestre_partition_list?format=json&formsemestre_id="
+ str(formsemestre_id)
) # format json
response = urllib2.urlopen(req)
js_data = response.read() js_data = response.read()
data = json.loads(js_data) data = json.loads(js_data)
group_id = data[0]['group'][0]['group_id'] # premier groupe (normalement existe toujours) group_id = data[0]["group"][0][
"group_id"
] # premier groupe (normalement existe toujours)
# Liste les étudiants de ce groupe: # Liste les étudiants de ce groupe:
req = urllib2.Request(BASEURL+'/Notes/group_list?format=json&with_codes=1&group_id='+group_id) # format json req = urllib2.Request(
response = urllib2.urlopen(req) BASEURL + "/Notes/group_list?format=json&with_codes=1&group_id=" + str(group_id)
) # format json
response = urllib2.urlopen(req)
js_data = response.read() js_data = response.read()
data = json.loads(js_data) data = json.loads(js_data)
# Le code du premier étudiant: # Le code du premier étudiant:
if not data: if not data:
print "pas d'etudiants dans ce semestre !" print ("pas d'etudiants dans ce semestre !")
else: else:
etudid = data[0]['etudid'] etudid = data[0]["etudid"]
# Récupère bulletin de notes: # Récupère bulletin de notes:
req = urllib2.Request(BASEURL+'/Notes/formsemestre_bulletinetud?formsemestre_id='+formsemestre_id+'&etudid=' + etudid + '&format=xml') # format XML ici ! req = urllib2.Request(
BASEURL
+ "/Notes/formsemestre_bulletinetud?formsemestre_id="
+ str(formsemestre_id)
+ "&etudid="
+ str(etudid)
+ "&format=xml"
) # format XML ici !
response = urllib2.urlopen(req) response = urllib2.urlopen(req)
xml_bulletin = response.read() xml_bulletin = response.read()
print '----- Bulletin de notes en XML:' print "----- Bulletin de notes en XML:"
print xml_bulletin print xml_bulletin
# Récupère la moyenne générale: # Récupère la moyenne générale:
import xml.dom.minidom import xml.dom.minidom
doc = xml.dom.minidom.parseString(xml_bulletin) doc = xml.dom.minidom.parseString(xml_bulletin)
moy = doc.getElementsByTagName('note')[0].getAttribute('value') # une chaine unicode moy = doc.getElementsByTagName("note")[0].getAttribute(
print '\nMoyenne generale: ', moy "value"
) # une chaine unicode
print "\nMoyenne generale: ", moy