forked from ScoDoc/ScoDoc
Merge ScoDoc 7.23
Merge branch 'master' of https://scodoc.org/git/viennet/ScoDoc into ScoDoc8
This commit is contained in:
commit
dc4bfe4d2e
@ -28,10 +28,16 @@
|
||||
""" Importation des etudiants à partir de fichiers CSV
|
||||
"""
|
||||
|
||||
import os, sys, time, pdb
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import pdb
|
||||
import collections
|
||||
import types
|
||||
import re
|
||||
|
||||
from sco_utils import *
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
import scolars
|
||||
import sco_formsemestre
|
||||
@ -42,6 +48,15 @@ import sco_news
|
||||
from sco_news import NEWS_INSCR, NEWS_NOTE, NEWS_FORM, NEWS_SEM, NEWS_MISC
|
||||
from sco_formsemestre_inscriptions import do_formsemestre_inscription_with_modules
|
||||
from gen_tables import GenTable
|
||||
from sco_exceptions import (
|
||||
AccessDenied,
|
||||
FormatError,
|
||||
ScoException,
|
||||
ScoValueError,
|
||||
ScoInvalidDateError,
|
||||
ScoLockedFormError,
|
||||
ScoGenError,
|
||||
)
|
||||
|
||||
# format description (relative to Product directory))
|
||||
FORMAT_FILE = "misc/format_import_etudiants.txt"
|
||||
@ -93,7 +108,7 @@ ADMISSION_MODIFIABLE_FIELDS = (
|
||||
def sco_import_format(with_codesemestre=True):
|
||||
"returns tuples (Attribut, Type, Table, AllowNulls, Description)"
|
||||
r = []
|
||||
for l in open(SCO_SRC_DIR + "/" + FORMAT_FILE):
|
||||
for l in open(scu.SCO_SRC_DIR + "/" + FORMAT_FILE):
|
||||
l = l.strip()
|
||||
if l and l[0] != "#":
|
||||
fs = l.split(";")
|
||||
@ -152,10 +167,10 @@ def sco_import_generate_excel_sample(
|
||||
titles = []
|
||||
titlesStyles = []
|
||||
for l in fmt:
|
||||
name = strlower(l[0])
|
||||
name = scu.strlower(l[0])
|
||||
if (not with_codesemestre) and name == "codesemestre":
|
||||
continue # pas de colonne codesemestre
|
||||
if only_tables is not None and strlower(l[2]) not in only_tables:
|
||||
if only_tables is not None and scu.strlower(l[2]) not in only_tables:
|
||||
continue # table non demandée
|
||||
if name in exclude_cols:
|
||||
continue # colonne exclue
|
||||
@ -192,7 +207,7 @@ def sco_import_generate_excel_sample(
|
||||
)
|
||||
l.append(etud["partitionsgroupes"])
|
||||
else:
|
||||
key = strlower(field).split()[0]
|
||||
key = scu.strlower(field).split()[0]
|
||||
l.append(etud.get(key, ""))
|
||||
lines.append(l)
|
||||
else:
|
||||
@ -224,7 +239,7 @@ def students_import_excel(
|
||||
if formsemestre_id:
|
||||
dest = "formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||
else:
|
||||
dest = REQUEST.URL1
|
||||
dest = context.NotesURL()
|
||||
H = [context.sco_header(REQUEST, page_title="Import etudiants")]
|
||||
H.append("<ul>")
|
||||
for d in diag:
|
||||
@ -249,7 +264,7 @@ def scolars_import_excel_file(
|
||||
"""
|
||||
log("scolars_import_excel_file: formsemestre_id=%s" % formsemestre_id)
|
||||
cnx = context.GetDBConnexion(autocommit=False)
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
annee_courante = time.localtime()[0]
|
||||
always_require_ine = context.get_preference("always_require_ine")
|
||||
exceldata = datafile.read()
|
||||
@ -265,7 +280,7 @@ def scolars_import_excel_file(
|
||||
titles = {}
|
||||
fmt = sco_import_format()
|
||||
for l in fmt:
|
||||
tit = strlower(l[0]).split()[0] # titles in lowercase, and take 1st word
|
||||
tit = scu.strlower(l[0]).split()[0] # titles in lowercase, and take 1st word
|
||||
if (
|
||||
(not formsemestre_id) or (tit != "codesemestre")
|
||||
) and tit not in exclude_cols:
|
||||
@ -274,7 +289,7 @@ def scolars_import_excel_file(
|
||||
# log("titles=%s" % titles)
|
||||
# remove quotes, downcase and keep only 1st word
|
||||
try:
|
||||
fs = [strlower(stripquotes(s)).split()[0] for s in data[0]]
|
||||
fs = [scu.strlower(scu.stripquotes(s)).split()[0] for s in data[0]]
|
||||
except:
|
||||
raise ScoValueError("Titres de colonnes invalides (ou vides ?)")
|
||||
# log("excel: fs='%s'\ndata=%s" % (str(fs), str(data)))
|
||||
@ -351,22 +366,22 @@ def scolars_import_excel_file(
|
||||
% (val, linenum, titleslist[i])
|
||||
)
|
||||
# xxx Ad-hoc checks (should be in format description)
|
||||
if strlower(titleslist[i]) == "sexe":
|
||||
if scu.strlower(titleslist[i]) == "sexe":
|
||||
try:
|
||||
val = scolars.normalize_sexe(val)
|
||||
val = scolars.input_civilite(val)
|
||||
except:
|
||||
raise ScoValueError(
|
||||
"valeur invalide pour 'SEXE' (doit etre 'M' ou 'MME' ou 'H' ou 'F', pas '%s') ligne %d, colonne %s"
|
||||
"valeur invalide pour 'SEXE' (doit etre 'M', 'F', ou 'MME', 'H', 'X' ou vide, mais pas '%s') ligne %d, colonne %s"
|
||||
% (val, linenum, titleslist[i])
|
||||
)
|
||||
# Excel date conversion:
|
||||
if strlower(titleslist[i]) == "date_naissance":
|
||||
if scu.strlower(titleslist[i]) == "date_naissance":
|
||||
if val:
|
||||
if re.match("^[0-9]*\.?[0-9]*$", str(val)):
|
||||
if re.match(r"^[0-9]*\.?[0-9]*$", str(val)):
|
||||
val = sco_excel.xldate_as_datetime(float(val))
|
||||
# INE
|
||||
if (
|
||||
strlower(titleslist[i]) == "code_ine"
|
||||
scu.strlower(titleslist[i]) == "code_ine"
|
||||
and always_require_ine
|
||||
and not val
|
||||
):
|
||||
@ -423,7 +438,7 @@ def scolars_import_excel_file(
|
||||
log("scolars_import_excel_file: aborting transaction !")
|
||||
# Nota: db transaction is sometimes partly commited...
|
||||
# here we try to remove all created students
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
for etudid in created_etudids:
|
||||
log("scolars_import_excel_file: deleting etudid=%s" % etudid)
|
||||
cursor.execute(
|
||||
@ -500,11 +515,11 @@ def _import_one_student(
|
||||
# Admissions
|
||||
args["etudid"] = etudid
|
||||
args["annee"] = annee_courante
|
||||
adm_id = scolars.admission_create(cnx, args)
|
||||
_ = scolars.admission_create(cnx, args)
|
||||
# Adresse
|
||||
args["typeadresse"] = "domicile"
|
||||
args["description"] = "(infos admission)"
|
||||
adresse_id = scolars.adresse_create(cnx, args)
|
||||
_ = scolars.adresse_create(cnx, args)
|
||||
# Inscription au semestre
|
||||
args["etat"] = "I" # etat insc. semestre
|
||||
if formsemestre_id:
|
||||
@ -689,7 +704,7 @@ _ADM_PATTERN = re.compile(r"[\W]+", re.UNICODE) # supprime tout sauf alphanum
|
||||
|
||||
|
||||
def adm_normalize_string(s): # normalize unicode title
|
||||
return suppression_diacritics(_ADM_PATTERN.sub("", s.strip().lower())).replace(
|
||||
return scu.suppression_diacritics(_ADM_PATTERN.sub("", s.strip().lower())).replace(
|
||||
"_", ""
|
||||
)
|
||||
|
||||
@ -729,19 +744,19 @@ def adm_get_fields(titles, formsemestre_id):
|
||||
|
||||
|
||||
def adm_convert_text(v):
|
||||
if type(v) == FloatType:
|
||||
if type(v) == types.FloatType:
|
||||
return "{:g}".format(v) # evite "1.0"
|
||||
return v
|
||||
|
||||
|
||||
def adm_convert_int(v):
|
||||
if type(v) != IntType and not v:
|
||||
if type(v) != types.IntType and not v:
|
||||
return None
|
||||
return int(float(v)) # accept "10.0"
|
||||
|
||||
|
||||
def adm_convert_real(v):
|
||||
if type(v) != FloatType and not v:
|
||||
if type(v) != types.FloatType and not v:
|
||||
return None
|
||||
return float(v)
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
v 1.2
|
||||
"""
|
||||
|
||||
from types import *
|
||||
from types import BooleanType, StringType
|
||||
|
||||
|
||||
def TrivialFormulator(
|
||||
@ -368,9 +368,6 @@ class TF:
|
||||
idx = 0
|
||||
for idx in range(len(self.formdescription)):
|
||||
(field, descr) = self.formdescription[idx]
|
||||
nextitemname = None
|
||||
if idx < len(self.formdescription) - 2:
|
||||
nextitemname = self.formdescription[idx + 1][0]
|
||||
if descr.get("readonly", False):
|
||||
R.append(self._ReadOnlyElement(field, descr))
|
||||
continue
|
||||
@ -682,7 +679,6 @@ class TF:
|
||||
"Generate HTML for an element, read-only"
|
||||
R = []
|
||||
title = descr.get("title", field.capitalize())
|
||||
withcheckbox = descr.get("withcheckbox", False)
|
||||
input_type = descr.get("input_type", "text")
|
||||
klass = descr.get("cssclass", "")
|
||||
klass = " " + klass
|
||||
|
@ -6,10 +6,16 @@ SCOVERSION = "8.00a"
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
SCONEWS = """
|
||||
<h4>Année 2021</h4>
|
||||
<ul>
|
||||
<li>Gestion du genre neutre (pas d'affichage de la civilité)</li>
|
||||
<li>Diverses corrections (PV de jurys, ...)</li>
|
||||
<li>Modernisation du code Python</li>
|
||||
</ul>
|
||||
<h4>Année 2020</h4>
|
||||
<ul>
|
||||
<li>Corrections d'erreurs, améliorations saise absences< et affichage bulletins</li>
|
||||
<li>Nouveau site <a href="https://scodoc.org">scodoc.org</a> pour la documentation.</li>
|
||||
<li>Nouveau site <a href="https://scodoc.org">scodoc.org</a> pour la documentation</li>
|
||||
<li>Enregistrement de semestres extérieurs</li>
|
||||
<li>Améliorations PV de Jury</li>
|
||||
<li>Contributions J.-M. Place: aide au diagnostic problèmes export Apogée
|
||||
|
23
ZAbsences.py
23
ZAbsences.py
@ -44,20 +44,19 @@ L'API de plus bas niveau est en gros:
|
||||
|
||||
"""
|
||||
|
||||
import urllib
|
||||
import datetime
|
||||
import jaxml
|
||||
import cgi
|
||||
import string
|
||||
import re
|
||||
import time
|
||||
import datetime
|
||||
import dateutil
|
||||
import dateutil.parser
|
||||
import calendar
|
||||
|
||||
from mx.DateTime import DateTime as mxDateTime
|
||||
from mx.DateTime.ISO import ParseDateTimeUTC
|
||||
import urllib
|
||||
import cgi
|
||||
import jaxml
|
||||
|
||||
# ---------------
|
||||
from sco_zope import *
|
||||
from sco_zope import * # pylint: disable=unused-wildcard-import
|
||||
|
||||
# ---------------
|
||||
import sco_utils as scu
|
||||
@ -1542,8 +1541,8 @@ ou entrez une date pour visualiser les absents un jour donné :
|
||||
return scu.log_unknown_etud(self, REQUEST=REQUEST)
|
||||
etud = etuds[0]
|
||||
# check dates
|
||||
begin_date = ParseDateTimeUTC(begin) # may raises ValueError
|
||||
end_date = ParseDateTimeUTC(end)
|
||||
begin_date = dateutil.parser.isoparse(begin) # may raises ValueError
|
||||
end_date = dateutil.parser.isoparse(end)
|
||||
if begin_date > end_date:
|
||||
raise ValueError("invalid dates")
|
||||
#
|
||||
@ -1605,7 +1604,7 @@ ou entrez une date pour visualiser les absents un jour donné :
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + self.sco_footer(REQUEST)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.ScoURL())
|
||||
else:
|
||||
e = tf[2]["begin"].split("/")
|
||||
begin = e[2] + "-" + e[1] + "-" + e[0] + " 00:00:00"
|
||||
@ -1866,7 +1865,7 @@ ou entrez une date pour visualiser les absents un jour donné :
|
||||
|
||||
return "\n".join(H) + "<br/>" + tf[1] + F + self.sco_footer(REQUEST)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.ScoURL())
|
||||
else:
|
||||
n = self._ProcessBilletAbsence(
|
||||
billet, tf[2]["estjust"], tf[2]["description"], REQUEST
|
||||
|
@ -296,7 +296,7 @@ class ZEntreprises(
|
||||
c[
|
||||
"_date_target"
|
||||
] = "%s/entreprise_contact_edit?entreprise_contact_id=%s" % (
|
||||
REQUEST.URL1,
|
||||
self.EntreprisesURL(),
|
||||
c["entreprise_contact_id"],
|
||||
)
|
||||
c["entreprise"] = sco_entreprises.do_entreprise_list(
|
||||
@ -306,7 +306,7 @@ class ZEntreprises(
|
||||
c["etud"] = self.getEtudInfo(etudid=c["etudid"], filled=1)[0]
|
||||
c["etudnom"] = c["etud"]["nomprenom"]
|
||||
c["_etudnom_target"] = "%s/ficheEtud?etudid=%s" % (
|
||||
REQUEST.URL1,
|
||||
self.ScoURL(),
|
||||
c["etudid"],
|
||||
)
|
||||
else:
|
||||
@ -374,7 +374,7 @@ class ZEntreprises(
|
||||
c[
|
||||
"_nomprenom_target"
|
||||
] = "%s/entreprise_correspondant_edit?entreprise_corresp_id=%s" % (
|
||||
REQUEST.URL1,
|
||||
self.EntreprisesURL(),
|
||||
c["entreprise_corresp_id"],
|
||||
)
|
||||
|
||||
@ -462,7 +462,7 @@ class ZEntreprises(
|
||||
)[0]
|
||||
link_create_corr = (
|
||||
'<a href="%s/entreprise_correspondant_create?entreprise_id=%s">créer un nouveau correspondant</a>'
|
||||
% (REQUEST.URL1, c["entreprise_id"])
|
||||
% (self.EntreprisesURL(), c["entreprise_id"])
|
||||
)
|
||||
E = sco_entreprises.do_entreprise_list(
|
||||
self, args={"entreprise_id": c["entreprise_id"]}
|
||||
@ -562,7 +562,7 @@ class ZEntreprises(
|
||||
% entreprise_contact_id
|
||||
)
|
||||
elif tf[0] == -1:
|
||||
REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
else:
|
||||
etudok = sco_entreprises.do_entreprise_check_etudiant(
|
||||
self, tf[2]["etudiant"]
|
||||
@ -572,8 +572,8 @@ class ZEntreprises(
|
||||
else:
|
||||
tf[2].update({"etudid": etudok[1]})
|
||||
sco_entreprises.do_entreprise_contact_edit(self, tf[2])
|
||||
REQUEST.RESPONSE.redirect(
|
||||
REQUEST.URL1
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
self.EntreprisesURL()
|
||||
+ "/entreprise_contact_list?entreprise_id="
|
||||
+ str(c["entreprise_id"])
|
||||
)
|
||||
@ -680,15 +680,15 @@ class ZEntreprises(
|
||||
if tf[0] == 0:
|
||||
H.append(tf[1])
|
||||
elif tf[0] == -1:
|
||||
REQUEST.RESPONSE.redirect(
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"%s/entreprise_correspondant_list?entreprise_id=%s"
|
||||
% (REQUEST.URL1, c["entreprise_id"])
|
||||
% (self.EntreprisesURL(), c["entreprise_id"])
|
||||
)
|
||||
else:
|
||||
sco_entreprises.do_entreprise_correspondant_edit(self, tf[2])
|
||||
REQUEST.RESPONSE.redirect(
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"%s/entreprise_correspondant_list?entreprise_id=%s"
|
||||
% (REQUEST.URL1, c["entreprise_id"])
|
||||
% (self.EntreprisesURL(), c["entreprise_id"])
|
||||
)
|
||||
H.append(entreprise_footer(self, REQUEST))
|
||||
return "\n".join(H)
|
||||
@ -708,7 +708,7 @@ class ZEntreprises(
|
||||
curtime = time.strftime("%d/%m/%Y")
|
||||
link_create_corr = (
|
||||
'<a href="%s/entreprise_correspondant_create?entreprise_id=%s">créer un nouveau correspondant</a>'
|
||||
% (REQUEST.URL1, entreprise_id)
|
||||
% (self.EntreprisesURL(), entreprise_id)
|
||||
)
|
||||
H = [
|
||||
entreprise_header(self, REQUEST=REQUEST, page_title="Suivi entreprises"),
|
||||
@ -789,7 +789,7 @@ class ZEntreprises(
|
||||
if tf[0] == 0:
|
||||
H.append(tf[1])
|
||||
elif tf[0] == -1:
|
||||
REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
else:
|
||||
etudok = sco_entreprises.do_entreprise_check_etudiant(
|
||||
self, tf[2]["etudiant"]
|
||||
@ -799,7 +799,7 @@ class ZEntreprises(
|
||||
else:
|
||||
tf[2].update({"etudid": etudok[1]})
|
||||
sco_entreprises.do_entreprise_contact_create(self, tf[2])
|
||||
REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
H.append(entreprise_footer(self, REQUEST))
|
||||
return "\n".join(H)
|
||||
|
||||
@ -828,12 +828,12 @@ class ZEntreprises(
|
||||
if tf[0] == 0:
|
||||
H.append(tf[1])
|
||||
elif tf[0] == -1:
|
||||
REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
else:
|
||||
sco_entreprises.do_entreprise_contact_delete(
|
||||
self, c["entreprise_contact_id"]
|
||||
)
|
||||
REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
H.append(entreprise_footer(self, REQUEST))
|
||||
return "\n".join(H)
|
||||
|
||||
@ -935,10 +935,10 @@ class ZEntreprises(
|
||||
if tf[0] == 0:
|
||||
H.append(tf[1])
|
||||
elif tf[0] == -1:
|
||||
REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
else:
|
||||
sco_entreprises.do_entreprise_correspondant_create(self, tf[2])
|
||||
REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
H.append(entreprise_footer(self, REQUEST))
|
||||
return "\n".join(H)
|
||||
|
||||
@ -967,12 +967,12 @@ class ZEntreprises(
|
||||
if tf[0] == 0:
|
||||
H.append(tf[1])
|
||||
elif tf[0] == -1:
|
||||
REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
else:
|
||||
sco_entreprises.do_entreprise_correspondant_delete(
|
||||
self, c["entreprise_corresp_id"]
|
||||
)
|
||||
REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
H.append(entreprise_footer(self, REQUEST))
|
||||
return "\n".join(H)
|
||||
|
||||
@ -1025,10 +1025,10 @@ class ZEntreprises(
|
||||
if tf[0] == 0:
|
||||
H.append(tf[1])
|
||||
elif tf[0] == -1:
|
||||
REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
else:
|
||||
sco_entreprises.do_entreprise_delete(self, E["entreprise_id"])
|
||||
REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
H.append(entreprise_footer(self, REQUEST))
|
||||
return "\n".join(H)
|
||||
|
||||
@ -1120,10 +1120,10 @@ class ZEntreprises(
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + entreprise_footer(self, REQUEST)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
else:
|
||||
sco_entreprises.do_entreprise_create(self, tf[2])
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL())
|
||||
|
||||
security.declareProtected(ScoEntrepriseView, "entreprise_edit")
|
||||
|
||||
@ -1295,7 +1295,7 @@ class ZEntreprises(
|
||||
H.append("</ul>")
|
||||
return "\n".join(H) + entreprise_footer(self, REQUEST)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1 + "?start=" + start)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL() + "?start=" + start)
|
||||
else:
|
||||
sco_entreprises.do_entreprise_edit(self, tf[2])
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1 + "?start=" + start)
|
||||
return REQUEST.RESPONSE.redirect(self.EntreprisesURL() + "?start=" + start)
|
||||
|
13
ZNotes.py
13
ZNotes.py
@ -35,7 +35,6 @@ import pprint
|
||||
from sco_zope import * # pylint: disable=unused-wildcard-import
|
||||
|
||||
# ---------------
|
||||
# from sco_utils import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log, sendAlarm
|
||||
@ -170,7 +169,7 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
|
||||
"Changes the instance values"
|
||||
self.title = title
|
||||
self._p_changed = 1
|
||||
RESPONSE.redirect("manage_editForm")
|
||||
return RESPONSE.redirect("manage_editForm")
|
||||
|
||||
def _getNotesCache(self):
|
||||
"returns CacheNotesTable instance for us"
|
||||
@ -267,10 +266,12 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
|
||||
sco_formsemestre_edit.formsemestre_createwithmodules
|
||||
)
|
||||
|
||||
security.declareProtected(ScoView, "formsemestre_editwithmodules")
|
||||
security.declareProtected(
|
||||
ScoView, "formsemestre_editwithmodules"
|
||||
) # controle d'acces specifique pour dir. etud
|
||||
formsemestre_editwithmodules = sco_formsemestre_edit.formsemestre_editwithmodules
|
||||
|
||||
security.declareProtected(ScoView, "formsemestre_clone")
|
||||
security.declareProtected(ScoImplement, "formsemestre_clone")
|
||||
formsemestre_clone = sco_formsemestre_edit.formsemestre_clone
|
||||
|
||||
security.declareProtected(ScoChangeFormation, "formsemestre_associate_new_version")
|
||||
@ -531,7 +532,7 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + footer
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.NotesURL())
|
||||
else:
|
||||
formation_id, _, _ = self.formation_import_xml(tf[2]["xmlfile"], REQUEST)
|
||||
|
||||
@ -685,7 +686,7 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
|
||||
#
|
||||
if not force:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
REQUEST.URL1 + "/ue_list?formation_id=" + str(ue["formation_id"])
|
||||
self.NotesURL() + "/ue_list?formation_id=" + str(ue["formation_id"])
|
||||
)
|
||||
else:
|
||||
return None
|
||||
|
@ -345,8 +345,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
||||
return (
|
||||
"<p>Département "
|
||||
+ DeptId
|
||||
+ """ supprimé du serveur web (la base de données n'est pas affectée)!</p><p><a href="%s">Continuer</a></p>"""
|
||||
% REQUEST.URL1
|
||||
+ """ supprimé du serveur web (la base de données n'est pas affectée)!</p><p><a href="/ScoDoc">Continuer</a></p>"""
|
||||
)
|
||||
|
||||
_top_level_css = """
|
||||
@ -410,7 +409,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
||||
except:
|
||||
admin_password_initialized = "0"
|
||||
if isAdmin and admin_password_initialized != "1":
|
||||
REQUEST.RESPONSE.redirect(
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"ScoDoc/change_admin_user_form?message=Le%20mot%20de%20passe%20administrateur%20doit%20etre%20change%20!"
|
||||
)
|
||||
|
||||
@ -980,5 +979,5 @@ def manage_addZScoDoc(self, id="ScoDoc", title="Site ScoDoc", REQUEST=None):
|
||||
) # ne cree (presque rien), tout se passe lors du 1er accès
|
||||
self._setObject(id, zscodoc)
|
||||
if REQUEST is not None:
|
||||
REQUEST.RESPONSE.redirect("%s/manage_workspace" % REQUEST.URL1)
|
||||
REQUEST.RESPONSE.redirect("/ScoDoc/manage_workspace")
|
||||
return id
|
||||
|
114
ZScoUsers.py
114
ZScoUsers.py
@ -27,28 +27,45 @@
|
||||
|
||||
""" Gestion des utilisateurs (table SQL pour Zope User Folder)
|
||||
"""
|
||||
import string, re
|
||||
import string
|
||||
import re
|
||||
import time
|
||||
import md5, base64
|
||||
import md5
|
||||
import base64
|
||||
import jaxml
|
||||
|
||||
|
||||
from sco_zope import *
|
||||
from sco_zope import * # pylint: disable=unused-wildcard-import
|
||||
|
||||
# ---------------
|
||||
|
||||
import notesdb
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
from scolog import logdb
|
||||
from sco_utils import *
|
||||
from scolars import format_prenom, format_nom
|
||||
import sco_import_users, sco_excel
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
import sco_import_users
|
||||
import sco_excel
|
||||
from TrivialFormulator import TrivialFormulator, TF, tf_error_message
|
||||
from gen_tables import GenTable
|
||||
import scolars
|
||||
import sco_cache
|
||||
import sco_users
|
||||
|
||||
from sco_permissions import (
|
||||
ScoEditAllEvals,
|
||||
ScoEditAllNotes,
|
||||
ScoImplement,
|
||||
ScoSuperAdmin,
|
||||
ScoUsersAdmin,
|
||||
ScoUsersView,
|
||||
ScoView,
|
||||
)
|
||||
from sco_exceptions import (
|
||||
AccessDenied,
|
||||
ScoException,
|
||||
ScoValueError,
|
||||
ScoInvalidDateError,
|
||||
ScoLockedFormError,
|
||||
ScoGenError,
|
||||
)
|
||||
|
||||
# ---------------
|
||||
# cache global: chaque instance, repérée par son URL, a un cache
|
||||
@ -93,7 +110,7 @@ class ZScoUsers(
|
||||
# Ugly but necessary during transition out of Zope:
|
||||
_db_cnx_string = "dbname=SCOUSERS port=5432"
|
||||
security.declareProtected("Change DTML Documents", "GetUsersDBConnexion")
|
||||
GetUsersDBConnexion = notesdb.GetUsersDBConnexion
|
||||
GetUsersDBConnexion = ndb.GetUsersDBConnexion
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
#
|
||||
@ -162,7 +179,7 @@ class ZScoUsers(
|
||||
F = self.sco_footer(REQUEST)
|
||||
return "\n".join(H) + F
|
||||
|
||||
_userEditor = EditableTable(
|
||||
_userEditor = ndb.EditableTable(
|
||||
"sco_users",
|
||||
"user_id",
|
||||
(
|
||||
@ -180,12 +197,12 @@ class ZScoUsers(
|
||||
"date_expiration",
|
||||
),
|
||||
output_formators={
|
||||
"date_modif_passwd": DateISOtoDMY,
|
||||
"date_expiration": DateISOtoDMY,
|
||||
"date_modif_passwd": ndb.DateISOtoDMY,
|
||||
"date_expiration": ndb.DateISOtoDMY,
|
||||
},
|
||||
input_formators={
|
||||
"date_modif_passwd": DateDMYtoISO,
|
||||
"date_expiration": DateDMYtoISO,
|
||||
"date_modif_passwd": ndb.DateDMYtoISO,
|
||||
"date_expiration": ndb.DateDMYtoISO,
|
||||
},
|
||||
sortkey="nom",
|
||||
filter_nulls=False,
|
||||
@ -217,12 +234,12 @@ class ZScoUsers(
|
||||
u = self._user_list(args={"user_name": user_name})[0]
|
||||
if u["status"] == "old" and u["roles"] and u["roles"][0] != "-":
|
||||
roles = ["-" + r for r in u["roles"].split(",")]
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
self.acl_users.scodoc_editUser(cursor, user_name, roles=roles)
|
||||
self.get_userlist_cache().inval_cache()
|
||||
elif not u["status"] and u["roles"] and u["roles"][0] == "-":
|
||||
roles = [r[1:] for r in u["roles"].split(",") if (r and r[0] == "-")]
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
self.acl_users.scodoc_editUser(cursor, user_name, roles=roles)
|
||||
self.get_userlist_cache().inval_cache()
|
||||
|
||||
@ -268,7 +285,7 @@ class ZScoUsers(
|
||||
"nom_fmt": user_name,
|
||||
"nomcomplet": user_name,
|
||||
"nomplogin": user_name,
|
||||
"nomnoacc": suppress_accents(user_name),
|
||||
"nomnoacc": scu.suppress_accents(user_name),
|
||||
"passwd_temp": 0,
|
||||
"status": "",
|
||||
"date_expiration": None,
|
||||
@ -289,7 +306,7 @@ class ZScoUsers(
|
||||
else:
|
||||
n = user_name
|
||||
|
||||
prenom_abbrv = abbrev_prenom(p)
|
||||
prenom_abbrv = scu.abbrev_prenom(p)
|
||||
# nomprenom est le nom capitalisé suivi de l'initiale du prénom
|
||||
info["nomprenom"] = (n + " " + prenom_abbrv).strip()
|
||||
# prenomnom est l'initiale du prénom suivie du nom
|
||||
@ -301,9 +318,9 @@ class ZScoUsers(
|
||||
info["nomcomplet"] = info["prenom_fmt"] + " " + info["nom_fmt"]
|
||||
# nomplogin est le nom en majuscules suivi du prénom et du login
|
||||
# e.g. Dupont Pierre (dupont)
|
||||
info["nomplogin"] = "%s %s (%s)" % (strupper(n), p, info["user_name"])
|
||||
info["nomplogin"] = "%s %s (%s)" % (scu.strupper(n), p, info["user_name"])
|
||||
# nomnoacc est le nom en minuscules sans accents
|
||||
info["nomnoacc"] = suppress_accents(strlower(info["nom"]))
|
||||
info["nomnoacc"] = scu.suppress_accents(scu.strlower(info["nom"]))
|
||||
|
||||
return info
|
||||
|
||||
@ -346,7 +363,7 @@ class ZScoUsers(
|
||||
assert len(user) == 1, "database inconsistency: len(user)=%d" % len(user)
|
||||
# should not occur, already tested in _can_handle_passwd
|
||||
cnx = self.GetUsersDBConnexion() # en mode autocommit
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"update sco_users set date_modif_passwd=now(), passwd_temp=0 where user_name=%(user_name)s",
|
||||
{"user_name": user_name},
|
||||
@ -417,7 +434,7 @@ class ZScoUsers(
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=%s" />
|
||||
<body><h1>Mot de passe changé !</h1>
|
||||
"""
|
||||
% (SCO_ENCODING, SCO_ENCODING)
|
||||
% (scu.SCO_ENCODING, scu.SCO_ENCODING)
|
||||
+ "\n".join(H)
|
||||
+ '<a href="%s" class="stdlink">Continuer</a></body></html>'
|
||||
% self.ScoURL()
|
||||
@ -536,7 +553,7 @@ class ZScoUsers(
|
||||
)
|
||||
else:
|
||||
for p in scoperms:
|
||||
permname, value = p[:2]
|
||||
permname, _ = p[:2]
|
||||
if thisuser.has_permission(permname, self):
|
||||
b = "oui"
|
||||
else:
|
||||
@ -775,11 +792,12 @@ class ZScoUsers(
|
||||
descr,
|
||||
initvalues=initvalues,
|
||||
submitlabel=submitlabel,
|
||||
cancelbutton="Annuler",
|
||||
)
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + "\n" + tf[1] + F
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.UsersURL())
|
||||
else:
|
||||
vals = tf[2]
|
||||
roles = set(vals["roles"]).intersection(editable_roles)
|
||||
@ -903,7 +921,7 @@ class ZScoUsers(
|
||||
|
||||
# Des noms/prénoms semblables existent ?
|
||||
cnx = self.GetUsersDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"select * from sco_users where lower(nom) ~ %(nom)s and lower(prenom) ~ %(prenom)s;",
|
||||
{"nom": nom.lower().strip(), "prenom": prenom.lower().strip()},
|
||||
@ -980,7 +998,7 @@ class ZScoUsers(
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + "</li></ol>" + help + F
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.UsersURL())
|
||||
else:
|
||||
# IMPORT
|
||||
diag = sco_import_users.import_excel_file(
|
||||
@ -989,7 +1007,9 @@ class ZScoUsers(
|
||||
H = [head]
|
||||
H.append("<p>Import excel: %s</p>" % diag)
|
||||
H.append("<p>OK, import terminé !</p>")
|
||||
H.append('<p><a class="stdlink" href="%s">Continuer</a></p>' % REQUEST.URL1)
|
||||
H.append(
|
||||
'<p><a class="stdlink" href="%s">Continuer</a></p>' % self.UsersURL()
|
||||
)
|
||||
return "\n".join(H) + help + F
|
||||
|
||||
security.declareProtected(ScoUsersAdmin, "import_users_generate_excel_sample")
|
||||
@ -1004,13 +1024,13 @@ class ZScoUsers(
|
||||
def create_user(self, args, REQUEST=None):
|
||||
"creation utilisateur zope"
|
||||
cnx = self.GetUsersDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
passwd = args["passwd"]
|
||||
args["passwd"] = "undefined"
|
||||
if "passwd2" in args:
|
||||
del args["passwd2"]
|
||||
log("create_user: args=%s" % args) # log apres supr. du mot de passe !
|
||||
r = self._userEditor.create(cnx, args)
|
||||
_ = self._userEditor.create(cnx, args)
|
||||
self.get_userlist_cache().inval_cache() # >
|
||||
|
||||
# call exUserFolder to set passwd
|
||||
@ -1020,7 +1040,7 @@ class ZScoUsers(
|
||||
)
|
||||
|
||||
if REQUEST:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(self.UsersURL())
|
||||
|
||||
security.declareProtected(ScoUsersAdmin, "delete_user_form")
|
||||
|
||||
@ -1048,11 +1068,13 @@ class ZScoUsers(
|
||||
% user_name,
|
||||
dest_url="",
|
||||
REQUEST=REQUEST,
|
||||
cancel_url=REQUEST.URL1,
|
||||
cancel_url=self.UsersURL(),
|
||||
parameters={"user_name": user_name},
|
||||
)
|
||||
self._user_delete(user_name)
|
||||
REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
self.UsersURL() + r"?head_message=Utilisateur%20supprimé"
|
||||
)
|
||||
|
||||
security.declareProtected(ScoView, "list_users")
|
||||
|
||||
@ -1100,15 +1122,15 @@ class ZScoUsers(
|
||||
|
||||
# Convert dates to ISO if XML output
|
||||
if format == "xml" and u["date_modif_passwd"] != "NA":
|
||||
u["date_modif_passwd"] = DateDMYtoISO(u["date_modif_passwd"]) or ""
|
||||
u["date_modif_passwd"] = ndb.DateDMYtoISO(u["date_modif_passwd"]) or ""
|
||||
|
||||
# Convert date_expiration and date_modif_passwd to ISO to ease sorting
|
||||
if u["date_expiration"]:
|
||||
u["date_expiration_iso"] = DateDMYtoISO(u["date_expiration"])
|
||||
u["date_expiration_iso"] = ndb.DateDMYtoISO(u["date_expiration"])
|
||||
else:
|
||||
u["date_expiration_iso"] = ""
|
||||
if u["date_modif_passwd"]:
|
||||
u["date_modif_passwd_iso"] = DateDMYtoISO(u["date_expiration"])
|
||||
u["date_modif_passwd_iso"] = ndb.DateDMYtoISO(u["date_expiration"])
|
||||
else:
|
||||
u["date_modif_passwd_iso"] = ""
|
||||
|
||||
@ -1202,13 +1224,13 @@ class ZScoUsers(
|
||||
"""Returns XML list of users with name (nomplogin) starting with start.
|
||||
Used for forms auto-completion."""
|
||||
userlist = self.get_userlist(dept=dept)
|
||||
start = suppression_diacritics(unicode(start, "utf-8"))
|
||||
start = strlower(str(start))
|
||||
start = scu.suppression_diacritics(unicode(start, "utf-8"))
|
||||
start = scu.strlower(str(start))
|
||||
|
||||
userlist = [user for user in userlist if user["nomnoacc"].startswith(start)]
|
||||
if REQUEST:
|
||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
||||
doc = jaxml.XML_document(encoding=SCO_ENCODING)
|
||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||
doc = jaxml.XML_document(encoding=scu.SCO_ENCODING)
|
||||
doc.results()
|
||||
for user in userlist[:limit]:
|
||||
doc._push()
|
||||
@ -1243,8 +1265,8 @@ Il devra ensuite se connecter et le changer.
|
||||
)
|
||||
self.reset_password(user_name=user_name, REQUEST=REQUEST)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
REQUEST.URL1
|
||||
+ "?head_message=mot%20de%20passe%20de%20"
|
||||
self.UsersURL()
|
||||
+ r"?head_message=mot%20de%20passe%20de%20"
|
||||
+ user_name
|
||||
+ "%20reinitialise"
|
||||
)
|
||||
@ -1269,14 +1291,14 @@ Il devra ensuite se connecter et le changer.
|
||||
log("reset_password: %s" % user_name)
|
||||
# Check that user has valid mail
|
||||
info = self.user_info(user_name=user_name)
|
||||
if not is_valid_mail(info["email"]):
|
||||
if not scu.is_valid_mail(info["email"]):
|
||||
raise Exception("pas de mail valide associé à l'utilisateur")
|
||||
# Generate random password
|
||||
password = sco_import_users.generate_password()
|
||||
self.do_change_password(user_name, password)
|
||||
# Flag it as temporary:
|
||||
cnx = self.GetUsersDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
ui = {"user_name": user_name}
|
||||
cursor.execute(
|
||||
"update sco_users set passwd_temp=1 where user_name='%(user_name)s'" % ui
|
||||
|
335
ZScolar.py
335
ZScolar.py
@ -30,8 +30,15 @@
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
import time, string, glob, re
|
||||
import urllib, urllib2, cgi, xml
|
||||
import time
|
||||
import string
|
||||
import glob
|
||||
import re
|
||||
import urllib
|
||||
import urllib2
|
||||
import cgi
|
||||
import xml
|
||||
import jaxml
|
||||
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
@ -41,7 +48,7 @@ from zipfile import ZipFile
|
||||
import thread
|
||||
import psycopg2
|
||||
|
||||
from sco_zope import *
|
||||
from sco_zope import * # pylint: disable=unused-wildcard-import
|
||||
|
||||
|
||||
# ---------------
|
||||
@ -52,19 +59,47 @@ log("restarting...")
|
||||
|
||||
log("ZScolar home=%s" % file_path)
|
||||
|
||||
import sco_utils
|
||||
from sco_utils import *
|
||||
import notesdb
|
||||
from notesdb import *
|
||||
from scolog import logdb
|
||||
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from scolog import logdb
|
||||
from sco_permissions import (
|
||||
ScoAbsChange,
|
||||
ScoView,
|
||||
ScoEnsView,
|
||||
ScoImplement,
|
||||
ScoChangeFormation,
|
||||
ScoChangePreferences,
|
||||
ScoObservateur,
|
||||
ScoEtudAddAnnotations,
|
||||
ScoEtudInscrit,
|
||||
ScoEtudChangeGroups,
|
||||
ScoEtudChangeAdr,
|
||||
ScoEtudSupprAnnotations,
|
||||
ScoEditAllEvals,
|
||||
ScoEditAllNotes,
|
||||
ScoEditFormationTags,
|
||||
ScoEditApo,
|
||||
ScoSuperAdmin,
|
||||
)
|
||||
import sco_permissions
|
||||
from sco_exceptions import (
|
||||
AccessDenied,
|
||||
ScoException,
|
||||
ScoValueError,
|
||||
ScoInvalidDateError,
|
||||
ScoLockedFormError,
|
||||
ScoGenError,
|
||||
)
|
||||
from TrivialFormulator import TrivialFormulator, tf_error_message
|
||||
import scolars
|
||||
import sco_codes_parcours
|
||||
import sco_preferences
|
||||
import sco_formations
|
||||
from scolars import (
|
||||
format_nom,
|
||||
format_prenom,
|
||||
format_sexe,
|
||||
format_civilite,
|
||||
format_lycee,
|
||||
format_lycee_from_code,
|
||||
)
|
||||
@ -110,9 +145,9 @@ import sco_dump_db
|
||||
|
||||
from VERSION import SCOVERSION, SCONEWS
|
||||
|
||||
if hasattr(CONFIG, "ABSOLUTE_URL") and CONFIG.ABSOLUTE_URL:
|
||||
log("ScoDoc: ABSOLUTE_URL='%s'" % CONFIG.ABSOLUTE_URL)
|
||||
log("ScoDoc: using encoding %s" % SCO_ENCODING)
|
||||
if hasattr(scu.CONFIG, "ABSOLUTE_URL") and scu.CONFIG.ABSOLUTE_URL:
|
||||
log("ScoDoc: ABSOLUTE_URL='%s'" % scu.CONFIG.ABSOLUTE_URL)
|
||||
log("ScoDoc: using encoding %s" % scu.SCO_ENCODING)
|
||||
|
||||
# import essai_cas
|
||||
|
||||
@ -171,11 +206,11 @@ class ZScolar(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
||||
# The for used to edit this object
|
||||
security.declareProtected(ScoView, "manage_editZScolar")
|
||||
|
||||
def manage_editZScolar(self, title, RESPONSE=None):
|
||||
def manage_editZScolar(self, title, REQUEST=None):
|
||||
"Changes the instance values"
|
||||
self.title = title
|
||||
self._p_changed = 1
|
||||
RESPONSE.redirect("manage_editForm")
|
||||
return REQUEST.RESPONSE.redirect("manage_editForm")
|
||||
|
||||
def _setup_initial_roles_and_permissions(self):
|
||||
"""Initialize roles and permissions
|
||||
@ -197,8 +232,10 @@ class ZScolar(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
||||
H.append(r)
|
||||
ok = False
|
||||
|
||||
for permission in Sco_Default_Permissions.keys():
|
||||
roles = [r + DeptId for r in Sco_Default_Permissions[permission]]
|
||||
for permission in sco_permissions.Sco_Default_Permissions.keys():
|
||||
roles = [
|
||||
r + DeptId for r in sco_permissions.Sco_Default_Permissions[permission]
|
||||
]
|
||||
roles.append("Manager")
|
||||
log("granting '%s' to %s" % (permission, roles))
|
||||
try:
|
||||
@ -257,11 +294,16 @@ class ZScolar(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span class="span_ue_apo" style="display: inline" id="toto">VRTU11</span>)</span>
|
||||
<span class="locked">[verrouillé]</span>
|
||||
<tt>
|
||||
REQUEST.URL=%s<br/>
|
||||
REQUEST.URL0=%s<br/>
|
||||
</tt>
|
||||
</p>
|
||||
</body>
|
||||
"""
|
||||
""" % (
|
||||
REQUEST.URL,
|
||||
REQUEST.URL0,
|
||||
)
|
||||
# return (
|
||||
# self.sco_header(REQUEST)
|
||||
# + """<div class="xp">%s</div>""" % x
|
||||
@ -271,51 +313,51 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
# raise ValueError("essai exception")
|
||||
# raise ScoValueError('essai exception !', dest_url='totoro', REQUEST=REQUEST)
|
||||
|
||||
# cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
# cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
# cursor.execute("select * from notes_formations")
|
||||
# b += str(cursor.fetchall())
|
||||
# b = self.Notes.gloups()
|
||||
# raise NoteProcessError('test exception !')
|
||||
|
||||
# essai: liste des permissions
|
||||
from AccessControl import getSecurityManager # pylint: disable=import-error
|
||||
from AccessControl.Permission import Permission # pylint: disable=import-error
|
||||
# from AccessControl import getSecurityManager # pylint: disable=import-error
|
||||
# from AccessControl.Permission import Permission # pylint: disable=import-error
|
||||
|
||||
permissions = self.ac_inherited_permissions(1)
|
||||
scoperms = [p for p in permissions if p[0][:3] == "Sco"]
|
||||
# H.append( str(self.aq_parent.aq_parent.permission_settings()) )
|
||||
# H.append('<p>perms: %s</p>'%str(scoperms))
|
||||
# H.append('<p>valid_roles: %s</p>'%str(self.valid_roles()))
|
||||
# H.append('<p>ac_inherited_permissions=%s</p>'%str(self.ac_inherited_permissions(1)))
|
||||
def collect_roles(context, rd):
|
||||
for p in scoperms:
|
||||
name, value = p[:2]
|
||||
P = Permission(name, value, context)
|
||||
roles = list(P.getRoles())
|
||||
if rd.has_key(name):
|
||||
rd[name] += roles
|
||||
else:
|
||||
rd[name] = roles
|
||||
if hasattr(context, "aq_parent"):
|
||||
collect_roles(context.aq_parent, rd)
|
||||
# permissions = self.ac_inherited_permissions(1)
|
||||
# scoperms = [p for p in permissions if p[0][:3] == "Sco"]
|
||||
# # H.append( str(self.aq_parent.aq_parent.permission_settings()) )
|
||||
# # H.append('<p>perms: %s</p>'%str(scoperms))
|
||||
# # H.append('<p>valid_roles: %s</p>'%str(self.valid_roles()))
|
||||
# # H.append('<p>ac_inherited_permissions=%s</p>'%str(self.ac_inherited_permissions(1)))
|
||||
# def collect_roles(context, rd):
|
||||
# for p in scoperms:
|
||||
# name, value = p[:2]
|
||||
# P = Permission(name, value, context)
|
||||
# roles = list(P.getRoles())
|
||||
# if rd.has_key(name):
|
||||
# rd[name] += roles
|
||||
# else:
|
||||
# rd[name] = roles
|
||||
# if hasattr(context, "aq_parent"):
|
||||
# collect_roles(context.aq_parent, rd)
|
||||
|
||||
b = ""
|
||||
rd = {}
|
||||
collect_roles(self, rd)
|
||||
b = "<p>" + str(rd) + "</p>"
|
||||
# b = ""
|
||||
# rd = {}
|
||||
# collect_roles(self, rd)
|
||||
# b = "<p>" + str(rd) + "</p>"
|
||||
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
for p in scoperms:
|
||||
permname, value = p[:2]
|
||||
b += "<p>" + permname + " : "
|
||||
if authuser.has_permission(permname, self):
|
||||
b += "yes"
|
||||
else:
|
||||
b += "no"
|
||||
b += "</p>"
|
||||
b += "<p>xxx</p><hr><p>" + str(self.aq_parent.aq_parent)
|
||||
# authuser = REQUEST.AUTHENTICATED_USER
|
||||
# for p in scoperms:
|
||||
# permname, _ = p[:2]
|
||||
# b += "<p>" + permname + " : "
|
||||
# if authuser.has_permission(permname, self):
|
||||
# b += "yes"
|
||||
# else:
|
||||
# b += "no"
|
||||
# b += "</p>"
|
||||
# b += "<p>xxx</p><hr><p>" + str(self.aq_parent.aq_parent)
|
||||
|
||||
return self.sco_header(REQUEST) + str(b) + self.sco_footer(REQUEST)
|
||||
# return self.sco_header(REQUEST) + str(b) + self.sco_footer(REQUEST)
|
||||
|
||||
# essais calendriers:
|
||||
security.declareProtected(ScoView, "experimental_calendar")
|
||||
@ -326,11 +368,39 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
security.declareProtected(ScoView, "ScoURL")
|
||||
|
||||
def ScoURL(self):
|
||||
"base URL for this sco instance"
|
||||
"""base URL for this sco instance.
|
||||
e.g. https://scodoc.xxx.fr/ScoDoc/DEPT/Scolarite
|
||||
= page accueil département
|
||||
"""
|
||||
# absolute_url is the classic Zope method
|
||||
# The avoid the burden of configuring a proxy zope object, we offer
|
||||
# a custom configuration via scodoc_config
|
||||
return CONFIG.ABSOLUTE_URL or self.absolute_url()
|
||||
# XXX ne devrait pas marcher car l'URL dépend du département !!!
|
||||
return scu.CONFIG.ABSOLUTE_URL or self.absolute_url()
|
||||
|
||||
def NotesURL(self):
|
||||
"""URL of Notes
|
||||
e.g. https://scodoc.xxx.fr/ScoDoc/DEPT/Scolarite/Notes
|
||||
= url de base des requêtes de ZNotes
|
||||
et page accueil programmes.
|
||||
"""
|
||||
return self.ScoURL() + "/Notes"
|
||||
|
||||
def EntreprisesURL(self):
|
||||
"""URL of Enterprises
|
||||
e.g. https://scodoc.xxx.fr/ScoDoc/DEPT/Scolarite/Entreprises
|
||||
= url de base des requêtes de ZEntreprises
|
||||
et page accueil Entreprises
|
||||
"""
|
||||
return self.ScoURL() + "/Entreprises"
|
||||
|
||||
def UsersURL(self):
|
||||
"""URL of Users
|
||||
e.g. https://scodoc.xxx.fr/ScoDoc/DEPT/Scolarite/Users
|
||||
= url de base des requêtes ZScoUsers
|
||||
et page accueil users
|
||||
"""
|
||||
return self.ScoURL() + "/Users"
|
||||
|
||||
security.declareProtected(ScoView, "sco_header")
|
||||
sco_header = html_sco_header.sco_header
|
||||
@ -349,7 +419,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
return self._db_cnx_string
|
||||
|
||||
security.declareProtected(ScoSuperAdmin, "GetDBConnexion")
|
||||
GetDBConnexion = notesdb.GetDBConnexion
|
||||
GetDBConnexion = ndb.GetDBConnexion
|
||||
|
||||
# A enlever après re-ecriture de ZEntreprises.py
|
||||
security.declareProtected(ScoView, "TrivialFormulator")
|
||||
@ -392,10 +462,10 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
"version info"
|
||||
H = [
|
||||
"""<h2>Système de gestion scolarité</h2>
|
||||
<p>© Emmanuel Viennet 1997-2020</p>
|
||||
<p>© Emmanuel Viennet 1997-2021</p>
|
||||
<p>Version %s</p>
|
||||
"""
|
||||
% (sco_utils.get_scodoc_version())
|
||||
% (scu.get_scodoc_version())
|
||||
]
|
||||
H.append(
|
||||
'<p>Logiciel libre écrit en <a href="http://www.python.org">Python</a>.</p><p>Utilise <a href="http://www.reportlab.org/">ReportLab</a> pour générer les documents PDF, et <a href="http://sourceforge.net/projects/pyexcelerator">pyExcelerator</a> pour le traitement des documents Excel.</p>'
|
||||
@ -403,7 +473,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
H.append("<h2>Dernières évolutions</h2>" + SCONEWS)
|
||||
H.append(
|
||||
'<div class="about-logo">'
|
||||
+ icontag("borgne_img")
|
||||
+ scu.icontag("borgne_img")
|
||||
+ " <em>Au pays des aveugles...</em></div>"
|
||||
)
|
||||
d = ""
|
||||
@ -417,12 +487,12 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
if format == "html" or format == "pdf":
|
||||
raise ScoValueError(msg)
|
||||
elif format == "xml":
|
||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
||||
doc = jaxml.XML_document(encoding=SCO_ENCODING)
|
||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||
doc = jaxml.XML_document(encoding=scu.SCO_ENCODING)
|
||||
doc.error(msg=msg)
|
||||
return repr(doc)
|
||||
elif format == "json":
|
||||
REQUEST.RESPONSE.setHeader("content-type", JSON_MIMETYPE)
|
||||
REQUEST.RESPONSE.setHeader("content-type", scu.JSON_MIMETYPE)
|
||||
return "undefined" # XXX voir quoi faire en cas d'erreur json
|
||||
else:
|
||||
raise ValueError("ScoErrorResponse: invalid format")
|
||||
@ -517,7 +587,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
page_title="Opérations sur %(nomprenom)s" % etud,
|
||||
html_title="<h2>Opérations effectuées sur l'étudiant %(nomprenom)s</h2>"
|
||||
% etud,
|
||||
filename="log_" + make_filename(etud["nomprenom"]),
|
||||
filename="log_" + scu.make_filename(etud["nomprenom"]),
|
||||
html_next_section='<ul><li><a href="ficheEtud?etudid=%(etudid)s">fiche de %(nomprenom)s</a></li></ul>'
|
||||
% etud,
|
||||
preferences=self.get_preferences(),
|
||||
@ -530,7 +600,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
def listScoLog(self, etudid):
|
||||
"liste des operations effectuees sur cet etudiant"
|
||||
cnx = self.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"select * from scolog where etudid=%(etudid)s ORDER BY DATE DESC",
|
||||
{"etudid": etudid},
|
||||
@ -545,7 +615,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
|
||||
def rssnews(self, REQUEST=None):
|
||||
"rss feed"
|
||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||
return sco_news.scolar_news_summary_rss(
|
||||
self, "Nouvelles de " + self.get_preference("DeptName"), self.ScoURL()
|
||||
)
|
||||
@ -846,18 +916,19 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
"nom": "?",
|
||||
"nom_usuel": "",
|
||||
"prenom": "?",
|
||||
"sexe": "?",
|
||||
"civilite": "?",
|
||||
"sexe": "?", # for backward compat
|
||||
"email": "?",
|
||||
"emailperso": "",
|
||||
"error": "code etudiant inconnu",
|
||||
}
|
||||
return sendResult(
|
||||
return scu.sendResult(
|
||||
REQUEST, d, name="etudiant", format=format, force_outer_xml_tag=False
|
||||
)
|
||||
d = {}
|
||||
etud = etuds[0]
|
||||
self.fillEtudsInfo([etud])
|
||||
etud["date_naissance_iso"] = DateDMYtoISO(etud["date_naissance"])
|
||||
etud["date_naissance_iso"] = ndb.DateDMYtoISO(etud["date_naissance"])
|
||||
for a in (
|
||||
"etudid",
|
||||
"code_nip",
|
||||
@ -865,7 +936,6 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
"nom",
|
||||
"nom_usuel",
|
||||
"prenom",
|
||||
"sexe",
|
||||
"nomprenom",
|
||||
"email",
|
||||
"emailperso",
|
||||
@ -885,8 +955,12 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
"codelycee",
|
||||
"date_naissance_iso",
|
||||
):
|
||||
d[a] = quote_xml_attr(etud[a])
|
||||
d["photo_url"] = quote_xml_attr(sco_photos.etud_photo_url(self, etud))
|
||||
d[a] = scu.quote_xml_attr(etud[a])
|
||||
d["civilite"] = scu.quote_xml_attr(
|
||||
etud["civilite_str"]
|
||||
) # exception: ne sort pas la civilite brute
|
||||
d["sexe"] = d["civilite"] # backward compat pour anciens clients
|
||||
d["photo_url"] = scu.quote_xml_attr(sco_photos.etud_photo_url(self, etud))
|
||||
|
||||
sem = etud["cursem"]
|
||||
if sem:
|
||||
@ -895,10 +969,10 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
{
|
||||
"current": "1",
|
||||
"formsemestre_id": sem["formsemestre_id"],
|
||||
"date_debut": DateDMYtoISO(sem["date_debut"]),
|
||||
"date_fin": DateDMYtoISO(sem["date_fin"]),
|
||||
"etat": quote_xml_attr(sem["ins"]["etat"]),
|
||||
"groupes": quote_xml_attr(
|
||||
"date_debut": ndb.DateDMYtoISO(sem["date_debut"]),
|
||||
"date_fin": ndb.DateDMYtoISO(sem["date_fin"]),
|
||||
"etat": scu.quote_xml_attr(sem["ins"]["etat"]),
|
||||
"groupes": scu.quote_xml_attr(
|
||||
etud["groupes"]
|
||||
), # slt pour semestre courant
|
||||
}
|
||||
@ -910,14 +984,14 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
d["insemestre"].append(
|
||||
{
|
||||
"formsemestre_id": sem["formsemestre_id"],
|
||||
"date_debut": DateDMYtoISO(sem["date_debut"]),
|
||||
"date_fin": DateDMYtoISO(sem["date_fin"]),
|
||||
"etat": quote_xml_attr(sem["ins"]["etat"]),
|
||||
"date_debut": ndb.DateDMYtoISO(sem["date_debut"]),
|
||||
"date_fin": ndb.DateDMYtoISO(sem["date_fin"]),
|
||||
"etat": scu.quote_xml_attr(sem["ins"]["etat"]),
|
||||
}
|
||||
)
|
||||
|
||||
log("etud_info (%gs)" % (time.time() - t0))
|
||||
return sendResult(
|
||||
return scu.sendResult(
|
||||
REQUEST, d, name="etudiant", format=format, force_outer_xml_tag=False
|
||||
)
|
||||
|
||||
@ -960,7 +1034,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
def _descr_situation_etud(self, etudid, ne=""):
|
||||
"""chaine decrivant la situation actuelle de l'etudiant"""
|
||||
cnx = self.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"select I.formsemestre_id, I.etat from notes_formsemestre_inscription I, notes_formsemestre S where etudid=%(etudid)s and S.formsemestre_id = I.formsemestre_id and date_debut < now() and date_fin > now() order by S.date_debut desc;",
|
||||
{"etudid": etudid},
|
||||
@ -1052,7 +1126,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
},
|
||||
)
|
||||
logdb(REQUEST, cnx, method="addAnnotation", etudid=etudid)
|
||||
REQUEST.RESPONSE.redirect("ficheEtud?etudid=" + etudid)
|
||||
return REQUEST.RESPONSE.redirect("ficheEtud?etudid=" + etudid)
|
||||
|
||||
security.declareProtected(ScoView, "canSuppressAnnotation")
|
||||
|
||||
@ -1091,7 +1165,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
logdb(REQUEST, cnx, method="SuppressAnnotation", etudid=etudid)
|
||||
scolars.etud_annotations_delete(cnx, annotation_id)
|
||||
|
||||
REQUEST.RESPONSE.redirect(
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"ficheEtud?etudid=%s&head_message=Annotation%%20supprimée" % (etudid)
|
||||
)
|
||||
|
||||
@ -1150,17 +1224,18 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
initvalues=adr,
|
||||
submitlabel="Valider le formulaire",
|
||||
)
|
||||
dest_url = self.ScoURL() + "/ficheEtud?etudid=" + etudid
|
||||
if tf[0] == 0:
|
||||
return header + "\n".join(H) + tf[1] + self.sco_footer(REQUEST)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
else:
|
||||
if adrs:
|
||||
scolars.adresse_edit(cnx, args=tf[2], context=self)
|
||||
else:
|
||||
scolars.adresse_create(cnx, args=tf[2])
|
||||
logdb(REQUEST, cnx, method="changeCoordonnees", etudid=etudid)
|
||||
REQUEST.RESPONSE.redirect("ficheEtud?etudid=" + etudid)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
|
||||
# --- Gestion des groupes:
|
||||
security.declareProtected(ScoView, "affectGroups")
|
||||
@ -1273,6 +1348,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
submitlabel="Valider",
|
||||
cancelbutton="Annuler",
|
||||
)
|
||||
dest_url = self.ScoURL() + "/ficheEtud?etudid=" + etud["etudid"]
|
||||
if tf[0] == 0:
|
||||
return (
|
||||
"\n".join(H)
|
||||
@ -1282,16 +1358,12 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
+ self.sco_footer(REQUEST)
|
||||
)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
REQUEST.URL1 + "/ficheEtud?etudid=" + etud["etudid"]
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
else:
|
||||
data = tf[2]["photofile"].read()
|
||||
status, diag = sco_photos.store_photo(self, etud, data, REQUEST=REQUEST)
|
||||
if status != 0:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
self.ScoURL() + "/ficheEtud?etudid=" + etud["etudid"]
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
else:
|
||||
H.append('<p class="warning">Erreur:' + diag + "</p>")
|
||||
return "\n".join(H) + self.sco_footer(REQUEST)
|
||||
@ -1313,7 +1385,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
sco_photos.suppress_photo(self, etud, REQUEST=REQUEST)
|
||||
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
REQUEST.URL1 + "/ficheEtud?etudid=" + etud["etudid"]
|
||||
self.ScoURL() + "/ficheEtud?etudid=" + etud["etudid"]
|
||||
)
|
||||
|
||||
#
|
||||
@ -1350,7 +1422,6 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
operation_method="",
|
||||
):
|
||||
"Formulaire démission ou défaillance Etudiant"
|
||||
cnx = self.GetDBConnexion()
|
||||
etud = self.getEtudInfo(etudid=etudid, filled=1, REQUEST=REQUEST)[0]
|
||||
sem = sco_formsemestre.get_formsemestre(self, formsemestre_id)
|
||||
if sem["etat"] != "1":
|
||||
@ -1374,7 +1445,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
"""<form action="%s" method="get">
|
||||
<b>Date de la %s (J/M/AAAA): </b>
|
||||
"""
|
||||
% (operation_method, strlower(operation_name))
|
||||
% (operation_method, scu.strlower(operation_name))
|
||||
)
|
||||
H.append(
|
||||
"""
|
||||
@ -1410,7 +1481,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
etudid,
|
||||
formsemestre_id,
|
||||
event_date=event_date,
|
||||
etat_new=DEF,
|
||||
etat_new=sco_codes_parcours.DEF,
|
||||
operation_method="defailleEtudiant",
|
||||
event_type="DEFAILLANCE",
|
||||
REQUEST=REQUEST,
|
||||
@ -1488,7 +1559,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
dialog_confirmed=dialog_confirmed,
|
||||
args=args,
|
||||
operation_name="défaillance",
|
||||
etat_current=DEF,
|
||||
etat_current=sco_codes_parcours.DEF,
|
||||
etat_new="I",
|
||||
operation_method="cancelDef",
|
||||
event_type="DEFAILLANCE",
|
||||
@ -1544,7 +1615,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
args=ins, formsemestre_id=formsemestre_id
|
||||
)
|
||||
logdb(REQUEST, cnx, method=operation_method, etudid=etudid)
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"delete from scolar_events where etudid=%(etudid)s and formsemestre_id=%(formsemestre_id)s and event_type='"
|
||||
+ event_type
|
||||
@ -1572,7 +1643,6 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
"Le formulaire HTML"
|
||||
H = [self.sco_header(REQUEST, init_jquery_ui=True)]
|
||||
F = self.sco_footer(REQUEST)
|
||||
AUTHENTICATED_USER = REQUEST.AUTHENTICATED_USER
|
||||
etudid = REQUEST.form.get("etudid", None)
|
||||
cnx = self.GetDBConnexion()
|
||||
descr = []
|
||||
@ -1607,12 +1677,14 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
# recuperation infos Apogee
|
||||
# Si on a le code NIP, fait juste une requete, sinon tente de rechercher par nom
|
||||
# (la recherche par nom ne fonctionne plus à Paris 13)
|
||||
code_nip = initvalues.get("code_nip", "")
|
||||
if code_nip:
|
||||
try:
|
||||
info = sco_portal_apogee.get_etud_apogee(self, code_nip)
|
||||
except ValueError:
|
||||
pass # XXX a terminer
|
||||
# XXX A terminer
|
||||
# code_nip = initvalues.get("code_nip", "")
|
||||
# if code_nip:
|
||||
# try:
|
||||
# infos = sco_portal_apogee.get_etud_apogee(self, code_nip)
|
||||
# except ValueError:
|
||||
# infos = None
|
||||
# pass # XXX a terminer
|
||||
nom = REQUEST.form.get("nom", None)
|
||||
if nom is None:
|
||||
nom = initvalues.get("nom", None)
|
||||
@ -1675,15 +1747,19 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
("nom_usuel", {"size": 25, "title": "Nom usuel", "allow_null": True}),
|
||||
(
|
||||
"prenom",
|
||||
{"size": 25, "title": "Prénom", "allow_null": CONFIG.ALLOW_NULL_PRENOM},
|
||||
{
|
||||
"size": 25,
|
||||
"title": "Prénom",
|
||||
"allow_null": scu.CONFIG.ALLOW_NULL_PRENOM,
|
||||
},
|
||||
),
|
||||
(
|
||||
"sexe",
|
||||
"civilite",
|
||||
{
|
||||
"input_type": "menu",
|
||||
"labels": ["H", "F"],
|
||||
"allowed_values": ["MR", "MME"],
|
||||
"title": "Genre",
|
||||
"labels": ["Homme", "Femme", "Autre/neutre"],
|
||||
"allowed_values": ["M", "F", "X"],
|
||||
"title": "Civilité",
|
||||
},
|
||||
),
|
||||
(
|
||||
@ -1776,7 +1852,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
{
|
||||
"input_type": "menu",
|
||||
"title": "Voie d'admission",
|
||||
"allowed_values": TYPES_ADMISSION,
|
||||
"allowed_values": scu.TYPES_ADMISSION,
|
||||
},
|
||||
),
|
||||
(
|
||||
@ -2009,7 +2085,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
"billet_absence",
|
||||
"identite",
|
||||
]
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
for table in tables:
|
||||
cursor.execute("delete from %s where etudid=%%(etudid)s" % table, etud)
|
||||
cnx.commit()
|
||||
@ -2017,7 +2093,9 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
to_inval = [s["formsemestre_id"] for s in etud["sems"]]
|
||||
if to_inval:
|
||||
self.Notes._inval_cache(formsemestre_id_list=to_inval) # >
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
self.ScoURL() + r"?head_message=Etudiant%20supprimé"
|
||||
)
|
||||
|
||||
security.declareProtected(ScoEtudInscrit, "check_group_apogee")
|
||||
|
||||
@ -2030,7 +2108,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
XXX A re-écrire pour API 2: prendre liste dans l'étape et vérifier à partir de cela.
|
||||
"""
|
||||
etat = etat or None
|
||||
members, group, group_tit, sem, nbdem = sco_groups.get_group_infos(
|
||||
members, group, _, sem, _ = sco_groups.get_group_infos(
|
||||
self, group_id, etat=etat
|
||||
)
|
||||
formsemestre_id = group["formsemestre_id"]
|
||||
@ -2136,8 +2214,8 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
% (
|
||||
REQUEST.URL0,
|
||||
formsemestre_id,
|
||||
strnone(group_id),
|
||||
strnone(etat),
|
||||
scu.strnone(group_id),
|
||||
scu.strnone(etat),
|
||||
formsemestre_id,
|
||||
)
|
||||
)
|
||||
@ -2155,8 +2233,8 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
% (
|
||||
REQUEST.URL0,
|
||||
formsemestre_id,
|
||||
strnone(group_id),
|
||||
strnone(etat),
|
||||
scu.strnone(group_id),
|
||||
scu.strnone(etat),
|
||||
formsemestre_id,
|
||||
)
|
||||
)
|
||||
@ -2169,8 +2247,13 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
||||
"formulaire import xls"
|
||||
if formsemestre_id:
|
||||
sem = sco_formsemestre.get_formsemestre(self.Notes, formsemestre_id)
|
||||
dest_url = (
|
||||
self.ScoURL()
|
||||
+ "/formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||
)
|
||||
else:
|
||||
sem = None
|
||||
dest_url = self.ScoURL()
|
||||
if sem and sem["etat"] != "1":
|
||||
raise ScoValueError("Modification impossible: semestre verrouille")
|
||||
H = [
|
||||
@ -2286,7 +2369,7 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + "</li></ol>" + "\n".join(S) + F
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
else:
|
||||
return ImportScolars.students_import_excel(
|
||||
self,
|
||||
@ -2335,7 +2418,6 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
|
||||
|
||||
def form_students_import_infos_admissions(self, REQUEST, formsemestre_id=None):
|
||||
"formulaire import xls"
|
||||
sem = sco_formsemestre.get_formsemestre(self.Notes, formsemestre_id)
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
F = self.sco_footer(REQUEST)
|
||||
if not authuser.has_permission(ScoEtudInscrit, self):
|
||||
@ -2424,7 +2506,11 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + help_text + F
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
self.ScoURL()
|
||||
+ "/formsemestre_status?formsemestre_id="
|
||||
+ formsemestre_id
|
||||
)
|
||||
else:
|
||||
return self._students_import_admission(
|
||||
tf[2]["csvfile"],
|
||||
@ -2505,7 +2591,6 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
|
||||
def stat_bac(self, formsemestre_id):
|
||||
"Renvoie statistisques sur nb d'etudiants par bac"
|
||||
cnx = self.GetDBConnexion()
|
||||
sem = sco_formsemestre.get_formsemestre(self, formsemestre_id)
|
||||
ins = self.Notes.do_formsemestre_inscription_list(
|
||||
args={"formsemestre_id": formsemestre_id}
|
||||
)
|
||||
@ -2634,23 +2719,23 @@ def manage_addZScolarForm(context, DeptId, REQUEST=None):
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + context.standard_html_footer(context)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect("/ScoDoc")
|
||||
else:
|
||||
DeptId = tf[2]["DeptId"].strip()
|
||||
db_cnx_string = tf[2]["db_cnx_string"].strip()
|
||||
# default connexion string
|
||||
if not db_cnx_string:
|
||||
db_name = "SCO" + DeptId.upper()
|
||||
db_user = SCO_DEFAULT_SQL_USER
|
||||
db_user = scu.SCO_DEFAULT_SQL_USER
|
||||
db_cnx_string = "user=%s dbname=%s port=%s" % (
|
||||
db_user,
|
||||
db_name,
|
||||
SCO_DEFAULT_SQL_PORT,
|
||||
scu.SCO_DEFAULT_SQL_PORT,
|
||||
)
|
||||
# vérifie que la bd existe et possede le meme nom de dept.
|
||||
try:
|
||||
cnx = psycopg2.connect(db_cnx_string)
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute("select * from sco_prefs where name='DeptName'")
|
||||
except:
|
||||
return _simple_error_page(
|
||||
|
@ -95,9 +95,6 @@ apt-get -y install python-cracklib # was python-crack
|
||||
apt-get -y install python-icalendar
|
||||
apt-get -y install python-requests
|
||||
|
||||
# XXX to fix: mx not needed anymore !
|
||||
apt-get -y install python-egenix-mxtools python-egenix-mxdatetime
|
||||
|
||||
|
||||
# ------------
|
||||
SVNVERSION=$(cd ..; svnversion)
|
||||
|
@ -1070,6 +1070,21 @@ for dept in get_depts():
|
||||
"etape",
|
||||
["alter table notes_formsemestre_inscription add column etape text"],
|
||||
)
|
||||
# Migre identite.sexe vers identite.civilite: normalise valeurs: M, F, X
|
||||
check_field(
|
||||
cnx,
|
||||
"identite",
|
||||
"civilite",
|
||||
[
|
||||
"UPDATE identite set sexe='M' where upper(sexe) = 'M' or upper(sexe) = 'M.' or upper(sexe) = 'MR' or upper(sexe) = 'H'",
|
||||
"UPDATE identite set sexe='F' where upper(sexe) = 'F' or upper(sexe) = 'MME' or upper(sexe) = 'MLLE' or upper(sexe) = 'MELLE' or upper(sexe) = 'MLLE.' or upper(sexe) = 'F'",
|
||||
"UPDATE identite set sexe='X' where sexe is NULL",
|
||||
"ALTER TABLE identite RENAME COLUMN sexe TO civilite",
|
||||
"ALTER TABLE identite ALTER COLUMN civilite SET NOT NULL",
|
||||
"ALTER TABLE identite ADD CONSTRAINT civchk CHECK (civilite IN ('M', 'F', 'X'))",
|
||||
],
|
||||
)
|
||||
|
||||
# Add here actions to performs after upgrades:
|
||||
cnx.commit()
|
||||
cnx.close()
|
||||
|
28
csv2rules.py
28
csv2rules.py
@ -45,7 +45,27 @@ HEAD = """# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Command: %s %s
|
||||
#
|
||||
from sco_codes_parcours import *
|
||||
from sco_codes_parcours import (
|
||||
DUTRule,
|
||||
ADC,
|
||||
ADJ,
|
||||
ADM,
|
||||
AJ,
|
||||
ALL,
|
||||
ATB,
|
||||
ATJ,
|
||||
ATT,
|
||||
CMP,
|
||||
NAR,
|
||||
NEXT,
|
||||
RA_OR_NEXT,
|
||||
RA_OR_RS,
|
||||
RAT,
|
||||
REO,
|
||||
REDOANNEE,
|
||||
REDOSEM,
|
||||
RS_OR_NEXT,
|
||||
)
|
||||
|
||||
rules_source_file='%s'
|
||||
|
||||
@ -55,15 +75,15 @@ rules_source_file='%s'
|
||||
sourcefile,
|
||||
)
|
||||
|
||||
from sco_codes_parcours import *
|
||||
import sco_utils as scu
|
||||
|
||||
|
||||
def _fmt(s):
|
||||
if not s:
|
||||
return None
|
||||
if strlower(s) in ("ok", "oui", "o", "y", "yes"):
|
||||
if scu.strlower(s) in ("ok", "oui", "o", "y", "yes"):
|
||||
return True
|
||||
if strlower(s) in ("no", "non"):
|
||||
if scu.strlower(s) in ("no", "non"):
|
||||
return False
|
||||
if s == "*":
|
||||
return ALL
|
||||
|
8
debug.py
8
debug.py
@ -32,10 +32,13 @@ nt = context.Notes._getNotesCache().get_NotesTable(context.Notes, formsemestre_i
|
||||
|
||||
"""
|
||||
import pdb
|
||||
import pprint
|
||||
|
||||
from notesdb import *
|
||||
import notesdb as ndb
|
||||
from notesdb import * # pylint: disable=unused-wildcard-import
|
||||
from notes_log import log
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from sco_utils import * # pylint: disable=unused-wildcard-import
|
||||
|
||||
from gen_tables import GenTable
|
||||
import sco_archives
|
||||
@ -106,7 +109,6 @@ class DummyRequest:
|
||||
self.AUTHENTICATED_USER = FakeUser("admin")
|
||||
self.form = {}
|
||||
self.URL = "http://scodoc/"
|
||||
self.URL1 = self.URL
|
||||
self.URL0 = self.URL
|
||||
self.BASE0 = "localhost"
|
||||
self.REMOTE_HOST = "localhost"
|
||||
|
@ -25,7 +25,9 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from sco_utils import *
|
||||
import cgi
|
||||
|
||||
import sco_utils as scu
|
||||
from sco_formsemestre_status import formsemestre_page_title
|
||||
|
||||
"""
|
||||
@ -95,7 +97,7 @@ def sco_header(
|
||||
"page_title": page_title or context.title_or_id(),
|
||||
"no_side_bar": no_side_bar,
|
||||
"ScoURL": context.ScoURL(),
|
||||
"encoding": SCO_ENCODING,
|
||||
"encoding": scu.SCO_ENCODING,
|
||||
"titrebandeau_mkup": "<td>" + titrebandeau + "</td>",
|
||||
"authuser": str(REQUEST.AUTHENTICATED_USER),
|
||||
}
|
||||
@ -224,7 +226,7 @@ def sco_header(
|
||||
|
||||
# Body et bandeau haut:
|
||||
H.append("""<body %(bodyOnLoad_mkup)s>""" % params)
|
||||
H.append(CUSTOM_HTML_HEADER)
|
||||
H.append(scu.CUSTOM_HTML_HEADER)
|
||||
#
|
||||
if not no_side_bar:
|
||||
H.append(context.sidebar(REQUEST))
|
||||
@ -258,4 +260,6 @@ def sco_header(
|
||||
|
||||
def sco_footer(context, REQUEST=None):
|
||||
"""Main HTMl pages footer"""
|
||||
return """</div><!-- /gtrcontent -->""" + CUSTOM_HTML_FOOTER + """</body></html>"""
|
||||
return (
|
||||
"""</div><!-- /gtrcontent -->""" + scu.CUSTOM_HTML_FOOTER + """</body></html>"""
|
||||
)
|
||||
|
@ -25,8 +25,14 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from sco_abs import getAbsSemEtud
|
||||
from sco_permissions import (
|
||||
ScoUsersAdmin,
|
||||
ScoUsersView,
|
||||
ScoChangePreferences,
|
||||
ScoAbsChange,
|
||||
)
|
||||
|
||||
"""
|
||||
Génération de la "sidebar" (marge gauche des pages HTML)
|
||||
@ -76,7 +82,7 @@ def sidebar_common(context, REQUEST=None):
|
||||
def sidebar(context, REQUEST=None):
|
||||
"Main HTML page sidebar"
|
||||
# rewritten from legacy DTML code
|
||||
params = {"ScoURL": context.ScoURL(), "SCO_USER_MANUAL": SCO_USER_MANUAL}
|
||||
params = {"ScoURL": context.ScoURL(), "SCO_USER_MANUAL": scu.SCO_USER_MANUAL}
|
||||
|
||||
H = ['<div class="sidebar">', sidebar_common(context, REQUEST)]
|
||||
|
||||
@ -97,7 +103,7 @@ def sidebar(context, REQUEST=None):
|
||||
# compte les absences du semestre en cours
|
||||
H.append(
|
||||
"""<h2 id="insidebar-etud"><a href="%(ScoURL)s/ficheEtud?etudid=%(etudid)s" class="sidebar">
|
||||
<font color="#FF0000">%(sexe)s %(nom_disp)s</font></a>
|
||||
<font color="#FF0000">%(civilite_str)s %(nom_disp)s</font></a>
|
||||
</h2>
|
||||
<b>Absences</b>"""
|
||||
% params
|
||||
@ -142,7 +148,7 @@ def sidebar(context, REQUEST=None):
|
||||
# ---------
|
||||
H.append("</div><br/> ") # /etud-insidebar
|
||||
# Logo
|
||||
scologo_img = icontag("scologo_img")
|
||||
scologo_img = scu.icontag("scologo_img")
|
||||
H.append('<div class="logo-insidebar"><div class="logo-logo">%s<br/>' % scologo_img)
|
||||
H.append(
|
||||
"""<a href="%(ScoURL)s/about" class="sidebar">A propos</a><br/>
|
||||
|
16
intervals.py
16
intervals.py
@ -173,17 +173,17 @@ if __name__ == "__main__":
|
||||
repr(i)
|
||||
== "{[None, 3] => 'My,', [3, 5] => 'Hello', [6, 7] => 'World', [8, 10] => '(Test)', [10, None] => '!'}"
|
||||
)
|
||||
i[5.5:6] = "Cruel"
|
||||
i[5.5:6] = "Cruel" # pylint: disable=invalid-slice-index
|
||||
assert (
|
||||
repr(i)
|
||||
== "{[None, 3] => 'My,', [3, 5] => 'Hello', [5.5, 6] => 'Cruel', [6, 7] => 'World', [8, 10] => '(Test)', [10, None] => '!'}"
|
||||
)
|
||||
i[6:6.5] = "And Harsh"
|
||||
i[6:6.5] = "And Harsh" # pylint: disable=invalid-slice-index
|
||||
assert (
|
||||
repr(i)
|
||||
== "{[None, 3] => 'My,', [3, 5] => 'Hello', [5.5, 6] => 'Cruel', [6, 6.5] => 'And Harsh', [6.5, 7] => 'World', [8, 10] => '(Test)', [10, None] => '!'}"
|
||||
)
|
||||
i[5.9:6.6] = None
|
||||
i[5.9:6.6] = None # pylint: disable=invalid-slice-index
|
||||
assert (
|
||||
repr(i)
|
||||
== "{[None, 3] => 'My,', [3, 5] => 'Hello', [5.5, 5.9000000000000004] => 'Cruel', [6.5999999999999996, 7] => 'World', [8, 10] => '(Test)', [10, None] => '!'}"
|
||||
@ -222,9 +222,13 @@ if __name__ == "__main__":
|
||||
print("Test 3 skipped")
|
||||
else:
|
||||
i = intervalmap()
|
||||
i[: datetime(2005, 10, 24)] = "A"
|
||||
i[datetime(2005, 11, 11) : datetime(2005, 11, 17)] = "B"
|
||||
i[datetime(2005, 11, 30) :] = "C"
|
||||
i[: datetime(2005, 10, 24)] = "A" # pylint: disable=invalid-slice-index
|
||||
i[
|
||||
datetime(2005, 11, 11) : datetime( # pylint: disable=invalid-slice-index
|
||||
2005, 11, 17
|
||||
)
|
||||
] = "B"
|
||||
i[datetime(2005, 11, 30) :] = "C" # pylint: disable=invalid-slice-index
|
||||
assert i[datetime(2005, 9, 25)] == "A"
|
||||
assert i[datetime(2005, 10, 23)] == "A"
|
||||
assert i[datetime(2005, 10, 26)] == None
|
||||
|
@ -49,7 +49,7 @@ CREATE TABLE identite (
|
||||
etudid text DEFAULT notes_newid_etud('EID'::text) UNIQUE NOT NULL,
|
||||
nom text,
|
||||
prenom text,
|
||||
sexe text,
|
||||
civilite text NOT NULL CHECK (civilite IN ('M', 'F', 'X')),
|
||||
date_naissance date, -- new: date en texte
|
||||
lieu_naissance text,
|
||||
dept_naissance text,
|
||||
|
@ -8,7 +8,7 @@ Code_INE; text; identite; 1; code INE;INE
|
||||
nom; text; identite; 0; nom de l'etudiant;
|
||||
nom_usuel; text; identite; 1; nom usuel (si different);
|
||||
prenom; text; identite; 0; prenom de l'etudiant
|
||||
sexe (H ou F); text; identite; 0; sexe ('H' ou 'F');sexe;genre
|
||||
civilite; text; identite; 1; sexe ('M', 'F', 'X');sexe;genre
|
||||
date_naissance;text;identite; 1; date de naissance (jj/mm/aaaa)
|
||||
lieu_naissance;text;identite; 1; lieu de naissance
|
||||
nationalite; text; identite; 1; nationalite
|
||||
|
15
notes_log.py
15
notes_log.py
@ -1,13 +1,26 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pdb, os, sys, time, re, inspect
|
||||
import pdb
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import inspect
|
||||
import time
|
||||
import traceback
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.base import MIMEBase
|
||||
from email.header import Header
|
||||
|
||||
from email.MIMEMultipart import ( # pylint: disable=no-name-in-module,import-error
|
||||
MIMEMultipart,
|
||||
)
|
||||
from email.MIMEText import MIMEText # pylint: disable=no-name-in-module,import-error
|
||||
from email.MIMEBase import MIMEBase # pylint: disable=no-name-in-module,import-error
|
||||
from email.Header import Header # pylint: disable=no-name-in-module,import-error
|
||||
from email import Encoders # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
# Simple & stupid file logguer, used only to debug
|
||||
# (logging to SQL is done in scolog)
|
||||
|
||||
|
@ -27,16 +27,19 @@
|
||||
|
||||
"""Calculs sur les notes et cache des resultats
|
||||
"""
|
||||
from types import StringType
|
||||
from types import StringType, FloatType
|
||||
import time
|
||||
import pdb
|
||||
import inspect
|
||||
|
||||
|
||||
import scolars
|
||||
import sco_groups
|
||||
from notes_log import log, logCallStack
|
||||
from sco_utils import *
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
import sco_codes_parcours
|
||||
from sco_codes_parcours import DEF, UE_SPORT, UE_is_fondamentale, UE_is_professionnelle
|
||||
from sco_parcours_dut import formsemestre_get_etud_capitalisation
|
||||
from sco_parcours_dut import list_formsemestre_utilisateurs_uecap
|
||||
import sco_parcours_dut
|
||||
@ -46,9 +49,15 @@ import sco_moduleimpl
|
||||
import sco_evaluations
|
||||
import sco_compute_moy
|
||||
from sco_formulas import NoteVector
|
||||
from sco_exceptions import (
|
||||
AccessDenied,
|
||||
NoteProcessError,
|
||||
ScoException,
|
||||
ScoValueError,
|
||||
)
|
||||
|
||||
# Support for old user-written "bonus" functions with 2 args:
|
||||
BONUS_TWO_ARGS = len(inspect.getargspec(CONFIG.compute_bonus)[0]) == 2
|
||||
BONUS_TWO_ARGS = len(inspect.getargspec(scu.CONFIG.compute_bonus)[0]) == 2
|
||||
|
||||
|
||||
def comp_ranks(T):
|
||||
@ -107,7 +116,7 @@ def comp_etud_sum_coef_modules_ue(context, formsemestre_id, etudid, ue_id):
|
||||
|
||||
(nécessaire pour éviter appels récursifs de nt, qui peuvent boucler)
|
||||
"""
|
||||
infos = SimpleDictFetch(
|
||||
infos = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT mod.coefficient
|
||||
FROM notes_modules mod, notes_moduleimpl mi, notes_moduleimpl_inscription ins
|
||||
@ -187,7 +196,7 @@ class NotesTable:
|
||||
for i in range(len(self.inscrlist)):
|
||||
rangalpha[self.inscrlist[i]["etudid"]] = i
|
||||
|
||||
self.bonus = DictDefault(defaultvalue=0)
|
||||
self.bonus = scu.DictDefault(defaultvalue=0)
|
||||
# Notes dans les modules { moduleimpl_id : { etudid: note_moyenne_dans_ce_module } }
|
||||
(
|
||||
self._modmoys,
|
||||
@ -363,29 +372,28 @@ class NotesTable:
|
||||
def get_sexnom(self, etudid):
|
||||
"M. DUPONT"
|
||||
etud = self.identdict[etudid]
|
||||
return etud["sexe"] + " " + strupper(etud["nom_usuel"] or etud["nom"])
|
||||
return (
|
||||
etud["civilite_str"] + " " + scu.strupper(etud["nom_usuel"] or etud["nom"])
|
||||
)
|
||||
|
||||
def get_nom_short(self, etudid):
|
||||
"formatte nom d'un etud (pour table recap)"
|
||||
etud = self.identdict[etudid]
|
||||
# Attention aux caracteres multibytes pour decouper les 2 premiers:
|
||||
return (
|
||||
strupper(etud["nom_usuel"] or etud["nom"])
|
||||
scu.strupper(etud["nom_usuel"] or etud["nom"])
|
||||
+ " "
|
||||
+ etud["prenom"].decode(SCO_ENCODING).capitalize()[:2].encode(SCO_ENCODING)
|
||||
+ etud["prenom"]
|
||||
.decode(scu.SCO_ENCODING)
|
||||
.capitalize()[:2]
|
||||
.encode(scu.SCO_ENCODING)
|
||||
+ "."
|
||||
)
|
||||
|
||||
def get_nom_long(self, etudid):
|
||||
"formatte nom d'un etud: M. Pierre DUPONT"
|
||||
etud = self.identdict[etudid]
|
||||
return " ".join(
|
||||
[
|
||||
scolars.format_sexe(etud["sexe"]),
|
||||
scolars.format_prenom(etud["prenom"]),
|
||||
scolars.format_nom(etud["nom_usuel"] or etud["nom"]),
|
||||
]
|
||||
)
|
||||
return scolars.format_nomprenom(etud)
|
||||
|
||||
def get_displayed_etud_code(self, etudid):
|
||||
'code à afficher sur les listings "anonymes"'
|
||||
@ -616,7 +624,7 @@ class NotesTable:
|
||||
# si 'NI', etudiant non inscrit a ce module
|
||||
if val != "NI":
|
||||
est_inscrit = True
|
||||
if modimpl["module"]["module_type"] == MODULE_STANDARD:
|
||||
if modimpl["module"]["module_type"] == scu.MODULE_STANDARD:
|
||||
coef = modimpl["module"]["coefficient"]
|
||||
if modimpl["ue"]["type"] != UE_SPORT:
|
||||
notes.append(val, name=modimpl["module"]["code"])
|
||||
@ -652,7 +660,7 @@ class NotesTable:
|
||||
except:
|
||||
# log('comp_etud_moy_ue: exception: val=%s coef=%s' % (val,coef))
|
||||
pass
|
||||
elif modimpl["module"]["module_type"] == MODULE_MALUS:
|
||||
elif modimpl["module"]["module_type"] == scu.MODULE_MALUS:
|
||||
try:
|
||||
ue_malus += val
|
||||
except:
|
||||
@ -672,7 +680,7 @@ class NotesTable:
|
||||
moy = sum_notes / sum_coefs
|
||||
if ue_malus:
|
||||
moy -= ue_malus
|
||||
moy = max(NOTES_MIN, min(moy, 20.0))
|
||||
moy = max(scu.NOTES_MIN, min(moy, 20.0))
|
||||
moy_valid = True
|
||||
else:
|
||||
moy = "NA"
|
||||
@ -898,7 +906,7 @@ class NotesTable:
|
||||
# mu["moy"] can be a number, or "NA", or "ERR" (user-defined UE formulas)
|
||||
if (
|
||||
(mu["ue"]["type"] != UE_SPORT)
|
||||
and isnumber(mu["moy"])
|
||||
and scu.isnumber(mu["moy"])
|
||||
and (mu["est_inscrit"] or mu["is_capitalized"])
|
||||
):
|
||||
coef_ue = mu["ue"]["coefficient"]
|
||||
@ -931,9 +939,11 @@ class NotesTable:
|
||||
|
||||
if BONUS_TWO_ARGS:
|
||||
# backward compat: compute_bonus took only 2 args
|
||||
bonus = CONFIG.compute_bonus(notes_bonus_gen, coefs_bonus_gen)
|
||||
bonus = scu.CONFIG.compute_bonus(
|
||||
notes_bonus_gen, coefs_bonus_gen
|
||||
)
|
||||
else:
|
||||
bonus = CONFIG.compute_bonus(
|
||||
bonus = scu.CONFIG.compute_bonus(
|
||||
notes_bonus_gen, coefs_bonus_gen, infos=infos
|
||||
)
|
||||
self.bonus[etudid] = bonus
|
||||
@ -1023,7 +1033,7 @@ class NotesTable:
|
||||
Si l'étudiant est défaillant, met un code DEF sur toutes les UE
|
||||
"""
|
||||
cnx = self.context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"select etudid, code, assidu, compense_formsemestre_id, event_date from scolar_formsemestre_validation where formsemestre_id=%(formsemestre_id)s and ue_id is NULL;",
|
||||
{"formsemestre_id": self.formsemestre_id},
|
||||
@ -1040,7 +1050,7 @@ class NotesTable:
|
||||
"code": code,
|
||||
"assidu": assidu,
|
||||
"compense_formsemestre_id": compense_formsemestre_id,
|
||||
"event_date": DateISOtoDMY(event_date),
|
||||
"event_date": ndb.DateISOtoDMY(event_date),
|
||||
}
|
||||
|
||||
self.decisions_jury = decisions_jury
|
||||
@ -1089,7 +1099,7 @@ class NotesTable:
|
||||
decisions_jury_ues[etudid][ue_id] = {
|
||||
"code": code,
|
||||
"ects": ects, # 0. si non UE validée ou si mode de calcul different (?)
|
||||
"event_date": DateISOtoDMY(event_date),
|
||||
"event_date": ndb.DateISOtoDMY(event_date),
|
||||
}
|
||||
|
||||
self.decisions_jury_ues = decisions_jury_ues
|
||||
@ -1146,7 +1156,7 @@ class NotesTable:
|
||||
ue_capitalisees = { etudid :
|
||||
[{ 'moy':, 'event_date' : ,'formsemestre_id' : }, ...] }
|
||||
"""
|
||||
self.ue_capitalisees = DictDefault(defaultvalue=[])
|
||||
self.ue_capitalisees = scu.DictDefault(defaultvalue=[])
|
||||
cnx = None
|
||||
for etudid in self.get_etudids():
|
||||
capital = formsemestre_get_etud_capitalisation(
|
||||
@ -1281,13 +1291,13 @@ class NotesTable:
|
||||
(ne compte que les notes en attente dans des évaluation avec coef. non nul).
|
||||
"""
|
||||
cnx = self.context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"select n.* from notes_notes n, notes_evaluation e, notes_moduleimpl m, notes_moduleimpl_inscription i where n.etudid = %(etudid)s and n.value = %(code_attente)s and n.evaluation_id=e.evaluation_id and e.moduleimpl_id=m.moduleimpl_id and m.formsemestre_id=%(formsemestre_id)s and e.coefficient != 0 and m.moduleimpl_id=i.moduleimpl_id and i.etudid=%(etudid)s",
|
||||
{
|
||||
"formsemestre_id": self.formsemestre_id,
|
||||
"etudid": etudid,
|
||||
"code_attente": NOTES_ATTENTE,
|
||||
"code_attente": scu.NOTES_ATTENTE,
|
||||
},
|
||||
)
|
||||
return len(cursor.fetchall()) > 0
|
||||
@ -1331,7 +1341,7 @@ class CacheNotesTable:
|
||||
# Cache des classeur PDF (bulletins)
|
||||
self.pdfcache = {} # { formsemestre_id : (filename, pdfdoc) }
|
||||
# Listeners:
|
||||
self.listeners = DictDefault(
|
||||
self.listeners = scu.DictDefault(
|
||||
defaultvalue={}
|
||||
) # {formsemestre_id : {listener_id : callback }}
|
||||
|
||||
|
20
notesdb.py
20
notesdb.py
@ -5,10 +5,11 @@ import pdb, os, sys, string
|
||||
import traceback
|
||||
import psycopg2
|
||||
import psycopg2.pool
|
||||
import psycopg2.extras
|
||||
import thread
|
||||
from notes_log import log
|
||||
from sco_exceptions import *
|
||||
from types import *
|
||||
from sco_exceptions import ScoException, ScoValueError, NoteProcessError
|
||||
from types import StringType
|
||||
from cgi import escape
|
||||
import datetime
|
||||
|
||||
@ -67,16 +68,17 @@ def GetUsersDBConnexion(context, autocommit=True):
|
||||
return cnx
|
||||
|
||||
|
||||
# Nota: on pourrait maintenant utiliser psycopg2.extras.DictCursor
|
||||
class ScoDocCursor(psycopg2.extensions.cursor):
|
||||
"""A database cursor emulating some methods of psycopg v1 cursors"""
|
||||
|
||||
def dictfetchall(cursor):
|
||||
col_names = [d[0] for d in cursor.description]
|
||||
return [dict(zip(col_names, row)) for row in cursor.fetchall()]
|
||||
def dictfetchall(self):
|
||||
col_names = [d[0] for d in self.description]
|
||||
return [dict(zip(col_names, row)) for row in self.fetchall()]
|
||||
|
||||
def dictfetchone(cursor):
|
||||
col_names = [d[0] for d in cursor.description]
|
||||
row = cursor.fetchone()
|
||||
def dictfetchone(self):
|
||||
col_names = [d[0] for d in self.description]
|
||||
row = self.fetchone()
|
||||
if row:
|
||||
return dict(zip(col_names, row))
|
||||
else:
|
||||
@ -173,7 +175,7 @@ def DBSelectArgs(
|
||||
cond = ""
|
||||
i = 1
|
||||
cl = []
|
||||
for (aux_tab, aux_id) in aux_tables:
|
||||
for (_, aux_id) in aux_tables:
|
||||
cl.append("T0.%s = T%d.%s" % (id_name, i, aux_id))
|
||||
i = i + 1
|
||||
cond += " and ".join(cl)
|
||||
|
@ -30,12 +30,14 @@
|
||||
# conçu et développé par Cléo Baras (IUT de Grenoble)
|
||||
##############################################################################
|
||||
|
||||
import os
|
||||
import codecs
|
||||
import re
|
||||
import scolars
|
||||
import pe_jurype, pe_tagtable, pe_tools
|
||||
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import scolars
|
||||
|
||||
import pe_jurype, pe_tagtable, pe_tools
|
||||
@ -55,7 +57,7 @@ def get_code_latex_from_modele(fichier):
|
||||
vers le modele : attention pas de vérification du format d'encodage
|
||||
Le fichier doit donc etre enregistré avec le même codage que ScoDoc (utf-8)
|
||||
"""
|
||||
fid_latex = codecs.open(fichier, "r", encoding=SCO_ENCODING)
|
||||
fid_latex = codecs.open(fichier, "r", encoding=scu.SCO_ENCODING)
|
||||
un_avis_latex = fid_latex.read()
|
||||
fid_latex.close()
|
||||
return un_avis_latex
|
||||
@ -72,7 +74,7 @@ def get_code_latex_from_scodoc_preference(
|
||||
template_latex = context.get_preference(champ, formsemestre_id)
|
||||
# Conversion du template en unicode:
|
||||
if template_latex:
|
||||
template_latex = template_latex.decode(SCO_ENCODING)
|
||||
template_latex = template_latex.decode(scu.SCO_ENCODING)
|
||||
else:
|
||||
template_latex = u"" # EV: preference non définie (None)
|
||||
|
||||
@ -119,10 +121,14 @@ def comp_latex_parcourstimeline(etudiant, promo, taille=17):
|
||||
\\end{parcourstimeline}
|
||||
"""
|
||||
reslatex = codelatexDebut
|
||||
reslatex = reslatex.replace("**debut**", etudiant["entree"].decode(SCO_ENCODING))
|
||||
reslatex = reslatex.replace("**fin**", str(etudiant["promo"]).decode(SCO_ENCODING))
|
||||
reslatex = reslatex.replace(
|
||||
"**nbreSemestres**", str(etudiant["nbSemestres"]).decode(SCO_ENCODING)
|
||||
"**debut**", etudiant["entree"].decode(scu.SCO_ENCODING)
|
||||
)
|
||||
reslatex = reslatex.replace(
|
||||
"**fin**", str(etudiant["promo"]).decode(scu.SCO_ENCODING)
|
||||
)
|
||||
reslatex = reslatex.replace(
|
||||
"**nbreSemestres**", str(etudiant["nbSemestres"]).decode(scu.SCO_ENCODING)
|
||||
)
|
||||
# Tri du parcours par ordre croissant : de la forme descr, nom sem date-date
|
||||
parcours = etudiant["parcours"][::-1] # EV: XXX je ne comprend pas ce commentaire ?
|
||||
@ -179,7 +185,7 @@ def get_code_latex_avis_etudiant(
|
||||
# Recherche des tags dans le fichier
|
||||
tags_latex = get_tags_latex(code)
|
||||
if DEBUG:
|
||||
print("Les tags" + str(tags_latex))
|
||||
log("Les tags" + str(tags_latex))
|
||||
|
||||
# Interprète et remplace chaque tags latex par les données numériques de l'étudiant (y compris les
|
||||
# tags "macros" tels que parcourstimeline
|
||||
@ -207,17 +213,16 @@ def get_code_latex_avis_etudiant(
|
||||
elif tag_latex == u"bilanParTag":
|
||||
valeur = get_bilanParTag(donnees_etudiant)
|
||||
|
||||
# Les tags "simples": par ex. nom, prenom, sexe, ...
|
||||
# Les tags "simples": par ex. nom, prenom, civilite, ...
|
||||
else:
|
||||
if tag_latex in donnees_etudiant:
|
||||
valeur = donnees_etudiant[tag_latex].decode(SCO_ENCODING)
|
||||
valeur = donnees_etudiant[tag_latex].decode(scu.SCO_ENCODING)
|
||||
elif tag_latex in prefs: # les champs **NomResponsablePE**, ...
|
||||
valeur = pe_tools.escape_for_latex(prefs[tag_latex]).decode(
|
||||
SCO_ENCODING
|
||||
scu.SCO_ENCODING
|
||||
)
|
||||
|
||||
# Gestion des pb d'encodage XXX debug
|
||||
# print(tag_latex, valeur)
|
||||
assert isinstance(tag_latex, unicode)
|
||||
assert isinstance(valeur, unicode)
|
||||
|
||||
@ -244,7 +249,7 @@ def get_annotation_PE(context, etudid, tag_annotation_pe):
|
||||
exp = re.compile(r"^" + tag_annotation_pe)
|
||||
|
||||
for a in annotations:
|
||||
commentaire = unescape_html(a["comment"]).decode(SCO_ENCODING)
|
||||
commentaire = scu.unescape_html(a["comment"]).decode(scu.SCO_ENCODING)
|
||||
if exp.match(commentaire): # tag en début de commentaire ?
|
||||
a["comment_u"] = commentaire # unicode, HTML non quoté
|
||||
annotationsPE.append(
|
||||
@ -282,7 +287,6 @@ def str_from_syntheseJury(donnees_etudiant, aggregat, groupe, tag_scodoc, champ)
|
||||
for chp in champ
|
||||
]
|
||||
else: # champ = str à priori
|
||||
# print(champ)
|
||||
valeur = DONNEE_MANQUANTE
|
||||
if (
|
||||
(aggregat in donnees_etudiant)
|
||||
@ -316,7 +320,6 @@ def str_from_syntheseJury(donnees_etudiant, aggregat, groupe, tag_scodoc, champ)
|
||||
else:
|
||||
valeur = u"%s" % donnees_numeriques[indice_champ]
|
||||
|
||||
# print(valeur)
|
||||
return valeur
|
||||
|
||||
|
||||
@ -339,7 +342,7 @@ def get_bilanParTag(donnees_etudiant, groupe="groupe"):
|
||||
|
||||
lignes = []
|
||||
valeurs = {"note": [], "rang": []}
|
||||
for (indice_aggregat, (aggregat, intitule, ordre)) in enumerate(entete):
|
||||
for (indice_aggregat, (aggregat, intitule, _)) in enumerate(entete):
|
||||
# print("> " + aggregat)
|
||||
# listeTags = jury.get_allTagForAggregat(aggregat) # les tags de l'aggrégat
|
||||
listeTags = [
|
||||
@ -366,25 +369,20 @@ def get_bilanParTag(donnees_etudiant, groupe="groupe"):
|
||||
("\\textit{" + rang + "}") if note else ""
|
||||
) # rang masqué si pas de notes
|
||||
|
||||
# pprint.pprint(valeurs)
|
||||
# print(len(entete))
|
||||
code_latex = u"\\begin{tabular}{|c|" + "|c" * (len(entete)) + "|}\n"
|
||||
code_latex += u"\\hline \n"
|
||||
code_latex += (
|
||||
u" & "
|
||||
+ " & ".join(
|
||||
["\\textbf{" + intitule + "}" for (agg, intitule, ordre) in entete]
|
||||
)
|
||||
+ " & ".join(["\\textbf{" + intitule + "}" for (agg, intitule, _) in entete])
|
||||
+ " \\\\ \n"
|
||||
)
|
||||
code_latex += u"\\hline"
|
||||
code_latex += u"\\hline \n"
|
||||
for (i, ligne_val) in enumerate(valeurs["note"]):
|
||||
titre = lignes[i] # règle le pb d'encodage
|
||||
# print titre, ligne_val
|
||||
code_latex += (
|
||||
u"\\textbf{"
|
||||
+ titre.decode(SCO_ENCODING)
|
||||
+ titre.decode(scu.SCO_ENCODING)
|
||||
+ u"} & "
|
||||
+ " & ".join(ligne_val)
|
||||
+ u"\\\\ \n"
|
||||
@ -412,9 +410,11 @@ def get_avis_poursuite_par_etudiant(
|
||||
if pe_tools.PE_DEBUG:
|
||||
pe_tools.pe_print(jury.syntheseJury[etudid]["nom"] + " " + etudid)
|
||||
|
||||
sexe = jury.syntheseJury[etudid]["sexe"].decode(SCO_ENCODING)
|
||||
nom = jury.syntheseJury[etudid]["nom"].replace(" ", "-").decode(SCO_ENCODING)
|
||||
prenom = jury.syntheseJury[etudid]["prenom"].replace(" ", "-").decode(SCO_ENCODING)
|
||||
civilite_str = jury.syntheseJury[etudid]["civilite_str"].decode(scu.SCO_ENCODING)
|
||||
nom = jury.syntheseJury[etudid]["nom"].replace(" ", "-").decode(scu.SCO_ENCODING)
|
||||
prenom = (
|
||||
jury.syntheseJury[etudid]["prenom"].replace(" ", "-").decode(scu.SCO_ENCODING)
|
||||
)
|
||||
|
||||
nom_fichier = (
|
||||
u"avis_poursuite_"
|
||||
@ -429,7 +429,9 @@ def get_avis_poursuite_par_etudiant(
|
||||
|
||||
# Entete (commentaire)
|
||||
|
||||
contenu_latex = u"%% ---- Etudiant: " + sexe + " " + nom + " " + prenom + u"\n"
|
||||
contenu_latex = (
|
||||
u"%% ---- Etudiant: " + civilite_str + " " + nom + " " + prenom + u"\n"
|
||||
)
|
||||
|
||||
# les annnotations
|
||||
annotationPE = get_annotation_PE(
|
||||
@ -460,11 +462,11 @@ def get_templates_from_distrib(template="avis"):
|
||||
|
||||
if template in ["avis", "footer"]:
|
||||
# pas de preference pour le template: utilise fichier du serveur
|
||||
p = os.path.join(SCO_SRC_DIR, pe_local_tmpl)
|
||||
p = os.path.join(scu.SCO_SRC_DIR, pe_local_tmpl)
|
||||
if os.path.exists(p):
|
||||
template_latex = get_code_latex_from_modele(p)
|
||||
else:
|
||||
p = os.path.join(SCO_SRC_DIR, pe_default_tmpl)
|
||||
p = os.path.join(scu.SCO_SRC_DIR, pe_default_tmpl)
|
||||
if os.path.exists(p):
|
||||
template_latex = get_code_latex_from_modele(p)
|
||||
else:
|
||||
@ -502,7 +504,7 @@ def table_syntheseAnnotationPE(context, syntheseJury, tag_annotation_pe):
|
||||
[syntheseJury[etudid]["nbSemestres"] for etudid in etudids]
|
||||
) # le nombre de semestre le + grand
|
||||
|
||||
infos = ["sexe", "nom", "prenom", "age", "nbSemestres"]
|
||||
infos = ["civilite", "nom", "prenom", "age", "nbSemestres"]
|
||||
entete = ["etudid"]
|
||||
entete.extend(infos)
|
||||
entete.extend(["P%d" % i for i in range(1, maxParcours + 1)]) # ajout du parcours
|
||||
@ -518,7 +520,7 @@ def table_syntheseAnnotationPE(context, syntheseJury, tag_annotation_pe):
|
||||
# Les info générales:
|
||||
row = {
|
||||
"etudid": etudid,
|
||||
"sexe": e["sexe"],
|
||||
"civilite": e["civilite"],
|
||||
"nom": e["nom"],
|
||||
"prenom": e["prenom"],
|
||||
"age": e["age"],
|
||||
@ -534,7 +536,9 @@ def table_syntheseAnnotationPE(context, syntheseJury, tag_annotation_pe):
|
||||
annotationPE = get_annotation_PE(
|
||||
context, etudid, tag_annotation_pe=tag_annotation_pe
|
||||
)
|
||||
row["Annotation PE"] = annotationPE.encode(SCO_ENCODING) if annotationPE else ""
|
||||
row["Annotation PE"] = (
|
||||
annotationPE.encode(scu.SCO_ENCODING) if annotationPE else ""
|
||||
)
|
||||
rows.append(row)
|
||||
|
||||
T = GenTable(
|
||||
|
29
pe_jurype.py
29
pe_jurype.py
@ -42,6 +42,7 @@ Created on Fri Sep 9 09:15:05 2016
|
||||
# a l'edition d'un jury de poursuites d'etudes
|
||||
# ----------------------------------------------------------
|
||||
|
||||
import os
|
||||
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
@ -54,10 +55,9 @@ from zipfile import ZipFile, BadZipfile
|
||||
import pprint
|
||||
|
||||
from gen_tables import GenTable, SeqGenTable
|
||||
|
||||
import sco_utils as scu
|
||||
import sco_codes_parcours # sco_codes_parcours.NEXT -> sem suivant
|
||||
import sco_report
|
||||
from sco_utils import *
|
||||
|
||||
import pe_tagtable, pe_tools, pe_avislatex, pe_semestretag, pe_settag
|
||||
|
||||
@ -85,7 +85,7 @@ class JuryPE:
|
||||
- context : le contexte Zope
|
||||
- juryEtudDict : dictionnaire récapitulant les étudiants participant au jury PE (données administratives +
|
||||
celles des semestres valides à prendre en compte permettant le calcul des moyennes ...
|
||||
{'etudid : { 'nom', 'prenom', 'sexe', 'diplome', '', }}
|
||||
{'etudid : { 'nom', 'prenom', 'civilite', 'diplome', '', }}
|
||||
Rq: il contient à la fois les étudiants qui vont être diplomés à la date prévue
|
||||
et ceux qui sont éliminés (abandon, redoublement, ...) pour affichage alternatif
|
||||
|
||||
@ -450,15 +450,15 @@ class JuryPE:
|
||||
end="",
|
||||
)
|
||||
|
||||
if pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 2:
|
||||
print
|
||||
# if pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 2:
|
||||
# print
|
||||
|
||||
# ------------------------------------------------------------------------------------------------------------------
|
||||
def est_un_etudiant_reoriente_ou_demissionnaire(self, etudid):
|
||||
"""Renvoie True si l'étudiant est réorienté (NAR) ou démissionnaire (DEM)"""
|
||||
reponse = False
|
||||
etud = self.get_cache_etudInfo_d_un_etudiant(self.context, etudid)
|
||||
(code, parcours) = sco_report.get_codeparcoursetud(self.context.Notes, etud)
|
||||
(_, parcours) = sco_report.get_codeparcoursetud(self.context.Notes, etud)
|
||||
if (
|
||||
len(set(sco_codes_parcours.CODES_SEM_REO.keys()) & set(parcours.values()))
|
||||
> 0
|
||||
@ -812,7 +812,7 @@ class JuryPE:
|
||||
self.syntheseJury[etudid] = {
|
||||
"nom": etudinfo["nom"],
|
||||
"prenom": etudinfo["prenom"],
|
||||
"sexe": etudinfo["sexe"],
|
||||
"civilite": etudinfo["civilite"],
|
||||
"age": str(pe_tools.calcul_age(etudinfo["date_naissance"])),
|
||||
"lycee": etudinfo["nomlycee"]
|
||||
+ (
|
||||
@ -862,13 +862,13 @@ class JuryPE:
|
||||
|
||||
def get_dateEntree(self, etudid):
|
||||
"""Renvoie l'année d'entrée de l'étudiant à l'IUT"""
|
||||
etudinfo = self.ETUDINFO_DICT[etudid]
|
||||
# etudinfo = self.ETUDINFO_DICT[etudid]
|
||||
semDeb = self.get_semestresDUT_d_un_etudiant(etudid)[-1] # le 1er sem à l'IUT
|
||||
return semDeb["annee_debut"]
|
||||
|
||||
def get_parcoursIUT(self, etudid):
|
||||
"""Renvoie une liste d'infos sur les semestres du parcours d'un étudiant"""
|
||||
etudinfo = self.ETUDINFO_DICT[etudid]
|
||||
# etudinfo = self.ETUDINFO_DICT[etudid]
|
||||
sems = self.get_semestresDUT_d_un_etudiant(etudid)
|
||||
|
||||
infos = []
|
||||
@ -985,7 +985,7 @@ class JuryPE:
|
||||
[self.syntheseJury[etudid]["nbSemestres"] for etudid in etudids]
|
||||
)
|
||||
|
||||
infos = ["sexe", "nom", "prenom", "age", "nbSemestres"]
|
||||
infos = ["civilite", "nom", "prenom", "age", "nbSemestres"]
|
||||
entete = ["etudid"]
|
||||
entete.extend(infos)
|
||||
entete.extend(["P%d" % i for i in range(1, maxParcours + 1)])
|
||||
@ -1036,7 +1036,7 @@ class JuryPE:
|
||||
# Les info générales:
|
||||
row = {
|
||||
"etudid": etudid,
|
||||
"sexe": e["sexe"],
|
||||
"civilite": e["civilite"],
|
||||
"nom": e["nom"],
|
||||
"prenom": e["prenom"],
|
||||
"age": e["age"],
|
||||
@ -1073,7 +1073,7 @@ class JuryPE:
|
||||
if mode == "singlesheet"
|
||||
else "%s " % (sem)
|
||||
)
|
||||
row[champ + "note"] = fmt_note(resgroupe[0])
|
||||
row[champ + "note"] = scu.fmt_note(resgroupe[0])
|
||||
row[champ + "class groupe"] = "%s / %s" % (
|
||||
resgroupe[2],
|
||||
resgroupe[3],
|
||||
@ -1083,11 +1083,12 @@ class JuryPE:
|
||||
respromo[3],
|
||||
)
|
||||
row[champ + "min/moy/max groupe"] = "%s / %s / %s" % tuple(
|
||||
fmt_note(x)
|
||||
scu.fmt_note(x)
|
||||
for x in (resgroupe[6], resgroupe[4], resgroupe[5])
|
||||
)
|
||||
row[champ + "min/moy/max promo"] = "%s / %s / %s" % tuple(
|
||||
fmt_note(x) for x in (respromo[6], respromo[4], respromo[5])
|
||||
scu.fmt_note(x)
|
||||
for x in (respromo[6], respromo[4], respromo[5])
|
||||
)
|
||||
rows.append(row)
|
||||
|
||||
|
@ -35,8 +35,10 @@ Created on Fri Sep 9 09:15:05 2016
|
||||
|
||||
@author: barasc
|
||||
"""
|
||||
import notes_table
|
||||
import datetime
|
||||
|
||||
from notes_log import log
|
||||
import notes_table
|
||||
import sco_codes_parcours
|
||||
import sco_tag_module
|
||||
import sco_utils
|
||||
@ -57,7 +59,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
||||
Attributs supplémentaires :
|
||||
- inscrlist/identdict: étudiants inscrits hors démissionnaires ou défaillants
|
||||
- _tagdict : Dictionnaire résumant les tags et les modules du semestre auxquels ils sont liés
|
||||
- _sum_coeff_semestre : la somme des coeffs du semestre
|
||||
|
||||
|
||||
Attributs hérités de TableTag :
|
||||
- nom :
|
||||
@ -111,7 +113,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
||||
self.modimpls = [
|
||||
modimpl
|
||||
for modimpl in self.nt._modimpls
|
||||
if modimpl["ue"]["type"] == sco_utils.UE_STANDARD
|
||||
if modimpl["ue"]["type"] == sco_codes_parcours.UE_STANDARD
|
||||
] # la liste des modules (objet modimpl)
|
||||
# self._modimpl_ids = [modimpl['moduleimpl_id'] for modimpl in self._modimpls] # la liste de id des modules (modimpl_id)
|
||||
self.somme_coeffs = sum(
|
||||
@ -136,8 +138,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def get_etudids(self):
|
||||
"""Renvoie la liste des etud_id des étudiants inscrits au semestre
|
||||
"""
|
||||
"""Renvoie la liste des etud_id des étudiants inscrits au semestre"""
|
||||
return [etud["etudid"] for etud in self.inscrlist]
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@ -227,7 +228,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def get_noteEtCoeff_modimpl(self, modimpl_id, etudid, profondeur=2):
|
||||
""" Renvoie un couple donnant la note et le coeff normalisé d'un étudiant à un module d'id modimpl_id.
|
||||
"""Renvoie un couple donnant la note et le coeff normalisé d'un étudiant à un module d'id modimpl_id.
|
||||
La note et le coeff sont extraits :
|
||||
1) soit des données du semestre en normalisant le coefficient par rapport à la somme des coefficients des modules du semestre,
|
||||
2) soit des données des UE précédemment capitalisées, en recherchant un module de même CODE que le modimpl_id proposé,
|
||||
@ -316,7 +317,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
||||
donnant -pour un tag donné- les note, coeff et ponderation de chaque modimpl à prendre en compte dans
|
||||
le calcul de la moyenne du tag.
|
||||
Les notes et coeff_norm sont extraits grâce à SemestreTag.get_noteEtCoeff_modimpl (donc dans semestre courant ou UE capitalisée).
|
||||
Les pondérations sont celles déclarées avec le tag (cf. _tagdict). """
|
||||
Les pondérations sont celles déclarées avec le tag (cf. _tagdict)."""
|
||||
|
||||
notes = []
|
||||
coeffs_norm = []
|
||||
@ -382,7 +383,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
||||
+ (
|
||||
"%1.5f" % (coeff * self.somme_coeffs)
|
||||
if coeff != None and isinstance(coeff, float)
|
||||
else str(coeff * self._sum_coeff_semestre)
|
||||
else "???" # str(coeff * self._sum_coeff_semestre) # voir avec Cléo
|
||||
)
|
||||
+ delim
|
||||
)
|
||||
@ -477,8 +478,9 @@ def get_moduleimpl(nt, modimpl_id):
|
||||
] # la liste de id des modules (modimpl_id)
|
||||
if modimpl_id not in modimplids:
|
||||
if SemestreTag.DEBUG:
|
||||
print "SemestreTag.get_moduleimpl( %s ) : le modimpl recherche n'existe pas" % (
|
||||
modimpl_id
|
||||
log(
|
||||
"SemestreTag.get_moduleimpl( %s ) : le modimpl recherche n'existe pas"
|
||||
% (modimpl_id)
|
||||
)
|
||||
return None
|
||||
return nt._modimpls[modimplids.index(modimpl_id)]
|
||||
|
@ -36,7 +36,7 @@ Created on Fri Sep 9 09:15:05 2016
|
||||
@author: barasc
|
||||
"""
|
||||
|
||||
from pe_tools import *
|
||||
from pe_tools import pe_print, PE_DEBUG
|
||||
|
||||
import pe_tagtable
|
||||
import pe_semestretag
|
||||
|
@ -210,7 +210,7 @@ class TableTag:
|
||||
]
|
||||
nb_notes_valides = len(notes_valides)
|
||||
if nb_notes_valides > 0:
|
||||
(moy, coeff) = moyenne_ponderee_terme_a_terme(notes_valides, force=True)
|
||||
(moy, _) = moyenne_ponderee_terme_a_terme(notes_valides, force=True)
|
||||
self.statistiques[tag] = (moy, max(notes_valides), min(notes_valides))
|
||||
|
||||
# ************************************************************************
|
||||
|
10
pe_tools.py
10
pe_tools.py
@ -37,12 +37,14 @@ Created on Thu Sep 8 09:36:33 2016
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import datetime
|
||||
import operator
|
||||
import re
|
||||
import unicodedata
|
||||
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import notes_table
|
||||
|
||||
PE_DEBUG = 0
|
||||
@ -175,7 +177,7 @@ def add_pe_stuff_to_zip(context, zipfile, ziproot):
|
||||
|
||||
Also copy logos
|
||||
"""
|
||||
PE_AUX_DIR = os.path.join(SCO_SRC_DIR, "config/doc_poursuites_etudes")
|
||||
PE_AUX_DIR = os.path.join(scu.SCO_SRC_DIR, "config/doc_poursuites_etudes")
|
||||
distrib_dir = os.path.join(PE_AUX_DIR, "distrib")
|
||||
distrib_pathnames = list_directory_filenames(
|
||||
distrib_dir
|
||||
@ -204,7 +206,7 @@ def add_pe_stuff_to_zip(context, zipfile, ziproot):
|
||||
# Logos: (add to logos/ directory in zip)
|
||||
logos_names = ["logo_header.jpg", "logo_footer.jpg"]
|
||||
for f in logos_names:
|
||||
logo = os.path.join(SCODOC_LOGOS_DIR, f)
|
||||
logo = os.path.join(scu.SCODOC_LOGOS_DIR, f)
|
||||
if os.path.isfile(logo):
|
||||
add_local_file_to_zip(zipfile, ziproot, logo, "avis/logos/" + f)
|
||||
|
||||
@ -215,7 +217,7 @@ JURY_SYNTHESE_POUR_DEBUG = {
|
||||
"EID1810": {
|
||||
"nom": "ROUX",
|
||||
"entree": "2016",
|
||||
"sexe": "M.",
|
||||
"civilite_str": "M.",
|
||||
"promo": 2016,
|
||||
"S2": {
|
||||
"groupe": {
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
"""
|
||||
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import sco_formsemestre
|
||||
import sco_formsemestre_status
|
||||
@ -44,7 +44,7 @@ from gen_tables import GenTable
|
||||
import sco_codes_parcours
|
||||
|
||||
import pe_tools
|
||||
from pe_tools import *
|
||||
from pe_tools import PE_LATEX_ENCODING
|
||||
import pe_tagtable
|
||||
import pe_semestretag
|
||||
import pe_settag
|
||||
@ -110,7 +110,7 @@ def pe_view_sem_recap(
|
||||
# template fourni via le formulaire Web
|
||||
if avis_tmpl_file:
|
||||
template_latex = avis_tmpl_file.read()
|
||||
template_latex = template_latex.decode(SCO_ENCODING)
|
||||
template_latex = template_latex.decode(scu.SCO_ENCODING)
|
||||
else:
|
||||
# template indiqué dans préférences ScoDoc ?
|
||||
template_latex = pe_avislatex.get_code_latex_from_scodoc_preference(
|
||||
@ -127,7 +127,7 @@ def pe_view_sem_recap(
|
||||
# template fourni via le formulaire Web
|
||||
if footer_tmpl_file:
|
||||
footer_latex = footer_tmpl_file.read()
|
||||
footer_latex = footer_latex.decode(SCO_ENCODING)
|
||||
footer_latex = footer_latex.decode(scu.SCO_ENCODING)
|
||||
else:
|
||||
footer_latex = pe_avislatex.get_code_latex_from_scodoc_preference(
|
||||
context, formsemestre_id, champ="pe_avis_latex_footer"
|
||||
|
@ -31,13 +31,15 @@
|
||||
|
||||
Il suffit d'appeler abs_notify() après chaque ajout d'absence.
|
||||
"""
|
||||
import datetime
|
||||
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.header import Header
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from scolog import logdb
|
||||
import sco_bulletins
|
||||
@ -54,8 +56,8 @@ def abs_notify(context, etudid, date):
|
||||
if not sem:
|
||||
return # non inscrit a la date, pas de notification
|
||||
|
||||
debut_sem = DateDMYtoISO(sem["date_debut"])
|
||||
fin_sem = DateDMYtoISO(sem["date_fin"])
|
||||
debut_sem = ndb.DateDMYtoISO(sem["date_debut"])
|
||||
fin_sem = ndb.DateDMYtoISO(sem["date_fin"])
|
||||
nbabs = context.CountAbs(etudid, debut=debut_sem, fin=fin_sem)
|
||||
nbabsjust = context.CountAbsJust(etudid, debut=debut_sem, fin=fin_sem)
|
||||
|
||||
@ -108,12 +110,12 @@ def abs_notify_send(
|
||||
"""Actually send the notification by email, and register it in database"""
|
||||
cnx = context.GetDBConnexion()
|
||||
log("abs_notify: sending notification to %s" % destinations)
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
for email in destinations:
|
||||
del msg["To"]
|
||||
msg["To"] = email
|
||||
context.sendEmail(msg)
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"""insert into absences_notifications (etudid, email, nbabs, nbabsjust, formsemestre_id) values (%(etudid)s, %(email)s, %(nbabs)s, %(nbabsjust)s, %(formsemestre_id)s)""",
|
||||
vars(),
|
||||
@ -200,7 +202,7 @@ def etud_nbabs_last_notified(context, etudid, formsemestre_id=None):
|
||||
"""nbabs lors de la dernière notification envoyée pour cet étudiant dans ce semestre
|
||||
ou sans semestre (ce dernier cas est nécessaire pour la transition au nouveau code)"""
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"""select * from absences_notifications where etudid = %(etudid)s and (formsemestre_id = %(formsemestre_id)s or formsemestre_id is NULL) order by notification_date desc""",
|
||||
vars(),
|
||||
@ -215,17 +217,15 @@ def etud_nbabs_last_notified(context, etudid, formsemestre_id=None):
|
||||
def user_nbdays_since_last_notif(context, email_addr, etudid):
|
||||
"""nb days since last notification to this email, or None if no previous notification"""
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"""select * from absences_notifications where email = %(email_addr)s and etudid=%(etudid)s order by notification_date desc""",
|
||||
{"email_addr": email_addr, "etudid": etudid},
|
||||
)
|
||||
res = cursor.dictfetchone()
|
||||
if res:
|
||||
mxd = res["notification_date"] # mx.DateTime instance
|
||||
lastdate = datetime.datetime(mxd.year, mxd.month, mxd.day)
|
||||
now = datetime.datetime.now()
|
||||
return (now - lastdate).days
|
||||
now = datetime.datetime.now(res["notification_date"].tzinfo)
|
||||
return (now - res["notification_date"]).days
|
||||
else:
|
||||
return None
|
||||
|
||||
@ -254,10 +254,10 @@ def abs_notification_message(context, sem, prefs, etudid, nbabs, nbabsjust):
|
||||
subject = """Trop d'absences pour %(nomprenom)s""" % etud
|
||||
#
|
||||
msg = MIMEMultipart()
|
||||
subj = Header("[ScoDoc] " + subject, SCO_ENCODING)
|
||||
subj = Header("[ScoDoc] " + subject, scu.SCO_ENCODING)
|
||||
msg["Subject"] = subj
|
||||
msg["From"] = prefs["email_from_addr"]
|
||||
txt = MIMEText(txt, "plain", SCO_ENCODING)
|
||||
txt = MIMEText(txt, "plain", scu.SCO_ENCODING)
|
||||
msg.attach(txt)
|
||||
return msg
|
||||
|
||||
@ -270,7 +270,7 @@ def retreive_current_formsemestre(context, etudid, cur_date):
|
||||
WHERE sem.formsemestre_id = i.formsemestre_id AND i.etudid=%(etudid)s
|
||||
AND (%(cur_date)s >= sem.date_debut) AND (%(cur_date)s <= sem.date_fin)"""
|
||||
|
||||
r = SimpleDictFetch(context, req, {"etudid": etudid, "cur_date": cur_date})
|
||||
r = ndb.SimpleDictFetch(context, req, {"etudid": etudid, "cur_date": cur_date})
|
||||
if not r:
|
||||
return None
|
||||
# s'il y a plusieurs semestres, prend le premier (rarissime et non significatif):
|
||||
@ -283,5 +283,5 @@ def mod_with_evals_at_date(context, date_abs, etudid):
|
||||
req = """SELECT m.* FROM notes_moduleimpl m, notes_evaluation e, notes_moduleimpl_inscription i
|
||||
WHERE m.moduleimpl_id = e.moduleimpl_id AND e.moduleimpl_id = i.moduleimpl_id
|
||||
AND i.etudid = %(etudid)s AND e.jour = %(date_abs)s"""
|
||||
r = SimpleDictFetch(context, req, {"etudid": etudid, "date_abs": date_abs})
|
||||
r = ndb.SimpleDictFetch(context, req, {"etudid": etudid, "date_abs": date_abs})
|
||||
return r
|
||||
|
@ -56,10 +56,21 @@ def doSignaleAbsence(
|
||||
demijournee=2,
|
||||
estjust=False,
|
||||
description=None,
|
||||
etudid=False,
|
||||
REQUEST=None,
|
||||
): # etudid implied
|
||||
"""Signalement d'une absence"""
|
||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
||||
"""Signalement d'une absence.
|
||||
|
||||
Args:
|
||||
datedebut: dd/mm/yyyy
|
||||
datefin: dd/mm/yyyy (non incluse)
|
||||
moduleimpl_id: module auquel imputer les absences
|
||||
demijournee: 2 si journée complète, 1 matin, 0 après-midi
|
||||
estjust: absence justifiée
|
||||
description: str
|
||||
etudid: etudiant concerné. Si non spécifié, cherche dans REQUEST.form
|
||||
"""
|
||||
etud = context.getEtudInfo(filled=1, etudid=etudid, REQUEST=REQUEST)[0]
|
||||
etudid = etud["etudid"]
|
||||
|
||||
description_abs = description
|
||||
@ -247,10 +258,25 @@ Raison: <input type="text" name="description" size="42"/> (optionnel)
|
||||
|
||||
|
||||
def doJustifAbsence(
|
||||
context, datedebut, datefin, demijournee, description=None, REQUEST=None
|
||||
context,
|
||||
datedebut,
|
||||
datefin,
|
||||
demijournee,
|
||||
description=None,
|
||||
etudid=False,
|
||||
REQUEST=None,
|
||||
): # etudid implied
|
||||
"""Justification d'une absence"""
|
||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
||||
"""Justification d'une absence
|
||||
|
||||
Args:
|
||||
datedebut: dd/mm/yyyy
|
||||
datefin: dd/mm/yyyy (non incluse)
|
||||
demijournee: 2 si journée complète, 1 matin, 0 après-midi
|
||||
estjust: absence justifiée
|
||||
description: str
|
||||
etudid: etudiant concerné. Si non spécifié, cherche dans REQUEST.form
|
||||
"""
|
||||
etud = context.getEtudInfo(filled=1, etudid=etudid, REQUEST=REQUEST)[0]
|
||||
etudid = etud["etudid"]
|
||||
description_abs = description
|
||||
dates = sco_abs.DateRangeISO(context, datedebut, datefin)
|
||||
@ -370,10 +396,10 @@ Raison: <input type="text" name="description" size="42"/> (optionnel)
|
||||
|
||||
|
||||
def doAnnuleAbsence(
|
||||
context, datedebut, datefin, demijournee, REQUEST=None
|
||||
context, datedebut, datefin, demijournee, etudid=False, REQUEST=None
|
||||
): # etudid implied
|
||||
"""Annulation des absences pour une demi journée"""
|
||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
||||
etud = context.getEtudInfo(filled=1, etudid=etudid, REQUEST=REQUEST)[0]
|
||||
etudid = etud["etudid"]
|
||||
|
||||
dates = sco_abs.DateRangeISO(context, datedebut, datefin)
|
||||
|
@ -46,10 +46,11 @@ Pour chaque étudiant commun:
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import sco_apogee_csv
|
||||
from gen_tables import GenTable
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
_help_txt = """
|
||||
<div class="help">
|
||||
|
@ -27,9 +27,7 @@
|
||||
|
||||
"""Exportation des résultats des étudiants vers Apogée.
|
||||
|
||||
EXPERIMENTAL / PRECAUTIONS !
|
||||
|
||||
Code inspiré par les travaux de Damien Mascré, scodoc2apogee (en Java).
|
||||
Ce code a été au départ inspiré par les travaux de Damien Mascré, scodoc2apogee (en Java).
|
||||
|
||||
A utiliser en fin de semestre, après les jury.
|
||||
|
||||
@ -81,6 +79,13 @@ XXX A vérifier:
|
||||
AJAC car 1 sem. validé et pas de NAR
|
||||
|
||||
"""
|
||||
|
||||
import collections
|
||||
from types import FloatType
|
||||
import re
|
||||
import time
|
||||
import datetime
|
||||
import os
|
||||
from cStringIO import StringIO
|
||||
from zipfile import ZipFile
|
||||
import pprint
|
||||
@ -90,6 +95,10 @@ try:
|
||||
except:
|
||||
chardet_detect = None
|
||||
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
from sco_exceptions import ScoValueError, FormatError
|
||||
import sco_formsemestre
|
||||
from sco_formsemestre import ApoEtapeVDI
|
||||
import sco_formsemestre_status
|
||||
@ -98,8 +107,6 @@ import sco_codes_parcours
|
||||
from sco_codes_parcours import code_semestre_validant
|
||||
from sco_codes_parcours import ATT, ATB, ADM, ADC, ADJ, ATJ, ATB, AJ, CMP, NAR, RAT, DEF
|
||||
from gen_tables import GenTable
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
|
||||
APO_PORTAL_ENCODING = (
|
||||
"utf8" # encodage du fichier CSV Apogée (était 'ISO-8859-1' avant jul. 2016)
|
||||
@ -347,10 +354,10 @@ class ApoEtud(dict):
|
||||
for col_id in apo_data.col_ids[:4]:
|
||||
self.new_cols[col_id] = self.cols[col_id]
|
||||
|
||||
def unassociated_codes(self, apo_data):
|
||||
"list of apo elements for this student without a value in ScoDoc"
|
||||
codes = set([apo_data.cols[col_id].code for col_id in apo_data.col_ids])
|
||||
return codes - set(sco_elts)
|
||||
# def unassociated_codes(self, apo_data):
|
||||
# "list of apo elements for this student without a value in ScoDoc"
|
||||
# codes = set([apo_data.cols[col_id].code for col_id in apo_data.col_ids])
|
||||
# return codes - set(sco_elts)
|
||||
|
||||
def search_elt_in_sem(self, context, code, sem, cur_sem, autre_sem):
|
||||
"""
|
||||
@ -749,7 +756,7 @@ class ApoData:
|
||||
if not data:
|
||||
raise FormatError("Fichier Apogée vide !")
|
||||
|
||||
data_utf8 = data.decode(APO_INPUT_ENCODING).encode(SCO_ENCODING)
|
||||
data_utf8 = data.decode(APO_INPUT_ENCODING).encode(scu.SCO_ENCODING)
|
||||
f = StringIOFileLineWrapper(data_utf8) # pour traiter comme un fichier
|
||||
# check that we are at the begining of Apogee CSV
|
||||
line = f.readline().strip()
|
||||
@ -1023,7 +1030,7 @@ def _apo_read_cols(f):
|
||||
line = f.readline().strip(" " + APO_NEWLINE)
|
||||
fs = line.split(APO_SEP)
|
||||
if fs[0] != "apoL_a01_code":
|
||||
raise FormatError("invalid line: %s (expecting apoL_a01_code)"(line, i))
|
||||
raise FormatError("invalid line: %s (expecting apoL_a01_code)" % line)
|
||||
col_keys = fs
|
||||
|
||||
while True: # skip premiere partie (apoL_a02_nom, ...)
|
||||
@ -1046,7 +1053,9 @@ def _apo_read_cols(f):
|
||||
raise FormatError("duplicate column definition: %s" % col_id)
|
||||
m = re.match(r"^apoL_c([0-9]{4})$", col_id)
|
||||
if not m:
|
||||
raise FormatError("invalid column id: %s (expecting apoL_c%04d)"(line, i))
|
||||
raise FormatError(
|
||||
"invalid column id: %s (expecting apoL_c%04d)" % (line, col_id)
|
||||
)
|
||||
if int(m.group(1)) != i:
|
||||
raise FormatError("invalid column id: %s for index %s" % (col_id, i))
|
||||
|
||||
@ -1281,7 +1290,7 @@ def export_csv_to_apogee(
|
||||
)
|
||||
log(logf.getvalue()) # sortie aussi sur le log ScoDoc
|
||||
|
||||
csv_data = f.getvalue().decode(SCO_ENCODING).encode(APO_OUTPUT_ENCODING)
|
||||
csv_data = f.getvalue().decode(scu.SCO_ENCODING).encode(APO_OUTPUT_ENCODING)
|
||||
|
||||
# Write data to ZIP
|
||||
dest_zip.writestr(csv_filename, csv_data)
|
||||
|
@ -45,15 +45,16 @@
|
||||
qui est une description (humaine, format libre) de l'archive.
|
||||
|
||||
"""
|
||||
|
||||
from mx.DateTime import DateTime as mxDateTime
|
||||
import mx.DateTime
|
||||
import os
|
||||
import time
|
||||
import datetime
|
||||
import re
|
||||
import shutil
|
||||
import glob
|
||||
|
||||
from sco_utils import *
|
||||
from notesdb import *
|
||||
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
import sco_formsemestre
|
||||
import sco_pvjury
|
||||
import sco_excel
|
||||
@ -62,6 +63,10 @@ import sco_groups
|
||||
import sco_groups_view
|
||||
from sco_recapcomplet import make_formsemestre_recapcomplet
|
||||
import sco_bulletins_pdf
|
||||
from TrivialFormulator import TrivialFormulator
|
||||
from sco_exceptions import (
|
||||
AccessDenied,
|
||||
)
|
||||
|
||||
|
||||
class BaseArchiver:
|
||||
@ -75,12 +80,12 @@ class BaseArchiver:
|
||||
for dir in dirs[1:]:
|
||||
path = os.path.join(path, dir)
|
||||
try:
|
||||
GSL.acquire()
|
||||
scu.GSL.acquire()
|
||||
if not os.path.isdir(path):
|
||||
log("creating directory %s" % path)
|
||||
os.mkdir(path)
|
||||
finally:
|
||||
GSL.release()
|
||||
scu.GSL.release()
|
||||
|
||||
def get_obj_dir(self, context, oid):
|
||||
"""
|
||||
@ -89,7 +94,7 @@ class BaseArchiver:
|
||||
"""
|
||||
dept_dir = os.path.join(self.root, context.DeptId())
|
||||
try:
|
||||
GSL.acquire()
|
||||
scu.GSL.acquire()
|
||||
if not os.path.isdir(dept_dir):
|
||||
log("creating directory %s" % dept_dir)
|
||||
os.mkdir(dept_dir)
|
||||
@ -98,7 +103,7 @@ class BaseArchiver:
|
||||
log("creating directory %s" % obj_dir)
|
||||
os.mkdir(obj_dir)
|
||||
finally:
|
||||
GSL.release()
|
||||
scu.GSL.release()
|
||||
return obj_dir
|
||||
|
||||
def list_oids(self, context):
|
||||
@ -126,23 +131,23 @@ class BaseArchiver:
|
||||
def delete_archive(self, archive_id):
|
||||
"""Delete (forever) this archive"""
|
||||
try:
|
||||
GSL.acquire()
|
||||
scu.GSL.acquire()
|
||||
shutil.rmtree(archive_id, ignore_errors=True)
|
||||
finally:
|
||||
GSL.release()
|
||||
scu.GSL.release()
|
||||
|
||||
def get_archive_date(self, archive_id):
|
||||
"""Returns date (as a DateTime object) of an archive"""
|
||||
dt = [int(x) for x in os.path.split(archive_id)[1].split("-")]
|
||||
return mxDateTime(*dt)
|
||||
return datetime.datetime(*dt)
|
||||
|
||||
def list_archive(self, archive_id):
|
||||
"""Return list of filenames (without path) in archive"""
|
||||
try:
|
||||
GSL.acquire()
|
||||
scu.GSL.acquire()
|
||||
files = os.listdir(archive_id)
|
||||
finally:
|
||||
GSL.release()
|
||||
scu.GSL.release()
|
||||
files.sort()
|
||||
return [f for f in files if f and f[0] != "_"]
|
||||
|
||||
@ -182,10 +187,10 @@ class BaseArchiver:
|
||||
)
|
||||
log("creating archive: %s" % archive_id)
|
||||
try:
|
||||
GSL.acquire()
|
||||
scu.GSL.acquire()
|
||||
os.mkdir(archive_id) # if exists, raises an OSError
|
||||
finally:
|
||||
GSL.release()
|
||||
scu.GSL.release()
|
||||
self.store(archive_id, "_description.txt", description)
|
||||
return archive_id
|
||||
|
||||
@ -194,21 +199,21 @@ class BaseArchiver:
|
||||
Filename may be modified (sanitized): return used filename
|
||||
The file is created or replaced.
|
||||
"""
|
||||
filename = sanitize_filename(filename)
|
||||
filename = scu.sanitize_filename(filename)
|
||||
log("storing %s (%d bytes) in %s" % (filename, len(data), archive_id))
|
||||
try:
|
||||
GSL.acquire()
|
||||
scu.GSL.acquire()
|
||||
fname = os.path.join(archive_id, filename)
|
||||
f = open(fname, "w")
|
||||
f.write(data)
|
||||
f.close()
|
||||
finally:
|
||||
GSL.release()
|
||||
scu.GSL.release()
|
||||
return filename
|
||||
|
||||
def get(self, archive_id, filename):
|
||||
"""Retreive data"""
|
||||
if not is_valid_filename(filename):
|
||||
if not scu.is_valid_filename(filename):
|
||||
log('Archiver.get: invalid filename "%s"' % filename)
|
||||
raise ValueError("invalid filename")
|
||||
fname = os.path.join(archive_id, filename)
|
||||
@ -220,18 +225,18 @@ class BaseArchiver:
|
||||
# XXX très incomplet: devrait inférer et assigner un type MIME
|
||||
archive_id = self.get_id_from_name(context, oid, archive_name)
|
||||
data = self.get(archive_id, filename)
|
||||
ext = os.path.splitext(strlower(filename))[1]
|
||||
ext = os.path.splitext(scu.strlower(filename))[1]
|
||||
if ext == ".html" or ext == ".htm":
|
||||
return data
|
||||
elif ext == ".xml":
|
||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||
return data
|
||||
elif ext == ".xls":
|
||||
return sco_excel.sendExcelFile(REQUEST, data, filename)
|
||||
elif ext == ".csv":
|
||||
return sendCSVFile(REQUEST, data, filename)
|
||||
return scu.sendCSVFile(REQUEST, data, filename)
|
||||
elif ext == ".pdf":
|
||||
return sendPDFFile(REQUEST, data, filename)
|
||||
return scu.sendPDFFile(REQUEST, data, filename)
|
||||
|
||||
return data # should set mimetype...
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
les dossiers d'admission et autres pièces utiles.
|
||||
"""
|
||||
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import ImportScolars
|
||||
import sco_formsemestre
|
||||
@ -38,6 +38,9 @@ import sco_groups
|
||||
import sco_trombino
|
||||
import sco_excel
|
||||
import sco_archives
|
||||
from sco_permissions import ScoEtudAddAnnotations
|
||||
from sco_exceptions import AccessDenied
|
||||
from TrivialFormulator import TrivialFormulator
|
||||
|
||||
|
||||
class EtudsArchiver(sco_archives.BaseArchiver):
|
||||
@ -65,10 +68,10 @@ def etud_list_archives_html(context, REQUEST, etudid):
|
||||
"content": EtudsArchive.list_archive(archive_id),
|
||||
}
|
||||
L.append(a)
|
||||
delete_icon = icontag(
|
||||
delete_icon = scu.icontag(
|
||||
"delete_small_img", title="Supprimer fichier", alt="supprimer"
|
||||
)
|
||||
delete_disabled_icon = icontag(
|
||||
delete_disabled_icon = scu.icontag(
|
||||
"delete_small_dis_img", title="Suppression non autorisée"
|
||||
)
|
||||
H = ['<div class="etudarchive"><ul>']
|
||||
@ -137,7 +140,7 @@ def etud_upload_file_form(context, REQUEST, etudid):
|
||||
% etud,
|
||||
"""<p>Le fichier ne doit pas dépasser %sMo.</p>
|
||||
"""
|
||||
% (CONFIG.ETUD_MAX_FILE_SIZE / (1024 * 1024)),
|
||||
% (scu.CONFIG.ETUD_MAX_FILE_SIZE / (1024 * 1024)),
|
||||
]
|
||||
tf = TrivialFormulator(
|
||||
REQUEST.URL0,
|
||||
@ -161,7 +164,9 @@ def etud_upload_file_form(context, REQUEST, etudid):
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1 + "/ficheEtud?etudid=" + etudid)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
context.NotesURL() + "/ficheEtud?etudid=" + etudid
|
||||
)
|
||||
else:
|
||||
data = tf[2]["datafile"].read()
|
||||
descr = tf[2]["description"]
|
||||
@ -169,7 +174,9 @@ def etud_upload_file_form(context, REQUEST, etudid):
|
||||
_store_etud_file_to_new_archive(
|
||||
context, REQUEST, etudid, data, filename, description=descr
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1 + "/ficheEtud?etudid=" + etudid)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
context.NotesURL() + "/ficheEtud?etudid=" + etudid
|
||||
)
|
||||
|
||||
|
||||
def _store_etud_file_to_new_archive(
|
||||
@ -177,7 +184,7 @@ def _store_etud_file_to_new_archive(
|
||||
):
|
||||
"""Store data to new archive."""
|
||||
filesize = len(data)
|
||||
if filesize < 10 or filesize > CONFIG.ETUD_MAX_FILE_SIZE:
|
||||
if filesize < 10 or filesize > scu.CONFIG.ETUD_MAX_FILE_SIZE:
|
||||
return 0, "Fichier image de taille invalide ! (%d)" % filesize
|
||||
archive_id = EtudsArchive.create_obj_archive(context, etudid, description)
|
||||
EtudsArchive.store(archive_id, filename, data)
|
||||
|
105
sco_bulletins.py
105
sco_bulletins.py
@ -28,18 +28,26 @@
|
||||
"""Génération des bulletins de notes
|
||||
|
||||
"""
|
||||
import time
|
||||
from types import StringType
|
||||
import pprint
|
||||
import urllib
|
||||
import htmlutils
|
||||
import email
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.base import MIMEBase
|
||||
from email.header import Header
|
||||
|
||||
import time
|
||||
from reportlab.lib.colors import Color
|
||||
|
||||
from sco_utils import *
|
||||
from notes_table import *
|
||||
import htmlutils
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
import scolars
|
||||
from sco_permissions import ScoImplement, ScoEtudInscrit
|
||||
from sco_exceptions import AccessDenied
|
||||
import sco_codes_parcours
|
||||
import sco_formsemestre
|
||||
import sco_groups
|
||||
import sco_pvjury
|
||||
@ -112,7 +120,7 @@ def formsemestre_bulletinetud_dict(
|
||||
context, formsemestre_id
|
||||
) # > toutes notes
|
||||
|
||||
I = DictDefault(defaultvalue="")
|
||||
I = scu.DictDefault(defaultvalue="")
|
||||
I["etudid"] = etudid
|
||||
I["formsemestre_id"] = formsemestre_id
|
||||
I["sem"] = nt.sem
|
||||
@ -180,7 +188,7 @@ def formsemestre_bulletinetud_dict(
|
||||
if I["etud_etat"] == "D":
|
||||
I["demission"] = "(Démission)"
|
||||
I["filigranne"] = "Démission"
|
||||
elif I["etud_etat"] == DEF:
|
||||
elif I["etud_etat"] == sco_codes_parcours.DEF:
|
||||
I["demission"] = "(Défaillant)"
|
||||
I["filigranne"] = "Défaillant"
|
||||
elif (prefs["bul_show_temporary"] and not I["decision_sem"]) or prefs[
|
||||
@ -204,16 +212,16 @@ def formsemestre_bulletinetud_dict(
|
||||
modimpls = nt.get_modimpls()
|
||||
moy_gen = nt.get_etud_moy_gen(etudid)
|
||||
I["nb_inscrits"] = len(nt.rangs)
|
||||
I["moy_gen"] = fmt_note(moy_gen)
|
||||
I["moy_min"] = fmt_note(nt.moy_min)
|
||||
I["moy_max"] = fmt_note(nt.moy_max)
|
||||
I["moy_gen"] = scu.fmt_note(moy_gen)
|
||||
I["moy_min"] = scu.fmt_note(nt.moy_min)
|
||||
I["moy_max"] = scu.fmt_note(nt.moy_max)
|
||||
I["mention"] = ""
|
||||
if dpv:
|
||||
decision_sem = dpv["decisions"][0]["decision_sem"]
|
||||
if decision_sem and sco_codes_parcours.code_semestre_validant(
|
||||
decision_sem["code"]
|
||||
):
|
||||
I["mention"] = get_mention(moy_gen)
|
||||
I["mention"] = scu.get_mention(moy_gen)
|
||||
|
||||
if dpv and dpv["decisions"][0]:
|
||||
I["sum_ects"] = dpv["decisions"][0]["sum_ects"]
|
||||
@ -221,7 +229,7 @@ def formsemestre_bulletinetud_dict(
|
||||
else:
|
||||
I["sum_ects"] = 0
|
||||
I["sum_ects_capitalises"] = 0
|
||||
I["moy_moy"] = fmt_note(nt.moy_moy) # moyenne des moyennes generales
|
||||
I["moy_moy"] = scu.fmt_note(nt.moy_moy) # moyenne des moyennes generales
|
||||
if type(moy_gen) != StringType and type(nt.moy_moy) != StringType:
|
||||
I["moy_gen_bargraph_html"] = " " + htmlutils.horizontal_bargraph(
|
||||
moy_gen * 5, nt.moy_moy * 5
|
||||
@ -241,8 +249,8 @@ def formsemestre_bulletinetud_dict(
|
||||
if nt.get_moduleimpls_attente():
|
||||
# n'affiche pas le rang sur le bulletin s'il y a des
|
||||
# notes en attente dans ce semestre
|
||||
rang = RANG_ATTENTE_STR
|
||||
rang_gr = DictDefault(defaultvalue=RANG_ATTENTE_STR)
|
||||
rang = scu.RANG_ATTENTE_STR
|
||||
rang_gr = scu.DictDefault(defaultvalue=scu.RANG_ATTENTE_STR)
|
||||
I["rang"] = rang
|
||||
I["rang_gr"] = rang_gr
|
||||
I["gr_name"] = gr_name
|
||||
@ -268,17 +276,17 @@ def formsemestre_bulletinetud_dict(
|
||||
u = ue.copy()
|
||||
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
||||
u["ue_status"] = ue_status # { 'moy', 'coef_ue', ...}
|
||||
if ue["type"] != UE_SPORT:
|
||||
u["cur_moy_ue_txt"] = fmt_note(ue_status["cur_moy_ue"])
|
||||
if ue["type"] != sco_codes_parcours.UE_SPORT:
|
||||
u["cur_moy_ue_txt"] = scu.fmt_note(ue_status["cur_moy_ue"])
|
||||
else:
|
||||
x = fmt_note(nt.bonus[etudid], keep_numeric=True)
|
||||
x = scu.fmt_note(nt.bonus[etudid], keep_numeric=True)
|
||||
if type(x) == StringType:
|
||||
u["cur_moy_ue_txt"] = "pas de bonus"
|
||||
else:
|
||||
u["cur_moy_ue_txt"] = "bonus de %.3g points" % x
|
||||
u["moy_ue_txt"] = fmt_note(ue_status["moy"])
|
||||
u["moy_ue_txt"] = scu.fmt_note(ue_status["moy"])
|
||||
if ue_status["coef_ue"] != None:
|
||||
u["coef_ue_txt"] = fmt_coef(ue_status["coef_ue"])
|
||||
u["coef_ue_txt"] = scu.fmt_coef(ue_status["coef_ue"])
|
||||
else:
|
||||
# C'est un bug:
|
||||
log("u=" + pprint.pformat(u))
|
||||
@ -290,7 +298,7 @@ def formsemestre_bulletinetud_dict(
|
||||
and ue["ue_id"] in dpv["decisions"][0]["decisions_ue"]
|
||||
):
|
||||
u["ects"] = dpv["decisions"][0]["decisions_ue"][ue["ue_id"]]["ects"]
|
||||
if ue["type"] == UE_ELECTIVE:
|
||||
if ue["type"] == sco_codes_parcours.UE_ELECTIVE:
|
||||
u["ects"] = (
|
||||
"%g+" % u["ects"]
|
||||
) # ajoute un "+" pour indiquer ECTS d'une UE élective
|
||||
@ -314,7 +322,7 @@ def formsemestre_bulletinetud_dict(
|
||||
sem_origin = sco_formsemestre.get_formsemestre(
|
||||
context, ue_status["formsemestre_id"]
|
||||
)
|
||||
u["ue_descr_txt"] = "Capitalisée le %s" % DateISOtoDMY(
|
||||
u["ue_descr_txt"] = "Capitalisée le %s" % ndb.DateISOtoDMY(
|
||||
ue_status["event_date"]
|
||||
)
|
||||
u[
|
||||
@ -345,10 +353,10 @@ def formsemestre_bulletinetud_dict(
|
||||
_sort_mod_by_matiere(u["modules_capitalized"], nt_cap, etudid)
|
||||
)
|
||||
else:
|
||||
if prefs["bul_show_ue_rangs"] and ue["type"] != UE_SPORT:
|
||||
if prefs["bul_show_ue_rangs"] and ue["type"] != sco_codes_parcours.UE_SPORT:
|
||||
if ue_attente: # nt.get_moduleimpls_attente():
|
||||
u["ue_descr_txt"] = "%s/%s" % (
|
||||
RANG_ATTENTE_STR,
|
||||
scu.RANG_ATTENTE_STR,
|
||||
nt.ue_rangs[ue["ue_id"]][1],
|
||||
)
|
||||
else:
|
||||
@ -384,7 +392,7 @@ def _sort_mod_by_matiere(modlist, nt, etudid):
|
||||
"titre": mod["mat"]["titre"],
|
||||
"modules": mod,
|
||||
"moy": moy,
|
||||
"moy_txt": fmt_note(moy),
|
||||
"moy_txt": scu.fmt_note(moy),
|
||||
}
|
||||
return matmod
|
||||
|
||||
@ -400,8 +408,8 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
||||
)
|
||||
if bul_show_abs_modules:
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
debut_sem = DateDMYtoISO(sem["date_debut"])
|
||||
fin_sem = DateDMYtoISO(sem["date_fin"])
|
||||
debut_sem = ndb.DateDMYtoISO(sem["date_debut"])
|
||||
fin_sem = ndb.DateDMYtoISO(sem["date_fin"])
|
||||
|
||||
ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue_id]
|
||||
mods = [] # result
|
||||
@ -412,7 +420,7 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
||||
mod_moy = nt.get_etud_mod_moy(
|
||||
modimpl["moduleimpl_id"], etudid
|
||||
) # peut etre 'NI'
|
||||
is_malus = mod["module"]["module_type"] == MODULE_MALUS
|
||||
is_malus = mod["module"]["module_type"] == scu.MODULE_MALUS
|
||||
if bul_show_abs_modules:
|
||||
mod_abs = [
|
||||
context.Absences.CountAbs(
|
||||
@ -428,25 +436,25 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
||||
moduleimpl_id=modimpl["moduleimpl_id"],
|
||||
),
|
||||
]
|
||||
mod["mod_abs_txt"] = fmt_abs(mod_abs)
|
||||
mod["mod_abs_txt"] = scu.fmt_abs(mod_abs)
|
||||
else:
|
||||
mod["mod_abs_txt"] = ""
|
||||
|
||||
mod["mod_moy_txt"] = fmt_note(mod_moy)
|
||||
mod["mod_moy_txt"] = scu.fmt_note(mod_moy)
|
||||
if mod["mod_moy_txt"][:2] == "NA":
|
||||
mod["mod_moy_txt"] = "-"
|
||||
if is_malus:
|
||||
if mod_moy > 0:
|
||||
mod["mod_moy_txt"] = fmt_note(mod_moy)
|
||||
mod["mod_moy_txt"] = scu.fmt_note(mod_moy)
|
||||
mod["mod_coef_txt"] = "Malus"
|
||||
elif mod_moy < 0:
|
||||
mod["mod_moy_txt"] = fmt_note(-mod_moy)
|
||||
mod["mod_moy_txt"] = scu.fmt_note(-mod_moy)
|
||||
mod["mod_coef_txt"] = "Bonus"
|
||||
else:
|
||||
mod["mod_moy_txt"] = "-"
|
||||
mod["mod_coef_txt"] = "-"
|
||||
else:
|
||||
mod["mod_coef_txt"] = fmt_coef(modimpl["module"]["coefficient"])
|
||||
mod["mod_coef_txt"] = scu.fmt_coef(modimpl["module"]["coefficient"])
|
||||
if mod["mod_moy_txt"] != "NI": # ne montre pas les modules 'non inscrit'
|
||||
mods.append(mod)
|
||||
if is_malus: # n'affiche pas les statistiques sur les modules malus
|
||||
@ -462,7 +470,7 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
||||
mod["stats"] = nt.get_mod_stats(modimpl["moduleimpl_id"])
|
||||
mod["mod_descr_txt"] = "Module %s, coef. %s (%s)" % (
|
||||
modimpl["module"]["titre"],
|
||||
fmt_coef(modimpl["module"]["coefficient"]),
|
||||
scu.fmt_coef(modimpl["module"]["coefficient"]),
|
||||
context.Users.user_info(modimpl["responsable_id"])["nomcomplet"],
|
||||
)
|
||||
link_mod = (
|
||||
@ -481,7 +489,7 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
||||
|
||||
mod_descr = "Module %s, coef. %s (%s)" % (
|
||||
modimpl["module"]["titre"],
|
||||
fmt_coef(modimpl["module"]["coefficient"]),
|
||||
scu.fmt_coef(modimpl["module"]["coefficient"]),
|
||||
context.Users.user_info(modimpl["responsable_id"])["nomcomplet"],
|
||||
)
|
||||
link_mod = (
|
||||
@ -525,18 +533,18 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
||||
if val == "NP":
|
||||
e["note_txt"] = "nd"
|
||||
e["note_html"] = '<span class="note_nd">nd</span>'
|
||||
e["coef_txt"] = fmt_coef(e["coefficient"])
|
||||
e["coef_txt"] = scu.fmt_coef(e["coefficient"])
|
||||
else:
|
||||
# (-0.15) s'affiche "bonus de 0.15"
|
||||
if is_malus:
|
||||
val = abs(val)
|
||||
e["note_txt"] = fmt_note(val, note_max=e["note_max"])
|
||||
e["note_txt"] = scu.fmt_note(val, note_max=e["note_max"])
|
||||
e["note_html"] = e["note_txt"]
|
||||
if is_malus:
|
||||
e["coef_txt"] = ""
|
||||
else:
|
||||
e["coef_txt"] = fmt_coef(e["coefficient"])
|
||||
if e["evaluation_type"] == EVALUATION_RATTRAPAGE:
|
||||
e["coef_txt"] = scu.fmt_coef(e["coefficient"])
|
||||
if e["evaluation_type"] == scu.EVALUATION_RATTRAPAGE:
|
||||
e["coef_txt"] = "rat."
|
||||
if e["etat"]["evalattente"]:
|
||||
mod_attente = True # une eval en attente dans ce module
|
||||
@ -567,12 +575,12 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
||||
e["name"],
|
||||
)
|
||||
e["note_txt"] = e["note_html"] = ""
|
||||
e["coef_txt"] = fmt_coef(e["coefficient"])
|
||||
e["coef_txt"] = scu.fmt_coef(e["coefficient"])
|
||||
# Classement
|
||||
if bul_show_mod_rangs and mod["mod_moy_txt"] != "-" and not is_malus:
|
||||
rg = nt.mod_rangs[modimpl["moduleimpl_id"]]
|
||||
if mod_attente: # nt.get_moduleimpls_attente():
|
||||
mod["mod_rang"] = RANG_ATTENTE_STR
|
||||
mod["mod_rang"] = scu.RANG_ATTENTE_STR
|
||||
else:
|
||||
mod["mod_rang"] = rg[0][etudid]
|
||||
mod["mod_eff"] = rg[1] # effectif dans ce module
|
||||
@ -637,7 +645,7 @@ def etud_descr_situation_semestre(
|
||||
descr_mention : 'Mention Bien', ou vide si pas de mention ou si pas show_mention
|
||||
"""
|
||||
cnx = context.GetDBConnexion()
|
||||
infos = DictDefault(defaultvalue="")
|
||||
infos = scu.DictDefault(defaultvalue="")
|
||||
|
||||
# --- Situation et décisions jury
|
||||
|
||||
@ -648,7 +656,6 @@ def etud_descr_situation_semestre(
|
||||
date_inscr = None
|
||||
date_dem = None
|
||||
date_def = None
|
||||
date_echec = None
|
||||
for event in events:
|
||||
event_type = event["event_type"]
|
||||
if event_type == "INSCRIPTION":
|
||||
@ -765,7 +772,7 @@ def formsemestre_bulletinetud(
|
||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
||||
etudid = etud["etudid"]
|
||||
except:
|
||||
return log_unknown_etud(context, REQUEST, format=format)
|
||||
return scu.log_unknown_etud(context, REQUEST, format=format)
|
||||
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
|
||||
@ -887,7 +894,7 @@ def do_formsemestre_bulletinetud(
|
||||
etud = I["etud"]
|
||||
|
||||
if format == "html":
|
||||
htm, junk = sco_bulletins_generator.make_formsemestre_bulletinetud(
|
||||
htm, _ = sco_bulletins_generator.make_formsemestre_bulletinetud(
|
||||
context, I, version=version, format="html", REQUEST=REQUEST
|
||||
)
|
||||
return htm, I["filigranne"]
|
||||
@ -903,7 +910,7 @@ def do_formsemestre_bulletinetud(
|
||||
)
|
||||
if format == "pdf":
|
||||
return (
|
||||
sendPDFFile(REQUEST, bul, filename),
|
||||
scu.sendPDFFile(REQUEST, bul, filename),
|
||||
I["filigranne"],
|
||||
) # unused ret. value
|
||||
else:
|
||||
@ -918,7 +925,7 @@ def do_formsemestre_bulletinetud(
|
||||
if nohtml:
|
||||
htm = "" # speed up if html version not needed
|
||||
else:
|
||||
htm, junk = sco_bulletins_generator.make_formsemestre_bulletinetud(
|
||||
htm, _ = sco_bulletins_generator.make_formsemestre_bulletinetud(
|
||||
context, I, version=version, format="html", REQUEST=REQUEST
|
||||
)
|
||||
|
||||
@ -962,7 +969,7 @@ def mail_bulletin(context, formsemestre_id, I, pdfdata, filename, recipient_addr
|
||||
"""
|
||||
etud = I["etud"]
|
||||
webmaster = context.get_preference("bul_mail_contact_addr", formsemestre_id)
|
||||
dept = unescape_html(context.get_preference("DeptName", formsemestre_id))
|
||||
dept = scu.unescape_html(context.get_preference("DeptName", formsemestre_id))
|
||||
copy_addr = context.get_preference("email_copy_bulletins", formsemestre_id)
|
||||
intro_mail = context.get_preference("bul_intro_mail", formsemestre_id)
|
||||
|
||||
@ -981,7 +988,7 @@ def mail_bulletin(context, formsemestre_id, I, pdfdata, filename, recipient_addr
|
||||
)
|
||||
|
||||
msg = MIMEMultipart()
|
||||
subj = Header("Relevé de notes de %s" % etud["nomprenom"], SCO_ENCODING)
|
||||
subj = Header("Relevé de notes de %s" % etud["nomprenom"], scu.SCO_ENCODING)
|
||||
recipients = [recipient_addr]
|
||||
msg["Subject"] = subj
|
||||
msg["From"] = context.get_preference("email_from_addr", formsemestre_id)
|
||||
@ -991,7 +998,7 @@ def mail_bulletin(context, formsemestre_id, I, pdfdata, filename, recipient_addr
|
||||
# Guarantees the message ends in a newline
|
||||
msg.epilogue = ""
|
||||
# Text
|
||||
txt = MIMEText(hea, "plain", SCO_ENCODING)
|
||||
txt = MIMEText(hea, "plain", scu.SCO_ENCODING)
|
||||
# log('hea:\n' + hea)
|
||||
msg.attach(txt)
|
||||
# Attach pdf
|
||||
@ -1155,7 +1162,7 @@ def _formsemestre_bulletinetud_header_html(
|
||||
url
|
||||
+ "?formsemestre_id=%s&etudid=%s&format=pdf&version=%s"
|
||||
% (formsemestre_id, etudid, version),
|
||||
ICON_PDF,
|
||||
scu.ICON_PDF,
|
||||
)
|
||||
)
|
||||
H.append("""</tr></table>""")
|
||||
|
@ -28,12 +28,14 @@
|
||||
"""Generation bulletins de notes: exemple minimal pour les programmeurs
|
||||
"""
|
||||
|
||||
# Quelques modules ScoDoc utiles:
|
||||
from sco_pdf import *
|
||||
import VERSION
|
||||
import sco_utils as scu
|
||||
import sco_pdf
|
||||
import sco_preferences
|
||||
from notes_log import log
|
||||
import sco_bulletins_generator
|
||||
import sco_bulletins_standard
|
||||
from reportlab.platypus import Paragraph
|
||||
|
||||
|
||||
class BulletinGeneratorExample(sco_bulletins_standard.BulletinGeneratorStandard):
|
||||
@ -59,7 +61,7 @@ class BulletinGeneratorExample(sco_bulletins_standard.BulletinGeneratorStandard)
|
||||
assert format == "pdf" # garde fou
|
||||
return [
|
||||
Paragraph(
|
||||
SU(
|
||||
sco_pdf.SU(
|
||||
"L'étudiant %(nomprenom)s a une moyenne générale de %(moy_gen)s"
|
||||
% self.infos
|
||||
),
|
||||
|
@ -28,9 +28,12 @@
|
||||
"""Génération du bulletin en format JSON (beta, non completement testé)
|
||||
|
||||
"""
|
||||
import datetime
|
||||
import json
|
||||
|
||||
from notes_table import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
import scolars
|
||||
import sco_formsemestre
|
||||
import sco_groups
|
||||
import sco_photos
|
||||
@ -62,9 +65,9 @@ def make_json_formsemestre_bulletinetud(
|
||||
)
|
||||
|
||||
if REQUEST:
|
||||
REQUEST.RESPONSE.setHeader("content-type", JSON_MIMETYPE)
|
||||
REQUEST.RESPONSE.setHeader("content-type", scu.JSON_MIMETYPE)
|
||||
|
||||
return json.dumps(d, cls=ScoDocJSONEncoder, encoding=SCO_ENCODING)
|
||||
return json.dumps(d, cls=scu.ScoDocJSONEncoder, encoding=scu.SCO_ENCODING)
|
||||
|
||||
|
||||
# (fonction séparée: n'utilise pas formsemestre_bulletinetud_dict()
|
||||
@ -119,16 +122,16 @@ def formsemestre_bulletinetud_published_dict(
|
||||
etudid=etudid,
|
||||
code_nip=etudinfo["code_nip"],
|
||||
code_ine=etudinfo["code_ine"],
|
||||
nom=quote_xml_attr(etudinfo["nom"]),
|
||||
prenom=quote_xml_attr(etudinfo["prenom"]),
|
||||
sexe=quote_xml_attr(etudinfo["sexe"]),
|
||||
photo_url=quote_xml_attr(
|
||||
nom=scu.quote_xml_attr(etudinfo["nom"]),
|
||||
prenom=scu.quote_xml_attr(etudinfo["prenom"]),
|
||||
civilite=scu.quote_xml_attr(etudinfo["civilite_str"]),
|
||||
photo_url=scu.quote_xml_attr(
|
||||
sco_photos.etud_photo_url(context, etudinfo, fast=True)
|
||||
),
|
||||
email=quote_xml_attr(etudinfo["email"]),
|
||||
emailperso=quote_xml_attr(etudinfo["emailperso"]),
|
||||
email=scu.quote_xml_attr(etudinfo["email"]),
|
||||
emailperso=scu.quote_xml_attr(etudinfo["emailperso"]),
|
||||
)
|
||||
|
||||
d["etudiant"]["sexe"] = d["etudiant"]["civilite"] # backward compat for our clients
|
||||
# Disponible pour publication ?
|
||||
if not published:
|
||||
return d # stop !
|
||||
@ -150,7 +153,7 @@ def formsemestre_bulletinetud_published_dict(
|
||||
ues = nt.get_ues()
|
||||
modimpls = nt.get_modimpls()
|
||||
nbetuds = len(nt.rangs)
|
||||
mg = fmt_note(nt.get_etud_moy_gen(etudid))
|
||||
mg = scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
||||
if (
|
||||
nt.get_moduleimpls_attente()
|
||||
or context.get_preference("bul_show_rangs", formsemestre_id) == 0
|
||||
@ -168,9 +171,9 @@ def formsemestre_bulletinetud_published_dict(
|
||||
|
||||
d["note"] = dict(
|
||||
value=mg,
|
||||
min=fmt_note(nt.moy_min),
|
||||
max=fmt_note(nt.moy_max),
|
||||
moy=fmt_note(nt.moy_moy),
|
||||
min=scu.fmt_note(nt.moy_min),
|
||||
max=scu.fmt_note(nt.moy_max),
|
||||
moy=scu.fmt_note(nt.moy_moy),
|
||||
)
|
||||
d["rang"] = dict(value=rang, ninscrits=nbetuds)
|
||||
d["rang_group"] = []
|
||||
@ -199,25 +202,27 @@ def formsemestre_bulletinetud_published_dict(
|
||||
ects_txt = ""
|
||||
u = dict(
|
||||
id=ue["ue_id"],
|
||||
numero=quote_xml_attr(ue["numero"]),
|
||||
acronyme=quote_xml_attr(ue["acronyme"]),
|
||||
titre=quote_xml_attr(ue["titre"]),
|
||||
numero=scu.quote_xml_attr(ue["numero"]),
|
||||
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||
titre=scu.quote_xml_attr(ue["titre"]),
|
||||
note=dict(
|
||||
value=fmt_note(ue_status["cur_moy_ue"]),
|
||||
min=fmt_note(ue["min"]),
|
||||
max=fmt_note(ue["max"]),
|
||||
value=scu.fmt_note(ue_status["cur_moy_ue"]),
|
||||
min=scu.fmt_note(ue["min"]),
|
||||
max=scu.fmt_note(ue["max"]),
|
||||
),
|
||||
rang=str(nt.ue_rangs[ue["ue_id"]][0][etudid]),
|
||||
effectif=str(nt.ue_rangs[ue["ue_id"]][1]),
|
||||
ects=ects_txt,
|
||||
code_apogee=quote_xml_attr(ue["code_apogee"]),
|
||||
code_apogee=scu.quote_xml_attr(ue["code_apogee"]),
|
||||
)
|
||||
d["ue"].append(u)
|
||||
u["module"] = []
|
||||
# Liste les modules de l'UE
|
||||
ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]]
|
||||
for modimpl in ue_modimpls:
|
||||
mod_moy = fmt_note(nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid))
|
||||
mod_moy = scu.fmt_note(
|
||||
nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid)
|
||||
)
|
||||
if mod_moy == "NI": # ne mentionne pas les modules ou n'est pas inscrit
|
||||
continue
|
||||
mod = modimpl["module"]
|
||||
@ -232,15 +237,15 @@ def formsemestre_bulletinetud_published_dict(
|
||||
code=mod["code"],
|
||||
coefficient=mod["coefficient"],
|
||||
numero=mod["numero"],
|
||||
titre=quote_xml_attr(mod["titre"]),
|
||||
abbrev=quote_xml_attr(mod["abbrev"]),
|
||||
titre=scu.quote_xml_attr(mod["titre"]),
|
||||
abbrev=scu.quote_xml_attr(mod["abbrev"]),
|
||||
# ects=ects, ects des modules maintenant inutilisés
|
||||
note=dict(value=mod_moy),
|
||||
code_apogee=quote_xml_attr(mod["code_apogee"]),
|
||||
code_apogee=scu.quote_xml_attr(mod["code_apogee"]),
|
||||
)
|
||||
m["note"].update(modstat)
|
||||
for k in ("min", "max", "moy"): # formatte toutes les notes
|
||||
m["note"][k] = fmt_note(m["note"][k])
|
||||
m["note"][k] = scu.fmt_note(m["note"][k])
|
||||
|
||||
u["module"].append(m)
|
||||
if context.get_preference("bul_show_mod_rangs", formsemestre_id):
|
||||
@ -258,19 +263,19 @@ def formsemestre_bulletinetud_published_dict(
|
||||
val = e["notes"].get(etudid, {"value": "NP"})[
|
||||
"value"
|
||||
] # NA si etud demissionnaire
|
||||
val = fmt_note(val, note_max=e["note_max"])
|
||||
val = scu.fmt_note(val, note_max=e["note_max"])
|
||||
m["evaluation"].append(
|
||||
dict(
|
||||
jour=DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||
heure_debut=TimetoISO8601(
|
||||
jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||
heure_debut=ndb.TimetoISO8601(
|
||||
e["heure_debut"], null_is_empty=True
|
||||
),
|
||||
heure_fin=TimetoISO8601(
|
||||
heure_fin=ndb.TimetoISO8601(
|
||||
e["heure_fin"], null_is_empty=True
|
||||
),
|
||||
coefficient=e["coefficient"],
|
||||
evaluation_type=e["evaluation_type"],
|
||||
description=quote_xml_attr(e["description"]),
|
||||
description=scu.quote_xml_attr(e["description"]),
|
||||
note=val,
|
||||
)
|
||||
)
|
||||
@ -285,15 +290,17 @@ def formsemestre_bulletinetud_published_dict(
|
||||
if e["evaluation_id"] not in complete_eval_ids:
|
||||
m["evaluation"].append(
|
||||
dict(
|
||||
jour=DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||
heure_debut=TimetoISO8601(
|
||||
jour=ndb.DateDMYtoISO(
|
||||
e["jour"], null_is_empty=True
|
||||
),
|
||||
heure_debut=ndb.TimetoISO8601(
|
||||
e["heure_debut"], null_is_empty=True
|
||||
),
|
||||
heure_fin=TimetoISO8601(
|
||||
heure_fin=ndb.TimetoISO8601(
|
||||
e["heure_fin"], null_is_empty=True
|
||||
),
|
||||
coefficient=e["coefficient"],
|
||||
description=quote_xml_attr(e["description"]),
|
||||
description=scu.quote_xml_attr(e["description"]),
|
||||
incomplete="1",
|
||||
)
|
||||
)
|
||||
@ -307,20 +314,18 @@ def formsemestre_bulletinetud_published_dict(
|
||||
d["ue_capitalisee"].append(
|
||||
dict(
|
||||
id=ue["ue_id"],
|
||||
numero=quote_xml_attr(ue["numero"]),
|
||||
acronyme=quote_xml_attr(ue["acronyme"]),
|
||||
titre=quote_xml_attr(ue["titre"]),
|
||||
note=fmt_note(ue_status["moy"]),
|
||||
coefficient_ue=fmt_note(ue_status["coef_ue"]),
|
||||
date_capitalisation=DateDMYtoISO(ue_status["event_date"]),
|
||||
numero=scu.quote_xml_attr(ue["numero"]),
|
||||
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||
titre=scu.quote_xml_attr(ue["titre"]),
|
||||
note=scu.fmt_note(ue_status["moy"]),
|
||||
coefficient_ue=scu.fmt_note(ue_status["coef_ue"]),
|
||||
date_capitalisation=ndb.DateDMYtoISO(ue_status["event_date"]),
|
||||
ects=ects_txt,
|
||||
)
|
||||
)
|
||||
|
||||
# --- Absences
|
||||
if context.get_preference("bul_show_abs", formsemestre_id):
|
||||
debut_sem = DateDMYtoISO(sem["date_debut"])
|
||||
fin_sem = DateDMYtoISO(sem["date_fin"])
|
||||
AbsEtudSem = sco_abs.getAbsSemEtud(context, sem, etudid)
|
||||
nbabs = AbsEtudSem.CountAbs()
|
||||
nbabsjust = AbsEtudSem.CountAbsJust()
|
||||
@ -339,7 +344,7 @@ def formsemestre_bulletinetud_published_dict(
|
||||
format="xml",
|
||||
show_uevalid=context.get_preference("bul_show_uevalid", formsemestre_id),
|
||||
)
|
||||
d["situation"] = quote_xml_attr(infos["situation"])
|
||||
d["situation"] = scu.quote_xml_attr(infos["situation"])
|
||||
if dpv:
|
||||
decision = dpv["decisions"][0]
|
||||
etat = decision["etat"]
|
||||
@ -366,11 +371,11 @@ def formsemestre_bulletinetud_published_dict(
|
||||
d["decision_ue"].append(
|
||||
dict(
|
||||
ue_id=ue["ue_id"],
|
||||
numero=quote_xml_attr(ue["numero"]),
|
||||
acronyme=quote_xml_attr(ue["acronyme"]),
|
||||
titre=quote_xml_attr(ue["titre"]),
|
||||
numero=scu.quote_xml_attr(ue["numero"]),
|
||||
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||
titre=scu.quote_xml_attr(ue["titre"]),
|
||||
code=decision["decisions_ue"][ue_id]["code"],
|
||||
ects=quote_xml_attr(ue["ects"] or ""),
|
||||
ects=scu.quote_xml_attr(ue["ects"] or ""),
|
||||
)
|
||||
)
|
||||
d["autorisation_inscription"] = []
|
||||
@ -389,7 +394,10 @@ def formsemestre_bulletinetud_published_dict(
|
||||
d["appreciation"] = []
|
||||
for app in apprecs:
|
||||
d["appreciation"].append(
|
||||
dict(comment=quote_xml_attr(app["comment"]), date=DateDMYtoISO(app["date"]))
|
||||
dict(
|
||||
comment=scu.quote_xml_attr(app["comment"]),
|
||||
date=ndb.DateDMYtoISO(app["date"]),
|
||||
)
|
||||
)
|
||||
|
||||
#
|
||||
|
@ -37,8 +37,13 @@
|
||||
|
||||
import traceback, re
|
||||
|
||||
import sco_utils as scu
|
||||
from sco_permissions import ScoEtudInscrit
|
||||
import sco_formsemestre
|
||||
from sco_pdf import *
|
||||
import sco_pdf
|
||||
from sco_pdf import Color, Paragraph, Spacer, Table
|
||||
from sco_pdf import blue, cm, mm
|
||||
from sco_pdf import SU
|
||||
import sco_preferences
|
||||
from notes_log import log
|
||||
import sco_bulletins_generator
|
||||
@ -81,9 +86,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
||||
|
||||
def bul_table_html(self):
|
||||
"""Génère la table centrale du bulletin de notes: chaine HTML"""
|
||||
format = "html"
|
||||
I = self.infos
|
||||
authuser = self.authuser
|
||||
formsemestre_id = self.infos["formsemestre_id"]
|
||||
context = self.context
|
||||
|
||||
@ -98,8 +101,8 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
||||
bgcolor = "background-color: rgb(255,255,240)"
|
||||
|
||||
linktmpl = '<span onclick="toggle_vis_ue(this);" class="toggle_ue">%s</span>'
|
||||
minuslink = linktmpl % icontag("minus_img", border="0", alt="-")
|
||||
pluslink = linktmpl % icontag("plus_img", border="0", alt="+")
|
||||
minuslink = linktmpl % scu.icontag("minus_img", border="0", alt="-")
|
||||
pluslink = linktmpl % scu.icontag("plus_img", border="0", alt="+")
|
||||
|
||||
H = ['<table class="notes_bulletin" style="background-color: %s;">' % bgcolor]
|
||||
|
||||
@ -131,8 +134,8 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
||||
if context.get_preference("bul_show_minmax_mod", formsemestre_id):
|
||||
rang_minmax = '%s <span class="bul_minmax" title="[min, max] UE">[%s, %s]</span>' % (
|
||||
mod["mod_rang_txt"],
|
||||
fmt_note(mod["stats"]["min"]),
|
||||
fmt_note(mod["stats"]["max"]),
|
||||
scu.fmt_note(mod["stats"]["min"]),
|
||||
scu.fmt_note(mod["stats"]["max"]),
|
||||
)
|
||||
else:
|
||||
rang_minmax = mod["mod_rang_txt"] # vide si pas option rang
|
||||
@ -209,9 +212,9 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
||||
moy_txt = (
|
||||
'%s <span class="bul_minmax" title="[min, max] UE">[%s, %s]</span>'
|
||||
% (
|
||||
fmt_note(ue["cur_moy_ue_txt"]),
|
||||
fmt_note(ue["min"]),
|
||||
fmt_note(ue["max"]),
|
||||
scu.fmt_note(ue["cur_moy_ue_txt"]),
|
||||
scu.fmt_note(ue["min"]),
|
||||
scu.fmt_note(ue["max"]),
|
||||
)
|
||||
)
|
||||
else:
|
||||
@ -441,7 +444,6 @@ def _bulletin_pdf_table_legacy(context, I, version="long"):
|
||||
S = BulTableStyle()
|
||||
P = [] # elems pour gen. pdf
|
||||
formsemestre_id = I["formsemestre_id"]
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
bul_show_abs_modules = context.get_preference(
|
||||
"bul_show_abs_modules", formsemestre_id
|
||||
)
|
||||
@ -460,7 +462,7 @@ def _bulletin_pdf_table_legacy(context, I, version="long"):
|
||||
]
|
||||
if bul_show_abs_modules:
|
||||
t.append("Abs (J. / N.J.)")
|
||||
P.append(bold_paras(t))
|
||||
P.append(sco_pdf.bold_paras(t))
|
||||
|
||||
def list_modules(ue_modules, ue_type=None):
|
||||
"ajoute les lignes decrivant les modules d'une UE, avec eventuellement les évaluations de chacun"
|
||||
@ -471,8 +473,8 @@ def _bulletin_pdf_table_legacy(context, I, version="long"):
|
||||
if context.get_preference("bul_show_minmax_mod", formsemestre_id):
|
||||
rang_minmax = '%s <font size="8">[%s, %s]</font>' % (
|
||||
mod["mod_rang_txt"],
|
||||
fmt_note(mod["stats"]["min"]),
|
||||
fmt_note(mod["stats"]["max"]),
|
||||
scu.fmt_note(mod["stats"]["min"]),
|
||||
scu.fmt_note(mod["stats"]["max"]),
|
||||
)
|
||||
else:
|
||||
rang_minmax = mod["mod_rang_txt"] # vide si pas option rang
|
||||
@ -504,7 +506,7 @@ def _bulletin_pdf_table_legacy(context, I, version="long"):
|
||||
t = [ue["acronyme"], ue["moy_ue_txt"], ue_descr, "", coef_ue]
|
||||
if bul_show_abs_modules:
|
||||
t.append("")
|
||||
P.append(bold_paras(t))
|
||||
P.append(sco_pdf.bold_paras(t))
|
||||
coef_ue = ""
|
||||
ue_descr = "(en cours, non prise en compte)"
|
||||
S.ueline()
|
||||
@ -523,7 +525,7 @@ def _bulletin_pdf_table_legacy(context, I, version="long"):
|
||||
t = [ue["acronyme"], moy_txt, ue_descr, "", coef_ue]
|
||||
if bul_show_abs_modules:
|
||||
t.append("")
|
||||
P.append(bold_paras(t))
|
||||
P.append(sco_pdf.bold_paras(t))
|
||||
S.ueline()
|
||||
list_modules(ue["modules"], ue_type=ue_type)
|
||||
|
||||
|
@ -50,13 +50,21 @@ Pour définir un nouveau type de bulletin:
|
||||
Chaque semestre peut si nécessaire utiliser un type de bulletin différent.
|
||||
|
||||
"""
|
||||
import htmlutils, time
|
||||
import pprint, traceback
|
||||
import htmlutils
|
||||
import time
|
||||
import pprint
|
||||
import traceback
|
||||
import re
|
||||
import cStringIO
|
||||
from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate
|
||||
|
||||
from notes_table import *
|
||||
import VERSION
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import sco_formsemestre
|
||||
import sco_bulletins
|
||||
|
||||
from sco_pdf import *
|
||||
import sco_pdf
|
||||
import os
|
||||
|
||||
|
||||
@ -84,10 +92,10 @@ def pdfassemblebulletins(
|
||||
report = cStringIO.StringIO() # in-memory document, no disk file
|
||||
document = BaseDocTemplate(report)
|
||||
document.addPageTemplates(
|
||||
ScolarsPageTemplate(
|
||||
sco_pdf.ScolarsPageTemplate(
|
||||
document,
|
||||
context=context,
|
||||
author="%s %s (E. Viennet)" % (SCONAME, SCOVERSION),
|
||||
author="%s %s (E. Viennet)" % (VERSION.SCONAME, VERSION.SCOVERSION),
|
||||
title="Bulletin %s" % bul_title,
|
||||
subject="Bulletin de note",
|
||||
server_name=server_name,
|
||||
@ -117,7 +125,7 @@ def process_field(
|
||||
If format = 'html', replaces <para> by <p>. HTML does not allow logos.
|
||||
"""
|
||||
try:
|
||||
text = (field or "") % WrapDict(
|
||||
text = (field or "") % scu.WrapDict(
|
||||
cdict
|
||||
) # note that None values are mapped to empty strings
|
||||
except:
|
||||
@ -135,9 +143,9 @@ def process_field(
|
||||
return text
|
||||
# --- PDF format:
|
||||
# handle logos:
|
||||
image_dir = SCODOC_LOGOS_DIR + "/logos_" + context.DeptId() + "/"
|
||||
image_dir = scu.SCODOC_LOGOS_DIR + "/logos_" + context.DeptId() + "/"
|
||||
if not os.path.exists(image_dir):
|
||||
image_dir = SCODOC_LOGOS_DIR + "/" # use global logos
|
||||
image_dir = scu.SCODOC_LOGOS_DIR + "/" # use global logos
|
||||
text = re.sub(
|
||||
r"<(\s*)logo(.*?)src\s*=\s*(.*?)>", r"<\1logo\2\3>", text
|
||||
) # remove forbidden src attribute
|
||||
@ -150,7 +158,7 @@ def process_field(
|
||||
# tentatives d'acceder à d'autres fichiers !
|
||||
|
||||
# log('field: %s' % (text))
|
||||
return makeParas(text, style, suppress_empty=suppress_empty_pars)
|
||||
return sco_pdf.makeParas(text, style, suppress_empty=suppress_empty_pars)
|
||||
|
||||
|
||||
def get_formsemestre_bulletins_pdf(
|
||||
@ -180,7 +188,7 @@ def get_formsemestre_bulletins_pdf(
|
||||
)
|
||||
fragments += frag
|
||||
filigrannes[i] = filigranne
|
||||
bookmarks[i] = suppress_accents(nt.get_sexnom(etudid))
|
||||
bookmarks[i] = scu.suppress_accents(nt.get_sexnom(etudid))
|
||||
i = i + 1
|
||||
#
|
||||
infos = {"DeptName": context.get_preference("DeptName", formsemestre_id)}
|
||||
@ -189,7 +197,7 @@ def get_formsemestre_bulletins_pdf(
|
||||
else:
|
||||
server_name = ""
|
||||
try:
|
||||
PDFLOCK.acquire()
|
||||
sco_pdf.PDFLOCK.acquire()
|
||||
pdfdoc = pdfassemblebulletins(
|
||||
formsemestre_id,
|
||||
fragments,
|
||||
@ -201,11 +209,11 @@ def get_formsemestre_bulletins_pdf(
|
||||
context=context,
|
||||
)
|
||||
finally:
|
||||
PDFLOCK.release()
|
||||
sco_pdf.PDFLOCK.release()
|
||||
#
|
||||
dt = time.strftime("%Y-%m-%d")
|
||||
filename = "bul-%s-%s.pdf" % (sem["titre_num"], dt)
|
||||
filename = unescape_html(filename).replace(" ", "_").replace("&", "")
|
||||
filename = scu.unescape_html(filename).replace(" ", "_").replace("&", "")
|
||||
# fill cache
|
||||
context._getNotesCache().store_bulletins_pdf(
|
||||
formsemestre_id, version, filename, pdfdoc
|
||||
@ -239,7 +247,7 @@ def get_etud_bulletins_pdf(context, etudid, REQUEST, version="selectedevals"):
|
||||
else:
|
||||
server_name = ""
|
||||
try:
|
||||
PDFLOCK.acquire()
|
||||
sco_pdf.PDFLOCK.acquire()
|
||||
pdfdoc = pdfassemblebulletins(
|
||||
None,
|
||||
fragments,
|
||||
@ -251,11 +259,11 @@ def get_etud_bulletins_pdf(context, etudid, REQUEST, version="selectedevals"):
|
||||
context=context,
|
||||
)
|
||||
finally:
|
||||
PDFLOCK.release()
|
||||
sco_pdf.PDFLOCK.release()
|
||||
#
|
||||
filename = "bul-%s" % (etud["nomprenom"])
|
||||
filename = (
|
||||
unescape_html(filename).replace(" ", "_").replace("&", "").replace(".", "")
|
||||
scu.unescape_html(filename).replace(" ", "_").replace("&", "").replace(".", "")
|
||||
+ ".pdf"
|
||||
)
|
||||
|
||||
|
@ -53,53 +53,53 @@ Lien sur Scolarite/edit_preferences (sans formsemestre_id)
|
||||
et sur page "réglages bulletin" (avec formsemestre_id)
|
||||
|
||||
"""
|
||||
import os
|
||||
# import os
|
||||
|
||||
|
||||
def form_change_bul_sig(context, side, formsemestre_id=None, REQUEST=None):
|
||||
"""Change pdf signature"""
|
||||
filename = _get_sig_existing_filename(
|
||||
context, side, formsemestre_id=formsemestre_id
|
||||
)
|
||||
if side == "left":
|
||||
sidetxt = "gauche"
|
||||
elif side == "right":
|
||||
sidetxt = "droite"
|
||||
else:
|
||||
raise ValueError("invalid value for 'side' parameter")
|
||||
signatureloc = get_bul_sig_img()
|
||||
H = [
|
||||
self.sco_header(REQUEST, page_title="Changement de signature"),
|
||||
"""<h2>Changement de la signature bulletin de %(sidetxt)s</h2>
|
||||
"""
|
||||
% (sidetxt,),
|
||||
]
|
||||
"<p>Photo actuelle (%(signatureloc)s): "
|
||||
# def form_change_bul_sig(context, side, formsemestre_id=None, REQUEST=None):
|
||||
# """Change pdf signature"""
|
||||
# filename = _get_sig_existing_filename(
|
||||
# context, side, formsemestre_id=formsemestre_id
|
||||
# )
|
||||
# if side == "left":
|
||||
# sidetxt = "gauche"
|
||||
# elif side == "right":
|
||||
# sidetxt = "droite"
|
||||
# else:
|
||||
# raise ValueError("invalid value for 'side' parameter")
|
||||
# signatureloc = get_bul_sig_img()
|
||||
# H = [
|
||||
# self.sco_header(REQUEST, page_title="Changement de signature"),
|
||||
# """<h2>Changement de la signature bulletin de %(sidetxt)s</h2>
|
||||
# """
|
||||
# % (sidetxt,),
|
||||
# ]
|
||||
# "<p>Photo actuelle (%(signatureloc)s): "
|
||||
|
||||
|
||||
def get_bul_sig_img(context, side, formsemestre_id=None):
|
||||
"send back signature image data"
|
||||
# slow, not cached, used for unfrequent access (do not bypass python)
|
||||
# def get_bul_sig_img(context, side, formsemestre_id=None):
|
||||
# "send back signature image data"
|
||||
# # slow, not cached, used for unfrequent access (do not bypass python)
|
||||
|
||||
|
||||
def _sig_filename(context, side, formsemestre_id=None):
|
||||
if not side in ("left", "right"):
|
||||
raise ValueError("side must be left or right")
|
||||
dirs = [SCODOC_LOGOS_DIR, context.DeptId()]
|
||||
if formsemestre_id:
|
||||
dirs.append(formsemestre_id)
|
||||
dirs.append("bul_sig_{}".format(side))
|
||||
return os.path.join(*dirs)
|
||||
# def _sig_filename(context, side, formsemestre_id=None):
|
||||
# if not side in ("left", "right"):
|
||||
# raise ValueError("side must be left or right")
|
||||
# dirs = [SCODOC_LOGOS_DIR, context.DeptId()]
|
||||
# if formsemestre_id:
|
||||
# dirs.append(formsemestre_id)
|
||||
# dirs.append("bul_sig_{}".format(side))
|
||||
# return os.path.join(*dirs)
|
||||
|
||||
|
||||
def _get_sig_existing_filename(context, side, formsemestre_id=None):
|
||||
"full path to signature to use, or None if no signature available"
|
||||
if formsemestre_id:
|
||||
filename = _sig_filename(context, side, formsemestre_id=formsemestre_id)
|
||||
if os.path.exists(filename):
|
||||
return filename
|
||||
filename = _sig_filename(context, side)
|
||||
if os.path.exists(filename):
|
||||
return filename
|
||||
else:
|
||||
return None
|
||||
# def _get_sig_existing_filename(context, side, formsemestre_id=None):
|
||||
# "full path to signature to use, or None if no signature available"
|
||||
# if formsemestre_id:
|
||||
# filename = _sig_filename(context, side, formsemestre_id=formsemestre_id)
|
||||
# if os.path.exists(filename):
|
||||
# return filename
|
||||
# filename = _sig_filename(context, side)
|
||||
# if os.path.exists(filename):
|
||||
# return filename
|
||||
# else:
|
||||
# return None
|
||||
|
@ -46,7 +46,10 @@ de la forme %(XXX)s sont remplacées par la valeur de XXX, pour XXX dans:
|
||||
Balises img: actuellement interdites.
|
||||
|
||||
"""
|
||||
import traceback, re
|
||||
import datetime
|
||||
import traceback
|
||||
import re
|
||||
import jaxml
|
||||
|
||||
import sco_utils as scu
|
||||
import sco_formsemestre
|
||||
|
@ -34,8 +34,12 @@ E. Viennet, juillet 2011
|
||||
"""
|
||||
import traceback
|
||||
|
||||
import sco_utils as scu
|
||||
import sco_formsemestre
|
||||
from sco_pdf import *
|
||||
import sco_pdf
|
||||
from sco_pdf import blue, cm, mm
|
||||
from sco_pdf import Color, Paragraph, Spacer, Table
|
||||
|
||||
import sco_preferences
|
||||
|
||||
from notes_log import log
|
||||
@ -72,7 +76,6 @@ class BulletinGeneratorUCAC(sco_bulletins_standard.BulletinGeneratorStandard):
|
||||
I = self.infos
|
||||
context = self.context
|
||||
formsemestre_id = I["formsemestre_id"]
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
prefs = context.get_preferences(formsemestre_id)
|
||||
|
||||
P = [] # elems pour générer table avec gen_table (liste de dicts)
|
||||
@ -134,7 +137,7 @@ class BulletinGeneratorUCAC(sco_bulletins_standard.BulletinGeneratorStandard):
|
||||
total_pt_ue_v = (
|
||||
ue["ue_status"]["cur_moy_ue"] * ue["ue_status"]["coef_ue"]
|
||||
)
|
||||
total_pt_ue = fmt_note(total_pt_ue_v)
|
||||
total_pt_ue = scu.fmt_note(total_pt_ue_v)
|
||||
# log('total_pt_ue = %s' % total_pt_ue)
|
||||
except:
|
||||
# log("ue['ue_status']['cur_moy_ue'] = %s" % ue['ue_status']['cur_moy_ue'] )
|
||||
@ -212,7 +215,6 @@ class BulletinGeneratorUCAC(sco_bulletins_standard.BulletinGeneratorStandard):
|
||||
|
||||
ue_descr = "(en cours, non prise en compte)"
|
||||
ue_type = "cur"
|
||||
rowstyle = " bul_ucac_row_ue_cur"
|
||||
|
||||
# --- UE ordinaire
|
||||
pt = list_ue(ue, ue_descr)
|
||||
@ -228,8 +230,8 @@ class BulletinGeneratorUCAC(sco_bulletins_standard.BulletinGeneratorStandard):
|
||||
{
|
||||
"code_ue": "Total",
|
||||
"moyenne_ue": I["moy_gen"],
|
||||
"coef": fmt_note(sum_coef_ues),
|
||||
"total": fmt_note(sum_pt_sem),
|
||||
"coef": scu.fmt_note(sum_coef_ues),
|
||||
"total": scu.fmt_note(sum_pt_sem),
|
||||
"_code_ue_colspan": 4,
|
||||
"_css_row_class": "bul_ucac_row_total",
|
||||
"_pdf_row_markup": ["b"],
|
||||
|
@ -37,7 +37,14 @@ Malheureusement, le code de génération JSON et XML sont séparés, ce qui est
|
||||
Je propose de considérer le XMl comme "deprecated" et de ne plus le modifier, sauf nécessité.
|
||||
"""
|
||||
|
||||
from notes_table import *
|
||||
import datetime
|
||||
import jaxml
|
||||
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
import scolars
|
||||
import sco_codes_parcours
|
||||
import sco_formsemestre
|
||||
import sco_groups
|
||||
import sco_photos
|
||||
@ -62,9 +69,9 @@ def make_xml_formsemestre_bulletinetud(
|
||||
"bulletin au format XML"
|
||||
log("xml_bulletin( formsemestre_id=%s, etudid=%s )" % (formsemestre_id, etudid))
|
||||
if REQUEST:
|
||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||
if not doc:
|
||||
doc = jaxml.XML_document(encoding=SCO_ENCODING)
|
||||
doc = jaxml.XML_document(encoding=scu.SCO_ENCODING)
|
||||
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
if sem["bul_hide_xml"] == "0" or force_publishing:
|
||||
@ -98,12 +105,13 @@ def make_xml_formsemestre_bulletinetud(
|
||||
etudid=etudid,
|
||||
code_nip=etudinfo["code_nip"],
|
||||
code_ine=etudinfo["code_ine"],
|
||||
nom=quote_xml_attr(etudinfo["nom"]),
|
||||
prenom=quote_xml_attr(etudinfo["prenom"]),
|
||||
sexe=quote_xml_attr(etudinfo["sexe"]),
|
||||
photo_url=quote_xml_attr(sco_photos.etud_photo_url(context, etudinfo)),
|
||||
email=quote_xml_attr(etudinfo["email"]),
|
||||
emailperso=quote_xml_attr(etudinfo["emailperso"]),
|
||||
nom=scu.quote_xml_attr(etudinfo["nom"]),
|
||||
prenom=scu.quote_xml_attr(etudinfo["prenom"]),
|
||||
civilite=scu.quote_xml_attr(etudinfo["civilite_str"]),
|
||||
sexe=scu.quote_xml_attr(etudinfo["civilite_str"]), # compat
|
||||
photo_url=scu.quote_xml_attr(sco_photos.etud_photo_url(context, etudinfo)),
|
||||
email=scu.quote_xml_attr(etudinfo["email"]),
|
||||
emailperso=scu.quote_xml_attr(etudinfo["emailperso"]),
|
||||
)
|
||||
doc._pop()
|
||||
|
||||
@ -128,7 +136,7 @@ def make_xml_formsemestre_bulletinetud(
|
||||
ues = nt.get_ues()
|
||||
modimpls = nt.get_modimpls()
|
||||
nbetuds = len(nt.rangs)
|
||||
mg = fmt_note(nt.get_etud_moy_gen(etudid))
|
||||
mg = scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
||||
if (
|
||||
nt.get_moduleimpls_attente()
|
||||
or context.get_preference("bul_show_rangs", formsemestre_id) == 0
|
||||
@ -147,9 +155,9 @@ def make_xml_formsemestre_bulletinetud(
|
||||
doc._push()
|
||||
doc.note(
|
||||
value=mg,
|
||||
min=fmt_note(nt.moy_min),
|
||||
max=fmt_note(nt.moy_max),
|
||||
moy=fmt_note(nt.moy_moy),
|
||||
min=scu.fmt_note(nt.moy_min),
|
||||
max=scu.fmt_note(nt.moy_max),
|
||||
moy=scu.fmt_note(nt.moy_moy),
|
||||
)
|
||||
doc._pop()
|
||||
doc._push()
|
||||
@ -177,17 +185,21 @@ def make_xml_formsemestre_bulletinetud(
|
||||
doc._push()
|
||||
doc.ue(
|
||||
id=ue["ue_id"],
|
||||
numero=quote_xml_attr(ue["numero"]),
|
||||
acronyme=quote_xml_attr(ue["acronyme"]),
|
||||
titre=quote_xml_attr(ue["titre"]),
|
||||
code_apogee=quote_xml_attr(ue["code_apogee"]),
|
||||
numero=scu.quote_xml_attr(ue["numero"]),
|
||||
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||
titre=scu.quote_xml_attr(ue["titre"]),
|
||||
code_apogee=scu.quote_xml_attr(ue["code_apogee"]),
|
||||
)
|
||||
doc._push()
|
||||
if ue["type"] != UE_SPORT:
|
||||
if ue["type"] != sco_codes_parcours.UE_SPORT:
|
||||
v = ue_status["cur_moy_ue"]
|
||||
else:
|
||||
v = nt.bonus[etudid]
|
||||
doc.note(value=fmt_note(v), min=fmt_note(ue["min"]), max=fmt_note(ue["max"]))
|
||||
doc.note(
|
||||
value=scu.fmt_note(v),
|
||||
min=scu.fmt_note(ue["min"]),
|
||||
max=scu.fmt_note(ue["max"]),
|
||||
)
|
||||
doc._pop()
|
||||
try:
|
||||
ects_txt = str(int(ue["ects"]))
|
||||
@ -205,7 +217,9 @@ def make_xml_formsemestre_bulletinetud(
|
||||
# Liste les modules de l'UE
|
||||
ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]]
|
||||
for modimpl in ue_modimpls:
|
||||
mod_moy = fmt_note(nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid))
|
||||
mod_moy = scu.fmt_note(
|
||||
nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid)
|
||||
)
|
||||
if mod_moy == "NI": # ne mentionne pas les modules ou n'est pas inscrit
|
||||
continue
|
||||
mod = modimpl["module"]
|
||||
@ -219,18 +233,18 @@ def make_xml_formsemestre_bulletinetud(
|
||||
code=mod["code"],
|
||||
coefficient=mod["coefficient"],
|
||||
numero=mod["numero"],
|
||||
titre=quote_xml_attr(mod["titre"]),
|
||||
abbrev=quote_xml_attr(mod["abbrev"]),
|
||||
code_apogee=quote_xml_attr(mod["code_apogee"])
|
||||
titre=scu.quote_xml_attr(mod["titre"]),
|
||||
abbrev=scu.quote_xml_attr(mod["abbrev"]),
|
||||
code_apogee=scu.quote_xml_attr(mod["code_apogee"])
|
||||
# ects=ects ects des modules maintenant inutilisés
|
||||
)
|
||||
doc._push()
|
||||
modstat = nt.get_mod_stats(modimpl["moduleimpl_id"])
|
||||
doc.note(
|
||||
value=mod_moy,
|
||||
min=fmt_note(modstat["min"]),
|
||||
max=fmt_note(modstat["max"]),
|
||||
moy=fmt_note(modstat["moy"]),
|
||||
min=scu.fmt_note(modstat["min"]),
|
||||
max=scu.fmt_note(modstat["max"]),
|
||||
moy=scu.fmt_note(modstat["moy"]),
|
||||
)
|
||||
doc._pop()
|
||||
if context.get_preference("bul_show_mod_rangs", formsemestre_id):
|
||||
@ -247,14 +261,16 @@ def make_xml_formsemestre_bulletinetud(
|
||||
if int(e["visibulletin"]) == 1 or version == "long":
|
||||
doc._push()
|
||||
doc.evaluation(
|
||||
jour=DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||
heure_debut=TimetoISO8601(
|
||||
jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||
heure_debut=ndb.TimetoISO8601(
|
||||
e["heure_debut"], null_is_empty=True
|
||||
),
|
||||
heure_fin=TimetoISO8601(e["heure_fin"], null_is_empty=True),
|
||||
heure_fin=ndb.TimetoISO8601(
|
||||
e["heure_fin"], null_is_empty=True
|
||||
),
|
||||
coefficient=e["coefficient"],
|
||||
evaluation_type=e["evaluation_type"],
|
||||
description=quote_xml_attr(e["description"]),
|
||||
description=scu.quote_xml_attr(e["description"]),
|
||||
note_max_origin=e[
|
||||
"note_max"
|
||||
], # notes envoyées sur 20, ceci juste pour garder trace
|
||||
@ -262,7 +278,7 @@ def make_xml_formsemestre_bulletinetud(
|
||||
val = e["notes"].get(etudid, {"value": "NP"})[
|
||||
"value"
|
||||
] # NA si etud demissionnaire
|
||||
val = fmt_note(val, note_max=e["note_max"])
|
||||
val = scu.fmt_note(val, note_max=e["note_max"])
|
||||
doc.note(value=val)
|
||||
doc._pop()
|
||||
# Evaluations incomplètes ou futures:
|
||||
@ -276,15 +292,15 @@ def make_xml_formsemestre_bulletinetud(
|
||||
if e["evaluation_id"] not in complete_eval_ids:
|
||||
doc._push()
|
||||
doc.evaluation(
|
||||
jour=DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||
heure_debut=TimetoISO8601(
|
||||
jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||
heure_debut=ndb.TimetoISO8601(
|
||||
e["heure_debut"], null_is_empty=True
|
||||
),
|
||||
heure_fin=TimetoISO8601(
|
||||
heure_fin=ndb.TimetoISO8601(
|
||||
e["heure_fin"], null_is_empty=True
|
||||
),
|
||||
coefficient=e["coefficient"],
|
||||
description=quote_xml_attr(e["description"]),
|
||||
description=scu.quote_xml_attr(e["description"]),
|
||||
incomplete="1",
|
||||
note_max_origin=e[
|
||||
"note_max"
|
||||
@ -302,27 +318,25 @@ def make_xml_formsemestre_bulletinetud(
|
||||
doc._push()
|
||||
doc.ue_capitalisee(
|
||||
id=ue["ue_id"],
|
||||
numero=quote_xml_attr(ue["numero"]),
|
||||
acronyme=quote_xml_attr(ue["acronyme"]),
|
||||
titre=quote_xml_attr(ue["titre"]),
|
||||
numero=scu.quote_xml_attr(ue["numero"]),
|
||||
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||
titre=scu.quote_xml_attr(ue["titre"]),
|
||||
)
|
||||
doc._push()
|
||||
doc.note(value=fmt_note(ue_status["moy"]))
|
||||
doc.note(value=scu.fmt_note(ue_status["moy"]))
|
||||
doc._pop()
|
||||
doc._push()
|
||||
doc.ects(value=ects_txt)
|
||||
doc._pop()
|
||||
doc._push()
|
||||
doc.coefficient_ue(value=fmt_note(ue_status["coef_ue"]))
|
||||
doc.coefficient_ue(value=scu.fmt_note(ue_status["coef_ue"]))
|
||||
doc._pop()
|
||||
doc._push()
|
||||
doc.date_capitalisation(value=DateDMYtoISO(ue_status["event_date"]))
|
||||
doc.date_capitalisation(value=ndb.DateDMYtoISO(ue_status["event_date"]))
|
||||
doc._pop()
|
||||
doc._pop()
|
||||
# --- Absences
|
||||
if context.get_preference("bul_show_abs", formsemestre_id):
|
||||
debut_sem = DateDMYtoISO(sem["date_debut"])
|
||||
fin_sem = DateDMYtoISO(sem["date_fin"])
|
||||
AbsEtudSem = sco_abs.getAbsSemEtud(context, sem, etudid)
|
||||
nbabs = AbsEtudSem.CountAbs()
|
||||
nbabsjust = AbsEtudSem.CountAbsJust()
|
||||
@ -341,7 +355,7 @@ def make_xml_formsemestre_bulletinetud(
|
||||
format="xml",
|
||||
show_uevalid=context.get_preference("bul_show_uevalid", formsemestre_id),
|
||||
)
|
||||
doc.situation(quote_xml_attr(infos["situation"]))
|
||||
doc.situation(scu.quote_xml_attr(infos["situation"]))
|
||||
if dpv:
|
||||
decision = dpv["decisions"][0]
|
||||
etat = decision["etat"]
|
||||
@ -375,9 +389,9 @@ def make_xml_formsemestre_bulletinetud(
|
||||
doc._push()
|
||||
doc.decision_ue(
|
||||
ue_id=ue["ue_id"],
|
||||
numero=quote_xml_attr(ue["numero"]),
|
||||
acronyme=quote_xml_attr(ue["acronyme"]),
|
||||
titre=quote_xml_attr(ue["titre"]),
|
||||
numero=scu.quote_xml_attr(ue["numero"]),
|
||||
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||
titre=scu.quote_xml_attr(ue["titre"]),
|
||||
code=decision["decisions_ue"][ue_id]["code"],
|
||||
)
|
||||
doc._pop()
|
||||
@ -396,5 +410,7 @@ def make_xml_formsemestre_bulletinetud(
|
||||
cnx, args={"etudid": etudid, "formsemestre_id": formsemestre_id}
|
||||
)
|
||||
for app in apprecs:
|
||||
doc.appreciation(quote_xml_attr(app["comment"]), date=DateDMYtoISO(app["date"]))
|
||||
doc.appreciation(
|
||||
scu.quote_xml_attr(app["comment"]), date=ndb.DateDMYtoISO(app["date"])
|
||||
)
|
||||
return doc
|
||||
|
@ -30,8 +30,8 @@
|
||||
|
||||
(coût théorique en heures équivalent TD)
|
||||
"""
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from gen_tables import GenTable
|
||||
import sco_excel, sco_pdf
|
||||
@ -39,6 +39,7 @@ from sco_pdf import SU
|
||||
import sco_formsemestre
|
||||
import sco_moduleimpl
|
||||
import sco_formsemestre_status
|
||||
import VERSION
|
||||
|
||||
|
||||
def formsemestre_table_estim_cost(
|
||||
@ -144,7 +145,7 @@ def formsemestre_table_estim_cost(
|
||||
(dans ce cas, retoucher le tableau excel exporté).
|
||||
</div>
|
||||
""",
|
||||
origin="Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + "",
|
||||
origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
|
||||
filename="EstimCout-S%s" % sem["semestre_id"],
|
||||
)
|
||||
return tab
|
||||
|
@ -115,7 +115,7 @@ def table_debouche_etudids(context, etudids, keep_numeric=True):
|
||||
)
|
||||
row = {
|
||||
"etudid": etudid,
|
||||
"sexe": etud["sexe"],
|
||||
"civilite": etud["civilite"],
|
||||
"nom": etud["nom"],
|
||||
"prenom": etud["prenom"],
|
||||
"_nom_target": "ficheEtud?etudid=" + etud["etudid"],
|
||||
@ -154,7 +154,7 @@ def table_debouche_etudids(context, etudids, keep_numeric=True):
|
||||
L.sort(key=lambda x: x["sem_ident"])
|
||||
|
||||
titles = {
|
||||
"sexe": "",
|
||||
"civilite": "",
|
||||
"nom": "Nom",
|
||||
"prenom": "Prénom",
|
||||
"semestre": "Dernier semestre",
|
||||
@ -170,7 +170,7 @@ def table_debouche_etudids(context, etudids, keep_numeric=True):
|
||||
"semestre",
|
||||
"semestre_id",
|
||||
"periode",
|
||||
"sexe",
|
||||
"civilite",
|
||||
"nom",
|
||||
"prenom",
|
||||
"moy",
|
||||
|
15
sco_dept.py
15
sco_dept.py
@ -27,14 +27,15 @@
|
||||
|
||||
"""Page accueil département (liste des semestres, etc)
|
||||
"""
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import sco_modalites
|
||||
import sco_news
|
||||
import sco_up_to_date
|
||||
import sco_formsemestre
|
||||
from gen_tables import GenTable
|
||||
from sco_permissions import ScoEtudInscrit, ScoEditApo
|
||||
|
||||
|
||||
def index_html(context, REQUEST=None, showcodes=0, showsemtable=0):
|
||||
@ -44,7 +45,7 @@ def index_html(context, REQUEST=None, showcodes=0, showsemtable=0):
|
||||
|
||||
# News:
|
||||
# 2020-12-30: abandonne l'icon rss
|
||||
# rssicon = icontag("rssscodoc_img", title="Flux RSS", border="0")
|
||||
# rssicon = scu.icontag("rssscodoc_img", title="Flux RSS", border="0")
|
||||
H.append(sco_news.scolar_news_summary_html(context)) # , rssicon=rssicon))
|
||||
|
||||
# Avertissement de mise à jour:
|
||||
@ -55,9 +56,11 @@ def index_html(context, REQUEST=None, showcodes=0, showsemtable=0):
|
||||
cursems = [] # semestres "courants"
|
||||
othersems = [] # autres (verrouillés)
|
||||
# icon image:
|
||||
groupicon = icontag("groupicon_img", title="Inscrits", border="0")
|
||||
emptygroupicon = icontag("emptygroupicon_img", title="Pas d'inscrits", border="0")
|
||||
lockicon = icontag("lock32_img", title="verrouillé", border="0")
|
||||
groupicon = scu.icontag("groupicon_img", title="Inscrits", border="0")
|
||||
emptygroupicon = scu.icontag(
|
||||
"emptygroupicon_img", title="Pas d'inscrits", border="0"
|
||||
)
|
||||
lockicon = scu.icontag("lock32_img", title="verrouillé", border="0")
|
||||
# Sélection sur l'etat du semestre
|
||||
for sem in sems:
|
||||
if sem["etat"] == "1" and sem["modalite"] != "EXT":
|
||||
|
@ -46,19 +46,20 @@ pg_dump SCORT | psql ANORT
|
||||
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import fcntl
|
||||
import subprocess
|
||||
import requests
|
||||
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.base import MIMEBase
|
||||
from email.header import Header
|
||||
|
||||
from notesdb import *
|
||||
import sco_utils
|
||||
from sco_utils import *
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
SCO_DUMP_LOCK = "/tmp/scodump.lock"
|
||||
|
||||
@ -67,14 +68,14 @@ def sco_dump_and_send_db(context, REQUEST=None):
|
||||
"""Dump base de données du département courant et l'envoie anonymisée pour debug"""
|
||||
H = [context.sco_header(REQUEST, page_title="Assistance technique")]
|
||||
# get currect (dept) DB name:
|
||||
cursor = SimpleQuery(context, "SELECT current_database()", {})
|
||||
cursor = ndb.SimpleQuery(context, "SELECT current_database()", {})
|
||||
db_name = cursor.fetchone()[0]
|
||||
ano_db_name = "ANO" + db_name
|
||||
# Lock
|
||||
try:
|
||||
x = open(SCO_DUMP_LOCK, "w+")
|
||||
fcntl.flock(x, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
except fcntl.BlockingIOError:
|
||||
except (IOError, OSError): # exception changed from Python 2 to 3
|
||||
raise ScoValueError(
|
||||
"Un envoi de la base "
|
||||
+ db_name
|
||||
@ -93,22 +94,25 @@ def sco_dump_and_send_db(context, REQUEST=None):
|
||||
|
||||
# Send
|
||||
r = _send_db(context, REQUEST, ano_db_name)
|
||||
if r.status_code == requests.codes.INSUFFICIENT_STORAGE:
|
||||
if (
|
||||
r.status_code
|
||||
== requests.codes.INSUFFICIENT_STORAGE # pylint: disable=no-member
|
||||
):
|
||||
H.append(
|
||||
"""<p class="warning">
|
||||
Erreur: espace serveur trop plein.
|
||||
Merci de contacter <a href="mailto:{0}">{0}</a></p>""".format(
|
||||
SCO_DEV_MAIL
|
||||
scu.SCO_DEV_MAIL
|
||||
)
|
||||
)
|
||||
elif r.status_code == requests.codes.OK:
|
||||
elif r.status_code == requests.codes.OK: # pylint: disable=no-member
|
||||
H.append("""<p>Opération effectuée.</p>""")
|
||||
else:
|
||||
H.append(
|
||||
"""<p class="warning">
|
||||
Erreur: code <tt>{0} {1}</tt>
|
||||
Merci de contacter <a href="mailto:{2}">{2}</a></p>""".format(
|
||||
r.status_code, r.reason, SCO_DEV_MAIL
|
||||
r.status_code, r.reason, scu.SCO_DEV_MAIL
|
||||
)
|
||||
)
|
||||
|
||||
@ -127,7 +131,7 @@ def _duplicate_db(db_name, ano_db_name):
|
||||
cmd = ["createdb", "-E", "UTF-8", ano_db_name]
|
||||
log("sco_dump_and_send_db/_duplicate_db: {}".format(cmd))
|
||||
try:
|
||||
out = subprocess.check_output(cmd)
|
||||
_ = subprocess.check_output(cmd)
|
||||
except subprocess.CalledProcessError as e:
|
||||
log("sco_dump_and_send_db: exception createdb {}".format(e))
|
||||
raise ScoValueError(
|
||||
@ -137,7 +141,7 @@ def _duplicate_db(db_name, ano_db_name):
|
||||
cmd = "pg_dump {} | psql {}".format(db_name, ano_db_name)
|
||||
log("sco_dump_and_send_db/_duplicate_db: {}".format(cmd))
|
||||
try:
|
||||
out = subprocess.check_output(cmd, shell=1)
|
||||
_ = subprocess.check_output(cmd, shell=1)
|
||||
except subprocess.CalledProcessError as e:
|
||||
log("sco_dump_and_send_db: exception {}".format(e))
|
||||
raise ScoValueError(
|
||||
@ -149,10 +153,10 @@ def _duplicate_db(db_name, ano_db_name):
|
||||
|
||||
def _anonymize_db(ano_db_name):
|
||||
"""Anonymize a departement database"""
|
||||
cmd = os.path.join(SCO_TOOLS_DIR, "anonymize_db.py")
|
||||
cmd = os.path.join(scu.SCO_TOOLS_DIR, "anonymize_db.py")
|
||||
log("_anonymize_db: {}".format(cmd))
|
||||
try:
|
||||
subprocess.check_output([cmd, ano_db_name])
|
||||
_ = subprocess.check_output([cmd, ano_db_name])
|
||||
except subprocess.CalledProcessError as e:
|
||||
log("sco_dump_and_send_db: exception in anonymisation: {}".format(e))
|
||||
raise ScoValueError(
|
||||
@ -162,7 +166,7 @@ def _anonymize_db(ano_db_name):
|
||||
|
||||
def _get_scodoc_serial(context):
|
||||
try:
|
||||
return int(open(os.path.join(SCODOC_VERSION_DIR, "scodoc.sn")).read())
|
||||
return int(open(os.path.join(scu.SCODOC_VERSION_DIR, "scodoc.sn")).read())
|
||||
except:
|
||||
return 0
|
||||
|
||||
@ -181,7 +185,7 @@ def _send_db(context, REQUEST, ano_db_name):
|
||||
log("uploading anonymized dump...")
|
||||
files = {"file": (ano_db_name + ".gz", data)}
|
||||
r = requests.post(
|
||||
SCO_DUMP_UP_URL,
|
||||
scu.SCO_DUMP_UP_URL,
|
||||
files=files,
|
||||
data={
|
||||
"dept_name": context.get_preference("DeptName"),
|
||||
@ -190,8 +194,8 @@ def _send_db(context, REQUEST, ano_db_name):
|
||||
"sent_by": context.Users.user_info(str(REQUEST.AUTHENTICATED_USER))[
|
||||
"nomcomplet"
|
||||
],
|
||||
"sco_version": SCOVERSION,
|
||||
"sco_fullversion": sco_utils.get_scodoc_version(),
|
||||
"sco_version": scu.SCOVERSION,
|
||||
"sco_fullversion": scu.get_scodoc_version(),
|
||||
},
|
||||
)
|
||||
return r
|
||||
@ -209,7 +213,7 @@ def _drop_ano_db(ano_db_name):
|
||||
cmd = ["dropdb", ano_db_name]
|
||||
log("sco_dump_and_send_db: {}".format(cmd))
|
||||
try:
|
||||
out = subprocess.check_output(cmd)
|
||||
_ = subprocess.check_output(cmd)
|
||||
except subprocess.CalledProcessError as e:
|
||||
log("sco_dump_and_send_db: exception dropdb {}".format(e))
|
||||
raise ScoValueError(
|
||||
|
@ -28,12 +28,13 @@
|
||||
"""Ajout/Modification/Supression formations
|
||||
(portage from DTML)
|
||||
"""
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
from TrivialFormulator import TrivialFormulator, TF, tf_error_message
|
||||
import sco_codes_parcours
|
||||
import sco_formsemestre
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
def formation_delete(context, formation_id=None, dialog_confirmed=False, REQUEST=None):
|
||||
@ -61,7 +62,7 @@ def formation_delete(context, formation_id=None, dialog_confirmed=False, REQUEST
|
||||
'<li><a href="formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titremois)s</a></li>'
|
||||
% sem
|
||||
)
|
||||
H.append('</ul><p><a href="%s">Revenir</a></p>' % REQUEST.URL1)
|
||||
H.append('</ul><p><a href="%s">Revenir</a></p>' % context.NotesURL())
|
||||
else:
|
||||
if not dialog_confirmed:
|
||||
return context.confirmDialog(
|
||||
@ -72,7 +73,7 @@ def formation_delete(context, formation_id=None, dialog_confirmed=False, REQUEST
|
||||
% F,
|
||||
REQUEST=REQUEST,
|
||||
OK="Supprimer cette formation",
|
||||
cancel_url=REQUEST.URL1,
|
||||
cancel_url=context.NotesURL(),
|
||||
parameters={"formation_id": formation_id},
|
||||
)
|
||||
else:
|
||||
@ -80,7 +81,7 @@ def formation_delete(context, formation_id=None, dialog_confirmed=False, REQUEST
|
||||
H.append(
|
||||
"""<p>OK, formation supprimée.</p>
|
||||
<p><a class="stdlink" href="%s">continuer</a></p>"""
|
||||
% REQUEST.URL1
|
||||
% context.NotesURL()
|
||||
)
|
||||
|
||||
H.append(context.sco_footer(REQUEST))
|
||||
@ -190,7 +191,7 @@ def formation_edit(context, formation_id=None, create=False, REQUEST=None):
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(context.NotesURL())
|
||||
else:
|
||||
# check unicity : constraint UNIQUE(acronyme,titre,version)
|
||||
if create:
|
||||
@ -202,7 +203,7 @@ def formation_edit(context, formation_id=None, create=False, REQUEST=None):
|
||||
"titre": tf[2]["titre"],
|
||||
"version": version,
|
||||
}
|
||||
quote_dict(args)
|
||||
ndb.quote_dict(args)
|
||||
others = context.formation_list(args=args)
|
||||
if others and ((len(others) > 1) or others[0]["formation_id"] != formation_id):
|
||||
return (
|
||||
|
@ -28,11 +28,12 @@
|
||||
"""Ajout/Modification/Supression matieres
|
||||
(portage from DTML)
|
||||
"""
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
from TrivialFormulator import TrivialFormulator, TF, tf_error_message
|
||||
import sco_formsemestre
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
def matiere_create(context, ue_id=None, REQUEST=None):
|
||||
@ -74,7 +75,7 @@ associé.
|
||||
submitlabel="Créer cette matière",
|
||||
)
|
||||
|
||||
dest_url = REQUEST.URL1 + "/ue_list?formation_id=" + UE["formation_id"]
|
||||
dest_url = context.NotesURL() + "/ue_list?formation_id=" + UE["formation_id"]
|
||||
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
||||
@ -90,7 +91,7 @@ associé.
|
||||
+ tf[1]
|
||||
+ context.sco_footer(REQUEST)
|
||||
)
|
||||
matiere_id = context.do_matiere_create(tf[2], REQUEST)
|
||||
_ = context.do_matiere_create(tf[2], REQUEST)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
|
||||
|
||||
@ -103,7 +104,7 @@ def matiere_delete(context, matiere_id=None, REQUEST=None):
|
||||
"<h2>Suppression de la matière %(titre)s" % M,
|
||||
" dans l'UE (%(acronyme)s))</h2>" % UE,
|
||||
]
|
||||
|
||||
dest_url = context.NotesURL() + "/ue_list?formation_id=" + str(UE["formation_id"])
|
||||
tf = TrivialFormulator(
|
||||
REQUEST.URL0,
|
||||
REQUEST.form,
|
||||
@ -115,12 +116,10 @@ def matiere_delete(context, matiere_id=None, REQUEST=None):
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
else:
|
||||
context.do_matiere_delete(matiere_id, REQUEST)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
REQUEST.URL1 + "/ue_list?formation_id=" + str(UE["formation_id"])
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
|
||||
|
||||
def matiere_edit(context, matiere_id=None, REQUEST=None):
|
||||
@ -180,7 +179,7 @@ associé.
|
||||
submitlabel="Modifier les valeurs",
|
||||
)
|
||||
|
||||
dest_url = REQUEST.URL1 + "/ue_list?formation_id=" + U["formation_id"]
|
||||
dest_url = context.NotesURL() + "/ue_list?formation_id=" + U["formation_id"]
|
||||
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + help + context.sco_footer(REQUEST)
|
||||
@ -202,7 +201,7 @@ associé.
|
||||
# changement d'UE ?
|
||||
if tf[2]["ue_id"] != F["ue_id"]:
|
||||
log("attaching mat %s to new UE %s" % (matiere_id, tf[2]["ue_id"]))
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"UPDATE notes_modules SET ue_id = %(ue_id)s WHERE matiere_id=%(matiere_id)s",
|
||||
{"ue_id": tf[2]["ue_id"], "matiere_id": matiere_id},
|
||||
|
@ -28,14 +28,16 @@
|
||||
"""Ajout/Modification/Supression UE
|
||||
(portage from DTML)
|
||||
"""
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import sco_codes_parcours
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
import sco_formsemestre
|
||||
import sco_edit_ue
|
||||
import sco_tag_module
|
||||
from sco_permissions import ScoChangeFormation
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
_MODULE_HELP = """<p class="help">
|
||||
Les modules sont décrits dans le programme pédagogique. Un module est pour ce
|
||||
@ -99,7 +101,7 @@ def module_create(context, matiere_id=None, REQUEST=None):
|
||||
"title": "Type",
|
||||
"explanation": "",
|
||||
"labels": ("Standard", "Malus"),
|
||||
"allowed_values": (str(MODULE_STANDARD), str(MODULE_MALUS)),
|
||||
"allowed_values": (str(scu.MODULE_STANDARD), str(scu.MODULE_MALUS)),
|
||||
},
|
||||
),
|
||||
(
|
||||
@ -140,7 +142,7 @@ def module_create(context, matiere_id=None, REQUEST=None):
|
||||
{
|
||||
"input_type": "menu",
|
||||
"type": "int",
|
||||
"title": strcapitalize(parcours.SESSION_NAME),
|
||||
"title": scu.strcapitalize(parcours.SESSION_NAME),
|
||||
"explanation": "%s de début du module dans la formation standard"
|
||||
% parcours.SESSION_NAME,
|
||||
"labels": [str(x) for x in semestres_indices],
|
||||
@ -170,9 +172,9 @@ def module_create(context, matiere_id=None, REQUEST=None):
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
||||
else:
|
||||
moduleid = context.do_module_create(tf[2], REQUEST)
|
||||
context.do_module_create(tf[2], REQUEST)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
REQUEST.URL1 + "/ue_list?formation_id=" + UE["formation_id"]
|
||||
context.NotesURL() + "/ue_list?formation_id=" + UE["formation_id"]
|
||||
)
|
||||
|
||||
|
||||
@ -189,7 +191,7 @@ def module_delete(context, module_id=None, REQUEST=None):
|
||||
"""<h2>Suppression du module %(titre)s (%(code)s)</h2>""" % Mod,
|
||||
]
|
||||
|
||||
dest_url = REQUEST.URL1 + "/ue_list?formation_id=" + Mod["formation_id"]
|
||||
dest_url = context.NotesURL() + "/ue_list?formation_id=" + Mod["formation_id"]
|
||||
tf = TrivialFormulator(
|
||||
REQUEST.URL0,
|
||||
REQUEST.form,
|
||||
@ -227,7 +229,7 @@ def module_edit(context, module_id=None, REQUEST=None):
|
||||
unlocked = not context.module_is_locked(module_id)
|
||||
Fo = context.formation_list(args={"formation_id": Mod["formation_id"]})[0]
|
||||
parcours = sco_codes_parcours.get_parcours_from_code(Fo["type_parcours"])
|
||||
M = SimpleDictFetch(
|
||||
M = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT ue.acronyme, mat.* FROM notes_matieres mat, notes_ue ue WHERE mat.ue_id = ue.ue_id AND ue.formation_id = %(formation_id)s ORDER BY ue.numero, mat.numero",
|
||||
{"formation_id": Mod["formation_id"]},
|
||||
@ -238,7 +240,7 @@ def module_edit(context, module_id=None, REQUEST=None):
|
||||
|
||||
semestres_indices = range(1, parcours.NB_SEM + 1)
|
||||
|
||||
dest_url = REQUEST.URL1 + "/ue_list?formation_id=" + Mod["formation_id"]
|
||||
dest_url = context.NotesURL() + "/ue_list?formation_id=" + Mod["formation_id"]
|
||||
|
||||
H = [
|
||||
context.sco_header(
|
||||
@ -286,7 +288,7 @@ def module_edit(context, module_id=None, REQUEST=None):
|
||||
"title": "Type",
|
||||
"explanation": "",
|
||||
"labels": ("Standard", "Malus"),
|
||||
"allowed_values": (str(MODULE_STANDARD), str(MODULE_MALUS)),
|
||||
"allowed_values": (str(scu.MODULE_STANDARD), str(scu.MODULE_MALUS)),
|
||||
"enabled": unlocked,
|
||||
},
|
||||
),
|
||||
@ -395,11 +397,10 @@ def edit_module_set_code_apogee(context, id=None, value=None, REQUEST=None):
|
||||
modules = context.do_module_list(args={"module_id": module_id})
|
||||
if not modules:
|
||||
return "module invalide" # shoud not occur
|
||||
module = modules[0]
|
||||
|
||||
context.do_module_edit({"module_id": module_id, "code_apogee": value})
|
||||
if not value:
|
||||
value = APO_MISSING_CODE_STR
|
||||
value = scu.APO_MISSING_CODE_STR
|
||||
return value
|
||||
|
||||
|
||||
@ -444,14 +445,14 @@ def formation_add_malus_modules(context, formation_id, titre=None, REQUEST=None)
|
||||
[
|
||||
mod
|
||||
for mod in context.do_module_list(args={"ue_id": ue["ue_id"]})
|
||||
if mod["module_type"] == MODULE_MALUS
|
||||
if mod["module_type"] == scu.MODULE_MALUS
|
||||
]
|
||||
)
|
||||
if nb_mod_malus == 0:
|
||||
ue_add_malus_module(context, ue["ue_id"], titre=titre, REQUEST=REQUEST)
|
||||
|
||||
if REQUEST:
|
||||
REQUEST.RESPONSE.redirect("ue_list?formation_id=" + formation_id)
|
||||
return REQUEST.RESPONSE.redirect("ue_list?formation_id=" + formation_id)
|
||||
|
||||
|
||||
def ue_add_malus_module(context, ue_id, titre=None, code=None, REQUEST=None):
|
||||
@ -490,7 +491,7 @@ def ue_add_malus_module(context, ue_id, titre=None, code=None, REQUEST=None):
|
||||
"matiere_id": matiere_id,
|
||||
"formation_id": ue["formation_id"],
|
||||
"semestre_id": semestre_id,
|
||||
"module_type": MODULE_MALUS,
|
||||
"module_type": scu.MODULE_MALUS,
|
||||
},
|
||||
REQUEST,
|
||||
)
|
||||
|
@ -28,8 +28,8 @@
|
||||
"""Ajout/Modification/Supression UE
|
||||
|
||||
"""
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
from gen_tables import GenTable
|
||||
@ -38,6 +38,8 @@ import sco_formsemestre
|
||||
import sco_formsemestre_validation
|
||||
import sco_codes_parcours
|
||||
import sco_tag_module
|
||||
from sco_permissions import ScoChangeFormation, ScoEditFormationTags, ScoImplement
|
||||
from sco_exceptions import ScoValueError, ScoLockedFormError
|
||||
|
||||
|
||||
def ue_create(context, formation_id=None, REQUEST=None):
|
||||
@ -84,7 +86,7 @@ def ue_edit(context, ue_id=None, create=False, formation_id=None, REQUEST=None):
|
||||
|
||||
ue_types = parcours.ALLOWED_UE_TYPES
|
||||
ue_types.sort()
|
||||
ue_types_names = [UE_TYPE_NAME[k] for k in ue_types]
|
||||
ue_types_names = [sco_codes_parcours.UE_TYPE_NAME[k] for k in ue_types]
|
||||
ue_types = [str(x) for x in ue_types]
|
||||
|
||||
fw = [
|
||||
@ -158,7 +160,7 @@ def ue_edit(context, ue_id=None, create=False, formation_id=None, REQUEST=None):
|
||||
{
|
||||
"input_type": "menu",
|
||||
"type": "int",
|
||||
"title": strcapitalize(parcours.SESSION_NAME),
|
||||
"title": scu.strcapitalize(parcours.SESSION_NAME),
|
||||
"explanation": "%s de début du module dans la formation"
|
||||
% parcours.SESSION_NAME,
|
||||
"labels": [str(x) for x in semestres_indices],
|
||||
@ -204,7 +206,7 @@ def ue_edit(context, ue_id=None, create=False, formation_id=None, REQUEST=None):
|
||||
)
|
||||
if parcours.UE_IS_MODULE:
|
||||
# dans ce mode, crée un (unique) module dans l'UE:
|
||||
module_id = context.do_module_create(
|
||||
_ = context.do_module_create(
|
||||
{
|
||||
"titre": tf[2]["titre"],
|
||||
"code": tf[2]["acronyme"],
|
||||
@ -217,9 +219,9 @@ def ue_edit(context, ue_id=None, create=False, formation_id=None, REQUEST=None):
|
||||
REQUEST,
|
||||
)
|
||||
else:
|
||||
ue_id = do_ue_edit(context, tf[2])
|
||||
do_ue_edit(context, tf[2])
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
REQUEST.URL1 + "/ue_list?formation_id=" + formation_id
|
||||
context.NotesURL() + "/ue_list?formation_id=" + formation_id
|
||||
)
|
||||
|
||||
|
||||
@ -306,15 +308,15 @@ def ue_list(context, formation_id=None, msg="", REQUEST=None):
|
||||
editable = perm_change
|
||||
tag_editable = authuser.has_permission(ScoEditFormationTags, context) or perm_change
|
||||
if locked:
|
||||
lockicon = icontag("lock32_img", title="verrouillé")
|
||||
lockicon = scu.icontag("lock32_img", title="verrouillé")
|
||||
else:
|
||||
lockicon = ""
|
||||
|
||||
arrow_up, arrow_down, arrow_none = sco_groups.getArrowIconsTags(context, REQUEST)
|
||||
delete_icon = icontag(
|
||||
delete_icon = scu.icontag(
|
||||
"delete_small_img", title="Supprimer (module inutilisé)", alt="supprimer"
|
||||
)
|
||||
delete_disabled_icon = icontag(
|
||||
delete_disabled_icon = scu.icontag(
|
||||
"delete_small_dis_img", title="Suppression impossible (module utilisé)"
|
||||
)
|
||||
H = [
|
||||
@ -415,7 +417,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
||||
klass = ""
|
||||
UE["code_apogee_str"] = (
|
||||
""", Apo: <span class="%s" data-url="edit_ue_set_code_apogee" id="%s" data-placeholder="%s">"""
|
||||
% (klass, UE["ue_id"], APO_MISSING_CODE_STR)
|
||||
% (klass, UE["ue_id"], scu.APO_MISSING_CODE_STR)
|
||||
+ (UE["code_apogee"] or "")
|
||||
+ "</span>"
|
||||
)
|
||||
@ -424,7 +426,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
||||
cur_ue_semestre_id = UE["semestre_id"]
|
||||
if iue > 0:
|
||||
H.append("</ul>")
|
||||
if UE["semestre_id"] == UE_SEM_DEFAULT:
|
||||
if UE["semestre_id"] == sco_codes_parcours.UE_SEM_DEFAULT:
|
||||
lab = "Pas d'indication de semestre:"
|
||||
else:
|
||||
lab = "Semestre %s:" % UE["semestre_id"]
|
||||
@ -456,8 +458,11 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
||||
% UE
|
||||
)
|
||||
|
||||
if UE["type"] != UE_STANDARD:
|
||||
H.append('<span class="ue_type">%s</span>' % UE_TYPE_NAME[UE["type"]])
|
||||
if UE["type"] != sco_codes_parcours.UE_STANDARD:
|
||||
H.append(
|
||||
'<span class="ue_type">%s</span>'
|
||||
% sco_codes_parcours.UE_TYPE_NAME[UE["type"]]
|
||||
)
|
||||
ue_editable = editable and not context.ue_is_locked(UE["ue_id"])
|
||||
if ue_editable:
|
||||
H.append(
|
||||
@ -488,7 +493,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
||||
Mod["module_id"]
|
||||
)
|
||||
klass = "notes_module_list"
|
||||
if Mod["module_type"] == MODULE_MALUS:
|
||||
if Mod["module_type"] == scu.MODULE_MALUS:
|
||||
klass += " module_malus"
|
||||
H.append('<li class="%s">' % klass)
|
||||
|
||||
@ -527,7 +532,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
||||
)
|
||||
H.append(
|
||||
'<span class="formation_module_tit">%s</span>'
|
||||
% join_words(Mod["code"], Mod["titre"])
|
||||
% scu.join_words(Mod["code"], Mod["titre"])
|
||||
)
|
||||
if mod_editable:
|
||||
H.append("</a>")
|
||||
@ -541,7 +546,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
||||
klass = ""
|
||||
heurescoef += (
|
||||
', Apo: <span class="%s" data-url="edit_module_set_code_apogee" id="%s" data-placeholder="%s">'
|
||||
% (klass, Mod["module_id"], APO_MISSING_CODE_STR)
|
||||
% (klass, Mod["module_id"], scu.APO_MISSING_CODE_STR)
|
||||
+ (Mod["code_apogee"] or "")
|
||||
+ "</span>"
|
||||
)
|
||||
@ -658,9 +663,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
||||
)
|
||||
# <li>(debug) <a class="stdlink" href="check_form_integrity?formation_id=%(formation_id)s">Vérifier cohérence</a></li>
|
||||
|
||||
warn, ue_multiples = sco_formsemestre_validation.check_formation_ues(
|
||||
context, formation_id
|
||||
)
|
||||
warn, _ = sco_formsemestre_validation.check_formation_ues(context, formation_id)
|
||||
H.append(warn)
|
||||
|
||||
H.append(context.sco_footer(REQUEST))
|
||||
@ -764,7 +767,6 @@ def edit_ue_set_code_apogee(context, id=None, value=None, REQUEST=None):
|
||||
ues = context.do_ue_list(args={"ue_id": ue_id})
|
||||
if not ues:
|
||||
return "ue invalide"
|
||||
ue = ues[0]
|
||||
|
||||
do_ue_edit(
|
||||
context,
|
||||
@ -773,7 +775,7 @@ def edit_ue_set_code_apogee(context, id=None, value=None, REQUEST=None):
|
||||
dont_invalidate_cache=False,
|
||||
)
|
||||
if not value:
|
||||
value = APO_MISSING_CODE_STR
|
||||
value = scu.APO_MISSING_CODE_STR
|
||||
return value
|
||||
|
||||
|
||||
@ -845,7 +847,9 @@ def formation_table_recap(context, formation_id, format="html", REQUEST=None):
|
||||
columns_ids=columns_ids,
|
||||
rows=T,
|
||||
titles=titles,
|
||||
origin="Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + "",
|
||||
origin="Généré par %s le " % scu.VERSION.SCONAME
|
||||
+ scu.timedate_human_repr()
|
||||
+ "",
|
||||
caption=title,
|
||||
html_caption=title,
|
||||
html_class="table_leftalign",
|
||||
|
@ -36,8 +36,10 @@ XXX incompatible avec les ics HyperPlanning Paris 13 (était pour GPU).
|
||||
import urllib2
|
||||
import traceback
|
||||
import icalendar
|
||||
import pprint
|
||||
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import sco_formsemestre
|
||||
import sco_groups
|
||||
import sco_groups_view
|
||||
@ -84,10 +86,10 @@ def formsemestre_load_ics(context, sem):
|
||||
return cal
|
||||
|
||||
|
||||
def formsemestre_edt_groups_used(context, sem):
|
||||
"""L'ensemble des groupes EDT utilisés dans l'emplois du temps publié"""
|
||||
cal = formsemestre_load_ics(context, sem)
|
||||
return {e["X-GROUP-ID"].decode("utf8") for e in events}
|
||||
# def formsemestre_edt_groups_used(context, sem):
|
||||
# """L'ensemble des groupes EDT utilisés dans l'emploi du temps publié"""
|
||||
# cal = formsemestre_load_ics(context, sem)
|
||||
# return {e["X-GROUP-ID"].decode("utf8") for e in events}
|
||||
|
||||
|
||||
def get_edt_transcodage_groups(context, formsemestre_id):
|
||||
@ -147,7 +149,7 @@ def group_edt_json(context, group_id, start="", end="", REQUEST=None):
|
||||
}
|
||||
J.append(d)
|
||||
|
||||
return sendJSON(REQUEST, J)
|
||||
return scu.sendJSON(REQUEST, J)
|
||||
|
||||
|
||||
"""XXX
|
||||
|
@ -75,7 +75,9 @@
|
||||
|
||||
"""
|
||||
|
||||
from sco_utils import *
|
||||
import re
|
||||
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import sco_formsemestre
|
||||
import notes_table
|
||||
@ -83,6 +85,7 @@ import sco_groups
|
||||
import sco_groups_view
|
||||
import sco_archives
|
||||
import sco_apogee_csv
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
class ApoCSVArchiver(sco_archives.BaseArchiver):
|
||||
@ -110,7 +113,7 @@ def apo_csv_store(context, csv_data, annee_scolaire, sem_id):
|
||||
"""
|
||||
# sanity check
|
||||
filesize = len(csv_data)
|
||||
if filesize < 10 or filesize > CONFIG.ETUD_MAX_FILE_SIZE:
|
||||
if filesize < 10 or filesize > scu.CONFIG.ETUD_MAX_FILE_SIZE:
|
||||
raise ScoValueError("Fichier csv de taille invalide ! (%d)" % filesize)
|
||||
|
||||
if not annee_scolaire:
|
||||
|
@ -31,7 +31,7 @@
|
||||
from cStringIO import StringIO
|
||||
from zipfile import ZipFile
|
||||
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import sco_formsemestre
|
||||
import sco_formsemestre_status
|
||||
@ -43,6 +43,7 @@ import sco_apogee_csv
|
||||
import sco_portal_apogee
|
||||
from sco_apogee_csv import APO_PORTAL_ENCODING, APO_INPUT_ENCODING
|
||||
import sco_archives
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
def apo_semset_maq_status(
|
||||
@ -447,7 +448,7 @@ def table_apo_csv_list(context, semset, REQUEST=None):
|
||||
)
|
||||
t["_filename_target"] = view_link
|
||||
t["_etape_apo_target"] = view_link
|
||||
t["suppress"] = icontag(
|
||||
t["suppress"] = scu.icontag(
|
||||
"delete_small_img", border="0", alt="supprimer", title="Supprimer"
|
||||
)
|
||||
t["_suppress_target"] = "view_apo_csv_delete?etape_apo=%s&semset_id=%s" % (
|
||||
@ -484,8 +485,8 @@ def view_apo_etuds(context, semset_id, title="", nips=[], format="html", REQUEST
|
||||
if not semset_id:
|
||||
raise ValueError("invalid null semset_id")
|
||||
semset = sco_semset.SemSet(context, semset_id=semset_id)
|
||||
annee_scolaire = semset["annee_scolaire"]
|
||||
sem_id = semset["sem_id"]
|
||||
# annee_scolaire = semset["annee_scolaire"]
|
||||
# sem_id = semset["sem_id"]
|
||||
|
||||
if nips and type(nips) != type([]):
|
||||
nips = [nips]
|
||||
@ -686,7 +687,7 @@ def view_apo_csv(context, etape_apo="", semset_id="", format="html", REQUEST=Non
|
||||
sem_id = semset["sem_id"]
|
||||
csv_data = sco_etape_apogee.apo_csv_get(context, etape_apo, annee_scolaire, sem_id)
|
||||
if format == "raw":
|
||||
return sendCSVFile(REQUEST, csv_data, etape_apo + ".txt")
|
||||
return scu.sendCSVFile(REQUEST, csv_data, etape_apo + ".txt")
|
||||
apo_data = sco_apogee_csv.ApoData(csv_data, periode=semset["sem_id"])
|
||||
|
||||
(
|
||||
@ -838,7 +839,7 @@ def apo_csv_export_results(
|
||||
+ "-%s-" % periode
|
||||
+ "-".join(etapes_apo)
|
||||
)
|
||||
basename = sco_archives.sanitize_filename(unescape_html(basename))
|
||||
basename = scu.sanitize_filename(scu.unescape_html(basename))
|
||||
|
||||
dest_zip.close()
|
||||
size = data.tell()
|
||||
|
@ -90,6 +90,7 @@ l'inscrition de semestres décalés (S1 en septembre, ...).
|
||||
Le filtrage s'effctue sur la date et non plus sur la parité du semestre (1-3/2-4).
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
from sco_portal_apogee import get_inscrits_etape
|
||||
from notes_log import log
|
||||
@ -540,7 +541,7 @@ class EtapeBilan:
|
||||
ind_col,
|
||||
comptage,
|
||||
"",
|
||||
self.titres[ind_col].replace("<br/>", " / "),
|
||||
json.dumps(self.titres[ind_col].replace("<br/>", " / "))[1:-1],
|
||||
)
|
||||
elif ind_col == COL_CUMUL:
|
||||
javascript = "doFiltrage(%s, %s, '.%s', '*', '%s', '%s', '%s');" % (
|
||||
@ -548,7 +549,7 @@ class EtapeBilan:
|
||||
self.all_cols_str,
|
||||
ind_row,
|
||||
" (%d étudiants)" % count,
|
||||
self.titres[ind_row],
|
||||
json.dumps(self.titres[ind_row])[1:-1],
|
||||
"",
|
||||
)
|
||||
else:
|
||||
@ -558,10 +559,10 @@ class EtapeBilan:
|
||||
ind_row,
|
||||
ind_col,
|
||||
comptage,
|
||||
self.titres[ind_row],
|
||||
self.titres[ind_col].replace("<br/>", " / "),
|
||||
json.dumps(self.titres[ind_row])[1:-1],
|
||||
json.dumps(self.titres[ind_col].replace("<br/>", " / "))[1:-1],
|
||||
)
|
||||
return "<a href='#synthese' onclick=\"%s\">%d</a>" % (javascript, count)
|
||||
return '<a href="#synthese" onclick="%s">%d</a>' % (javascript, count)
|
||||
|
||||
def _diagtable(self):
|
||||
H = []
|
||||
|
81
sco_excel.py
81
sco_excel.py
@ -33,8 +33,9 @@ from pyExcelerator import *
|
||||
|
||||
from notes_log import log
|
||||
from scolog import logdb
|
||||
from sco_exceptions import *
|
||||
from sco_utils import *
|
||||
|
||||
from sco_exceptions import ScoValueError
|
||||
import sco_utils as scu
|
||||
import notesdb
|
||||
|
||||
import time, datetime
|
||||
@ -57,9 +58,11 @@ def sendExcelFile(REQUEST, data, filename):
|
||||
(on ne doit rien avoir émis avant, car ici sont générés les entetes)
|
||||
"""
|
||||
filename = (
|
||||
unescape_html(suppress_accents(filename)).replace("&", "").replace(" ", "_")
|
||||
scu.unescape_html(scu.suppress_accents(filename))
|
||||
.replace("&", "")
|
||||
.replace(" ", "_")
|
||||
)
|
||||
REQUEST.RESPONSE.setHeader("content-type", XLS_MIMETYPE)
|
||||
REQUEST.RESPONSE.setHeader("content-type", scu.XLS_MIMETYPE)
|
||||
REQUEST.RESPONSE.setHeader(
|
||||
"content-disposition", 'attachment; filename="%s"' % filename
|
||||
)
|
||||
@ -216,7 +219,7 @@ class ScoExcelSheet:
|
||||
sauvegarde = True
|
||||
else:
|
||||
sauvegarde = False
|
||||
ws0 = wb.add_sheet(self.sheet_name.decode(SCO_ENCODING))
|
||||
ws0 = wb.add_sheet(self.sheet_name.decode(scu.SCO_ENCODING))
|
||||
li = 0
|
||||
for l in self.cells:
|
||||
co = 0
|
||||
@ -225,7 +228,7 @@ class ScoExcelSheet:
|
||||
if type(c) == LongType:
|
||||
c = int(c) # assume all ScoDoc longs fits in int !
|
||||
elif type(c) not in (IntType, FloatType):
|
||||
c = str(c).decode(SCO_ENCODING)
|
||||
c = str(c).decode(scu.SCO_ENCODING)
|
||||
|
||||
ws0.write(li, co, c, self.get_cell_style(li, co))
|
||||
co += 1
|
||||
@ -240,14 +243,14 @@ def Excel_SimpleTable(titles=[], lines=[[]], SheetName="feuille", titlesStyles=[
|
||||
"""Export simple type 'CSV': 1ere ligne en gras, le reste tel quel"""
|
||||
# XXX devrait maintenant utiliser ScoExcelSheet
|
||||
wb = Workbook()
|
||||
ws0 = wb.add_sheet(SheetName.decode(SCO_ENCODING))
|
||||
ws0 = wb.add_sheet(SheetName.decode(scu.SCO_ENCODING))
|
||||
if not titlesStyles:
|
||||
style = Excel_MakeStyle(bold=True)
|
||||
titlesStyles = [style] * len(titles)
|
||||
# ligne de titres
|
||||
col = 0
|
||||
for it in titles:
|
||||
ws0.write(0, col, it.decode(SCO_ENCODING), titlesStyles[col])
|
||||
ws0.write(0, col, it.decode(scu.SCO_ENCODING), titlesStyles[col])
|
||||
col += 1
|
||||
# suite
|
||||
default_style = Excel_MakeStyle()
|
||||
@ -262,7 +265,7 @@ def Excel_SimpleTable(titles=[], lines=[[]], SheetName="feuille", titlesStyles=[
|
||||
if type(it) == LongType:
|
||||
it = int(it) # assume all ScoDoc longs fits in int !
|
||||
elif type(it) not in (IntType, FloatType):
|
||||
it = str(it).decode(SCO_ENCODING)
|
||||
it = str(it).decode(scu.SCO_ENCODING)
|
||||
cell_style = text_style
|
||||
ws0.write(li, col, it, cell_style)
|
||||
col += 1
|
||||
@ -279,7 +282,7 @@ def Excel_feuille_saisie(E, titreannee, description, lines):
|
||||
"""
|
||||
SheetName = "Saisie notes"
|
||||
wb = Workbook()
|
||||
ws0 = wb.add_sheet(SheetName.decode(SCO_ENCODING))
|
||||
ws0 = wb.add_sheet(SheetName.decode(scu.SCO_ENCODING))
|
||||
# ajuste largeurs colonnes (unite inconnue, empirique)
|
||||
ws0.col(0).width = 400 # codes
|
||||
ws0.col(1).width = 6000 # noms
|
||||
@ -366,10 +369,14 @@ def Excel_feuille_saisie(E, titreannee, description, lines):
|
||||
ws0.write(li, 0, u"Ne pas modifier les cases en mauve !", style_expl)
|
||||
li += 1
|
||||
# Nom du semestre
|
||||
ws0.write(li, 0, unescape_html(titreannee).decode(SCO_ENCODING), style_titres)
|
||||
ws0.write(
|
||||
li, 0, scu.unescape_html(titreannee).decode(scu.SCO_ENCODING), style_titres
|
||||
)
|
||||
li += 1
|
||||
# description evaluation
|
||||
ws0.write(li, 0, unescape_html(description).decode(SCO_ENCODING), style_titres)
|
||||
ws0.write(
|
||||
li, 0, scu.unescape_html(description).decode(scu.SCO_ENCODING), style_titres
|
||||
)
|
||||
li += 1
|
||||
ws0.write(
|
||||
li, 0, u"Evaluation du %s (coef. %g)" % (E["jour"], E["coefficient"]), style
|
||||
@ -387,7 +394,7 @@ def Excel_feuille_saisie(E, titreannee, description, lines):
|
||||
for line in lines:
|
||||
li += 1
|
||||
st = style_nom
|
||||
ws0.write(li, 0, ("!" + line[0]).decode(SCO_ENCODING), style_ro) # code
|
||||
ws0.write(li, 0, ("!" + line[0]).decode(scu.SCO_ENCODING), style_ro) # code
|
||||
if line[3] != "I":
|
||||
st = style_dem
|
||||
if line[3] == "D": # demissionnaire
|
||||
@ -396,15 +403,15 @@ def Excel_feuille_saisie(E, titreannee, description, lines):
|
||||
s = line[3] # etat autre
|
||||
else:
|
||||
s = line[4] # groupes TD/TP/...
|
||||
ws0.write(li, 1, line[1].decode(SCO_ENCODING), st)
|
||||
ws0.write(li, 2, line[2].decode(SCO_ENCODING), st)
|
||||
ws0.write(li, 3, s.decode(SCO_ENCODING), st)
|
||||
ws0.write(li, 1, line[1].decode(scu.SCO_ENCODING), st)
|
||||
ws0.write(li, 2, line[2].decode(scu.SCO_ENCODING), st)
|
||||
ws0.write(li, 3, s.decode(scu.SCO_ENCODING), st)
|
||||
try:
|
||||
val = float(line[5])
|
||||
except:
|
||||
val = line[5].decode(SCO_ENCODING)
|
||||
val = line[5].decode(scu.SCO_ENCODING)
|
||||
ws0.write(li, 4, val, style_notes) # note
|
||||
ws0.write(li, 5, line[6].decode(SCO_ENCODING), style_comment) # comment
|
||||
ws0.write(li, 5, line[6].decode(scu.SCO_ENCODING), style_comment) # comment
|
||||
# explication en bas
|
||||
li += 2
|
||||
ws0.write(li, 1, u"Code notes", style_titres)
|
||||
@ -426,7 +433,7 @@ def Excel_to_list(data, convert_to_string=str): # we may need 'encoding' argume
|
||||
convert_to_string is a conversion function applied to all non-string values (ie numbers)
|
||||
"""
|
||||
try:
|
||||
P = parse_xls("", SCO_ENCODING, doc=data)
|
||||
P = parse_xls("", scu.SCO_ENCODING, doc=data)
|
||||
except:
|
||||
log("Excel_to_list: failure to import document")
|
||||
open("/tmp/last_scodoc_import_failure.xls", "w").write(data)
|
||||
@ -443,7 +450,7 @@ def Excel_to_list(data, convert_to_string=str): # we may need 'encoding' argume
|
||||
diag.append("Attention: n'utilise que la première feuille du classeur !")
|
||||
# fill matrix
|
||||
sheet_name, values = P[0]
|
||||
sheet_name = sheet_name.encode(SCO_ENCODING, "backslashreplace")
|
||||
sheet_name = sheet_name.encode(scu.SCO_ENCODING, "backslashreplace")
|
||||
if not values:
|
||||
diag.append("Aucune valeur trouvée dans le classeur !")
|
||||
return diag, None
|
||||
@ -454,13 +461,13 @@ def Excel_to_list(data, convert_to_string=str): # we may need 'encoding' argume
|
||||
nbcols = max(cols) + 1
|
||||
nbrows = max(rows) + 1
|
||||
M = []
|
||||
for i in range(nbrows):
|
||||
for _ in range(nbrows):
|
||||
M.append([""] * nbcols)
|
||||
|
||||
for row_idx, col_idx in indexes:
|
||||
v = values[(row_idx, col_idx)]
|
||||
if isinstance(v, unicode):
|
||||
v = v.encode(SCO_ENCODING, "backslashreplace")
|
||||
v = v.encode(scu.SCO_ENCODING, "backslashreplace")
|
||||
elif convert_to_string:
|
||||
v = convert_to_string(v)
|
||||
M[row_idx][col_idx] = v
|
||||
@ -485,7 +492,7 @@ def Excel_feuille_listeappel(
|
||||
formsemestre_id = sem["formsemestre_id"]
|
||||
SheetName = "Liste " + groupname
|
||||
wb = Workbook()
|
||||
ws0 = wb.add_sheet(SheetName.decode(SCO_ENCODING))
|
||||
ws0 = wb.add_sheet(SheetName.decode(scu.SCO_ENCODING))
|
||||
|
||||
font1 = Font()
|
||||
font1.name = "Arial"
|
||||
@ -569,7 +576,7 @@ def Excel_feuille_listeappel(
|
||||
sem["date_debut"],
|
||||
sem["date_fin"],
|
||||
)
|
||||
).decode(SCO_ENCODING),
|
||||
).decode(scu.SCO_ENCODING),
|
||||
style2,
|
||||
)
|
||||
# ligne 2
|
||||
@ -578,7 +585,7 @@ def Excel_feuille_listeappel(
|
||||
# ligne 3
|
||||
li += 1
|
||||
ws0.write(li, 1, u"Enseignant :", style2)
|
||||
ws0.write(li, 5, ("Groupe %s" % groupname).decode(SCO_ENCODING), style3)
|
||||
ws0.write(li, 5, ("Groupe %s" % groupname).decode(scu.SCO_ENCODING), style3)
|
||||
# Avertissement pour ne pas confondre avec listes notes
|
||||
ws0.write(
|
||||
li + 1, 2, u"Ne pas utiliser cette feuille pour saisir les notes !", style1i
|
||||
@ -590,7 +597,9 @@ def Excel_feuille_listeappel(
|
||||
co = 2
|
||||
for partition in partitions:
|
||||
if partition["partition_name"]:
|
||||
ws0.write(li, co, partition["partition_name"].decode(SCO_ENCODING), style3)
|
||||
ws0.write(
|
||||
li, co, partition["partition_name"].decode(scu.SCO_ENCODING), style3
|
||||
)
|
||||
co += 1
|
||||
if with_codes:
|
||||
coc = co
|
||||
@ -607,7 +616,11 @@ def Excel_feuille_listeappel(
|
||||
li += 1
|
||||
ws0.write(li, 0, n, style1b)
|
||||
nomprenom = (
|
||||
t["sexe"] + " " + t["nom"] + " " + strcapitalize(strlower(t["prenom"]))
|
||||
t["civilite_str"]
|
||||
+ " "
|
||||
+ t["nom"]
|
||||
+ " "
|
||||
+ scu.strcapitalize(scu.strlower(t["prenom"]))
|
||||
)
|
||||
style_nom = style2t3
|
||||
if with_paiement:
|
||||
@ -618,31 +631,31 @@ def Excel_feuille_listeappel(
|
||||
elif not paie:
|
||||
nomprenom += " (non paiement)"
|
||||
style_nom = style2t3bold
|
||||
ws0.write(li, 1, nomprenom.decode(SCO_ENCODING), style_nom)
|
||||
ws0.write(li, 1, nomprenom.decode(scu.SCO_ENCODING), style_nom)
|
||||
co = 2
|
||||
for partition in partitions:
|
||||
if partition["partition_name"]:
|
||||
ws0.write(
|
||||
li,
|
||||
co,
|
||||
t.get(partition["partition_id"], "").decode(SCO_ENCODING),
|
||||
t.get(partition["partition_id"], "").decode(scu.SCO_ENCODING),
|
||||
style2t3,
|
||||
)
|
||||
co += 1
|
||||
if with_codes:
|
||||
ws0.write(li, coc, t["etudid"].decode(SCO_ENCODING), style2t3)
|
||||
ws0.write(li, coc, t["etudid"].decode(scu.SCO_ENCODING), style2t3)
|
||||
if t["code_nip"]:
|
||||
code_nip = t["code_nip"].decode(SCO_ENCODING)
|
||||
code_nip = t["code_nip"].decode(scu.SCO_ENCODING)
|
||||
else:
|
||||
code_nip = u""
|
||||
ws0.write(li, coc + 1, code_nip, style2t3)
|
||||
if t["code_ine"]:
|
||||
code_ine = t["code_ine"].decode(SCO_ENCODING)
|
||||
code_ine = t["code_ine"].decode(scu.SCO_ENCODING)
|
||||
else:
|
||||
code_ine = u""
|
||||
ws0.write(li, coc + 2, code_ine, style2t3)
|
||||
if t["etath"]:
|
||||
etath = t["etath"].decode(SCO_ENCODING)
|
||||
etath = t["etath"].decode(scu.SCO_ENCODING)
|
||||
else:
|
||||
etath = u""
|
||||
ws0.write(li, co, etath, style2b) # etat
|
||||
@ -654,7 +667,7 @@ def Excel_feuille_listeappel(
|
||||
dt = time.strftime("%d/%m/%Y à %Hh%M")
|
||||
if server_name:
|
||||
dt += " sur " + server_name
|
||||
ws0.write(li, 1, ("Liste éditée le " + dt).decode(SCO_ENCODING), style1i)
|
||||
ws0.write(li, 1, ("Liste éditée le " + dt).decode(scu.SCO_ENCODING), style1i)
|
||||
#
|
||||
ws0.col(0).width = 850
|
||||
ws0.col(1).width = 9000
|
||||
|
@ -27,7 +27,11 @@
|
||||
|
||||
"""Export d'une table avec les résultats de tous les étudiants
|
||||
"""
|
||||
from types import ListType
|
||||
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import scolars
|
||||
import sco_bac
|
||||
import sco_formsemestre
|
||||
@ -35,11 +39,10 @@ import sco_parcours_dut
|
||||
import sco_codes_parcours
|
||||
from sco_codes_parcours import NO_SEMESTRE_ID
|
||||
import sco_excel
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
from gen_tables import GenTable
|
||||
import sco_pvjury
|
||||
import html_sco_header
|
||||
import VERSION
|
||||
|
||||
|
||||
def _build_results_table(context, start_date=None, end_date=None, types_parcours=[]):
|
||||
@ -96,9 +99,9 @@ def _build_results_table(context, start_date=None, end_date=None, types_parcours
|
||||
rows=rows,
|
||||
titles=titles,
|
||||
columns_ids=columns_ids,
|
||||
filename=make_filename("scodoc-results-%s-%s" % (start_date, end_date)),
|
||||
filename=scu.make_filename("scodoc-results-%s-%s" % (start_date, end_date)),
|
||||
caption="Résultats ScoDoc de %s à %s" % (start_date, end_date),
|
||||
origin="Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + "",
|
||||
origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
|
||||
html_class="table_leftalign",
|
||||
html_sortable=True,
|
||||
preferences=context.get_preferences(),
|
||||
@ -119,7 +122,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
|
||||
"code_nip": "NIP",
|
||||
"nom": "Nom",
|
||||
"prenom": "Prénom",
|
||||
"sexe": "Civ.",
|
||||
"civilite_str": "Civ.",
|
||||
"nom_usuel": "Nom usuel",
|
||||
"bac": "Bac",
|
||||
"parcours": "Parcours",
|
||||
@ -130,7 +133,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
|
||||
"periode",
|
||||
"sid",
|
||||
"code_nip",
|
||||
"sexe",
|
||||
"civilite_str",
|
||||
"nom",
|
||||
# 'nom_usuel', # inutile ?
|
||||
"prenom",
|
||||
@ -168,7 +171,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
|
||||
"nom": etud["nom"],
|
||||
"nom_usuel": etud["nom_usuel"],
|
||||
"prenom": etud["prenom"],
|
||||
"sexe": etud["sexe"],
|
||||
"civilite_str": etud["civilite_str"],
|
||||
"_nom_target": "%s/ficheEtud?etudid=%s" % (context.ScoURL(), etudid),
|
||||
"_nom_td_attrs": 'id="%s" class="etudinfo"' % etudid,
|
||||
"bac": bac.abbrev(),
|
||||
@ -189,7 +192,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
|
||||
code = "-"
|
||||
r[sem["semestre_id"]] = code
|
||||
r["periode"] = sem["periode"]
|
||||
r["anneescolaire"] = annee_scolaire_debut(
|
||||
r["anneescolaire"] = scu.annee_scolaire_debut(
|
||||
int(sem["annee_debut"]), sem["mois_debut_ord"]
|
||||
)
|
||||
r["sid"] = "{} {} {}".format(
|
||||
@ -202,7 +205,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
|
||||
|
||||
def get_set_formsemestre_id_dates(context, start_date, end_date):
|
||||
"""Ensemble des formsemestre_id entre ces dates"""
|
||||
s = SimpleDictFetch(
|
||||
s = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT formsemestre_id FROM notes_formsemestre WHERE date_debut >= %(start_date)s AND date_fin <= %(end_date)s",
|
||||
{"start_date": start_date, "end_date": end_date},
|
||||
@ -224,9 +227,9 @@ def scodoc_table_results(
|
||||
if not isinstance(types_parcours, ListType):
|
||||
types_parcours = [types_parcours]
|
||||
if start_date:
|
||||
start_date_iso = DateDMYtoISO(start_date)
|
||||
start_date_iso = ndb.DateDMYtoISO(start_date)
|
||||
if end_date:
|
||||
end_date_iso = DateDMYtoISO(end_date)
|
||||
end_date_iso = ndb.DateDMYtoISO(end_date)
|
||||
types_parcours = [int(x) for x in types_parcours if x]
|
||||
|
||||
if start_date and end_date:
|
||||
@ -237,7 +240,7 @@ def scodoc_table_results(
|
||||
REQUEST.URL0,
|
||||
start_date,
|
||||
end_date,
|
||||
"&types_parcours=".join([str(x) for s in types_parcours]),
|
||||
"&types_parcours=".join([str(x) for x in types_parcours]),
|
||||
)
|
||||
if format != "html":
|
||||
return tab.make_page(
|
||||
|
@ -27,17 +27,19 @@
|
||||
|
||||
"""Recherche d'étudiants
|
||||
"""
|
||||
|
||||
from sco_utils import *
|
||||
from types import ListType
|
||||
import xml.dom.minidom
|
||||
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
from gen_tables import GenTable
|
||||
|
||||
import scolars
|
||||
import sco_formsemestre
|
||||
import sco_groups
|
||||
from sco_permissions import ScoView
|
||||
|
||||
|
||||
def form_search_etud(
|
||||
@ -128,7 +130,7 @@ def search_etud_in_dept(
|
||||
if title:
|
||||
H.append("<h2>%s</h2>" % title)
|
||||
|
||||
if is_valid_code_nip(expnom):
|
||||
if scu.is_valid_code_nip(expnom):
|
||||
etuds = search_etuds_infos(context, code_nip=expnom, REQUEST=REQUEST)
|
||||
elif expnom:
|
||||
etuds = search_etuds_infos(context, expnom=expnom, REQUEST=REQUEST)
|
||||
@ -218,10 +220,10 @@ def search_etuds_infos(context, expnom=None, code_nip=None, REQUEST=None):
|
||||
"""recherche les étudiants correspondants à expnom ou au code_nip
|
||||
et ramene liste de mappings utilisables en DTML.
|
||||
"""
|
||||
may_be_nip = is_valid_code_nip(expnom)
|
||||
may_be_nip = scu.is_valid_code_nip(expnom)
|
||||
cnx = context.GetDBConnexion()
|
||||
if expnom and not may_be_nip:
|
||||
expnom = strupper(expnom) # les noms dans la BD sont en uppercase
|
||||
expnom = scu.strupper(expnom) # les noms dans la BD sont en uppercase
|
||||
etuds = scolars.etudident_list(cnx, args={"nom": expnom}, test="~")
|
||||
else:
|
||||
code_nip = code_nip or expnom
|
||||
@ -238,20 +240,19 @@ def search_etud_by_name(context, term, REQUEST=None):
|
||||
Accepte aussi un début de code NIP (au moins 6 caractères)
|
||||
Renvoie une liste de nom en JSON
|
||||
"""
|
||||
cnx = context.GetDBConnexion()
|
||||
may_be_nip = is_valid_code_nip(term)
|
||||
# term = strupper(term) # conserve les accents
|
||||
may_be_nip = scu.is_valid_code_nip(term)
|
||||
# term = scu.strupper(term) # conserve les accents
|
||||
term = term.upper()
|
||||
if (
|
||||
not ALPHANUM_EXP.match(
|
||||
term.decode(SCO_ENCODING)
|
||||
not scu.ALPHANUM_EXP.match(
|
||||
term.decode(scu.SCO_ENCODING)
|
||||
) # n'autorise pas les caractères spéciaux
|
||||
and not may_be_nip
|
||||
):
|
||||
data = []
|
||||
else:
|
||||
if may_be_nip:
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT nom, prenom, code_nip FROM identite WHERE code_nip LIKE %(beginning)s ORDER BY nom",
|
||||
{"beginning": term + "%"},
|
||||
@ -265,7 +266,7 @@ def search_etud_by_name(context, term, REQUEST=None):
|
||||
for x in r
|
||||
]
|
||||
else:
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT nom, prenom FROM identite WHERE nom LIKE %(beginning)s ORDER BY nom",
|
||||
{"beginning": term + "%"},
|
||||
@ -279,7 +280,7 @@ def search_etud_by_name(context, term, REQUEST=None):
|
||||
for x in r
|
||||
]
|
||||
# log(data)
|
||||
return sendJSON(REQUEST, data)
|
||||
return scu.sendJSON(REQUEST, data)
|
||||
|
||||
|
||||
# ---------- Recherche sur plusieurs département
|
||||
@ -383,9 +384,9 @@ def search_inscr_etud_by_nip(context, code_nip, REQUEST=None, format="json"):
|
||||
Seuls les départements accessibles par l'utilisateur sont cherchés.
|
||||
|
||||
Renvoie une liste des inscriptions de l'étudiants dans tout ScoDoc:
|
||||
code_nip, nom, prenom, sexe, dept, formsemestre_id, date_debut_sem, date_fin_sem
|
||||
code_nip, nom, prenom, civilite_str, dept, formsemestre_id, date_debut_sem, date_fin_sem
|
||||
"""
|
||||
result, depts = search_etud_in_accessible_depts(
|
||||
result, _ = search_etud_in_accessible_depts(
|
||||
context, code_nip=code_nip, REQUEST=REQUEST
|
||||
)
|
||||
|
||||
@ -400,7 +401,7 @@ def search_inscr_etud_by_nip(context, code_nip, REQUEST=None, format="json"):
|
||||
"dept": DeptId,
|
||||
"etudid": e["etudid"],
|
||||
"code_nip": e["code_nip"],
|
||||
"sexe": e["sexe"],
|
||||
"civilite_str": e["civilite_str"],
|
||||
"nom": e["nom"],
|
||||
"prenom": e["prenom"],
|
||||
"formsemestre_id": sem["formsemestre_id"],
|
||||
@ -413,7 +414,7 @@ def search_inscr_etud_by_nip(context, code_nip, REQUEST=None, format="json"):
|
||||
"dept",
|
||||
"etudid",
|
||||
"code_nip",
|
||||
"sexe",
|
||||
"civilite_str",
|
||||
"nom",
|
||||
"prenom",
|
||||
"formsemestre_id",
|
||||
|
@ -28,16 +28,19 @@
|
||||
"""Import / Export de formations
|
||||
"""
|
||||
from operator import itemgetter
|
||||
|
||||
from sco_utils import *
|
||||
import xml.dom.minidom
|
||||
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
import sco_codes_parcours
|
||||
import sco_formsemestre
|
||||
import sco_tag_module
|
||||
from gen_tables import GenTable
|
||||
from sco_exceptions import ScoValueError
|
||||
from sco_permissions import ScoChangeFormation
|
||||
import VERSION
|
||||
|
||||
|
||||
def formation_export(
|
||||
@ -81,7 +84,7 @@ def formation_export(
|
||||
if mod["ects"] is None:
|
||||
del mod["ects"]
|
||||
|
||||
return sendResult(
|
||||
return scu.sendResult(
|
||||
REQUEST, F, name="formation", format=format, force_outer_xml_tag=False
|
||||
)
|
||||
|
||||
@ -113,7 +116,7 @@ def XMLToDicts(element, encoding):
|
||||
|
||||
|
||||
def formation_import_xml(
|
||||
context, REQUEST, doc, import_tags=True, encoding=SCO_ENCODING
|
||||
context, REQUEST, doc, import_tags=True, encoding=scu.SCO_ENCODING
|
||||
):
|
||||
"""Create a formation from XML representation
|
||||
(format dumped by formation_export( format='xml' ))
|
||||
@ -131,11 +134,11 @@ def formation_import_xml(
|
||||
F = D[1]
|
||||
F_quoted = F.copy()
|
||||
log("F=%s" % F)
|
||||
quote_dict(F_quoted)
|
||||
ndb.quote_dict(F_quoted)
|
||||
log("F_quoted=%s" % F_quoted)
|
||||
# find new version number
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
log(
|
||||
"select max(version) from notes_formations where acronyme=%(acronyme)s and titre=%(titre)s"
|
||||
% F_quoted
|
||||
@ -204,13 +207,13 @@ def formation_list_table(context, formation_id=None, args={}, REQUEST=None):
|
||||
"""
|
||||
formations = context.formation_list(formation_id=formation_id, args=args)
|
||||
title = "Programmes pédagogiques"
|
||||
lockicon = icontag(
|
||||
lockicon = scu.icontag(
|
||||
"lock32_img", title="Comporte des semestres verrouillés", border="0"
|
||||
)
|
||||
suppricon = icontag(
|
||||
suppricon = scu.icontag(
|
||||
"delete_small_img", border="0", alt="supprimer", title="Supprimer"
|
||||
)
|
||||
editicon = icontag(
|
||||
editicon = scu.icontag(
|
||||
"edit_img", border="0", alt="modifier", title="Modifier titres et code"
|
||||
)
|
||||
|
||||
@ -302,7 +305,7 @@ def formation_list_table(context, formation_id=None, args={}, REQUEST=None):
|
||||
columns_ids=columns_ids,
|
||||
rows=formations,
|
||||
titles=titles,
|
||||
origin="Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + "",
|
||||
origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
|
||||
caption=title,
|
||||
html_caption=title,
|
||||
table_id="formation_list_table",
|
||||
|
@ -27,16 +27,18 @@
|
||||
|
||||
"""Operations de base sur les formsemestres
|
||||
"""
|
||||
import time
|
||||
|
||||
from sco_utils import *
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
from gen_tables import GenTable
|
||||
|
||||
import sco_codes_parcours
|
||||
from sco_codes_parcours import NO_SEMESTRE_ID
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
_formsemestreEditor = EditableTable(
|
||||
_formsemestreEditor = ndb.EditableTable(
|
||||
"notes_formsemestre",
|
||||
"formsemestre_id",
|
||||
(
|
||||
@ -60,16 +62,16 @@ _formsemestreEditor = EditableTable(
|
||||
),
|
||||
sortkey="date_debut",
|
||||
output_formators={
|
||||
"date_debut": DateISOtoDMY,
|
||||
"date_fin": DateISOtoDMY,
|
||||
"date_debut": ndb.DateISOtoDMY,
|
||||
"date_fin": ndb.DateISOtoDMY,
|
||||
"gestion_compensation": str,
|
||||
"gestion_semestrielle": str,
|
||||
"etat": str,
|
||||
"bul_hide_xml": str,
|
||||
},
|
||||
input_formators={
|
||||
"date_debut": DateDMYtoISO,
|
||||
"date_fin": DateDMYtoISO,
|
||||
"date_debut": ndb.DateDMYtoISO,
|
||||
"date_fin": ndb.DateDMYtoISO,
|
||||
"gestion_compensation": int,
|
||||
"gestion_semestrielle": int,
|
||||
"etat": int,
|
||||
@ -144,9 +146,9 @@ def formsemestre_enrich(context, sem):
|
||||
sem["semestre_id"],
|
||||
) # eg "DUT Informatique semestre 2"
|
||||
|
||||
sem["dateord"] = DateDMYtoISO(sem["date_debut"])
|
||||
sem["date_debut_iso"] = DateDMYtoISO(sem["date_debut"])
|
||||
sem["date_fin_iso"] = DateDMYtoISO(sem["date_fin"])
|
||||
sem["dateord"] = ndb.DateDMYtoISO(sem["date_debut"])
|
||||
sem["date_debut_iso"] = ndb.DateDMYtoISO(sem["date_debut"])
|
||||
sem["date_fin_iso"] = ndb.DateDMYtoISO(sem["date_fin"])
|
||||
try:
|
||||
mois_debut, annee_debut = sem["date_debut"].split("/")[1:]
|
||||
except:
|
||||
@ -162,7 +164,9 @@ def formsemestre_enrich(context, sem):
|
||||
|
||||
sem["annee"] = annee_debut
|
||||
# 2007 ou 2007-2008:
|
||||
sem["anneescolaire"] = annee_scolaire_repr(int(annee_debut), sem["mois_debut_ord"])
|
||||
sem["anneescolaire"] = scu.annee_scolaire_repr(
|
||||
int(annee_debut), sem["mois_debut_ord"]
|
||||
)
|
||||
# La période: considère comme "S1" (ou S3) les débuts en aout-sept-octobre
|
||||
# devrait sans doute pouvoir etre changé...
|
||||
if sem["mois_debut_ord"] >= 8 and sem["mois_debut_ord"] <= 10:
|
||||
@ -229,7 +233,7 @@ def read_formsemestre_responsables(context, formsemestre_id):
|
||||
"""recupere liste des responsables de ce semestre
|
||||
:returns: liste de chaines
|
||||
"""
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT responsable_id FROM notes_formsemestre_responsables WHERE formsemestre_id = %(formsemestre_id)s",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
@ -243,7 +247,7 @@ def write_formsemestre_responsables(context, sem):
|
||||
|
||||
# ---------------------- Coefs des UE
|
||||
|
||||
_formsemestre_uecoef_editor = EditableTable(
|
||||
_formsemestre_uecoef_editor = ndb.EditableTable(
|
||||
"notes_formsemestre_uecoef",
|
||||
"formsemestre_uecoef_id",
|
||||
("formsemestre_uecoef_id", "formsemestre_id", "ue_id", "coefficient"),
|
||||
@ -292,7 +296,7 @@ def read_formsemestre_etapes(context, formsemestre_id):
|
||||
"""recupere liste des codes etapes associés à ce semestre
|
||||
:returns: liste d'instance de ApoEtapeVDI
|
||||
"""
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT etape_apo FROM notes_formsemestre_etapes WHERE formsemestre_id = %(formsemestre_id)s",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
@ -311,7 +315,7 @@ def _write_formsemestre_aux(context, sem, fieldname, valuename):
|
||||
if not "etapes" in sem:
|
||||
return
|
||||
cnx = context.GetDBConnexion(autocommit=False)
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
tablename = "notes_formsemestre_" + fieldname
|
||||
try:
|
||||
cursor.execute(
|
||||
@ -428,7 +432,7 @@ def sem_in_semestre_scolaire(context, sem, year=False, saison=0, REQUEST=None):
|
||||
)
|
||||
"""
|
||||
if not year:
|
||||
year = AnneeScolaire(REQUEST)
|
||||
year = scu.AnneeScolaire(REQUEST)
|
||||
# est-on dans la même année universitaire ?
|
||||
if sem["mois_debut_ord"] > 7:
|
||||
if sem["annee_debut"] != str(year):
|
||||
@ -452,7 +456,7 @@ def sem_in_annee_scolaire(context, sem, year=False, REQUEST=None):
|
||||
Si annee non specifiée, année scolaire courante
|
||||
"""
|
||||
if not year:
|
||||
year = AnneeScolaire(REQUEST)
|
||||
year = scu.AnneeScolaire(REQUEST)
|
||||
return ((sem["annee_debut"] == str(year)) and (sem["mois_debut_ord"] > 7)) or (
|
||||
(sem["annee_debut"] == str(year + 1)) and (sem["mois_debut_ord"] <= 7)
|
||||
)
|
||||
@ -481,8 +485,8 @@ def sem_une_annee(context, sem):
|
||||
def sem_est_courant(context, sem):
|
||||
"""Vrai si la date actuelle (now) est dans le semestre (les dates de début et fin sont incluses)"""
|
||||
now = time.strftime("%Y-%m-%d")
|
||||
debut = DateDMYtoISO(sem["date_debut"])
|
||||
fin = DateDMYtoISO(sem["date_fin"])
|
||||
debut = ndb.DateDMYtoISO(sem["date_debut"])
|
||||
fin = ndb.DateDMYtoISO(sem["date_fin"])
|
||||
return (debut <= now) and (now <= fin)
|
||||
|
||||
|
||||
@ -594,7 +598,7 @@ def view_formsemestre_by_etape(context, etape_apo=None, format="html", REQUEST=N
|
||||
tab = table_formsemestres(
|
||||
context,
|
||||
list_formsemestre_by_etape(
|
||||
context, etape_apo=etape_apo, annee_scolaire=AnneeScolaire(REQUEST)
|
||||
context, etape_apo=etape_apo, annee_scolaire=scu.AnneeScolaire(REQUEST)
|
||||
),
|
||||
html_title=html_title,
|
||||
html_next_section="""<form action="view_formsemestre_by_etape">
|
||||
|
@ -29,15 +29,15 @@
|
||||
"""
|
||||
|
||||
|
||||
from sco_utils import *
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
import sco_formsemestre
|
||||
import sco_formsemestre_status
|
||||
import sco_edt_cal
|
||||
|
||||
_custommenuEditor = EditableTable(
|
||||
_custommenuEditor = ndb.EditableTable(
|
||||
"notes_formsemestre_custommenu",
|
||||
"custommenu_id",
|
||||
("custommenu_id", "formsemestre_id", "title", "url", "idx"),
|
||||
@ -80,6 +80,9 @@ def formsemestre_custommenu_html(context, formsemestre_id, base_url=""):
|
||||
def formsemestre_custommenu_edit(context, formsemestre_id, REQUEST=None):
|
||||
"""Dialog to edit the custom menu"""
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
dest_url = (
|
||||
context.NotesURL() + "formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||
)
|
||||
H = [
|
||||
context.html_sem_header(REQUEST, "Modification du menu du semestre ", sem),
|
||||
"""<p class="help">Ce menu, spécifique à chaque semestre, peut être utilisé pour placer des liens vers vos applications préférées.</p>
|
||||
@ -126,7 +129,7 @@ def formsemestre_custommenu_edit(context, formsemestre_id, REQUEST=None):
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + "\n" + tf[1] + context.sco_footer(REQUEST)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
else:
|
||||
# form submission
|
||||
cnx = context.GetDBConnexion()
|
||||
@ -153,6 +156,4 @@ def formsemestre_custommenu_edit(context, formsemestre_id, REQUEST=None):
|
||||
"url": tf[2]["url_" + custommenu_id],
|
||||
},
|
||||
)
|
||||
REQUEST.RESPONSE.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
|
@ -28,8 +28,8 @@
|
||||
"""Form choix modules / responsables et creation formsemestre
|
||||
"""
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
import sco_groups
|
||||
from notes_log import log
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
@ -43,6 +43,8 @@ import sco_modalites
|
||||
import sco_formsemestre
|
||||
import sco_moduleimpl
|
||||
from sco_formsemestre import ApoEtapeVDI
|
||||
from sco_permissions import ScoImplement
|
||||
from sco_exceptions import AccessDenied, ScoValueError
|
||||
|
||||
|
||||
def _default_sem_title(F):
|
||||
@ -70,9 +72,7 @@ def formsemestre_createwithmodules(context, REQUEST=None):
|
||||
def formsemestre_editwithmodules(context, REQUEST, formsemestre_id):
|
||||
"""Page modification semestre"""
|
||||
# portage from dtml
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
F = context.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
||||
H = [
|
||||
context.html_sem_header(
|
||||
REQUEST,
|
||||
@ -86,7 +86,7 @@ def formsemestre_editwithmodules(context, REQUEST, formsemestre_id):
|
||||
if sem["etat"] != "1":
|
||||
H.append(
|
||||
"""<p>%s<b>Ce semestre est verrouillé.</b></p>"""
|
||||
% icontag("lock_img", border="0", title="Semestre verrouillé")
|
||||
% scu.icontag("lock_img", border="0", title="Semestre verrouillé")
|
||||
)
|
||||
else:
|
||||
H.append(do_formsemestre_createwithmodules(context, REQUEST=REQUEST, edit=1))
|
||||
@ -176,7 +176,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
||||
|
||||
# Liste des ID de semestres
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute("select semestre_id from notes_semestres")
|
||||
semestre_id_list = [str(x[0]) for x in cursor.fetchall()]
|
||||
semestre_id_labels = []
|
||||
@ -344,7 +344,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
||||
# fallback: code etape libre
|
||||
mf = mf_manual
|
||||
|
||||
for n in range(1, EDIT_NB_ETAPES + 1):
|
||||
for n in range(1, scu.EDIT_NB_ETAPES + 1):
|
||||
mf["title"] = "Etape Apogée (%d)" % n
|
||||
modform.append(("etape_apo" + str(n), mf.copy()))
|
||||
modform.append(
|
||||
@ -639,10 +639,10 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
||||
msg = ""
|
||||
if tf[0] == 1:
|
||||
# check dates
|
||||
if DateDMYtoISO(tf[2]["date_debut"]) > DateDMYtoISO(tf[2]["date_fin"]):
|
||||
if ndb.DateDMYtoISO(tf[2]["date_debut"]) > ndb.DateDMYtoISO(tf[2]["date_fin"]):
|
||||
msg = '<ul class="tf-msg"><li class="tf-msg">Dates de début et fin incompatibles !</li></ul>'
|
||||
if context.get_preference("always_require_apo_sem_codes") and not any(
|
||||
[tf[2]["etape_apo" + str(n)] for n in range(0, EDIT_NB_ETAPES + 1)]
|
||||
[tf[2]["etape_apo" + str(n)] for n in range(0, scu.EDIT_NB_ETAPES + 1)]
|
||||
):
|
||||
msg = '<ul class="tf-msg"><li class="tf-msg">Code étape Apogée manquant</li></ul>'
|
||||
|
||||
@ -693,7 +693,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
||||
start_i = 0
|
||||
else:
|
||||
start_i = 1
|
||||
for n in range(start_i, EDIT_NB_ETAPES + 1):
|
||||
for n in range(start_i, scu.EDIT_NB_ETAPES + 1):
|
||||
tf[2]["etapes"].append(
|
||||
ApoEtapeVDI(
|
||||
etape=tf[2]["etape_apo" + str(n)], vdi=tf[2]["vdi_apo" + str(n)]
|
||||
@ -709,7 +709,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
||||
"formsemestre_id": formsemestre_id,
|
||||
"responsable_id": tf[2][module_id],
|
||||
}
|
||||
mid = sco_moduleimpl.do_moduleimpl_create(context, modargs)
|
||||
_ = sco_moduleimpl.do_moduleimpl_create(context, modargs)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s&head_message=Nouveau%%20semestre%%20créé"
|
||||
% formsemestre_id
|
||||
@ -846,7 +846,6 @@ def formsemestre_clone(context, formsemestre_id, REQUEST=None):
|
||||
"""
|
||||
Formulaire clonage d'un semestre
|
||||
"""
|
||||
authuser = REQUEST.AUTHENTICATED_USER
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
# Liste des enseignants avec forme pour affichage / saisie avec suggestion
|
||||
userlist = context.Users.get_userlist()
|
||||
@ -942,7 +941,7 @@ def formsemestre_clone(context, formsemestre_id, REQUEST=None):
|
||||
msg = ""
|
||||
if tf[0] == 1:
|
||||
# check dates
|
||||
if DateDMYtoISO(tf[2]["date_debut"]) > DateDMYtoISO(tf[2]["date_fin"]):
|
||||
if ndb.DateDMYtoISO(tf[2]["date_debut"]) > ndb.DateDMYtoISO(tf[2]["date_fin"]):
|
||||
msg = '<ul class="tf-msg"><li class="tf-msg">Dates de début et fin incompatibles !</li></ul>'
|
||||
if tf[0] == 0 or msg:
|
||||
return "".join(H) + msg + tf[1] + context.sco_footer(REQUEST)
|
||||
@ -1017,7 +1016,7 @@ def do_formsemestre_clone(
|
||||
args = e.copy()
|
||||
del args["jour"] # erase date
|
||||
args["moduleimpl_id"] = mid
|
||||
evaluation_id = context.do_evaluation_create(REQUEST=REQUEST, **args)
|
||||
_ = context.do_evaluation_create(REQUEST=REQUEST, **args)
|
||||
|
||||
# 3- copy uecoefs
|
||||
objs = sco_formsemestre.formsemestre_uecoef_list(
|
||||
@ -1026,7 +1025,7 @@ def do_formsemestre_clone(
|
||||
for obj in objs:
|
||||
args = obj.copy()
|
||||
args["formsemestre_id"] = formsemestre_id
|
||||
c = sco_formsemestre.formsemestre_uecoef_create(cnx, args)
|
||||
_ = sco_formsemestre.formsemestre_uecoef_create(cnx, args)
|
||||
|
||||
# NB: don't copy notes_formsemestre_custommenu (usually specific)
|
||||
|
||||
@ -1049,7 +1048,7 @@ def do_formsemestre_clone(
|
||||
for obj in objs:
|
||||
args = obj.copy()
|
||||
args["formsemestre_id"] = formsemestre_id
|
||||
c = sco_compute_moy.formsemestre_ue_computation_expr_create(cnx, args)
|
||||
_ = sco_compute_moy.formsemestre_ue_computation_expr_create(cnx, args)
|
||||
|
||||
# 5- Copy partitions
|
||||
if clone_partitions:
|
||||
@ -1059,7 +1058,6 @@ def do_formsemestre_clone(
|
||||
for part in sco_groups.get_partitions_list(context, orig_formsemestre_id):
|
||||
if part["partition_name"] != None:
|
||||
partname = part["partition_name"]
|
||||
orig_partition_id = part["partition_id"]
|
||||
new_partition_id = sco_groups.partition_create(
|
||||
context,
|
||||
formsemestre_id,
|
||||
@ -1079,7 +1077,7 @@ def do_formsemestre_clone(
|
||||
if newpart["partition_id"] == g[0]:
|
||||
part_id = g[0]
|
||||
for group_name in g[1]:
|
||||
group_id = sco_groups.createGroup(
|
||||
_ = sco_groups.createGroup(
|
||||
context, part_id, group_name=group_name, REQUEST=REQUEST
|
||||
)
|
||||
|
||||
@ -1261,7 +1259,11 @@ def formsemestre_delete(context, formsemestre_id, REQUEST=None):
|
||||
H.append(tf[1])
|
||||
return "\n".join(H) + context.sco_footer(REQUEST)
|
||||
elif tf[0] == -1: # cancel
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
context.NotesURL()
|
||||
+ "formsemestre_status?formsemestre_id="
|
||||
+ formsemestre_id
|
||||
)
|
||||
else:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"formsemestre_delete2?formsemestre_id=" + formsemestre_id
|
||||
@ -1272,9 +1274,6 @@ def formsemestre_delete2(
|
||||
context, formsemestre_id, dialog_confirmed=False, REQUEST=None
|
||||
):
|
||||
"""Delete a formsemestre (confirmation)"""
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
F = context.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
||||
H = [context.html_sem_header(REQUEST, "Suppression du semestre", sem)]
|
||||
# Confirmation dialog
|
||||
if not dialog_confirmed:
|
||||
return context.confirmDialog(
|
||||
@ -1286,14 +1285,16 @@ def formsemestre_delete2(
|
||||
)
|
||||
# Bon, s'il le faut...
|
||||
do_formsemestre_delete(context, formsemestre_id, REQUEST)
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL2 + "?head_message=Semestre%20supprimé")
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
context.ScoURL() + "?head_message=Semestre%20supprimé"
|
||||
)
|
||||
|
||||
|
||||
def formsemestre_has_decisions_or_compensations(context, formsemestre_id):
|
||||
"""True if decision de jury dans ce semestre
|
||||
ou bien compensation de ce semestre par d'autre ssemestres.
|
||||
"""
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT v.* FROM scolar_formsemestre_validation v WHERE v.formsemestre_id = %(formsemestre_id)s OR v.compense_formsemestre_id = %(formsemestre_id)s",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
@ -1314,17 +1315,17 @@ def do_formsemestre_delete(context, formsemestre_id, REQUEST):
|
||||
# evaluations
|
||||
evals = context.do_evaluation_list(args={"moduleimpl_id": mod["moduleimpl_id"]})
|
||||
for e in evals:
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"DELETE FROM notes_notes WHERE evaluation_id=%(evaluation_id)s",
|
||||
e,
|
||||
)
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"DELETE FROM notes_notes_log WHERE evaluation_id=%(evaluation_id)s",
|
||||
e,
|
||||
)
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"DELETE FROM notes_evaluation WHERE evaluation_id=%(evaluation_id)s",
|
||||
e,
|
||||
@ -1335,7 +1336,7 @@ def do_formsemestre_delete(context, formsemestre_id, REQUEST):
|
||||
context, mod["moduleimpl_id"], formsemestre_id=formsemestre_id
|
||||
)
|
||||
# --- Desinscription des etudiants
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
req = "DELETE FROM notes_formsemestre_inscription WHERE formsemestre_id=%(formsemestre_id)s"
|
||||
cursor.execute(req, {"formsemestre_id": formsemestre_id})
|
||||
# --- Suppression des evenements
|
||||
@ -1437,7 +1438,7 @@ def formsemestre_change_lock(
|
||||
args = {"formsemestre_id": formsemestre_id, "etat": etat}
|
||||
context.do_formsemestre_edit(args)
|
||||
if REQUEST:
|
||||
REQUEST.RESPONSE.redirect(
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||
)
|
||||
|
||||
@ -1477,9 +1478,10 @@ def formsemestre_change_publication_bul(
|
||||
args = {"formsemestre_id": formsemestre_id, "bul_hide_xml": etat}
|
||||
context.do_formsemestre_edit(args)
|
||||
if REQUEST:
|
||||
REQUEST.RESPONSE.redirect(
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def formsemestre_edit_uecoefs(context, formsemestre_id, err_ue_id=None, REQUEST=None):
|
||||
@ -1489,7 +1491,6 @@ def formsemestre_edit_uecoefs(context, formsemestre_id, err_ue_id=None, REQUEST=
|
||||
if not ok:
|
||||
return err
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
F = context.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
||||
|
||||
footer = context.sco_footer(REQUEST)
|
||||
help = """<p class="help">
|
||||
@ -1664,12 +1665,12 @@ def get_formsemestre_session_id(context, sem, F, parcours):
|
||||
(modalite or "").replace("FAP", "FA").replace("APP", "FA")
|
||||
) # exception pour code Apprentissage
|
||||
if sem["semestre_id"] > 0:
|
||||
decale = sem_decale_str(sem)
|
||||
decale = scu.sem_decale_str(sem)
|
||||
semestre_id = "S%d" % sem["semestre_id"] + decale
|
||||
else:
|
||||
semestre_id = F["code_specialite"]
|
||||
annee_sco = str(annee_scolaire_debut(sem["annee_debut"], sem["mois_debut_ord"]))
|
||||
annee_sco = str(scu.annee_scolaire_debut(sem["annee_debut"], sem["mois_debut_ord"]))
|
||||
|
||||
return sanitize_string(
|
||||
return scu.sanitize_string(
|
||||
"-".join((ImputationDept, parcours_type, modalite, semestre_id, annee_sco))
|
||||
)
|
||||
|
@ -28,8 +28,11 @@
|
||||
"""Opérations d'inscriptions aux semestres et modules
|
||||
"""
|
||||
|
||||
from sco_utils import ScoEtudInscrit, log, ScoValueError, DictDefault
|
||||
from sco_utils import UE_STANDARD, UE_SPORT, UE_TYPE_NAME
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from sco_exceptions import ScoValueError
|
||||
from sco_permissions import ScoEtudInscrit
|
||||
from sco_codes_parcours import UE_STANDARD, UE_SPORT, UE_TYPE_NAME
|
||||
from notesdb import ScoDocCursor, DateISOtoDMY, DateDMYtoISO
|
||||
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
@ -287,8 +290,10 @@ def formsemestre_inscription_option(context, etudid, formsemestre_id, REQUEST=No
|
||||
)
|
||||
inscr = sco_moduleimpl.do_moduleimpl_inscription_list(context, etudid=etudid)
|
||||
# Formulaire
|
||||
modimpls_by_ue_ids = DictDefault(defaultvalue=[]) # ue_id : [ moduleimpl_id ]
|
||||
modimpls_by_ue_names = DictDefault(defaultvalue=[]) # ue_id : [ moduleimpl_name ]
|
||||
modimpls_by_ue_ids = scu.DictDefault(defaultvalue=[]) # ue_id : [ moduleimpl_id ]
|
||||
modimpls_by_ue_names = scu.DictDefault(
|
||||
defaultvalue=[]
|
||||
) # ue_id : [ moduleimpl_name ]
|
||||
ues = []
|
||||
ue_ids = set()
|
||||
initvalues = {}
|
||||
|
@ -29,7 +29,6 @@
|
||||
"""
|
||||
|
||||
# Rewritten from ancient DTML code
|
||||
from mx.DateTime import DateTime as mxDateTime
|
||||
|
||||
from notes_log import log
|
||||
import sco_utils as scu
|
||||
|
@ -29,14 +29,14 @@
|
||||
"""
|
||||
import urllib, time, datetime
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from scolog import logdb
|
||||
from notes_table import *
|
||||
import notes_table
|
||||
from TrivialFormulator import TrivialFormulator, tf_error_message
|
||||
from sco_exceptions import ScoValueError
|
||||
from sco_abs import getAbsSemEtud
|
||||
|
||||
import sco_formsemestre
|
||||
import sco_formsemestre_edit
|
||||
import sco_formsemestre_status
|
||||
@ -346,7 +346,7 @@ def formsemestre_validation_etud(
|
||||
raise ValueError("code choix invalide ! (%s)" % codechoice)
|
||||
#
|
||||
Se.valide_decision(choice, REQUEST) # enregistre
|
||||
_redirect_valid_choice(
|
||||
return _redirect_valid_choice(
|
||||
formsemestre_id, etudid, Se, choice, desturl, sortcol, REQUEST
|
||||
)
|
||||
|
||||
@ -393,7 +393,7 @@ def formsemestre_validation_etud_manu(
|
||||
#
|
||||
Se.valide_decision(choice, REQUEST) # enregistre
|
||||
if redirect:
|
||||
_redirect_valid_choice(
|
||||
return _redirect_valid_choice(
|
||||
formsemestre_id, etudid, Se, choice, desturl, sortcol, REQUEST
|
||||
)
|
||||
|
||||
@ -407,9 +407,9 @@ def _redirect_valid_choice(
|
||||
)
|
||||
if sortcol:
|
||||
adr += "&sortcol=" + sortcol
|
||||
if desturl:
|
||||
desturl += "&desturl=" + desturl
|
||||
REQUEST.RESPONSE.redirect(adr)
|
||||
# if desturl:
|
||||
# desturl += "&desturl=" + desturl
|
||||
return REQUEST.RESPONSE.redirect(adr)
|
||||
# Si le precedent a été modifié, demande relecture du parcours.
|
||||
# sinon renvoie au listing general,
|
||||
|
||||
@ -486,8 +486,8 @@ def formsemestre_recap_parcours_table(
|
||||
"""
|
||||
H = []
|
||||
linktmpl = '<span onclick="toggle_vis(this);" class="toggle_sem sem_%%s">%s</span>'
|
||||
minuslink = linktmpl % icontag("minus_img", border="0", alt="-")
|
||||
pluslink = linktmpl % icontag("plus_img", border="0", alt="+")
|
||||
minuslink = linktmpl % scu.icontag("minus_img", border="0", alt="-")
|
||||
pluslink = linktmpl % scu.icontag("plus_img", border="0", alt="+")
|
||||
if show_details:
|
||||
sd = " recap_show_details"
|
||||
plusminus = minuslink
|
||||
@ -497,7 +497,7 @@ def formsemestre_recap_parcours_table(
|
||||
H.append('<table class="recap_parcours%s"><tr>' % sd)
|
||||
H.append(
|
||||
'<th><span onclick="toggle_all_sems(this);" title="Ouvrir/fermer tous les semestres">%s</span></th><th></th><th>Semestre</th>'
|
||||
% icontag("plus18_img", width=18, height=18, border=0, title="", alt="+")
|
||||
% scu.icontag("plus18_img", width=18, height=18, border=0, title="", alt="+")
|
||||
)
|
||||
H.append("<th>Etat</th><th>Abs</th>")
|
||||
# titres des UE
|
||||
@ -591,7 +591,7 @@ def formsemestre_recap_parcours_table(
|
||||
else:
|
||||
default_sem_info = ""
|
||||
if sem["etat"] != "1": # locked
|
||||
lockicon = icontag("lock32_img", title="verrouillé", border="0")
|
||||
lockicon = scu.icontag("lock32_img", title="verrouillé", border="0")
|
||||
default_sem_info += lockicon
|
||||
if sem["formation_code"] != Se.formation["formation_code"]:
|
||||
default_sem_info += "Autre formation: %s" % sem["formation_code"]
|
||||
@ -601,8 +601,7 @@ def formsemestre_recap_parcours_table(
|
||||
)
|
||||
# Moy Gen (sous le code decision)
|
||||
H.append(
|
||||
'<td class="rcp_moy">%s</td>'
|
||||
% notes_table.fmt_note(nt.get_etud_moy_gen(etudid))
|
||||
'<td class="rcp_moy">%s</td>' % scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
||||
)
|
||||
# Absences (nb d'abs non just. dans ce semestre)
|
||||
AbsEtudSem = getAbsSemEtud(context, sem, etudid)
|
||||
@ -642,7 +641,7 @@ def formsemestre_recap_parcours_table(
|
||||
|
||||
H.append(
|
||||
'<td class="%s" title="%s">%s</td>'
|
||||
% (class_ue, " ".join(explanation_ue), notes_table.fmt_note(moy_ue))
|
||||
% (class_ue, " ".join(explanation_ue), scu.fmt_note(moy_ue))
|
||||
)
|
||||
if len(ues) < Se.nb_max_ue:
|
||||
H.append('<td colspan="%d"></td>' % (Se.nb_max_ue - len(ues)))
|
||||
@ -1035,7 +1034,7 @@ def formsemestre_validation_suppress_etud(context, formsemestre_id, etudid):
|
||||
"""Suppression des decisions de jury pour un etudiant."""
|
||||
log("formsemestre_validation_suppress_etud( %s, %s)" % (formsemestre_id, etudid))
|
||||
cnx = context.GetDBConnexion(autocommit=False)
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
args = {"formsemestre_id": formsemestre_id, "etudid": etudid}
|
||||
try:
|
||||
# -- Validation du semestre et des UEs
|
||||
@ -1246,7 +1245,7 @@ def do_formsemestre_validate_previous_ue(
|
||||
|
||||
def _invalidate_etud_formation_caches(context, etudid, formation_id):
|
||||
"Invalide tous les semestres de cette formation où l'etudiant est inscrit..."
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT sem.*
|
||||
FROM notes_formsemestre sem, notes_formsemestre_inscription i
|
||||
@ -1264,7 +1263,7 @@ def _invalidate_etud_formation_caches(context, etudid, formation_id):
|
||||
|
||||
def get_etud_ue_cap_html(context, etudid, formsemestre_id, ue_id, REQUEST=None):
|
||||
"""Ramene bout de HTML pour pouvoir supprimer une validation de cette UE"""
|
||||
valids = SimpleDictFetch(
|
||||
valids = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT SFV.* FROM scolar_formsemestre_validation SFV
|
||||
WHERE ue_id=%(ue_id)s AND etudid=%(etudid)s""",
|
||||
@ -1276,7 +1275,7 @@ def get_etud_ue_cap_html(context, etudid, formsemestre_id, ue_id, REQUEST=None):
|
||||
'<div class="existing_valids"><span>Validations existantes pour cette UE:</span><ul>'
|
||||
]
|
||||
for valid in valids:
|
||||
valid["event_date"] = DateISOtoDMY(valid["event_date"])
|
||||
valid["event_date"] = ndb.DateISOtoDMY(valid["event_date"])
|
||||
if valid["moy_ue"] != None:
|
||||
valid["m"] = ", moyenne %(moy_ue)g/20" % valid
|
||||
else:
|
||||
@ -1301,7 +1300,7 @@ def etud_ue_suppress_validation(context, etudid, formsemestre_id, ue_id, REQUEST
|
||||
"""Suppress a validation (ue_id, etudid) and redirect to formsemestre"""
|
||||
log("etud_ue_suppress_validation( %s, %s, %s)" % (etudid, formsemestre_id, ue_id))
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"DELETE FROM scolar_formsemestre_validation WHERE etudid=%(etudid)s and ue_id=%(ue_id)s",
|
||||
{"etudid": etudid, "ue_id": ue_id},
|
||||
@ -1327,7 +1326,7 @@ def check_formation_ues(context, formation_id):
|
||||
ue_multiples = {} # { ue_id : [ liste des formsemestre ] }
|
||||
for ue in ues:
|
||||
# formsemestres utilisant cette ue ?
|
||||
sems = SimpleDictFetch(
|
||||
sems = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT DISTINCT sem.*
|
||||
FROM notes_formsemestre sem, notes_modules mod, notes_moduleimpl mi
|
||||
|
@ -32,7 +32,7 @@ import operator
|
||||
import traceback
|
||||
from types import FloatType, IntType, LongType, StringType
|
||||
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
|
||||
|
||||
|
124
sco_groups.py
124
sco_groups.py
@ -33,22 +33,27 @@ Optimisation possible:
|
||||
et éviter ainsi l'appel ulterieur à get_etud_groups() dans _make_table_notes
|
||||
|
||||
"""
|
||||
|
||||
import re, sets
|
||||
import time
|
||||
import collections
|
||||
import re
|
||||
import sets
|
||||
import operator
|
||||
|
||||
# XML generation package (apt-get install jaxml)
|
||||
import jaxml
|
||||
import xml.dom.minidom
|
||||
|
||||
from sco_utils import *
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
from scolog import logdb
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
import sco_formsemestre
|
||||
import scolars
|
||||
import sco_parcours_dut
|
||||
import sco_codes_parcours
|
||||
from sco_permissions import ScoEtudChangeGroups
|
||||
from sco_exceptions import ScoException, AccessDenied, ScoValueError
|
||||
|
||||
|
||||
def can_change_groups(context, REQUEST, formsemestre_id):
|
||||
@ -70,13 +75,14 @@ def checkGroupName(
|
||||
): # XXX unused: now allow any string as a group or partition name
|
||||
"Raises exception if not a valid group name"
|
||||
if groupName and (
|
||||
not re.match(r"^\w+$", groupName) or (simplesqlquote(groupName) != groupName)
|
||||
not re.match(r"^\w+$", groupName)
|
||||
or (scu.simplesqlquote(groupName) != groupName)
|
||||
):
|
||||
log("!!! invalid group name: " + groupName)
|
||||
raise ValueError("invalid group name: " + groupName)
|
||||
|
||||
|
||||
partitionEditor = EditableTable(
|
||||
partitionEditor = ndb.EditableTable(
|
||||
"partition",
|
||||
"partition_id",
|
||||
(
|
||||
@ -90,7 +96,7 @@ partitionEditor = EditableTable(
|
||||
),
|
||||
)
|
||||
|
||||
groupEditor = EditableTable(
|
||||
groupEditor = ndb.EditableTable(
|
||||
"group_descr", "group_id", ("group_id", "partition_id", "group_name")
|
||||
)
|
||||
|
||||
@ -99,7 +105,7 @@ group_list = groupEditor.list
|
||||
|
||||
def get_group(context, group_id):
|
||||
"""Returns group object, with partition"""
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT gd.*, p.* FROM group_descr gd, partition p WHERE gd.group_id=%(group_id)s AND p.partition_id = gd.partition_id",
|
||||
{"group_id": group_id},
|
||||
@ -114,15 +120,17 @@ def group_delete(context, group, force=False):
|
||||
# if not group['group_name'] and not force:
|
||||
# raise ValueError('cannot suppress this group')
|
||||
# remove memberships:
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
context, "DELETE FROM group_membership WHERE group_id=%(group_id)s", group
|
||||
)
|
||||
# delete group:
|
||||
SimpleQuery(context, "DELETE FROM group_descr WHERE group_id=%(group_id)s", group)
|
||||
ndb.SimpleQuery(
|
||||
context, "DELETE FROM group_descr WHERE group_id=%(group_id)s", group
|
||||
)
|
||||
|
||||
|
||||
def get_partition(context, partition_id):
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT p.* FROM partition p WHERE p.partition_id = %(partition_id)s",
|
||||
{"partition_id": partition_id},
|
||||
@ -134,7 +142,7 @@ def get_partition(context, partition_id):
|
||||
|
||||
def get_partitions_list(context, formsemestre_id, with_default=True):
|
||||
"""Liste des partitions pour ce semestre (list of dicts)"""
|
||||
partitions = SimpleDictFetch(
|
||||
partitions = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT * FROM partition WHERE formsemestre_id=%(formsemestre_id)s order by numero",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
@ -148,7 +156,7 @@ def get_partitions_list(context, formsemestre_id, with_default=True):
|
||||
|
||||
def get_default_partition(context, formsemestre_id):
|
||||
"""Get partition for 'all' students (this one always exists, with NULL name)"""
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT * FROM partition WHERE formsemestre_id=%(formsemestre_id)s AND partition_name is NULL",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
@ -176,7 +184,7 @@ def get_formsemestre_groups(context, formsemestre_id, with_default=False):
|
||||
def get_partition_groups(context, partition):
|
||||
"""List of groups in this partition (list of dicts).
|
||||
Some groups may be empty."""
|
||||
return SimpleDictFetch(
|
||||
return ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT gd.*, p.* FROM group_descr gd, partition p WHERE gd.partition_id=%(partition_id)s AND gd.partition_id=p.partition_id ORDER BY group_name",
|
||||
partition,
|
||||
@ -185,7 +193,7 @@ def get_partition_groups(context, partition):
|
||||
|
||||
def get_default_group(context, formsemestre_id, fix_if_missing=False, REQUEST=None):
|
||||
"""Returns group_id for default ('tous') group"""
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT gd.group_id FROM group_descr gd, partition p WHERE p.formsemestre_id=%(formsemestre_id)s AND p.partition_name is NULL AND p.partition_id = gd.partition_id",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
@ -217,7 +225,7 @@ def get_default_group(context, formsemestre_id, fix_if_missing=False, REQUEST=No
|
||||
|
||||
def get_sem_groups(context, formsemestre_id):
|
||||
"""Returns groups for this sem (in all partitions)."""
|
||||
return SimpleDictFetch(
|
||||
return ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT gd.*, p.* FROM group_descr gd, partition p WHERE p.formsemestre_id=%(formsemestre_id)s AND p.partition_id = gd.partition_id",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
@ -233,14 +241,14 @@ def get_group_members(context, group_id, etat=None):
|
||||
if etat is not None:
|
||||
req += " and ins.etat = %(etat)s"
|
||||
|
||||
r = SimpleDictFetch(context, req, {"group_id": group_id, "etat": etat})
|
||||
r = ndb.SimpleDictFetch(context, req, {"group_id": group_id, "etat": etat})
|
||||
|
||||
for etud in r:
|
||||
scolars.format_etud_ident(etud)
|
||||
|
||||
r.sort(key=operator.itemgetter("nom_disp", "prenom")) # tri selon nom_usuel ou nom
|
||||
|
||||
if CONFIG.ALLOW_NULL_PRENOM:
|
||||
if scu.CONFIG.ALLOW_NULL_PRENOM:
|
||||
for x in r:
|
||||
x["prenom"] = x["prenom"] or ""
|
||||
|
||||
@ -294,7 +302,7 @@ def get_group_infos(context, group_id, etat=None): # was _getlisteetud
|
||||
else:
|
||||
t["etath"] = "(dem.)"
|
||||
nbdem += 1
|
||||
elif t["etat"] == DEF:
|
||||
elif t["etat"] == sco_codes_parcours.DEF:
|
||||
t["etath"] = "Défaillant"
|
||||
else:
|
||||
t["etath"] = t["etat"]
|
||||
@ -329,7 +337,7 @@ def get_etud_groups(context, etudid, sem, exclude_default=False):
|
||||
req = "SELECT p.*, g.* from group_descr g, partition p, group_membership gm WHERE gm.etudid=%(etudid)s and gm.group_id = g.group_id and g.partition_id = p.partition_id and p.formsemestre_id = %(formsemestre_id)s"
|
||||
if exclude_default:
|
||||
req += " and p.partition_name is not NULL"
|
||||
groups = SimpleDictFetch(
|
||||
groups = ndb.SimpleDictFetch(
|
||||
context,
|
||||
req + " ORDER BY p.numero",
|
||||
{"etudid": etudid, "formsemestre_id": sem["formsemestre_id"]},
|
||||
@ -357,7 +365,7 @@ def formsemestre_get_etud_groupnames(context, formsemestre_id, attr="group_name"
|
||||
"""Recupere les groupes de tous les etudiants d'un semestre
|
||||
{ etudid : { partition_id : group_name }} (attr=group_name or group_id)
|
||||
"""
|
||||
infos = SimpleDictFetch(
|
||||
infos = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"select i.etudid, p.partition_id, gd.group_name, gd.group_id from notes_formsemestre_inscription i, partition p, group_descr gd, group_membership gm where i.formsemestre_id=%(formsemestre_id)s and i.formsemestre_id=p.formsemestre_id and p.partition_id=gd.partition_id and gm.etudid=i.etudid and gm.group_id = gd.group_id and p.partition_name is not NULL",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
@ -380,7 +388,7 @@ def etud_add_group_infos(context, etud, sem, sep=" "):
|
||||
etud["groupes"] = ""
|
||||
return etud
|
||||
|
||||
infos = SimpleDictFetch(
|
||||
infos = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT p.partition_name, g.* from group_descr g, partition p, group_membership gm WHERE gm.etudid=%(etudid)s and gm.group_id = g.group_id and g.partition_id = p.partition_id and p.formsemestre_id = %(formsemestre_id)s ORDER BY p.numero",
|
||||
{"etudid": etud["etudid"], "formsemestre_id": sem["formsemestre_id"]},
|
||||
@ -407,7 +415,7 @@ def etud_add_group_infos(context, etud, sem, sep=" "):
|
||||
|
||||
def get_etud_groups_in_partition(context, partition_id):
|
||||
"""Returns { etudid : group }, with all students in this partition"""
|
||||
infos = SimpleDictFetch(
|
||||
infos = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT gd.*, etudid from group_descr gd, group_membership gm where gd.partition_id = %(partition_id)s and gm.group_id = gd.group_id",
|
||||
{"partition_id": partition_id},
|
||||
@ -426,7 +434,7 @@ def formsemestre_partition_list(context, formsemestre_id, format="xml", REQUEST=
|
||||
# Ajoute les groupes
|
||||
for p in partitions:
|
||||
p["group"] = get_partition_groups(context, p)
|
||||
return sendResult(REQUEST, partitions, name="partition", format=format)
|
||||
return scu.sendResult(REQUEST, partitions, name="partition", format=format)
|
||||
|
||||
|
||||
def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetGroupesTD
|
||||
@ -447,8 +455,8 @@ def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetG
|
||||
) # > inscrdict
|
||||
etuds_set = set(nt.inscrdict)
|
||||
# XML response:
|
||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
||||
doc = jaxml.XML_document(encoding=SCO_ENCODING)
|
||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||
doc = jaxml.XML_document(encoding=scu.SCO_ENCODING)
|
||||
doc._text('<ajax-response><response type="object" id="MyUpdater">')
|
||||
doc._push()
|
||||
|
||||
@ -465,7 +473,8 @@ def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetG
|
||||
doc._push()
|
||||
doc.etud(
|
||||
etudid=e["etudid"],
|
||||
sexe=scolars.format_sexe(etud["sexe"]),
|
||||
civilite=etud["civilite_str"],
|
||||
sexe=etud["civilite_str"], # compat
|
||||
nom=scolars.format_nom(etud["nom"]),
|
||||
prenom=scolars.format_prenom(etud["prenom"]),
|
||||
origin=comp_origin(etud, sem),
|
||||
@ -489,7 +498,7 @@ def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetG
|
||||
doc._push()
|
||||
doc.etud(
|
||||
etudid=etud["etudid"],
|
||||
sexe=scolars.format_sexe(etud["sexe"]),
|
||||
sexe=etud["civilite_str"],
|
||||
nom=scolars.format_nom(etud["nom"]),
|
||||
prenom=scolars.format_prenom(etud["prenom"]),
|
||||
origin=comp_origin(etud, sem),
|
||||
@ -530,10 +539,10 @@ def set_group(context, etudid, group_id):
|
||||
Warning: don't check if group_id exists (the caller should check).
|
||||
"""
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
args = {"etudid": etudid, "group_id": group_id}
|
||||
# déjà inscrit ?
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT * FROM group_membership gm WHERE etudid=%(etudid)s and group_id=%(group_id)s",
|
||||
args,
|
||||
@ -542,7 +551,7 @@ def set_group(context, etudid, group_id):
|
||||
if len(r):
|
||||
return False
|
||||
# inscrit
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"INSERT INTO group_membership (etudid, group_id) VALUES (%(etudid)s, %(group_id)s)",
|
||||
args,
|
||||
@ -569,7 +578,7 @@ def change_etud_group_in_partition(
|
||||
else:
|
||||
partition = get_partition(context, group["partition_id"])
|
||||
# 1- Supprime membership dans cette partition
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"""DELETE FROM group_membership WHERE group_membership_id IN
|
||||
(SELECT gm.group_membership_id
|
||||
@ -651,10 +660,10 @@ def setGroups(
|
||||
)
|
||||
# Retire les anciens membres:
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
for etudid in old_members_set:
|
||||
log("removing %s from group %s" % (etudid, group_id))
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
context,
|
||||
"DELETE FROM group_membership WHERE etudid=%(etudid)s and group_id=%(group_id)s",
|
||||
{"etudid": etudid, "group_id": group_id},
|
||||
@ -680,7 +689,7 @@ def setGroups(
|
||||
if not group_name:
|
||||
continue
|
||||
# ajax arguments are encoded in utf-8:
|
||||
group_name = unicode(group_name, "utf-8").encode(SCO_ENCODING)
|
||||
group_name = unicode(group_name, "utf-8").encode(scu.SCO_ENCODING)
|
||||
group_id = createGroup(context, partition_id, group_name, REQUEST=REQUEST)
|
||||
# Place dans ce groupe les etudiants indiqués:
|
||||
for etudid in fs[1:-1]:
|
||||
@ -688,7 +697,7 @@ def setGroups(
|
||||
context, etudid, group_id, partition, REQUEST=REQUEST
|
||||
)
|
||||
|
||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||
return (
|
||||
'<?xml version="1.0" encoding="utf-8"?><response>Groupes enregistrés</response>'
|
||||
)
|
||||
@ -790,9 +799,9 @@ def partition_create(
|
||||
def getArrowIconsTags(context, REQUEST):
|
||||
"""returns html tags for arrows"""
|
||||
#
|
||||
arrow_up = icontag("arrow_up", title="remonter")
|
||||
arrow_down = icontag("arrow_down", title="descendre")
|
||||
arrow_none = icontag("arrow_none", title="")
|
||||
arrow_up = scu.icontag("arrow_up", title="remonter")
|
||||
arrow_down = scu.icontag("arrow_down", title="descendre")
|
||||
arrow_none = scu.icontag("arrow_none", title="")
|
||||
|
||||
return arrow_up, arrow_down, arrow_none
|
||||
|
||||
@ -804,7 +813,7 @@ def editPartitionForm(context, formsemestre_id=None, REQUEST=None):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
partitions = get_partitions_list(context, formsemestre_id)
|
||||
arrow_up, arrow_down, arrow_none = getArrowIconsTags(context, REQUEST)
|
||||
suppricon = icontag(
|
||||
suppricon = scu.icontag(
|
||||
"delete_small_img", border="0", alt="supprimer", title="Supprimer"
|
||||
)
|
||||
#
|
||||
@ -1079,7 +1088,7 @@ def partition_set_name(context, partition_id, partition_name, REQUEST=None, redi
|
||||
formsemestre_id = partition["formsemestre_id"]
|
||||
|
||||
# check unicity
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT p.* FROM partition p WHERE p.partition_name = %(partition_name)s AND formsemestre_id = %(formsemestre_id)s",
|
||||
{"partition_name": partition_name, "formsemestre_id": formsemestre_id},
|
||||
@ -1177,6 +1186,8 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
|
||||
"""
|
||||
partition = get_partition(context, partition_id)
|
||||
formsemestre_id = partition["formsemestre_id"]
|
||||
# renvoie sur page édition groupes
|
||||
dest_url = "affectGroups?partition_id=%s" % partition_id
|
||||
if not can_change_groups(context, REQUEST, formsemestre_id):
|
||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
@ -1217,7 +1228,7 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + "\n" + tf[1] + context.sco_footer(REQUEST)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
else:
|
||||
# form submission
|
||||
log(
|
||||
@ -1245,34 +1256,33 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
|
||||
context.Notes, formsemestre_id
|
||||
) # > identdict
|
||||
identdict = nt.identdict
|
||||
# build: { sexe : liste etudids trie par niveau croissant }
|
||||
sexes = sets.Set([x["sexe"] for x in identdict.values()])
|
||||
# build: { civilite : liste etudids trie par niveau croissant }
|
||||
civilites = sets.Set([x["civilite"] for x in identdict.values()])
|
||||
listes = {}
|
||||
for sexe in sexes:
|
||||
listes[sexe] = [
|
||||
for civilite in civilites:
|
||||
listes[civilite] = [
|
||||
(get_prev_moy(context.Notes, x["etudid"], formsemestre_id), x["etudid"])
|
||||
for x in identdict.values()
|
||||
if x["sexe"] == sexe
|
||||
if x["civilite"] == civilite
|
||||
]
|
||||
listes[sexe].sort()
|
||||
log("listes[%s] = %s" % (sexe, listes[sexe]))
|
||||
listes[civilite].sort()
|
||||
log("listes[%s] = %s" % (civilite, listes[civilite]))
|
||||
# affect aux groupes:
|
||||
n = len(identdict)
|
||||
igroup = 0
|
||||
nbgroups = len(group_ids)
|
||||
while n > 0:
|
||||
for sexe in sexes:
|
||||
if len(listes[sexe]):
|
||||
for civilite in civilites:
|
||||
if len(listes[civilite]):
|
||||
n -= 1
|
||||
etudid = listes[sexe].pop()[1]
|
||||
etudid = listes[civilite].pop()[1]
|
||||
group_id = group_ids[igroup]
|
||||
igroup = (igroup + 1) % nbgroups
|
||||
change_etud_group_in_partition(
|
||||
context, etudid, group_id, partition, REQUEST=REQUEST
|
||||
)
|
||||
log("%s in group %s" % (etudid, group_id))
|
||||
# envoie sur page edition groupes
|
||||
return REQUEST.RESPONSE.redirect("affectGroups?partition_id=%s" % partition_id)
|
||||
return REQUEST.RESPONSE.redirect(dest_url)
|
||||
|
||||
|
||||
def get_prev_moy(context, etudid, formsemestre_id):
|
||||
@ -1374,7 +1384,7 @@ def do_evaluation_listeetuds_groups(
|
||||
req += " and Isem.etat='I'"
|
||||
req += r
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(req, {"evaluation_id": evaluation_id})
|
||||
# log('listeetuds_groups: getallstudents=%s groups=%s' % (getallstudents,groups))
|
||||
# log('req=%s' % (req % { 'evaluation_id' : "'"+evaluation_id+"'" }))
|
||||
@ -1393,7 +1403,7 @@ def do_evaluation_listegroupes(context, evaluation_id, include_default=False):
|
||||
else:
|
||||
c = " AND p.partition_name is not NULL"
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"SELECT DISTINCT gd.group_id FROM group_descr gd, group_membership gm, partition p, notes_moduleimpl m, notes_evaluation e WHERE gm.group_id = gd.group_id and gd.partition_id = p.partition_id and p.formsemestre_id = m.formsemestre_id and m.moduleimpl_id = e.moduleimpl_id and e.evaluation_id = %(evaluation_id)s"
|
||||
+ c,
|
||||
@ -1406,7 +1416,7 @@ def do_evaluation_listegroupes(context, evaluation_id, include_default=False):
|
||||
|
||||
def listgroups(context, group_ids):
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
groups = []
|
||||
for group_id in group_ids:
|
||||
cursor.execute(
|
||||
|
@ -30,11 +30,12 @@
|
||||
|
||||
import re
|
||||
|
||||
from sco_utils import *
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
import sco_formsemestre
|
||||
import sco_groups
|
||||
from sco_exceptions import AccessDenied
|
||||
|
||||
|
||||
def affectGroups(context, partition_id, REQUEST=None):
|
||||
|
@ -464,8 +464,9 @@ def groups_table(
|
||||
% (with_paiement, with_archives, with_annotations)
|
||||
)
|
||||
#
|
||||
columns_ids = ["nom_disp", "prenom"] # colonnes a inclure
|
||||
columns_ids = ["civilite_str", "nom_disp", "prenom"] # colonnes a inclure
|
||||
titles = {
|
||||
"civilite_str": "Civ.",
|
||||
"nom_disp": "Nom",
|
||||
"prenom": "Prénom",
|
||||
"email": "Mail",
|
||||
@ -733,7 +734,7 @@ def groups_table(
|
||||
"etudid",
|
||||
"code_nip",
|
||||
"etat",
|
||||
"sexe",
|
||||
"civilite_str",
|
||||
"nom",
|
||||
"nom_usuel",
|
||||
"prenom",
|
||||
|
@ -28,12 +28,18 @@
|
||||
"""Import d'utilisateurs via fichier Excel
|
||||
"""
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import email
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.header import Header
|
||||
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
import sco_news
|
||||
import sco_excel
|
||||
from sco_exceptions import AccessDenied, ScoValueError, ScoException
|
||||
|
||||
TITLES = ("user_name", "nom", "prenom", "email", "roles", "dept")
|
||||
|
||||
@ -66,11 +72,11 @@ def import_excel_file(datafile, REQUEST=None, context=None):
|
||||
exceldata = datafile.read()
|
||||
if not exceldata:
|
||||
raise ScoValueError("Ficher excel vide ou invalide")
|
||||
diag, data = sco_excel.Excel_to_list(exceldata)
|
||||
_, data = sco_excel.Excel_to_list(exceldata)
|
||||
if not data: # probably a bug
|
||||
raise ScoException("import_excel_file: empty file !")
|
||||
# 1- --- check title line
|
||||
fs = [strlower(stripquotes(s)) for s in data[0]]
|
||||
fs = [scu.strlower(scu.stripquotes(s)) for s in data[0]]
|
||||
log("excel: fs='%s'\ndata=%s" % (str(fs), str(data)))
|
||||
# check cols
|
||||
cols = {}.fromkeys(TITLES)
|
||||
@ -163,13 +169,6 @@ def generate_password():
|
||||
return "".join(RNG.sample(l, PASSLEN))
|
||||
|
||||
|
||||
import email
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.base import MIMEBase
|
||||
from email.header import Header
|
||||
|
||||
|
||||
def mail_password(u, context=None, reset=False):
|
||||
"Send password by email"
|
||||
if not u["email"]:
|
||||
@ -220,16 +219,16 @@ ScoDoc est un logiciel libre développé à l'Université Paris 13 par Emmanuel
|
||||
Pour plus d'informations sur ce logiciel, voir %s
|
||||
|
||||
"""
|
||||
% SCO_WEBSITE
|
||||
% scu.SCO_WEBSITE
|
||||
)
|
||||
msg = MIMEMultipart()
|
||||
if reset:
|
||||
msg["Subject"] = Header("Mot de passe ScoDoc", SCO_ENCODING)
|
||||
msg["Subject"] = Header("Mot de passe ScoDoc", scu.SCO_ENCODING)
|
||||
else:
|
||||
msg["Subject"] = Header("Votre accès ScoDoc", SCO_ENCODING)
|
||||
msg["Subject"] = Header("Votre accès ScoDoc", scu.SCO_ENCODING)
|
||||
msg["From"] = context.get_preference("email_from_addr")
|
||||
msg["To"] = u["email"]
|
||||
msg.epilogue = ""
|
||||
txt = MIMEText(txt, "plain", SCO_ENCODING)
|
||||
txt = MIMEText(txt, "plain", scu.SCO_ENCODING)
|
||||
msg.attach(txt)
|
||||
context.sendEmail(msg)
|
||||
|
@ -28,12 +28,12 @@
|
||||
"""Form. pour inscription rapide des etudiants d'un semestre dans un autre
|
||||
Utilise les autorisations d'inscription délivrées en jury.
|
||||
"""
|
||||
import datetime
|
||||
|
||||
from gen_tables import GenTable
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from gen_tables import GenTable
|
||||
import sco_codes_parcours
|
||||
import sco_pvjury
|
||||
import sco_formsemestre
|
||||
@ -41,6 +41,7 @@ import sco_formsemestre_inscriptions
|
||||
import sco_formsemestre
|
||||
import sco_groups
|
||||
import scolars
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
def list_authorized_etuds_by_sem(context, sem, delai=274):
|
||||
@ -60,7 +61,9 @@ def list_authorized_etuds_by_sem(context, sem, delai=274):
|
||||
auth_used = False # autorisation deja utilisée ?
|
||||
etud = context.getEtudInfo(etudid=e["etudid"], filled=True)[0]
|
||||
for isem in etud["sems"]:
|
||||
if DateDMYtoISO(isem["date_debut"]) >= DateDMYtoISO(src["date_fin"]):
|
||||
if ndb.DateDMYtoISO(isem["date_debut"]) >= ndb.DateDMYtoISO(
|
||||
src["date_fin"]
|
||||
):
|
||||
auth_used = True
|
||||
if not auth_used:
|
||||
candidats[e["etudid"]] = etud
|
||||
@ -134,8 +137,8 @@ def list_inscrits_date(context, sem):
|
||||
SAUF sem à la date de début de sem.
|
||||
"""
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
sem["date_debut_iso"] = DateDMYtoISO(sem["date_debut"])
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
sem["date_debut_iso"] = ndb.DateDMYtoISO(sem["date_debut"])
|
||||
cursor.execute(
|
||||
"""select I.etudid
|
||||
from notes_formsemestre_inscription I, notes_formsemestre S
|
||||
@ -223,14 +226,9 @@ def list_source_sems(context, sem, delai=None):
|
||||
othersems = []
|
||||
d, m, y = [int(x) for x in sem["date_debut"].split("/")]
|
||||
date_debut_dst = datetime.date(y, m, d)
|
||||
d, m, y = [int(x) for x in sem["date_fin"].split("/")]
|
||||
date_fin_dst = datetime.date(y, m, d)
|
||||
|
||||
delais = datetime.timedelta(delai)
|
||||
for s in sems:
|
||||
# pdb.set_trace()
|
||||
# if s['etat'] != '1':
|
||||
# continue # saute semestres pas ouverts
|
||||
if s["formsemestre_id"] == sem["formsemestre_id"]:
|
||||
continue # saute le semestre destination
|
||||
if s["date_fin"]:
|
||||
@ -276,9 +274,6 @@ def formsemestre_inscr_passage(
|
||||
|
||||
"""
|
||||
inscrit_groupes = int(inscrit_groupes)
|
||||
# log('formsemestre_inscr_passage: formsemestre_id=%s submitted=%s, dialog_confirmed=%s len(etuds)=%d'
|
||||
# % (formsemestre_id, submitted, dialog_confirmed, len(etuds)) )
|
||||
cnx = context.GetDBConnexion()
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
# -- check lock
|
||||
if sem["etat"] != "1":
|
||||
@ -558,7 +553,7 @@ def etuds_select_boxes(
|
||||
if base_url and etuds:
|
||||
H.append(
|
||||
'<a href="%s&export_cat_xls=%s">%s</a> '
|
||||
% (base_url, src_cat, ICON_XLS)
|
||||
% (base_url, src_cat, scu.ICON_XLS)
|
||||
)
|
||||
H.append("</div>")
|
||||
for etud in etuds:
|
||||
@ -616,7 +611,7 @@ def etuds_select_boxes(
|
||||
def etuds_select_box_xls(context, src_cat):
|
||||
"export a box to excel"
|
||||
etuds = src_cat["etuds"]
|
||||
columns_ids = ["etudid", "sexe", "nom", "prenom", "etape"]
|
||||
columns_ids = ["etudid", "civilite_str", "nom", "prenom", "etape"]
|
||||
titles = {x: x for x in columns_ids}
|
||||
|
||||
# Ajoute colonne paiement inscription
|
||||
|
@ -27,12 +27,13 @@
|
||||
|
||||
"""Liste des notes d'une évaluation
|
||||
"""
|
||||
import urllib
|
||||
from types import StringType
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
from notes_table import *
|
||||
import sco_formsemestre
|
||||
import sco_moduleimpl
|
||||
import sco_groups
|
||||
@ -41,6 +42,7 @@ import htmlutils
|
||||
import sco_excel
|
||||
from gen_tables import GenTable
|
||||
from htmlutils import histogram_notes
|
||||
import VERSION
|
||||
|
||||
|
||||
def do_evaluation_listenotes(context, REQUEST):
|
||||
@ -49,7 +51,6 @@ def do_evaluation_listenotes(context, REQUEST):
|
||||
|
||||
args: evaluation_id
|
||||
"""
|
||||
cnx = context.GetDBConnexion()
|
||||
mode = None
|
||||
if REQUEST.form.has_key("evaluation_id"):
|
||||
evaluation_id = REQUEST.form["evaluation_id"]
|
||||
@ -66,9 +67,6 @@ def do_evaluation_listenotes(context, REQUEST):
|
||||
|
||||
format = REQUEST.form.get("format", "html")
|
||||
E = evals[0] # il y a au moins une evaluation
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
formsemestre_id = M["formsemestre_id"]
|
||||
|
||||
# description de l'evaluation
|
||||
if mode == "eval":
|
||||
H = [
|
||||
@ -315,11 +313,11 @@ def _make_table_notes(
|
||||
"code": code,
|
||||
"_code_td_attrs": 'style="padding-left: 1em; padding-right: 2em;"',
|
||||
"etudid": etudid,
|
||||
"nom": strupper(etud["nom"]),
|
||||
"nom": scu.strupper(etud["nom"]),
|
||||
"_nomprenom_target": "formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s"
|
||||
% (M["formsemestre_id"], etudid),
|
||||
"_nomprenom_td_attrs": 'id="%s" class="etudinfo"' % (etud["etudid"]),
|
||||
"prenom": strcapitalize(strlower(etud["prenom"])),
|
||||
"prenom": scu.strcapitalize(scu.strlower(etud["prenom"])),
|
||||
"nomprenom": etud["nomprenom"],
|
||||
"group": grc,
|
||||
"email": etud["email"],
|
||||
@ -432,9 +430,9 @@ def _make_table_notes(
|
||||
if with_emails:
|
||||
gl = "&with_emails%3Alist=yes" + gl
|
||||
if len(evals) == 1:
|
||||
evalname = "%s-%s" % (Mod["code"], DateDMYtoISO(E["jour"]))
|
||||
evalname = "%s-%s" % (Mod["code"], ndb.DateDMYtoISO(E["jour"]))
|
||||
hh = "%s, %s (%d étudiants)" % (E["description"], gr_title, len(etudids))
|
||||
filename = make_filename("notes_%s_%s" % (evalname, gr_title_filename))
|
||||
filename = scu.make_filename("notes_%s_%s" % (evalname, gr_title_filename))
|
||||
caption = hh
|
||||
pdf_title = "%(description)s (%(jour)s)" % e
|
||||
html_title = ""
|
||||
@ -444,7 +442,7 @@ def _make_table_notes(
|
||||
% (nb_abs, nb_att)
|
||||
)
|
||||
else:
|
||||
filename = make_filename("notes_%s_%s" % (Mod["code"], gr_title_filename))
|
||||
filename = scu.make_filename("notes_%s_%s" % (Mod["code"], gr_title_filename))
|
||||
title = "Notes du module %(code)s %(titre)s" % Mod
|
||||
title += " semestre %(titremois)s" % sem
|
||||
if gr_title and gr_title != "tous":
|
||||
@ -467,7 +465,7 @@ def _make_table_notes(
|
||||
html_sortable=True,
|
||||
base_url=base_url,
|
||||
filename=filename,
|
||||
origin="Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + "",
|
||||
origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
|
||||
caption=caption,
|
||||
html_next_section=html_next_section,
|
||||
page_title="Notes de " + sem["titremois"],
|
||||
@ -549,10 +547,10 @@ def _add_eval_columns(
|
||||
val = NotesDB[etudid]["value"]
|
||||
if val is None:
|
||||
nb_abs += 1
|
||||
if val == NOTES_ATTENTE:
|
||||
if val == scu.NOTES_ATTENTE:
|
||||
nb_att += 1
|
||||
# calcul moyenne SANS LES ABSENTS
|
||||
if val != None and val != NOTES_NEUTRALISE and val != NOTES_ATTENTE:
|
||||
if val != None and val != scu.NOTES_NEUTRALISE and val != scu.NOTES_ATTENTE:
|
||||
if e["note_max"] > 0:
|
||||
valsur20 = val * 20.0 / e["note_max"] # remet sur 20
|
||||
else:
|
||||
@ -562,7 +560,7 @@ def _add_eval_columns(
|
||||
val = valsur20 # affichage notes / 20 demandé
|
||||
nb_notes = nb_notes + 1
|
||||
sum_notes += val
|
||||
val_fmt = fmt_note(val, keep_numeric=keep_numeric)
|
||||
val_fmt = scu.fmt_note(val, keep_numeric=keep_numeric)
|
||||
comment = NotesDB[etudid]["comment"]
|
||||
if comment is None:
|
||||
comment = ""
|
||||
@ -603,13 +601,13 @@ def _add_eval_columns(
|
||||
|
||||
coefs[evaluation_id] = "coef. %s" % e["coefficient"]
|
||||
if note_sur_20:
|
||||
nmx = 20.0
|
||||
nmax = 20.0
|
||||
else:
|
||||
nmx = e["note_max"]
|
||||
nmax = e["note_max"]
|
||||
if keep_numeric:
|
||||
note_max[evaluation_id] = nmx
|
||||
note_max[evaluation_id] = nmax
|
||||
else:
|
||||
note_max[evaluation_id] = "/ %s" % nmx
|
||||
note_max[evaluation_id] = "/ %s" % nmax
|
||||
|
||||
if nb_notes > 0:
|
||||
moys[evaluation_id] = "%.3g" % (sum_notes / nb_notes)
|
||||
@ -658,7 +656,7 @@ def _add_moymod_column(
|
||||
val = nt.get_etud_mod_moy(
|
||||
e["moduleimpl_id"], etudid
|
||||
) # note sur 20, ou 'NA','NI'
|
||||
row[col_id] = fmt_note(val, keep_numeric=keep_numeric)
|
||||
row[col_id] = scu.fmt_note(val, keep_numeric=keep_numeric)
|
||||
row["_" + col_id + "_td_attrs"] = ' class="moyenne" '
|
||||
if type(val) != StringType:
|
||||
notes.append(val)
|
||||
@ -712,8 +710,6 @@ def evaluation_check_absences(context, evaluation_id):
|
||||
if not E["jour"]:
|
||||
return [], [], [], [], [] # evaluation sans date
|
||||
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
formsemestre_id = M["formsemestre_id"]
|
||||
etudids = sco_groups.do_evaluation_listeetuds_groups(
|
||||
context, evaluation_id, getallstudents=True
|
||||
)
|
||||
@ -721,12 +717,12 @@ def evaluation_check_absences(context, evaluation_id):
|
||||
am, pm, demijournee = _eval_demijournee(E)
|
||||
|
||||
# Liste les absences à ce moment:
|
||||
A = context.Absences.ListeAbsJour(DateDMYtoISO(E["jour"]), am=am, pm=pm)
|
||||
A = context.Absences.ListeAbsJour(ndb.DateDMYtoISO(E["jour"]), am=am, pm=pm)
|
||||
As = set([x["etudid"] for x in A]) # ensemble des etudiants absents
|
||||
NJ = context.Absences.ListeAbsNonJustJour(DateDMYtoISO(E["jour"]), am=am, pm=pm)
|
||||
NJ = context.Absences.ListeAbsNonJustJour(ndb.DateDMYtoISO(E["jour"]), am=am, pm=pm)
|
||||
NJs = set([x["etudid"] for x in NJ]) # ensemble des etudiants absents non justifies
|
||||
Just = context.Absences.ListeAbsJour(
|
||||
DateDMYtoISO(E["jour"]), am=am, pm=pm, is_abs=None, is_just=True
|
||||
ndb.DateDMYtoISO(E["jour"]), am=am, pm=pm, is_abs=None, is_just=True
|
||||
)
|
||||
Justs = set([x["etudid"] for x in Just]) # ensemble des etudiants avec justif
|
||||
|
||||
@ -741,17 +737,17 @@ def evaluation_check_absences(context, evaluation_id):
|
||||
if NotesDB.has_key(etudid):
|
||||
val = NotesDB[etudid]["value"]
|
||||
if (
|
||||
val != None and val != NOTES_NEUTRALISE and val != NOTES_ATTENTE
|
||||
val != None and val != scu.NOTES_NEUTRALISE and val != scu.NOTES_ATTENTE
|
||||
) and etudid in As:
|
||||
# note valide et absent
|
||||
ValButAbs.append(etudid)
|
||||
if val is None and not etudid in As:
|
||||
# absent mais pas signale comme tel
|
||||
AbsNonSignalee.append(etudid)
|
||||
if val == NOTES_NEUTRALISE and not etudid in As:
|
||||
if val == scu.NOTES_NEUTRALISE and not etudid in As:
|
||||
# Neutralisé mais pas signale absent
|
||||
ExcNonSignalee.append(etudid)
|
||||
if val == NOTES_NEUTRALISE and etudid in NJs:
|
||||
if val == scu.NOTES_NEUTRALISE and etudid in NJs:
|
||||
# EXC mais pas justifié
|
||||
ExcNonJust.append(etudid)
|
||||
if val is None and etudid in Justs:
|
||||
|
13
sco_lycee.py
13
sco_lycee.py
@ -32,14 +32,14 @@
|
||||
|
||||
import tempfile, urllib, re
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import scolars
|
||||
import sco_groups
|
||||
import sco_report
|
||||
from gen_tables import GenTable
|
||||
import sco_formsemestre
|
||||
import VERSION
|
||||
|
||||
|
||||
def formsemestre_table_etuds_lycees(
|
||||
@ -100,7 +100,7 @@ def _table_etuds_lycees(
|
||||
context, etuds, group_lycees, title, preferences, no_links=False
|
||||
):
|
||||
etuds = [scolars.etud_add_lycee_infos(e) for e in etuds]
|
||||
etuds_by_lycee = group_by_key(etuds, "codelycee")
|
||||
etuds_by_lycee = scu.group_by_key(etuds, "codelycee")
|
||||
#
|
||||
if group_lycees:
|
||||
L = [etuds_by_lycee[codelycee][0] for codelycee in etuds_by_lycee]
|
||||
@ -128,7 +128,7 @@ def _table_etuds_lycees(
|
||||
else:
|
||||
L = etuds
|
||||
columns_ids = (
|
||||
"sexe",
|
||||
"civilite_str",
|
||||
"nom",
|
||||
"prenom",
|
||||
"codelycee",
|
||||
@ -148,7 +148,7 @@ def _table_etuds_lycees(
|
||||
rows=L,
|
||||
titles={
|
||||
"nbetuds": "Nb d'étudiants",
|
||||
"sexe": "",
|
||||
"civilite_str": "",
|
||||
"nom": "Nom",
|
||||
"prenom": "Prénom",
|
||||
"etudid": "etudid",
|
||||
@ -157,7 +157,7 @@ def _table_etuds_lycees(
|
||||
"nomlycee": "Lycée",
|
||||
"villelycee": "Commune",
|
||||
},
|
||||
origin="Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + "",
|
||||
origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
|
||||
caption=title,
|
||||
page_title="Carte lycées d'origine",
|
||||
html_sortable=True,
|
||||
@ -177,7 +177,6 @@ def formsemestre_etuds_lycees(
|
||||
REQUEST=None,
|
||||
):
|
||||
"""Table des lycées d'origine"""
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
tab, etuds_by_lycee = formsemestre_table_etuds_lycees(
|
||||
context, formsemestre_id, only_primo=only_primo, group_lycees=not no_grouping
|
||||
)
|
||||
|
@ -108,5 +108,5 @@ def do_modalite_edit(context, *args, **kw):
|
||||
"edit a modalite"
|
||||
cnx = context.GetDBConnexion()
|
||||
# check
|
||||
m = do_modalite_list(context, {"form_modalite_id": args[0]["form_modalite_id"]})[0]
|
||||
_ = do_modalite_list(context, {"form_modalite_id": args[0]["form_modalite_id"]})[0]
|
||||
_modaliteEditor.edit(cnx, *args, **kw)
|
||||
|
@ -29,15 +29,16 @@
|
||||
"""
|
||||
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from scolog import logdb
|
||||
from notes_table import *
|
||||
import sco_formsemestre
|
||||
import sco_moduleimpl
|
||||
import sco_groups
|
||||
import htmlutils
|
||||
from sco_permissions import ScoEtudInscrit
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
def moduleimpl_inscriptions_edit(
|
||||
@ -182,7 +183,7 @@ def moduleimpl_inscriptions_edit(
|
||||
sco_moduleimpl.do_moduleimpl_inscrit_etuds(
|
||||
context, moduleimpl_id, formsemestre_id, etuds, reset=True, REQUEST=REQUEST
|
||||
)
|
||||
REQUEST.RESPONSE.redirect(
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
"moduleimpl_status?moduleimpl_id=%s" % (moduleimpl_id)
|
||||
)
|
||||
#
|
||||
@ -453,7 +454,7 @@ def get_etuds_with_capitalized_ue(context, formsemestre_id):
|
||||
"""For each UE, computes list of students capitalizing the UE.
|
||||
returns { ue_id : [ { infos } ] }
|
||||
"""
|
||||
UECaps = DictDefault(defaultvalue=[])
|
||||
UECaps = scu.DictDefault(defaultvalue=[])
|
||||
nt = context._getNotesCache().get_NotesTable(
|
||||
context, formsemestre_id
|
||||
) # > get_ues, get_etud_ue_status
|
||||
@ -481,7 +482,7 @@ def is_inscrit_ue(context, etudid, formsemestre_id, ue_id):
|
||||
"""Modules de cette UE dans ce semestre
|
||||
auxquels l'étudiant est inscrit.
|
||||
"""
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT mod.*
|
||||
FROM notes_moduleimpl mi, notes_modules mod,
|
||||
@ -502,7 +503,7 @@ def is_inscrit_ue(context, etudid, formsemestre_id, ue_id):
|
||||
def do_etud_desinscrit_ue(context, etudid, formsemestre_id, ue_id, REQUEST=None):
|
||||
"""Desincrit l'etudiant de tous les modules de cette UE dans ce semestre."""
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"""DELETE FROM notes_moduleimpl_inscription
|
||||
WHERE moduleimpl_inscription_id IN (
|
||||
@ -543,7 +544,7 @@ def do_etud_inscrit_ue(context, etudid, formsemestre_id, ue_id, REQUEST=None):
|
||||
raise ScoValueError("%s n'est pas inscrit au semestre !" % etudid)
|
||||
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"""SELECT mi.moduleimpl_id
|
||||
FROM notes_moduleimpl mi, notes_modules mod, notes_formsemestre sem
|
||||
|
12
sco_news.py
12
sco_news.py
@ -37,20 +37,20 @@ from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.header import Header
|
||||
|
||||
from notesdb import * # pylint: disable=unused-wildcard-import
|
||||
import notesdb as ndb # pylint: disable=unused-wildcard-import
|
||||
from notes_log import log
|
||||
import scolars
|
||||
from sco_utils import SCO_ENCODING, SCO_ANNONCES_WEBSITE
|
||||
import sco_formsemestre
|
||||
import sco_moduleimpl
|
||||
|
||||
_scolar_news_editor = EditableTable(
|
||||
_scolar_news_editor = ndb.EditableTable(
|
||||
"scolar_news",
|
||||
"news_id",
|
||||
("date", "authenticated_user", "type", "object", "text", "url"),
|
||||
sortkey="date desc",
|
||||
output_formators={"date": DateISOtoDMY},
|
||||
input_formators={"date": DateDMYtoISO},
|
||||
output_formators={"date": ndb.DateISOtoDMY},
|
||||
input_formators={"date": ndb.DateDMYtoISO},
|
||||
html_quote=False, # no user supplied data, needed to store html links
|
||||
)
|
||||
|
||||
@ -110,7 +110,7 @@ def scolar_news_summary(context, n=5):
|
||||
"""
|
||||
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute("select * from scolar_news order by date desc limit 100")
|
||||
selected_news = {} # (type,object) : news dict
|
||||
news = cursor.dictfetchall() # la plus récente d'abord
|
||||
@ -118,7 +118,7 @@ def scolar_news_summary(context, n=5):
|
||||
for r in reversed(news): # la plus ancienne d'abord
|
||||
# si on a deja une news avec meme (type,object)
|
||||
# et du meme jour, on la remplace
|
||||
dmy = DateISOtoDMY(r["date"]) # round
|
||||
dmy = ndb.DateISOtoDMY(r["date"]) # round
|
||||
key = (r["type"], r["object"], dmy)
|
||||
selected_news[key] = r
|
||||
|
||||
|
@ -31,8 +31,9 @@
|
||||
|
||||
"""
|
||||
|
||||
from sco_utils import *
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
import scolars
|
||||
import sco_bac
|
||||
import sco_photos
|
||||
@ -43,9 +44,17 @@ import sco_formsemestre_status
|
||||
import htmlutils
|
||||
from sco_bulletins import etud_descr_situation_semestre
|
||||
import sco_parcours_dut
|
||||
import sco_codes_parcours
|
||||
from sco_formsemestre_validation import formsemestre_recap_parcours_table
|
||||
import sco_archives_etud
|
||||
import sco_report
|
||||
from sco_permissions import (
|
||||
ScoEtudChangeGroups,
|
||||
ScoEtudInscrit,
|
||||
ScoImplement,
|
||||
ScoEtudChangeAdr,
|
||||
)
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
def _menuScolarite(context, authuser, sem, etudid):
|
||||
@ -54,7 +63,7 @@ def _menuScolarite(context, authuser, sem, etudid):
|
||||
"""
|
||||
locked = sem["etat"] != "1"
|
||||
if locked:
|
||||
lockicon = icontag("lock32_img", title="verrouillé", border="0")
|
||||
lockicon = scu.icontag("lock32_img", title="verrouillé", border="0")
|
||||
return lockicon # no menu
|
||||
if not authuser.has_permission(
|
||||
ScoEtudInscrit, context
|
||||
@ -76,12 +85,12 @@ def _menuScolarite(context, authuser, sem, etudid):
|
||||
)
|
||||
|
||||
# Note: seul un etudiant inscrit (I) peut devenir défaillant.
|
||||
if ins["etat"] != DEF:
|
||||
if ins["etat"] != sco_codes_parcours.DEF:
|
||||
def_title = "Déclarer défaillance"
|
||||
def_url = (
|
||||
"formDef?etudid=%(etudid)s&formsemestre_id=%(formsemestre_id)s" % args
|
||||
)
|
||||
elif ins["etat"] == DEF:
|
||||
elif ins["etat"] == sco_codes_parcours.DEF:
|
||||
def_title = "Annuler la défaillance"
|
||||
def_url = (
|
||||
"doCancelDef?etudid=%(etudid)s&formsemestre_id=%(formsemestre_id)s"
|
||||
@ -212,7 +221,7 @@ def ficheEtud(context, etudid=None, REQUEST=None):
|
||||
sem_info = {}
|
||||
for sem in info["sems"]:
|
||||
if sem["ins"]["etat"] != "I":
|
||||
descr, junk = etud_descr_situation_semestre(
|
||||
descr, _ = etud_descr_situation_semestre(
|
||||
context.Notes,
|
||||
etudid,
|
||||
sem["formsemestre_id"],
|
||||
@ -280,7 +289,7 @@ def ficheEtud(context, etudid=None, REQUEST=None):
|
||||
] = '<td class="annodel"><a href="doSuppressAnnotation?etudid=%s&annotation_id=%s">%s</a></td>' % (
|
||||
etudid,
|
||||
a["id"],
|
||||
icontag(
|
||||
scu.icontag(
|
||||
"delete_img",
|
||||
border="0",
|
||||
alt="suppress",
|
||||
@ -379,7 +388,7 @@ def ficheEtud(context, etudid=None, REQUEST=None):
|
||||
else:
|
||||
info["tit_anno"] = ""
|
||||
# Inscriptions
|
||||
if info["sems"]:
|
||||
if info["sems"]: # XXX rcl unused ? à voir
|
||||
rcl = (
|
||||
"""(<a href="%(ScoURL)s/Notes/formsemestre_validation_etud_form?check=1&etudid=%(etudid)s&formsemestre_id=%(last_formsemestre_id)s&desturl=ficheEtud?etudid=%(etudid)s">récapitulatif parcours</a>)"""
|
||||
% info
|
||||
|
@ -27,12 +27,39 @@
|
||||
|
||||
"""Semestres: gestion parcours DUT (Arreté du 13 août 2005)
|
||||
"""
|
||||
from notesdb import *
|
||||
from types import FloatType
|
||||
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
from scolog import logdb
|
||||
import sco_formsemestre
|
||||
from sco_codes_parcours import *
|
||||
|
||||
from sco_codes_parcours import (
|
||||
CMP,
|
||||
ADC,
|
||||
ADJ,
|
||||
ADM,
|
||||
AJ,
|
||||
ATT,
|
||||
NO_SEMESTRE_ID,
|
||||
BUG,
|
||||
NEXT,
|
||||
NEXT2,
|
||||
NEXT_OR_NEXT2,
|
||||
REO,
|
||||
REDOANNEE,
|
||||
REDOSEM,
|
||||
RA_OR_NEXT,
|
||||
RA_OR_RS,
|
||||
RS_OR_NEXT,
|
||||
CODES_SEM_VALIDES,
|
||||
NOTES_BARRE_GEN_COMPENSATION,
|
||||
code_semestre_attente,
|
||||
code_semestre_validant,
|
||||
)
|
||||
from dutrules import DUTRules # regles generees a partir du CSV
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
class DecisionSem:
|
||||
@ -165,7 +192,7 @@ class SituationEtudParcoursGeneric:
|
||||
if rule.conclusion[5] == BUG:
|
||||
log("get_possible_choices: inconsistency: state=%s" % str(state))
|
||||
#
|
||||
valid_semestre = code_semestre_validant(rule.conclusion[0])
|
||||
# valid_semestre = code_semestre_validant(rule.conclusion[0])
|
||||
choices.append(
|
||||
DecisionSem(
|
||||
code_etat=rule.conclusion[0],
|
||||
@ -390,7 +417,7 @@ class SituationEtudParcoursGeneric:
|
||||
)
|
||||
self.moy_gen = self.nt.get_etud_moy_gen(self.etudid)
|
||||
self.barre_moy_ok = (type(self.moy_gen) == FloatType) and (
|
||||
self.moy_gen >= (self.parcours.BARRE_MOY - NOTES_TOLERANCE)
|
||||
self.moy_gen >= (self.parcours.BARRE_MOY - scu.NOTES_TOLERANCE)
|
||||
)
|
||||
# conserve etat UEs
|
||||
ue_ids = [
|
||||
@ -607,7 +634,7 @@ class SituationEtudParcoursGeneric:
|
||||
) # > modif decisions jury (sem, UE)
|
||||
|
||||
# -- supprime autorisations venant de ce formsemestre
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
try:
|
||||
cursor.execute(
|
||||
"""delete from scolar_autorisation_inscription
|
||||
@ -742,7 +769,7 @@ def int_or_null(s):
|
||||
return int(s)
|
||||
|
||||
|
||||
_scolar_formsemestre_validation_editor = EditableTable(
|
||||
_scolar_formsemestre_validation_editor = ndb.EditableTable(
|
||||
"scolar_formsemestre_validation",
|
||||
"formsemestre_validation_id",
|
||||
(
|
||||
@ -758,8 +785,8 @@ _scolar_formsemestre_validation_editor = EditableTable(
|
||||
"semestre_id",
|
||||
"is_external",
|
||||
),
|
||||
output_formators={"event_date": DateISOtoDMY, "assidu": str},
|
||||
input_formators={"event_date": DateDMYtoISO, "assidu": int_or_null},
|
||||
output_formators={"event_date": ndb.DateISOtoDMY, "assidu": str},
|
||||
input_formators={"event_date": ndb.DateDMYtoISO, "assidu": int_or_null},
|
||||
)
|
||||
|
||||
scolar_formsemestre_validation_create = _scolar_formsemestre_validation_editor.create
|
||||
@ -779,7 +806,7 @@ def formsemestre_validate_sem(
|
||||
"Ajoute ou change validation semestre"
|
||||
args = {"formsemestre_id": formsemestre_id, "etudid": etudid}
|
||||
# delete existing
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
try:
|
||||
cursor.execute(
|
||||
"""delete from scolar_formsemestre_validation
|
||||
@ -827,7 +854,7 @@ def formsemestre_update_validation_sem(
|
||||
"assidu": int(assidu),
|
||||
}
|
||||
log("formsemestre_update_validation_sem: %s" % args)
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
to_invalidate = []
|
||||
|
||||
# enleve compensations si necessaire
|
||||
@ -945,7 +972,7 @@ def do_formsemestre_validate_ue(
|
||||
args["event_date"] = date
|
||||
|
||||
# delete existing
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
try:
|
||||
cond = "etudid = %(etudid)s and ue_id=%(ue_id)s"
|
||||
if formsemestre_id:
|
||||
@ -983,7 +1010,7 @@ def formsemestre_has_decisions(context, formsemestre_id):
|
||||
|
||||
def etud_est_inscrit_ue(cnx, etudid, formsemestre_id, ue_id):
|
||||
"""Vrai si l'étudiant est inscrit a au moins un module de cette UE dans ce semestre"""
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"""select mi.* from notes_moduleimpl mi, notes_modules mo, notes_ue ue, notes_moduleimpl_inscription i
|
||||
where i.etudid = %(etudid)s and i.moduleimpl_id=mi.moduleimpl_id
|
||||
@ -997,12 +1024,12 @@ def etud_est_inscrit_ue(cnx, etudid, formsemestre_id, ue_id):
|
||||
return len(cursor.fetchall())
|
||||
|
||||
|
||||
_scolar_autorisation_inscription_editor = EditableTable(
|
||||
_scolar_autorisation_inscription_editor = ndb.EditableTable(
|
||||
"scolar_autorisation_inscription",
|
||||
"autorisation_inscription_id",
|
||||
("etudid", "formation_code", "semestre_id", "date", "origin_formsemestre_id"),
|
||||
output_formators={"date": DateISOtoDMY},
|
||||
input_formators={"date": DateDMYtoISO},
|
||||
output_formators={"date": ndb.DateISOtoDMY},
|
||||
input_formators={"date": ndb.DateDMYtoISO},
|
||||
)
|
||||
scolar_autorisation_inscription_list = _scolar_autorisation_inscription_editor.list
|
||||
|
||||
@ -1033,7 +1060,7 @@ def formsemestre_get_etud_capitalisation(context, sem, etudid):
|
||||
} ]
|
||||
"""
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"""select distinct SFV.*, ue.ue_code from notes_ue ue, notes_formations nf, notes_formations nf2,
|
||||
scolar_formsemestre_validation SFV, notes_formsemestre sem
|
||||
@ -1058,7 +1085,7 @@ def formsemestre_get_etud_capitalisation(context, sem, etudid):
|
||||
"etudid": etudid,
|
||||
"formation_id": sem["formation_id"],
|
||||
"semestre_id": sem["semestre_id"],
|
||||
"date_debut": DateDMYtoISO(sem["date_debut"]),
|
||||
"date_debut": ndb.DateDMYtoISO(sem["date_debut"]),
|
||||
},
|
||||
)
|
||||
|
||||
@ -1072,7 +1099,7 @@ def list_formsemestre_utilisateurs_uecap(context, formsemestre_id):
|
||||
cnx = context.GetDBConnexion()
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
F = context.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"""select sem.formsemestre_id
|
||||
from notes_formsemestre sem, notes_formations F
|
||||
@ -1086,7 +1113,7 @@ def list_formsemestre_utilisateurs_uecap(context, formsemestre_id):
|
||||
"formation_code": F["formation_code"],
|
||||
"semestre_id": sem["semestre_id"],
|
||||
"formsemestre_id": formsemestre_id,
|
||||
"date_debut": DateDMYtoISO(sem["date_debut"]),
|
||||
"date_debut": ndb.DateDMYtoISO(sem["date_debut"]),
|
||||
},
|
||||
)
|
||||
return [x[0] for x in cursor.fetchall()]
|
||||
|
@ -30,9 +30,11 @@
|
||||
Contribution M. Salomon, UFC / IUT DE BELFORT-MONTBÉLIARD, 2016
|
||||
|
||||
"""
|
||||
import urllib
|
||||
import random
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
import scolars
|
||||
import sco_formsemestre
|
||||
@ -42,8 +44,9 @@ import sco_evaluations
|
||||
import sco_saisie_notes
|
||||
import sco_excel
|
||||
from sco_excel import *
|
||||
from TrivialFormulator import TrivialFormulator
|
||||
from gen_tables import GenTable
|
||||
import random
|
||||
import VERSION
|
||||
|
||||
|
||||
def do_placement_selectetuds(context, REQUEST):
|
||||
@ -124,7 +127,10 @@ def do_placement_selectetuds(context, REQUEST):
|
||||
(
|
||||
"group_ids",
|
||||
{
|
||||
"default": [g["group_id"] for g in groups],
|
||||
"default": [
|
||||
g["group_id"] # pylint: disable=invalid-sequence-index
|
||||
for g in groups
|
||||
],
|
||||
"input_type": "hidden",
|
||||
"type": "list",
|
||||
},
|
||||
@ -211,7 +217,9 @@ def do_placement_selectetuds(context, REQUEST):
|
||||
)
|
||||
+ "&".join(gs)
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1 + "/do_placement?" + query)
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
context.NotesURL() + "/do_placement?" + query
|
||||
)
|
||||
else:
|
||||
raise ValueError(
|
||||
"invalid placement_method (%s)" % tf[2]["placement_method"]
|
||||
@ -260,7 +268,6 @@ def do_placement(context, REQUEST):
|
||||
|
||||
if None in [g["group_name"] for g in groups]: # tous les etudiants
|
||||
getallstudents = True
|
||||
gr_title = "tous"
|
||||
gr_title_filename = "tous"
|
||||
else:
|
||||
getallstudents = False
|
||||
@ -273,7 +280,7 @@ def do_placement(context, REQUEST):
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
Mod = context.do_module_list(args={"module_id": M["module_id"]})[0]
|
||||
sem = sco_formsemestre.get_formsemestre(context, M["formsemestre_id"])
|
||||
evalname = "%s-%s" % (Mod["code"], DateDMYtoISO(E["jour"]))
|
||||
evalname = "%s-%s" % (Mod["code"], ndb.DateDMYtoISO(E["jour"]))
|
||||
if E["description"]:
|
||||
evaltitre = E["description"]
|
||||
else:
|
||||
@ -297,8 +304,8 @@ def do_placement(context, REQUEST):
|
||||
{"etudid": etudid, "formsemestre_id": M["formsemestre_id"]}
|
||||
)[0]
|
||||
if inscr["etat"] != "D":
|
||||
nom = strupper(ident["nom"])
|
||||
prenom = strcapitalize(strlower(ident["prenom"]))
|
||||
nom = scu.strupper(ident["nom"])
|
||||
prenom = scu.strcapitalize(scu.strlower(ident["prenom"]))
|
||||
listetud.append((nom, prenom))
|
||||
random.shuffle(listetud)
|
||||
|
||||
@ -374,7 +381,9 @@ def do_placement(context, REQUEST):
|
||||
columns_ids=columns_ids,
|
||||
rows=rows,
|
||||
filename=filename,
|
||||
origin="Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + "",
|
||||
origin="Généré par %s le " % VERSION.SCONAME
|
||||
+ scu.timedate_human_repr()
|
||||
+ "",
|
||||
pdf_title=pdf_title,
|
||||
# pdf_shorttitle = '',
|
||||
preferences=context.get_preferences(M["formsemestre_id"]),
|
||||
@ -444,7 +453,7 @@ def Excel_feuille_placement(
|
||||
wb = Workbook()
|
||||
|
||||
SheetName0 = "Emargement"
|
||||
ws0 = wb.add_sheet(SheetName0.decode(SCO_ENCODING))
|
||||
ws0 = wb.add_sheet(SheetName0.decode(scu.SCO_ENCODING))
|
||||
# ajuste largeurs colonnes (unite inconnue, empirique)
|
||||
width = 4500
|
||||
if nbcolumns > 5:
|
||||
@ -455,7 +464,7 @@ def Excel_feuille_placement(
|
||||
ws0.col(0).width = 750
|
||||
|
||||
SheetName1 = "Positions"
|
||||
ws1 = wb.add_sheet(SheetName1.decode(SCO_ENCODING))
|
||||
ws1 = wb.add_sheet(SheetName1.decode(scu.SCO_ENCODING))
|
||||
if numbering == "coordinate":
|
||||
ws1.col(0).width = 4000
|
||||
ws1.col(1).width = 4500
|
||||
@ -654,8 +663,8 @@ def Excel_feuille_placement(
|
||||
else:
|
||||
li += 1
|
||||
line += 1
|
||||
ws0.write(li, 0, desceval[0].decode(SCO_ENCODING), style_titres)
|
||||
ws1.write(li, 0, desceval[0].decode(SCO_ENCODING), style_titres)
|
||||
ws0.write(li, 0, desceval[0].decode(scu.SCO_ENCODING), style_titres)
|
||||
ws1.write(li, 0, desceval[0].decode(scu.SCO_ENCODING), style_titres)
|
||||
li += 1
|
||||
ws0.write(
|
||||
li,
|
||||
@ -727,8 +736,8 @@ def Excel_feuille_placement(
|
||||
ws0.write(li0, 0, line, style2b)
|
||||
col = 1
|
||||
for etudid in linetud:
|
||||
ws0.write(li0, col, (etudid[0]).decode(SCO_ENCODING), style1t)
|
||||
ws0.write(li0 + 1, col, (etudid[1]).decode(SCO_ENCODING), style1m)
|
||||
ws0.write(li0, col, (etudid[0]).decode(scu.SCO_ENCODING), style1t)
|
||||
ws0.write(li0 + 1, col, (etudid[1]).decode(scu.SCO_ENCODING), style1m)
|
||||
ws0.row(li0 + 2).height = space
|
||||
if numbering == "coordinate":
|
||||
ws0.write(li0 + 2, col, " ", style1bb)
|
||||
@ -757,8 +766,8 @@ def Excel_feuille_placement(
|
||||
for etudid in orderetud:
|
||||
li1 += 1
|
||||
line += 1
|
||||
ws1.write(li1, col, (etudid[0]).decode(SCO_ENCODING), style2l)
|
||||
ws1.write(li1, col + 1, (etudid[1]).decode(SCO_ENCODING), style2m1)
|
||||
ws1.write(li1, col, (etudid[0]).decode(scu.SCO_ENCODING), style2l)
|
||||
ws1.write(li1, col + 1, (etudid[1]).decode(scu.SCO_ENCODING), style2m1)
|
||||
if numbering == "coordinate":
|
||||
ws1.write(li1, col + 2, etudid[2], style2m2)
|
||||
ws1.write(li1, col + 3, etudid[3], style2r)
|
||||
|
@ -35,11 +35,13 @@ import xml.sax.saxutils
|
||||
import xml.dom.minidom
|
||||
import datetime
|
||||
|
||||
import sco_utils
|
||||
from sco_utils import ScoEtudInscrit, log, ScoValueError, DictDefault
|
||||
from sco_utils import SCO_TMP_DIR, SCO_ENCODING
|
||||
import sco_utils as scu
|
||||
from sco_utils import SCO_ENCODING
|
||||
from sco_permissions import ScoEtudInscrit
|
||||
from sco_exceptions import ScoValueError
|
||||
from notes_log import log
|
||||
|
||||
SCO_CACHE_ETAPE_FILENAME = os.path.join(SCO_TMP_DIR, "last_etapes.xml")
|
||||
SCO_CACHE_ETAPE_FILENAME = os.path.join(scu.SCO_TMP_DIR, "last_etapes.xml")
|
||||
|
||||
|
||||
def has_portal(context):
|
||||
@ -162,7 +164,7 @@ def get_inscrits_etape(context, code_etape, anneeapogee=None, ntrials=2):
|
||||
if portal_timeout > 0:
|
||||
actual_timeout = max(1, actual_timeout)
|
||||
for _ntrial in range(ntrials):
|
||||
doc = sco_utils.query_portal(req, timeout=actual_timeout)
|
||||
doc = scu.query_portal(req, timeout=actual_timeout)
|
||||
if doc:
|
||||
break
|
||||
if not doc:
|
||||
@ -203,7 +205,7 @@ def query_apogee_portal(context, **args):
|
||||
return []
|
||||
portal_timeout = context.get_preference("portal_timeout")
|
||||
req = etud_url + "?" + urllib.urlencode(args.items())
|
||||
doc = sco_utils.query_portal(req, timeout=portal_timeout) # sco_utils
|
||||
doc = scu.query_portal(req, timeout=portal_timeout) # sco_utils
|
||||
return xml_to_list_of_dicts(doc, req=req)
|
||||
|
||||
|
||||
@ -259,7 +261,7 @@ def get_infos_apogee_allaccents(context, nom, prenom):
|
||||
"essai recup infos avec differents codages des accents"
|
||||
if nom:
|
||||
unom = unicode(nom, SCO_ENCODING)
|
||||
nom_noaccents = str(sco_utils.suppression_diacritics(unom))
|
||||
nom_noaccents = str(scu.suppression_diacritics(unom))
|
||||
nom_utf8 = unom.encode("utf-8")
|
||||
else:
|
||||
nom_noaccents = nom
|
||||
@ -267,7 +269,7 @@ def get_infos_apogee_allaccents(context, nom, prenom):
|
||||
|
||||
if prenom:
|
||||
uprenom = unicode(prenom, SCO_ENCODING)
|
||||
prenom_noaccents = str(sco_utils.suppression_diacritics(uprenom))
|
||||
prenom_noaccents = str(scu.suppression_diacritics(uprenom))
|
||||
prenom_utf8 = uprenom.encode("utf-8")
|
||||
else:
|
||||
prenom_noaccents = prenom
|
||||
@ -323,7 +325,7 @@ def get_etud_apogee(context, code_nip):
|
||||
return {}
|
||||
portal_timeout = context.get_preference("portal_timeout")
|
||||
req = etud_url + "?" + urllib.urlencode((("nip", code_nip),))
|
||||
doc = sco_utils.query_portal(req, timeout=portal_timeout)
|
||||
doc = scu.query_portal(req, timeout=portal_timeout)
|
||||
d = _normalize_apo_fields(xml_to_list_of_dicts(doc, req=req))
|
||||
if not d:
|
||||
return None
|
||||
@ -387,7 +389,7 @@ def get_etapes_apogee(context):
|
||||
"get_etapes_apogee: requesting '%s' with timeout=%s"
|
||||
% (etapes_url, portal_timeout)
|
||||
)
|
||||
doc = sco_utils.query_portal(etapes_url, timeout=portal_timeout)
|
||||
doc = scu.query_portal(etapes_url, timeout=portal_timeout)
|
||||
try:
|
||||
infos = _parse_etapes_from_xml(context, doc)
|
||||
# cache le resultat (utile si le portail repond de façon intermitente)
|
||||
@ -482,7 +484,7 @@ def _normalize_apo_fields(infolist):
|
||||
for infos in infolist:
|
||||
if infos.has_key("paiementinscription"):
|
||||
infos["paiementinscription"] = (
|
||||
sco_utils.strlower(infos["paiementinscription"]) == "true"
|
||||
scu.strlower(infos["paiementinscription"]) == "true"
|
||||
)
|
||||
if infos["paiementinscription"]:
|
||||
infos["paiementinscription_str"] = "ok"
|
||||
@ -562,5 +564,5 @@ def get_maquette_apogee(context, etape="", annee_scolaire=""):
|
||||
+ "?"
|
||||
+ urllib.urlencode((("etape", etape), ("annee", annee_scolaire)))
|
||||
)
|
||||
doc = sco_utils.query_portal(req, timeout=portal_timeout)
|
||||
doc = scu.query_portal(req, timeout=portal_timeout)
|
||||
return doc
|
||||
|
@ -29,21 +29,22 @@
|
||||
|
||||
Recapitule tous les semestres validés dans une feuille excel.
|
||||
"""
|
||||
import collections
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from gen_tables import GenTable
|
||||
import sco_formsemestre
|
||||
import sco_groups
|
||||
import sco_abs
|
||||
from sco_codes_parcours import code_semestre_validant, code_semestre_attente
|
||||
import VERSION
|
||||
|
||||
|
||||
def etud_get_poursuite_info(context, sem, etud):
|
||||
"""{ 'nom' : ..., 'semlist' : [ { 'semestre_id': , 'moy' : ... }, {}, ...] }"""
|
||||
I = {}
|
||||
I.update(etud) # copie nom, prenom, sexe, ...
|
||||
I.update(etud) # copie nom, prenom, civilite, ...
|
||||
|
||||
# Now add each semester, starting from the first one
|
||||
semlist = []
|
||||
@ -62,7 +63,7 @@ def etud_get_poursuite_info(context, sem, etud):
|
||||
moy_ues = [
|
||||
(
|
||||
ue["acronyme"],
|
||||
fmt_note(nt.get_etud_ue_status(etudid, ue["ue_id"])["moy"]),
|
||||
scu.fmt_note(nt.get_etud_ue_status(etudid, ue["ue_id"])["moy"]),
|
||||
)
|
||||
for ue in ues
|
||||
]
|
||||
@ -79,7 +80,7 @@ def etud_get_poursuite_info(context, sem, etud):
|
||||
for modimpl in modimpls: # dans chaque UE les modules
|
||||
if modimpl["module"]["ue_id"] == ue["ue_id"]:
|
||||
codeModule = modimpl["module"]["code"]
|
||||
noteModule = fmt_note(
|
||||
noteModule = scu.fmt_note(
|
||||
nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid)
|
||||
)
|
||||
if noteModule != "NI": # si étudiant inscrit au module
|
||||
@ -103,8 +104,8 @@ def etud_get_poursuite_info(context, sem, etud):
|
||||
and nt.get_etud_etat(etudid) == "I"
|
||||
):
|
||||
d = [
|
||||
("moy", fmt_note(nt.get_etud_moy_gen(etudid))),
|
||||
("moy_promo", fmt_note(nt.moy_moy)),
|
||||
("moy", scu.fmt_note(nt.get_etud_moy_gen(etudid))),
|
||||
("moy_promo", scu.fmt_note(nt.moy_moy)),
|
||||
("rang", nt.get_etud_rang(etudid)),
|
||||
("effectif", len(nt.T)),
|
||||
("date_debut", s["date_debut"]),
|
||||
@ -154,7 +155,6 @@ def formsemestre_poursuite_report(
|
||||
):
|
||||
"""Table avec informations "poursuite" """
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
nt = context._getNotesCache().get_NotesTable(context, formsemestre_id)
|
||||
etuds = context.getEtudInfoGroupes(
|
||||
[sco_groups.get_default_group(context, formsemestre_id)]
|
||||
)
|
||||
@ -174,7 +174,7 @@ def formsemestre_poursuite_report(
|
||||
infos.append(info)
|
||||
#
|
||||
column_ids = (
|
||||
("sexe", "nom", "prenom", "annee", "date_naissance")
|
||||
("civilite_str", "nom", "prenom", "annee", "date_naissance")
|
||||
+ tuple(ids)
|
||||
+ ("debouche",)
|
||||
)
|
||||
@ -191,9 +191,9 @@ def formsemestre_poursuite_report(
|
||||
pdf_link=False, # pas d'export pdf
|
||||
preferences=context.get_preferences(formsemestre_id),
|
||||
)
|
||||
tab.filename = make_filename("poursuite " + sem["titreannee"])
|
||||
tab.filename = scu.make_filename("poursuite " + sem["titreannee"])
|
||||
|
||||
tab.origin = "Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + ""
|
||||
tab.origin = "Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + ""
|
||||
tab.caption = "Récapitulatif %s." % sem["titreannee"]
|
||||
tab.html_caption = "Récapitulatif %s." % sem["titreannee"]
|
||||
tab.base_url = "%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id)
|
||||
|
@ -28,11 +28,13 @@
|
||||
"""ScoDoc preferences (replaces old Zope properties)
|
||||
"""
|
||||
|
||||
from sco_utils import *
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
import sco_formsemestre
|
||||
import sco_bulletins_generator
|
||||
from sco_exceptions import ScoValueError, ScoException
|
||||
|
||||
"""Global/Semestre Preferences for ScoDoc (version dec 2008)
|
||||
|
||||
@ -1722,7 +1724,7 @@ PREFS_DICT = dict(PREFS)
|
||||
|
||||
|
||||
class sco_base_preferences:
|
||||
_editor = EditableTable(
|
||||
_editor = ndb.EditableTable(
|
||||
"sco_prefs",
|
||||
"pref_id",
|
||||
("pref_id", "name", "value", "formsemestre_id"),
|
||||
@ -1741,7 +1743,7 @@ class sco_base_preferences:
|
||||
"""Load all preferences from db"""
|
||||
log("loading preferences")
|
||||
try:
|
||||
GSL.acquire()
|
||||
scu.GSL.acquire()
|
||||
cnx = self.context.GetDBConnexion()
|
||||
preflist = self._editor.list(cnx)
|
||||
self.prefs = {None: {}} # { formsemestre_id (or None) : { name : value } }
|
||||
@ -1788,9 +1790,9 @@ class sco_base_preferences:
|
||||
% (name, value)
|
||||
)
|
||||
except:
|
||||
# search in CONFIG
|
||||
if hasattr(CONFIG, name):
|
||||
value = getattr(CONFIG, name)
|
||||
# search in scu.CONFIG
|
||||
if hasattr(scu.CONFIG, name):
|
||||
value = getattr(scu.CONFIG, name)
|
||||
log(
|
||||
"sco_preferences: found default value in config for %s=%s"
|
||||
% (name, value)
|
||||
@ -1805,7 +1807,7 @@ class sco_base_preferences:
|
||||
# add to db table
|
||||
self._editor.create(cnx, {"name": name, "value": value})
|
||||
finally:
|
||||
GSL.release()
|
||||
scu.GSL.release()
|
||||
|
||||
def get(self, formsemestre_id, name):
|
||||
"""Returns preference value.
|
||||
@ -1837,7 +1839,7 @@ class sco_base_preferences:
|
||||
def save(self, formsemestre_id=None, name=None):
|
||||
"""Write one or all (if name is None) values to db"""
|
||||
try:
|
||||
GSL.acquire()
|
||||
scu.GSL.acquire()
|
||||
modif = False
|
||||
cnx = self.context.GetDBConnexion()
|
||||
if name is None:
|
||||
@ -1884,7 +1886,7 @@ class sco_base_preferences:
|
||||
if modif:
|
||||
self.context.Notes._inval_cache(pdfonly=False) # > modif preferences
|
||||
finally:
|
||||
GSL.release()
|
||||
scu.GSL.release()
|
||||
|
||||
def set(self, formsemestre_id, name, value):
|
||||
if not name or name[0] == "_" or name not in PREFS_NAMES:
|
||||
@ -1900,7 +1902,7 @@ class sco_base_preferences:
|
||||
if not formsemestre_id:
|
||||
raise ScoException()
|
||||
try:
|
||||
GSL.acquire()
|
||||
scu.GSL.acquire()
|
||||
if formsemestre_id in self.prefs and name in self.prefs[formsemestre_id]:
|
||||
del self.prefs[formsemestre_id][name]
|
||||
cnx = self.context.GetDBConnexion()
|
||||
@ -1912,7 +1914,7 @@ class sco_base_preferences:
|
||||
self._editor.delete(cnx, pdb[0]["pref_id"])
|
||||
self.context.Notes._inval_cache(pdfonly=False) # > modif preferences
|
||||
finally:
|
||||
GSL.release()
|
||||
scu.GSL.release()
|
||||
|
||||
def edit(self, REQUEST):
|
||||
"""HTML dialog: edit global preferences"""
|
||||
@ -1934,13 +1936,13 @@ class sco_base_preferences:
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + self.context.sco_footer(REQUEST)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1) # cancel
|
||||
return REQUEST.RESPONSE.redirect(self.context.ScoURL()) # cancel
|
||||
else:
|
||||
for pref in PREFS:
|
||||
self.prefs[None][pref[0]] = tf[2][pref[0]]
|
||||
self.save()
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
REQUEST.URL1 + "?head_message=Préférences modifiées"
|
||||
self.context.ScoURL() + "?head_message=Préférences modifiées"
|
||||
)
|
||||
|
||||
|
||||
@ -1982,7 +1984,6 @@ class sem_preferences:
|
||||
# The dialog
|
||||
def edit(self, categories=[], REQUEST=None):
|
||||
"""Dialog to edit semestre preferences in given categories"""
|
||||
# log('XXX edit')
|
||||
if not self.formsemestre_id:
|
||||
raise ScoValueError(
|
||||
"sem_preferences.edit doit etre appele sur un semestre !"
|
||||
@ -2029,7 +2030,6 @@ function set_global_pref(el, pref_name) {
|
||||
form.append(("create_local", {"input_type": "hidden"}))
|
||||
form.append(("destination", {"input_type": "hidden"}))
|
||||
form.append(("formsemestre_id", {"input_type": "hidden"}))
|
||||
# log('REQUEST form=%s'%REQUEST.form)
|
||||
tf = TrivialFormulator(
|
||||
REQUEST.URL0,
|
||||
REQUEST.form,
|
||||
@ -2038,17 +2038,19 @@ function set_global_pref(el, pref_name) {
|
||||
cssclass="sco_pref",
|
||||
submitlabel="Enregistrer les modifications",
|
||||
)
|
||||
dest_url = (
|
||||
self.context.NotesURL()
|
||||
+ "formsemestre_status?formsemestre_id=%s" % self.formsemestre_id
|
||||
)
|
||||
if tf[0] == 0:
|
||||
return "\n".join(H) + tf[1] + self.context.sco_footer(REQUEST)
|
||||
elif tf[0] == -1:
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
REQUEST.URL1 + "?head_message=Annulé"
|
||||
dest_url + "&head_message=Annulé"
|
||||
) # cancel
|
||||
else:
|
||||
# log('tf[2]=%s' % tf[2]) # XXX
|
||||
# Supprime pref locale du semestre (retour à la valeur globale)
|
||||
if tf[2]["suppress"]:
|
||||
# log('suppress %s' % tf[2]['suppress']) # XXX
|
||||
self.base_prefs.delete(self.formsemestre_id, tf[2]["suppress"])
|
||||
# Cree pref local (copie valeur globale)
|
||||
if tf[2]["create_local"]:
|
||||
@ -2080,9 +2082,7 @@ function set_global_pref(el, pref_name) {
|
||||
destination = tf[2]["destination"]
|
||||
if destination == "done" or destination == "":
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
REQUEST.URL1
|
||||
+ "/formsemestre_status?head_message=Préférences modifiées&formsemestre_id="
|
||||
+ self.formsemestre_id
|
||||
dest_url + "&head_message=Préférences modifiées"
|
||||
)
|
||||
elif destination == "again":
|
||||
return REQUEST.RESPONSE.redirect(
|
||||
|
@ -27,9 +27,9 @@
|
||||
|
||||
"""Feuille excel pour preparation des jurys
|
||||
"""
|
||||
import time
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import notes_table
|
||||
import sco_groups
|
||||
@ -37,8 +37,9 @@ import sco_excel
|
||||
import sco_formsemestre
|
||||
import sco_parcours_dut
|
||||
import sco_codes_parcours
|
||||
from scolars import format_nom, format_prenom, format_sexe, format_lycee
|
||||
from scolars import format_nom, format_prenom, format_civilite, format_lycee
|
||||
from sco_abs import getAbsSemEtud
|
||||
import VERSION
|
||||
|
||||
|
||||
def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
||||
@ -54,10 +55,10 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
||||
context, formsemestre_id
|
||||
)["partition_id"]
|
||||
|
||||
prev_moy_ue = DictDefault(defaultvalue={}) # ue_code_s : { etudid : moy ue }
|
||||
prev_moy_ue = scu.DictDefault(defaultvalue={}) # ue_code_s : { etudid : moy ue }
|
||||
prev_ue_acro = {} # ue_code_s : acronyme (à afficher)
|
||||
prev_moy = {} # moyennes gen sem prec
|
||||
moy_ue = DictDefault(defaultvalue={}) # ue_acro : moyennes { etudid : moy ue }
|
||||
moy_ue = scu.DictDefault(defaultvalue={}) # ue_acro : moyennes { etudid : moy ue }
|
||||
ue_acro = {} # ue_code_s : acronyme (à afficher)
|
||||
moy = {} # moyennes gen
|
||||
moy_inter = {} # moyenne gen. sur les 2 derniers semestres
|
||||
@ -136,11 +137,17 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
||||
# Codes des UE "semestre précédent":
|
||||
ue_prev_codes = prev_moy_ue.keys()
|
||||
ue_prev_codes.sort(
|
||||
lambda x, y, prev_ue_acro=prev_ue_acro: cmp(prev_ue_acro[x], prev_ue_acro[y])
|
||||
lambda x, y, prev_ue_acro=prev_ue_acro: cmp( # pylint: disable=undefined-variable
|
||||
prev_ue_acro[x], prev_ue_acro[y]
|
||||
)
|
||||
)
|
||||
# Codes des UE "semestre courant":
|
||||
ue_codes = moy_ue.keys()
|
||||
ue_codes.sort(lambda x, y, ue_acro=ue_acro: cmp(ue_acro[x], ue_acro[y]))
|
||||
ue_codes.sort(
|
||||
lambda x, y, ue_acro=ue_acro: cmp( # pylint: disable=undefined-variable
|
||||
ue_acro[x], ue_acro[y]
|
||||
)
|
||||
)
|
||||
|
||||
sid = sem["semestre_id"]
|
||||
sn = sp = ""
|
||||
@ -150,7 +157,7 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
||||
sp = "S%s" % (sid - 1)
|
||||
|
||||
L = sco_excel.ScoExcelSheet(sheet_name="Prepa Jury %s" % sn)
|
||||
L.append(["Feuille préparation Jury %s" % unescape_html(sem["titreannee"])])
|
||||
L.append(["Feuille préparation Jury %s" % scu.unescape_html(sem["titreannee"])])
|
||||
L.append([]) # empty line
|
||||
|
||||
titles = ["Rang"]
|
||||
@ -206,7 +213,7 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
||||
|
||||
def fmt(x):
|
||||
"reduit les notes a deux chiffres"
|
||||
x = notes_table.fmt_note(x, keep_numeric=False)
|
||||
x = scu.fmt_note(x, keep_numeric=False)
|
||||
try:
|
||||
return float(x)
|
||||
except:
|
||||
@ -222,7 +229,7 @@ def feuille_preparation_jury(context, formsemestre_id, REQUEST):
|
||||
l.append(etud["code_ine"])
|
||||
l += [
|
||||
etudid,
|
||||
format_sexe(etud["sexe"]),
|
||||
etud["civilite_str"],
|
||||
format_nom(etud["nom"]),
|
||||
format_prenom(etud["prenom"]),
|
||||
etud["date_naissance"],
|
||||
|
@ -27,7 +27,13 @@
|
||||
|
||||
"""Edition des PV de jury
|
||||
"""
|
||||
import time
|
||||
from reportlab.platypus import Paragraph
|
||||
from reportlab.lib import styles
|
||||
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
import scolars
|
||||
import sco_formsemestre
|
||||
import sco_groups
|
||||
@ -36,11 +42,11 @@ import sco_parcours_dut
|
||||
import sco_codes_parcours
|
||||
from sco_codes_parcours import NO_SEMESTRE_ID
|
||||
import sco_excel
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
from TrivialFormulator import TrivialFormulator
|
||||
from gen_tables import GenTable
|
||||
import sco_pvpdf
|
||||
from sco_pdf import *
|
||||
import sco_pdf
|
||||
from sco_pdf import PDFLOCK
|
||||
|
||||
"""PV Jury IUTV 2006: on détaillait 8 cas:
|
||||
Jury de semestre n
|
||||
@ -71,9 +77,9 @@ def _descr_decisions_ues(context, nt, etudid, decisions_ue, decision_sem):
|
||||
for ue_id in decisions_ue.keys():
|
||||
try:
|
||||
if decisions_ue[ue_id] and (
|
||||
decisions_ue[ue_id]["code"] == ADM
|
||||
decisions_ue[ue_id]["code"] == sco_codes_parcours.ADM
|
||||
or (
|
||||
CONFIG.CAPITALIZE_ALL_UES
|
||||
scu.CONFIG.CAPITALIZE_ALL_UES
|
||||
and sco_codes_parcours.code_semestre_validant(decision_sem["code"])
|
||||
)
|
||||
):
|
||||
@ -135,7 +141,7 @@ def _comp_ects_by_ue_code_and_type(nt, decision_ues):
|
||||
return {}, {}
|
||||
|
||||
ects_by_ue_code = {}
|
||||
ects_by_ue_type = DictDefault(defaultvalue=0) # { ue_type : ects validés }
|
||||
ects_by_ue_type = scu.DictDefault(defaultvalue=0) # { ue_type : ects validés }
|
||||
for ue_id in decision_ues:
|
||||
d = decision_ues[ue_id]
|
||||
ue = nt.uedict[ue_id]
|
||||
@ -245,7 +251,7 @@ def dict_pvjury(
|
||||
if d["decision_sem"] and sco_codes_parcours.code_semestre_validant(
|
||||
d["decision_sem"]["code"]
|
||||
):
|
||||
d["mention"] = get_mention(nt.get_etud_moy_gen(etudid))
|
||||
d["mention"] = scu.get_mention(nt.get_etud_moy_gen(etudid))
|
||||
else:
|
||||
d["mention"] = ""
|
||||
# Versions "en français": (avec les UE capitalisées d'ailleurs)
|
||||
@ -310,13 +316,13 @@ def dict_pvjury(
|
||||
|
||||
# Cherche la date de decision (sem ou UE) la plus récente:
|
||||
if d["decision_sem"]:
|
||||
date = DateDMYtoISO(d["decision_sem"]["event_date"])
|
||||
date = ndb.DateDMYtoISO(d["decision_sem"]["event_date"])
|
||||
if date > max_date: # decision plus recente
|
||||
max_date = date
|
||||
if d["decisions_ue"]:
|
||||
for dec_ue in d["decisions_ue"].values():
|
||||
if dec_ue:
|
||||
date = DateDMYtoISO(dec_ue["event_date"])
|
||||
date = ndb.DateDMYtoISO(dec_ue["event_date"])
|
||||
if date > max_date: # decision plus recente
|
||||
max_date = date
|
||||
# Code semestre precedent
|
||||
@ -343,7 +349,7 @@ def dict_pvjury(
|
||||
D[etudid] = d
|
||||
|
||||
return {
|
||||
"date": DateISOtoDMY(max_date),
|
||||
"date": ndb.DateISOtoDMY(max_date),
|
||||
"formsemestre": sem,
|
||||
"has_prev": has_prev,
|
||||
"semestre_non_terminal": semestre_non_terminal,
|
||||
@ -412,9 +418,11 @@ def pvjury_table(
|
||||
if context.get_preference("bul_show_ects", formsemestre_id):
|
||||
columns_ids += ["ects"]
|
||||
|
||||
# if dpv['semestre_non_terminal']:
|
||||
# dec 2017: indique toujours le devenir ("diplôme obtenu" ou semestre suivant)
|
||||
columns_ids += ["validation_parcours_code", "devenir"]
|
||||
# XXX if not dpv["semestre_non_terminal"]:
|
||||
# La colonne doit être présente: redoublants validant leur diplome
|
||||
# en répétant un semestre ancien: exemple: S1 (ADM), S2 (ADM), S3 (AJ), S4 (ADM), S3 (ADM)=> diplôme
|
||||
columns_ids += ["validation_parcours_code"]
|
||||
columns_ids += ["devenir"]
|
||||
columns_ids += ["observations"]
|
||||
|
||||
lines = []
|
||||
@ -432,9 +440,9 @@ def pvjury_table(
|
||||
context, e["etat"], e["decision_sem"]
|
||||
),
|
||||
"ue_cap": e["decisions_ue_descr"],
|
||||
"validation_parcours_code": "ADM" if e["validation_parcours"] else "AJ",
|
||||
"validation_parcours_code": "ADM" if e["validation_parcours"] else "",
|
||||
"devenir": e["autorisations_descr"],
|
||||
"observations": unquote(e["observation"]),
|
||||
"observations": ndb.unquote(e["observation"]),
|
||||
"mention": e["mention"],
|
||||
"ects": str(e["sum_ects"]),
|
||||
}
|
||||
@ -449,10 +457,10 @@ def pvjury_table(
|
||||
) # vertical space
|
||||
i = e["identite"]
|
||||
l["nomprenom"] = [
|
||||
Paragraph(SU(i["nomprenom"]), cell_style),
|
||||
Paragraph(SU(i["code_nip"]), cell_style),
|
||||
Paragraph(sco_pdf.SU(i["nomprenom"]), cell_style),
|
||||
Paragraph(sco_pdf.SU(i["code_nip"]), cell_style),
|
||||
Paragraph(
|
||||
SU(
|
||||
sco_pdf.SU(
|
||||
"Né le %s" % i["date_naissance"]
|
||||
+ (" à %s" % i["lieu_naissance"] if i["lieu_naissance"] else "")
|
||||
+ (" (%s)" % i["dept_naissance"] if i["dept_naissance"] else "")
|
||||
@ -513,8 +521,10 @@ def formsemestre_pvjury(
|
||||
rows=rows,
|
||||
titles=titles,
|
||||
columns_ids=columns_ids,
|
||||
filename=make_filename("decisions " + sem["titreannee"]),
|
||||
origin="Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + "",
|
||||
filename=scu.make_filename("decisions " + sem["titreannee"]),
|
||||
origin="Généré par %s le " % scu.VERSION.SCONAME
|
||||
+ scu.timedate_human_repr()
|
||||
+ "",
|
||||
caption="Décisions jury pour " + sem["titreannee"],
|
||||
html_class="table_leftalign",
|
||||
html_sortable=True,
|
||||
@ -552,7 +562,7 @@ def formsemestre_pvjury(
|
||||
H.append(tab.html())
|
||||
|
||||
# Count number of cases for each decision
|
||||
counts = DictDefault()
|
||||
counts = scu.DictDefault()
|
||||
for row in rows:
|
||||
counts[row["decision"]] += 1
|
||||
# add codes for previous (for explanation, without count)
|
||||
@ -673,10 +683,6 @@ def formsemestre_pvjury_pdf(
|
||||
tf[2]["showTitle"] = True
|
||||
else:
|
||||
tf[2]["showTitle"] = False
|
||||
if tf[2]["with_paragraph_nom"]:
|
||||
tf[2]["with_paragraph_nom"] = True
|
||||
else:
|
||||
tf[2]["with_paragraph_nom"] = False
|
||||
if tf[2]["anonymous"]:
|
||||
tf[2]["anonymous"] = True
|
||||
else:
|
||||
@ -705,7 +711,7 @@ def formsemestre_pvjury_pdf(
|
||||
else:
|
||||
groups_filename = ""
|
||||
filename = "PV-%s%s-%s.pdf" % (sem["titre_num"], groups_filename, dt)
|
||||
return sendPDFFile(REQUEST, pdfdoc, filename)
|
||||
return scu.sendPDFFile(REQUEST, pdfdoc, filename)
|
||||
|
||||
|
||||
def descrform_pvjury(context, sem):
|
||||
@ -771,12 +777,10 @@ def descrform_pvjury(context, sem):
|
||||
(
|
||||
"with_paragraph_nom",
|
||||
{
|
||||
"input_type": "checkbox",
|
||||
"input_type": "boolcheckbox",
|
||||
"title": "Avec date naissance et code",
|
||||
"explanation": "ajoute informations sous le nom",
|
||||
"default": "1",
|
||||
"labels": [""],
|
||||
"allowed_values": ("1",),
|
||||
"default": True,
|
||||
},
|
||||
),
|
||||
(
|
||||
@ -848,7 +852,6 @@ def formsemestre_lettres_individuelles(
|
||||
else:
|
||||
# submit
|
||||
sf = tf[2]["signature"]
|
||||
# pdb.set_trace()
|
||||
signature = sf.read() # image of signature
|
||||
try:
|
||||
PDFLOCK.acquire()
|
||||
@ -872,7 +875,7 @@ def formsemestre_lettres_individuelles(
|
||||
dt = time.strftime("%Y-%m-%d")
|
||||
groups_filename = "-" + groups_infos.groups_filename
|
||||
filename = "lettres-%s%s-%s.pdf" % (sem["titre_num"], groups_filename, dt)
|
||||
return sendPDFFile(REQUEST, pdfdoc, filename)
|
||||
return scu.sendPDFFile(REQUEST, pdfdoc, filename)
|
||||
|
||||
|
||||
def descrform_lettres_individuelles():
|
||||
|
75
sco_pvpdf.py
75
sco_pvpdf.py
@ -27,26 +27,39 @@
|
||||
|
||||
"""Edition des PV de jury
|
||||
"""
|
||||
import os
|
||||
import types
|
||||
import re
|
||||
import cStringIO
|
||||
import reportlab
|
||||
from reportlab.lib.units import cm, mm
|
||||
from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
|
||||
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Frame, PageBreak
|
||||
from reportlab.platypus import Table, TableStyle, Image, KeepInFrame
|
||||
from reportlab.platypus.flowables import Flowable
|
||||
from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate
|
||||
from reportlab.lib.pagesizes import A4, landscape
|
||||
from reportlab.lib import styles
|
||||
from reportlab.lib.colors import Color
|
||||
|
||||
import sco_utils as scu
|
||||
import sco_pdf
|
||||
from sco_pdf import SU
|
||||
import sco_formsemestre
|
||||
from sco_pdf import *
|
||||
import sco_pvjury
|
||||
import sco_codes_parcours
|
||||
from sco_utils import *
|
||||
from sco_pdf import PDFLOCK
|
||||
import sco_preferences
|
||||
import sco_bulletins_pdf
|
||||
import VERSION
|
||||
|
||||
import os
|
||||
import types
|
||||
LOGO_FOOTER_ASPECT = scu.CONFIG.LOGO_FOOTER_ASPECT # XXX A AUTOMATISER
|
||||
LOGO_FOOTER_HEIGHT = scu.CONFIG.LOGO_FOOTER_HEIGHT * mm
|
||||
LOGO_FOOTER_WIDTH = LOGO_FOOTER_HEIGHT * scu.CONFIG.LOGO_FOOTER_ASPECT
|
||||
|
||||
LOGO_FOOTER_ASPECT = CONFIG.LOGO_FOOTER_ASPECT # XXX A AUTOMATISER
|
||||
LOGO_FOOTER_HEIGHT = CONFIG.LOGO_FOOTER_HEIGHT * mm
|
||||
LOGO_FOOTER_WIDTH = LOGO_FOOTER_HEIGHT * CONFIG.LOGO_FOOTER_ASPECT
|
||||
|
||||
LOGO_HEADER_ASPECT = CONFIG.LOGO_HEADER_ASPECT # XXX logo IUTV (A AUTOMATISER)
|
||||
LOGO_HEADER_HEIGHT = CONFIG.LOGO_HEADER_HEIGHT * mm
|
||||
LOGO_HEADER_WIDTH = LOGO_HEADER_HEIGHT * CONFIG.LOGO_HEADER_ASPECT
|
||||
LOGO_HEADER_ASPECT = scu.CONFIG.LOGO_HEADER_ASPECT # XXX logo IUTV (A AUTOMATISER)
|
||||
LOGO_HEADER_HEIGHT = scu.CONFIG.LOGO_HEADER_HEIGHT * mm
|
||||
LOGO_HEADER_WIDTH = LOGO_HEADER_HEIGHT * scu.CONFIG.LOGO_HEADER_ASPECT
|
||||
|
||||
|
||||
def pageFooter(canvas, doc, logo, preferences, with_page_numbers=True):
|
||||
@ -76,7 +89,7 @@ def pageFooter(canvas, doc, logo, preferences, with_page_numbers=True):
|
||||
RightFootStyle.fontSize = preferences["SCOLAR_FONT_SIZE_FOOT"]
|
||||
RightFootStyle.alignment = TA_RIGHT
|
||||
|
||||
p = makeParas(
|
||||
p = sco_pdf.makeParas(
|
||||
"""<para>%s</para><para>%s</para>"""
|
||||
% (preferences["INSTITUTION_NAME"], preferences["INSTITUTION_ADDRESS"]),
|
||||
LeftFootStyle,
|
||||
@ -186,12 +199,12 @@ class CourrierIndividuelTemplate(PageTemplate):
|
||||
self.background_image_filename = None
|
||||
self.logo_footer = None
|
||||
self.logo_header = None
|
||||
# Search logos in dept specific dir, then in global config dir
|
||||
# Search logos in dept specific dir, then in global scu.CONFIG dir
|
||||
for image_dir in (
|
||||
SCODOC_LOGOS_DIR + "/logos_" + context.DeptId() + "/",
|
||||
SCODOC_LOGOS_DIR + "/", # global logos
|
||||
scu.SCODOC_LOGOS_DIR + "/logos_" + context.DeptId() + "/",
|
||||
scu.SCODOC_LOGOS_DIR + "/", # global logos
|
||||
):
|
||||
for suffix in LOGOS_IMAGES_ALLOWED_TYPES:
|
||||
for suffix in scu.LOGOS_IMAGES_ALLOWED_TYPES:
|
||||
if template_name == "PVJuryTemplate":
|
||||
fn = image_dir + "/pvjury_background" + "." + suffix
|
||||
else:
|
||||
@ -354,7 +367,7 @@ def pdf_lettres_individuelles(
|
||||
if e["decision_sem"]: # decision prise
|
||||
etud = context.getEtudInfo(e["identite"]["etudid"], filled=True)[0]
|
||||
params["nomEtud"] = etud["nomprenom"]
|
||||
bookmarks[npages + 1] = suppress_accents(etud["nomprenom"])
|
||||
bookmarks[npages + 1] = scu.suppress_accents(etud["nomprenom"])
|
||||
objects += pdf_lettre_individuelle(
|
||||
dpv["formsemestre"], e, etud, params, signature, context=context
|
||||
)
|
||||
@ -377,7 +390,7 @@ def pdf_lettres_individuelles(
|
||||
CourrierIndividuelTemplate(
|
||||
document,
|
||||
context=context,
|
||||
author="%s %s (E. Viennet)" % (SCONAME, SCOVERSION),
|
||||
author="%s %s (E. Viennet)" % (VERSION.SCONAME, VERSION.SCOVERSION),
|
||||
title="Lettres décision %s" % sem["titreannee"],
|
||||
subject="Décision jury",
|
||||
margins=margins,
|
||||
@ -514,7 +527,7 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None, context
|
||||
% params
|
||||
)
|
||||
sig = _simulate_br(sig, '<para leftindent="%(htab1)s">')
|
||||
objects += makeParas(
|
||||
objects += sco_pdf.makeParas(
|
||||
(
|
||||
"""<para leftindent="%(htab1)s" spaceBefore="25mm">"""
|
||||
+ sig
|
||||
@ -529,7 +542,7 @@ def pdf_lettre_individuelle(sem, decision, etud, params, signature=None, context
|
||||
% params
|
||||
)
|
||||
sig = _simulate_br(sig, '<para leftindent="%(htab1)s">')
|
||||
objects += makeParas(
|
||||
objects += sco_pdf.makeParas(
|
||||
(
|
||||
"""<para leftindent="%(htab1)s" spaceBefore="25mm">"""
|
||||
+ sig
|
||||
@ -650,7 +663,7 @@ def pvjury_pdf(
|
||||
PVTemplate(
|
||||
document,
|
||||
context=context,
|
||||
author="%s %s (E. Viennet)" % (SCONAME, SCOVERSION),
|
||||
author="%s %s (E. Viennet)" % (VERSION.SCONAME, VERSION.SCOVERSION),
|
||||
title=SU("PV du jury de %s" % sem["titre_num"]),
|
||||
subject="PV jury",
|
||||
preferences=context.get_preferences(formsemestre_id),
|
||||
@ -683,7 +696,7 @@ def _pvjury_pdf_type(
|
||||
|
||||
sem = dpv["formsemestre"]
|
||||
formsemestre_id = sem["formsemestre_id"]
|
||||
titre_jury, titre_court_jury = _descr_jury(sem, diplome)
|
||||
titre_jury, _ = _descr_jury(sem, diplome)
|
||||
titre_diplome = pv_title or dpv["formation"]["titre_officiel"]
|
||||
objects = []
|
||||
|
||||
@ -708,7 +721,7 @@ def _pvjury_pdf_type(
|
||||
bulletStyle.spaceAfter = 5 * mm
|
||||
|
||||
objects += [Spacer(0, 5 * mm)]
|
||||
objects += makeParas(
|
||||
objects += sco_pdf.makeParas(
|
||||
"""
|
||||
<para align="center"><b>Procès-verbal de %s du département %s - Session unique %s</b></para>
|
||||
"""
|
||||
@ -720,7 +733,7 @@ def _pvjury_pdf_type(
|
||||
style,
|
||||
)
|
||||
|
||||
objects += makeParas(
|
||||
objects += sco_pdf.makeParas(
|
||||
"""
|
||||
<para align="center"><b><i>%s</i></b></para>
|
||||
"""
|
||||
@ -729,20 +742,20 @@ def _pvjury_pdf_type(
|
||||
)
|
||||
|
||||
if showTitle:
|
||||
objects += makeParas(
|
||||
objects += sco_pdf.makeParas(
|
||||
"""<para align="center"><b>Semestre: %s</b></para>""" % sem["titre"], style
|
||||
)
|
||||
if context.get_preference("PV_TITLE_WITH_VDI", formsemestre_id):
|
||||
objects += makeParas(
|
||||
objects += sco_pdf.makeParas(
|
||||
"""<para align="center">VDI et Code: %s</para>""" % (VDICode or ""), style
|
||||
)
|
||||
|
||||
if date_jury:
|
||||
objects += makeParas(
|
||||
objects += sco_pdf.makeParas(
|
||||
"""<para align="center">Jury tenu le %s</para>""" % date_jury, style
|
||||
)
|
||||
|
||||
objects += makeParas(
|
||||
objects += sco_pdf.makeParas(
|
||||
"<para>"
|
||||
+ context.get_preference("PV_INTRO", formsemestre_id)
|
||||
% {
|
||||
@ -757,7 +770,7 @@ def _pvjury_pdf_type(
|
||||
bulletStyle,
|
||||
)
|
||||
|
||||
objects += makeParas(
|
||||
objects += sco_pdf.makeParas(
|
||||
"""<para>Le jury propose les décisions suivantes :</para>""", style
|
||||
)
|
||||
objects += [Spacer(0, 4 * mm)]
|
||||
@ -809,7 +822,7 @@ def _pvjury_pdf_type(
|
||||
objects.append(Table(Pt, repeatRows=1, colWidths=widths, style=table_style))
|
||||
|
||||
# Signature du directeur
|
||||
objects += makeParas(
|
||||
objects += sco_pdf.makeParas(
|
||||
"""<para spaceBefore="10mm" align="right">
|
||||
Le %s, %s</para>"""
|
||||
% (
|
||||
@ -822,7 +835,7 @@ def _pvjury_pdf_type(
|
||||
# Légende des codes
|
||||
codes = sco_codes_parcours.CODES_EXPL.keys()
|
||||
codes.sort()
|
||||
objects += makeParas(
|
||||
objects += sco_pdf.makeParas(
|
||||
"""<para spaceBefore="15mm" fontSize="14">
|
||||
<b>Codes utilisés :</b></para>""",
|
||||
style,
|
||||
|
@ -27,8 +27,13 @@
|
||||
|
||||
"""Tableau recapitulatif des notes d'un semestre
|
||||
"""
|
||||
import time
|
||||
import datetime
|
||||
import jaxml
|
||||
|
||||
from notes_table import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import scolars
|
||||
import sco_bulletins, sco_excel
|
||||
import sco_groups
|
||||
import sco_evaluations
|
||||
@ -37,6 +42,7 @@ import sco_formsemestre_status
|
||||
import sco_bulletins_xml
|
||||
import sco_bulletins_json
|
||||
import sco_codes_parcours
|
||||
from sco_codes_parcours import DEF, UE_SPORT
|
||||
import sco_bac
|
||||
|
||||
|
||||
@ -133,7 +139,7 @@ def formsemestre_recapcomplet(
|
||||
H.append("checked")
|
||||
H.append(""" >cacher bac</input>""")
|
||||
if tabformat == "xml":
|
||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||
H.append(
|
||||
do_formsemestre_recapcomplet(
|
||||
context,
|
||||
@ -201,11 +207,11 @@ def do_formsemestre_recapcomplet(
|
||||
if format == "xml" or format == "html":
|
||||
return data
|
||||
elif format == "csv":
|
||||
return sendCSVFile(REQUEST, data, filename)
|
||||
return scu.sendCSVFile(REQUEST, data, filename)
|
||||
elif format[:3] == "xls":
|
||||
return sco_excel.sendExcelFile(REQUEST, data, filename)
|
||||
elif format == "json":
|
||||
return sendJSON(REQUEST, data)
|
||||
return scu.sendJSON(REQUEST, data)
|
||||
else:
|
||||
raise ValueError("unknown format %s" % format)
|
||||
|
||||
@ -229,6 +235,7 @@ def make_formsemestre_recapcomplet(
|
||||
pour tous les étudiants, les moyennes par UE et générale,
|
||||
trié par moyenne générale décroissante.
|
||||
"""
|
||||
civ_nom_prenom = False # 3 colonnes différentes ou une seule avec prénom abrégé ?
|
||||
if format == "xml":
|
||||
return _formsemestre_recapcomplet_xml(
|
||||
context,
|
||||
@ -246,6 +253,7 @@ def make_formsemestre_recapcomplet(
|
||||
force_publishing=force_publishing,
|
||||
)
|
||||
if format[:3] == "xls":
|
||||
civ_nom_prenom = True # 3 cols: civilite, nom, prenom
|
||||
keep_numeric = True # pas de conversion des notes en strings
|
||||
else:
|
||||
keep_numeric = False
|
||||
@ -265,7 +273,7 @@ def make_formsemestre_recapcomplet(
|
||||
)[0]
|
||||
nt = context._getNotesCache().get_NotesTable(
|
||||
context, formsemestre_id
|
||||
) # > get_modimpls, get_ues, get_table_moyennes_triees, get_etud_decision_sem, get_etud_etat, get_etud_rang, get_nom_short, get_mod_stats, nt.moy_moy, get_nom_long, get_etud_decision_sem,
|
||||
) # > get_modimpls, get_ues, get_table_moyennes_triees, get_etud_decision_sem, get_etud_etat, get_etud_rang, get_nom_short, get_mod_stats, nt.moy_moy, get_etud_decision_sem,
|
||||
modimpls = nt.get_modimpls()
|
||||
ues = nt.get_ues() # incluant le(s) UE de sport
|
||||
#
|
||||
@ -287,7 +295,11 @@ def make_formsemestre_recapcomplet(
|
||||
|
||||
# Construit une liste de listes de chaines: le champs du tableau resultat (HTML ou CSV)
|
||||
F = []
|
||||
h = [rank_label, "Nom"]
|
||||
h = [rank_label]
|
||||
if civ_nom_prenom:
|
||||
h += ["Civilité", "Nom", "Prénom"]
|
||||
else:
|
||||
h += ["Nom"]
|
||||
if not hidebac:
|
||||
h.append("Bac")
|
||||
|
||||
@ -345,7 +357,7 @@ def make_formsemestre_recapcomplet(
|
||||
return val
|
||||
|
||||
# Compte les decisions de jury
|
||||
codes_nb = DictDefault(defaultvalue=0)
|
||||
codes_nb = scu.DictDefault(defaultvalue=0)
|
||||
#
|
||||
is_dem = {} # etudid : bool
|
||||
for t in T:
|
||||
@ -365,7 +377,7 @@ def make_formsemestre_recapcomplet(
|
||||
gr_name = group["group_name"] or ""
|
||||
is_dem[etudid] = False
|
||||
if rank_partition_id:
|
||||
rang_gr, ninscrits_gr, rank_gr_name = sco_bulletins.get_etud_rangs_groups(
|
||||
rang_gr, _, rank_gr_name = sco_bulletins.get_etud_rangs_groups(
|
||||
context, etudid, formsemestre_id, partitions, partitions_etud_groups, nt
|
||||
)
|
||||
if rank_gr_name[rank_partition_id]:
|
||||
@ -378,8 +390,13 @@ def make_formsemestre_recapcomplet(
|
||||
else:
|
||||
rank = nt.get_etud_rang(etudid)
|
||||
|
||||
l = [rank, nt.get_nom_short(etudid)] # rang, nom,
|
||||
e = nt.identdict[etudid]
|
||||
if civ_nom_prenom:
|
||||
scolars.format_etud_ident(e)
|
||||
l = [rank, e["civilite_str"], e["nom_disp"], e["prenom"]] # civ, nom prenom
|
||||
else:
|
||||
l = [rank, nt.get_nom_short(etudid)] # rang, nom,
|
||||
|
||||
if not hidebac:
|
||||
bac = sco_bac.Baccalaureat(e["bac"], e["specialite"])
|
||||
l.append(bac.abbrev())
|
||||
@ -396,7 +413,7 @@ def make_formsemestre_recapcomplet(
|
||||
else:
|
||||
l.append(gr_name) # groupe
|
||||
|
||||
l.append(fmtnum(fmt_note(t[0], keep_numeric=keep_numeric))) # moy_gen
|
||||
l.append(fmtnum(scu.fmt_note(t[0], keep_numeric=keep_numeric))) # moy_gen
|
||||
# Ajoute rangs dans groupes seulement si CSV ou XLS
|
||||
if format[:3] == "xls" or format == "csv":
|
||||
rang_gr, ninscrits_gr, gr_name = sco_bulletins.get_etud_rangs_groups(
|
||||
@ -410,7 +427,7 @@ def make_formsemestre_recapcomplet(
|
||||
i += 1
|
||||
if ue["type"] != UE_SPORT:
|
||||
l.append(
|
||||
fmtnum(fmt_note(t[i], keep_numeric=keep_numeric))
|
||||
fmtnum(scu.fmt_note(t[i], keep_numeric=keep_numeric))
|
||||
) # moyenne etud dans ue
|
||||
else: # UE_SPORT:
|
||||
# n'affiche pas la moyenne d'UE dans ce cas
|
||||
@ -423,7 +440,9 @@ def make_formsemestre_recapcomplet(
|
||||
if modimpl["module"]["ue_id"] == ue["ue_id"]:
|
||||
l.append(
|
||||
fmtnum(
|
||||
fmt_note(t[j + len(ues) + 1], keep_numeric=keep_numeric)
|
||||
scu.fmt_note(
|
||||
t[j + len(ues) + 1], keep_numeric=keep_numeric
|
||||
)
|
||||
)
|
||||
) # moyenne etud dans module
|
||||
if format == "xlsall":
|
||||
@ -450,6 +469,8 @@ def make_formsemestre_recapcomplet(
|
||||
|
||||
def add_bottom_stat(key, title, corner_value=""):
|
||||
l = ["", title]
|
||||
if civ_nom_prenom:
|
||||
l += ["", ""]
|
||||
if not hidebac:
|
||||
l.append("")
|
||||
if format[:3] == "xls" or format == "csv":
|
||||
@ -458,7 +479,7 @@ def make_formsemestre_recapcomplet(
|
||||
l += [""]
|
||||
l.append(corner_value)
|
||||
if format[:3] == "xls" or format == "csv":
|
||||
for partition in partitions:
|
||||
for _ in partitions:
|
||||
l += [""] # rangs dans les groupes
|
||||
for ue in ues:
|
||||
if ue["type"] != UE_SPORT:
|
||||
@ -476,7 +497,7 @@ def make_formsemestre_recapcomplet(
|
||||
else:
|
||||
l.append(str(ue[key]))
|
||||
else:
|
||||
l.append(fmt_note(ue[key], keep_numeric=keep_numeric))
|
||||
l.append(scu.fmt_note(ue[key], keep_numeric=keep_numeric))
|
||||
else: # UE_SPORT:
|
||||
# n'affiche pas la moyenne d'UE dans ce cas
|
||||
if not hidemodules:
|
||||
@ -500,7 +521,7 @@ def make_formsemestre_recapcomplet(
|
||||
): # garde val numerique pour excel
|
||||
val = str(val)
|
||||
else: # moyenne du module
|
||||
val = fmt_note(val, keep_numeric=keep_numeric)
|
||||
val = scu.fmt_note(val, keep_numeric=keep_numeric)
|
||||
l.append(val)
|
||||
|
||||
if format == "xlsall":
|
||||
@ -514,13 +535,15 @@ def make_formsemestre_recapcomplet(
|
||||
F.append(l + ["", ""]) # ajoute cellules code_nip et etudid inutilisees ici
|
||||
|
||||
add_bottom_stat(
|
||||
"min", "Min", corner_value=fmt_note(nt.moy_min, keep_numeric=keep_numeric)
|
||||
"min", "Min", corner_value=scu.fmt_note(nt.moy_min, keep_numeric=keep_numeric)
|
||||
)
|
||||
add_bottom_stat(
|
||||
"max", "Max", corner_value=fmt_note(nt.moy_max, keep_numeric=keep_numeric)
|
||||
"max", "Max", corner_value=scu.fmt_note(nt.moy_max, keep_numeric=keep_numeric)
|
||||
)
|
||||
add_bottom_stat(
|
||||
"moy", "Moyennes", corner_value=fmt_note(nt.moy_moy, keep_numeric=keep_numeric)
|
||||
"moy",
|
||||
"Moyennes",
|
||||
corner_value=scu.fmt_note(nt.moy_moy, keep_numeric=keep_numeric),
|
||||
)
|
||||
add_bottom_stat("coef", "Coef")
|
||||
add_bottom_stat("nb_valid_evals", "Nb évals")
|
||||
@ -619,7 +642,6 @@ def make_formsemestre_recapcomplet(
|
||||
"formsemestre_id": formsemestre_id,
|
||||
"etudid": etudid,
|
||||
"name": l[1],
|
||||
"nomprenom": nt.get_nom_long(etudid),
|
||||
}
|
||||
if ir % 2 == 0:
|
||||
cells = '<tr class="recap_row_even" id="etudid%s">' % etudid
|
||||
@ -645,7 +667,9 @@ def make_formsemestre_recapcomplet(
|
||||
idx_col_moy = idx_col_gr + 1
|
||||
cssclass = "recap_col_moy"
|
||||
try:
|
||||
if float(nsn[idx_col_moy]) < (nt.parcours.BARRE_MOY - NOTES_TOLERANCE):
|
||||
if float(nsn[idx_col_moy]) < (
|
||||
nt.parcours.BARRE_MOY - scu.NOTES_TOLERANCE
|
||||
):
|
||||
cssclass = "recap_col_moy_inf"
|
||||
except:
|
||||
pass
|
||||
@ -734,7 +758,7 @@ def make_formsemestre_recapcomplet(
|
||||
H.append("</table>")
|
||||
return "\n".join(H), "", "html"
|
||||
elif format == "csv":
|
||||
CSV = CSV_LINESEP.join([CSV_FIELDSEP.join(str(x)) for x in F])
|
||||
CSV = scu.CSV_LINESEP.join([scu.CSV_FIELDSEP.join(str(x)) for x in F])
|
||||
semname = sem["titre_num"].replace(" ", "_")
|
||||
date = time.strftime("%d-%m-%Y")
|
||||
filename = "notes_modules-%s-%s.csv" % (semname, date)
|
||||
@ -774,8 +798,8 @@ def _list_notes_evals(context, evals, etudid):
|
||||
val = NotesDB[etudid]["value"]
|
||||
else:
|
||||
# Note manquante mais prise en compte immédiate: affiche ATT
|
||||
val = NOTES_ATTENTE
|
||||
val_fmt = fmt_note(val, keep_numeric=True)
|
||||
val = scu.NOTES_ATTENTE
|
||||
val_fmt = scu.fmt_note(val, keep_numeric=True)
|
||||
L.append(val_fmt)
|
||||
return L
|
||||
|
||||
@ -806,7 +830,7 @@ def _list_notes_evals_stats(context, evals, key):
|
||||
):
|
||||
if key == "moy":
|
||||
val = e["etat"]["moy_num"]
|
||||
L.append(fmt_note(val, keep_numeric=True))
|
||||
L.append(scu.fmt_note(val, keep_numeric=True))
|
||||
elif key == "max":
|
||||
L.append(e["note_max"])
|
||||
elif key == "min":
|
||||
@ -834,7 +858,7 @@ def _formsemestre_recapcomplet_xml(
|
||||
if not T:
|
||||
return "", "", "xml"
|
||||
|
||||
doc = jaxml.XML_document(encoding=SCO_ENCODING)
|
||||
doc = jaxml.XML_document(encoding=scu.SCO_ENCODING)
|
||||
if xml_nodate:
|
||||
docdate = ""
|
||||
else:
|
||||
@ -928,4 +952,4 @@ def formsemestres_bulletins(context, annee_scolaire, REQUEST=None):
|
||||
)
|
||||
jslist.append(J)
|
||||
|
||||
return sendJSON(REQUEST, jslist)
|
||||
return scu.sendJSON(REQUEST, jslist)
|
||||
|
154
sco_report.py
154
sco_report.py
@ -34,9 +34,7 @@ import tempfile
|
||||
import urllib
|
||||
import re
|
||||
import time
|
||||
import mx
|
||||
import mx.DateTime
|
||||
from mx.DateTime import DateTime as mxDateTime
|
||||
import datetime
|
||||
|
||||
import sco_utils as scu
|
||||
import VERSION
|
||||
@ -295,7 +293,7 @@ def formsemestre_report_counts(
|
||||
"codedecision",
|
||||
"devenir",
|
||||
"etat",
|
||||
"sexe",
|
||||
"civilite",
|
||||
"qualite",
|
||||
"villelycee",
|
||||
"statut",
|
||||
@ -367,7 +365,7 @@ def table_suivi_cohorte(
|
||||
bac="", # selection sur type de bac
|
||||
bacspecialite="",
|
||||
annee_bac="",
|
||||
sexe="",
|
||||
civilite=None,
|
||||
statut="",
|
||||
only_primo=False,
|
||||
):
|
||||
@ -406,7 +404,7 @@ def table_suivi_cohorte(
|
||||
bacs = set()
|
||||
bacspecialites = set()
|
||||
annee_bacs = set()
|
||||
sexes = set()
|
||||
civilites = set()
|
||||
statuts = set()
|
||||
for etudid in etudids:
|
||||
etud = context.getEtudInfo(etudid=etudid, filled=True)[0]
|
||||
@ -416,7 +414,7 @@ def table_suivi_cohorte(
|
||||
(not bac or (bac == etud["bac"]))
|
||||
and (not bacspecialite or (bacspecialite == bacspe))
|
||||
and (not annee_bac or (annee_bac == str(etud["annee_bac"])))
|
||||
and (not sexe or (sexe == etud["sexe"]))
|
||||
and (not civilite or (civilite == etud["civilite"]))
|
||||
and (not statut or (statut == etud["statut"]))
|
||||
and (not only_primo or context.isPrimoEtud(etud, sem))
|
||||
):
|
||||
@ -428,15 +426,15 @@ def table_suivi_cohorte(
|
||||
bacs.add(etud["bac"])
|
||||
bacspecialites.add(bacspe)
|
||||
annee_bacs.add(etud["annee_bac"])
|
||||
sexes.add(etud["sexe"])
|
||||
civilites.add(etud["civilite"])
|
||||
if etud["statut"]: # ne montre pas les statuts non renseignés
|
||||
statuts.add(etud["statut"])
|
||||
sems = S.values()
|
||||
# tri les semestres par date de debut
|
||||
for s in sems:
|
||||
d, m, y = [int(x) for x in s["date_debut"].split("/")]
|
||||
s["date_debut_mx"] = mxDateTime(y, m, d) # pylint: disable=not-callable
|
||||
sems.sort(lambda x, y: cmp(x["date_debut_mx"], y["date_debut_mx"]))
|
||||
s["date_debut_dt"] = datetime.datetime(y, m, d)
|
||||
sems.sort(lambda x, y: cmp(x["date_debut_dt"], y["date_debut_dt"]))
|
||||
|
||||
# 2-- Pour chaque semestre, trouve l'ensemble des etudiants venant de sem
|
||||
logt("B: etuds sets")
|
||||
@ -467,21 +465,21 @@ def table_suivi_cohorte(
|
||||
# semestre de depart:
|
||||
porigin = periodsem()
|
||||
d, m, y = [int(x) for x in sem["date_debut"].split("/")]
|
||||
porigin.datedebut = mxDateTime(y, m, d) # pylint: disable=not-callable
|
||||
porigin.datedebut = datetime.datetime(y, m, d)
|
||||
porigin.sems = [sem]
|
||||
|
||||
#
|
||||
tolerance = mx.DateTime.DateTimeDelta(45) # 45 days
|
||||
tolerance = datetime.timedelta(days=45)
|
||||
for s in sems:
|
||||
merged = False
|
||||
for p in P:
|
||||
if abs(s["date_debut_mx"] - p.datedebut) < tolerance:
|
||||
if abs(s["date_debut_dt"] - p.datedebut) < tolerance:
|
||||
p.sems.append(s)
|
||||
merged = True
|
||||
break
|
||||
if not merged:
|
||||
p = periodsem()
|
||||
p.datedebut = s["date_debut_mx"]
|
||||
p.datedebut = s["date_debut_dt"]
|
||||
p.sems = [s]
|
||||
P.append(p)
|
||||
|
||||
@ -619,8 +617,8 @@ def table_suivi_cohorte(
|
||||
dbac += " (spécialité %s)" % bacspecialite
|
||||
if annee_bac:
|
||||
dbac += " (année bac %s)" % annee_bac
|
||||
if sexe:
|
||||
dbac += " genre: %s" % sexe
|
||||
if civilite:
|
||||
dbac += " civilité: %s" % civilite
|
||||
if statut:
|
||||
dbac += " statut: %s" % statut
|
||||
tab = GenTable(
|
||||
@ -654,7 +652,15 @@ def table_suivi_cohorte(
|
||||
expl.append(", ".join(ls) + "</li>")
|
||||
expl.append("</ul>")
|
||||
logt("Z: table_suivi_cohorte done")
|
||||
return tab, "\n".join(expl), bacs, bacspecialites, annee_bacs, sexes, statuts
|
||||
return (
|
||||
tab,
|
||||
"\n".join(expl),
|
||||
bacs,
|
||||
bacspecialites,
|
||||
annee_bacs,
|
||||
civilites,
|
||||
statuts,
|
||||
)
|
||||
|
||||
|
||||
def formsemestre_suivi_cohorte(
|
||||
@ -665,27 +671,35 @@ def formsemestre_suivi_cohorte(
|
||||
bac="",
|
||||
bacspecialite="",
|
||||
annee_bac="",
|
||||
sexe="",
|
||||
civilite=None,
|
||||
statut="",
|
||||
only_primo=False,
|
||||
REQUEST=None,
|
||||
):
|
||||
"""Affiche suivi cohortes par numero de semestre"""
|
||||
percent = int(percent)
|
||||
tab, expl, bacs, bacspecialites, annee_bacs, sexes, statuts = table_suivi_cohorte(
|
||||
(
|
||||
tab,
|
||||
expl,
|
||||
bacs,
|
||||
bacspecialites,
|
||||
annee_bacs,
|
||||
civilites,
|
||||
statuts,
|
||||
) = table_suivi_cohorte(
|
||||
context,
|
||||
formsemestre_id,
|
||||
percent=percent,
|
||||
bac=bac,
|
||||
bacspecialite=bacspecialite,
|
||||
annee_bac=annee_bac,
|
||||
sexe=sexe,
|
||||
civilite=civilite,
|
||||
statut=statut,
|
||||
only_primo=only_primo,
|
||||
)
|
||||
tab.base_url = (
|
||||
"%s?formsemestre_id=%s&percent=%s&bac=%s&bacspecialite=%s&sexe=%s"
|
||||
% (REQUEST.URL0, formsemestre_id, percent, bac, bacspecialite, sexe)
|
||||
"%s?formsemestre_id=%s&percent=%s&bac=%s&bacspecialite=%s&civilite=%s"
|
||||
% (REQUEST.URL0, formsemestre_id, percent, bac, bacspecialite, civilite)
|
||||
)
|
||||
if only_primo:
|
||||
tab.base_url += "&only_primo=on"
|
||||
@ -695,8 +709,8 @@ def formsemestre_suivi_cohorte(
|
||||
|
||||
base_url = REQUEST.URL0
|
||||
burl = (
|
||||
"%s?formsemestre_id=%s&bac=%s&bacspecialite=%s&sexe=%s&statut=%s"
|
||||
% (base_url, formsemestre_id, bac, bacspecialite, sexe, statut)
|
||||
"%s?formsemestre_id=%s&bac=%s&bacspecialite=%s&civilite=%s&statut=%s"
|
||||
% (base_url, formsemestre_id, bac, bacspecialite, civilite, statut)
|
||||
)
|
||||
if percent:
|
||||
pplink = (
|
||||
@ -726,12 +740,12 @@ def formsemestre_suivi_cohorte(
|
||||
bac=bac,
|
||||
bacspecialite=bacspecialite,
|
||||
annee_bac=annee_bac,
|
||||
sexe=sexe,
|
||||
civilite=civilite,
|
||||
statut=statut,
|
||||
bacs=bacs,
|
||||
bacspecialites=bacspecialites,
|
||||
annee_bacs=annee_bacs,
|
||||
sexes=sexes,
|
||||
civilites=civilites,
|
||||
statuts=statuts,
|
||||
percent=percent,
|
||||
),
|
||||
@ -751,12 +765,12 @@ def _gen_form_selectetuds(
|
||||
bac=None,
|
||||
bacspecialite=None,
|
||||
annee_bac=None,
|
||||
sexe=None,
|
||||
civilite=None,
|
||||
statut=None,
|
||||
bacs=None,
|
||||
bacspecialites=None,
|
||||
annee_bacs=None,
|
||||
sexes=None,
|
||||
civilites=None,
|
||||
statuts=None,
|
||||
):
|
||||
"""HTML form pour choix criteres selection etudiants"""
|
||||
@ -766,8 +780,8 @@ def _gen_form_selectetuds(
|
||||
bacspecialites.sort()
|
||||
annee_bacs = list(annee_bacs)
|
||||
annee_bacs.sort()
|
||||
sexes = list(sexes)
|
||||
sexes.sort()
|
||||
civilites = list(civilites)
|
||||
civilites.sort()
|
||||
statuts = list(statuts)
|
||||
statuts.sort()
|
||||
#
|
||||
@ -826,13 +840,13 @@ def _gen_form_selectetuds(
|
||||
F.append("</select>")
|
||||
#
|
||||
F.append(
|
||||
""" Genre: <select name="sexe" onchange="javascript: submit(this);">
|
||||
""" Genre: <select name="civilite" onchange="javascript: submit(this);">
|
||||
<option value="" %s>tous</option>
|
||||
"""
|
||||
% selected
|
||||
)
|
||||
for b in sexes:
|
||||
if sexe == b:
|
||||
for b in civilites:
|
||||
if civilite == b:
|
||||
selected = 'selected="selected"'
|
||||
else:
|
||||
selected = ""
|
||||
@ -986,7 +1000,7 @@ def tsp_etud_list(
|
||||
bac="", # selection sur type de bac
|
||||
bacspecialite="",
|
||||
annee_bac="",
|
||||
sexe="",
|
||||
civilite="",
|
||||
statut="",
|
||||
):
|
||||
"""Liste des etuds a considerer dans table suivi parcours
|
||||
@ -1002,7 +1016,7 @@ def tsp_etud_list(
|
||||
bacs = set()
|
||||
bacspecialites = set()
|
||||
annee_bacs = set()
|
||||
sexes = set()
|
||||
civilites = set()
|
||||
statuts = set()
|
||||
for etudid in etudids:
|
||||
etud = context.getEtudInfo(etudid=etudid, filled=True)[0]
|
||||
@ -1012,7 +1026,7 @@ def tsp_etud_list(
|
||||
(not bac or (bac == etud["bac"]))
|
||||
and (not bacspecialite or (bacspecialite == bacspe))
|
||||
and (not annee_bac or (annee_bac == str(etud["annee_bac"])))
|
||||
and (not sexe or (sexe == etud["sexe"]))
|
||||
and (not civilite or (civilite == etud["civilite"]))
|
||||
and (not statut or (statut == etud["statut"]))
|
||||
and (not only_primo or context.isPrimoEtud(etud, sem))
|
||||
):
|
||||
@ -1021,11 +1035,11 @@ def tsp_etud_list(
|
||||
bacs.add(etud["bac"])
|
||||
bacspecialites.add(bacspe)
|
||||
annee_bacs.add(etud["annee_bac"])
|
||||
sexes.add(etud["sexe"])
|
||||
civilites.add(etud["civilite"])
|
||||
if etud["statut"]: # ne montre pas les statuts non renseignés
|
||||
statuts.add(etud["statut"])
|
||||
# log('tsp_etud_list: %s etuds' % len(etuds))
|
||||
return etuds, bacs, bacspecialites, annee_bacs, sexes, statuts
|
||||
return etuds, bacs, bacspecialites, annee_bacs, civilites, statuts
|
||||
|
||||
|
||||
def tsp_grouped_list(context, codes_etuds):
|
||||
@ -1051,7 +1065,7 @@ def table_suivi_parcours(
|
||||
):
|
||||
"""Tableau recapitulant tous les parcours"""
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = tsp_etud_list(
|
||||
etuds, bacs, bacspecialites, annee_bacs, civilites, statuts = tsp_etud_list(
|
||||
context, formsemestre_id, only_primo=only_primo
|
||||
)
|
||||
codes_etuds = scu.DictDefault(defaultvalue=[])
|
||||
@ -1067,7 +1081,7 @@ def table_suivi_parcours(
|
||||
titles = {
|
||||
"parcours": "Code parcours",
|
||||
"nb": "Nombre d'étudiants",
|
||||
"sexe": "",
|
||||
"civilite": "",
|
||||
"nom": "Nom",
|
||||
"prenom": "Prénom",
|
||||
"etudid": "etudid",
|
||||
@ -1084,7 +1098,7 @@ def table_suivi_parcours(
|
||||
L = etuds
|
||||
columns_ids = (
|
||||
"etudid",
|
||||
"sexe",
|
||||
"civilite",
|
||||
"nom",
|
||||
"prenom",
|
||||
"bac",
|
||||
@ -1211,25 +1225,25 @@ def graph_parcours(
|
||||
bac="", # selection sur type de bac
|
||||
bacspecialite="",
|
||||
annee_bac="",
|
||||
sexe="",
|
||||
civilite="",
|
||||
statut="",
|
||||
):
|
||||
""""""
|
||||
if not scu.WITH_PYDOT:
|
||||
raise ScoValueError("pydot module is not installed")
|
||||
etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = tsp_etud_list(
|
||||
etuds, bacs, bacspecialites, annee_bacs, civilites, statuts = tsp_etud_list(
|
||||
context,
|
||||
formsemestre_id,
|
||||
only_primo=only_primo,
|
||||
bac=bac,
|
||||
bacspecialite=bacspecialite,
|
||||
annee_bac=annee_bac,
|
||||
sexe=sexe,
|
||||
civilite=civilite,
|
||||
statut=statut,
|
||||
)
|
||||
# log('graph_parcours: %s etuds (only_primo=%s)' % (len(etuds), only_primo))
|
||||
if not etuds:
|
||||
return "", etuds, bacs, bacspecialites, annee_bacs, sexes, statuts
|
||||
return "", etuds, bacs, bacspecialites, annee_bacs, civilites, statuts
|
||||
edges = scu.DictDefault(
|
||||
defaultvalue=set()
|
||||
) # {(formsemestre_id_origin, formsemestre_id_dest) : etud_set}
|
||||
@ -1242,7 +1256,7 @@ def graph_parcours(
|
||||
dem_nodes = {} # formsemestre_id : noeud pour demissionnaires
|
||||
nar_nodes = {} # formsemestre_id : noeud pour NAR
|
||||
for etud in etuds:
|
||||
nxt = None
|
||||
nxt = {}
|
||||
etudid = etud["etudid"]
|
||||
for s in etud["sems"]: # du plus recent au plus ancien
|
||||
nt = context._getNotesCache().get_NotesTable(
|
||||
@ -1419,7 +1433,7 @@ def graph_parcours(
|
||||
# cf http://groups.google.com/group/pydot/browse_thread/thread/b3704c53e331e2ec
|
||||
data = data.replace("font-family:Arial", "font-family:Helvetica")
|
||||
|
||||
return data, etuds, bacs, bacspecialites, annee_bacs, sexes, statuts
|
||||
return data, etuds, bacs, bacspecialites, annee_bacs, civilites, statuts
|
||||
|
||||
|
||||
def formsemestre_graph_parcours(
|
||||
@ -1430,7 +1444,7 @@ def formsemestre_graph_parcours(
|
||||
bac="", # selection sur type de bac
|
||||
bacspecialite="",
|
||||
annee_bac="",
|
||||
sexe="",
|
||||
civilite="",
|
||||
statut="",
|
||||
allkeys=False, # unused
|
||||
REQUEST=None,
|
||||
@ -1439,7 +1453,15 @@ def formsemestre_graph_parcours(
|
||||
# log("formsemestre_graph_parcours")
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
if format == "pdf":
|
||||
doc, etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = graph_parcours(
|
||||
(
|
||||
doc,
|
||||
etuds,
|
||||
bacs,
|
||||
bacspecialites,
|
||||
annee_bacs,
|
||||
civilites,
|
||||
statuts,
|
||||
) = graph_parcours(
|
||||
context,
|
||||
formsemestre_id,
|
||||
format="pdf",
|
||||
@ -1447,14 +1469,22 @@ def formsemestre_graph_parcours(
|
||||
bac=bac,
|
||||
bacspecialite=bacspecialite,
|
||||
annee_bac=annee_bac,
|
||||
sexe=sexe,
|
||||
civilite=civilite,
|
||||
statut=statut,
|
||||
)
|
||||
filename = scu.make_filename("flux " + sem["titreannee"])
|
||||
return scu.sendPDFFile(REQUEST, doc, filename + ".pdf")
|
||||
elif format == "png":
|
||||
#
|
||||
doc, etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = graph_parcours(
|
||||
(
|
||||
doc,
|
||||
etuds,
|
||||
bacs,
|
||||
bacspecialites,
|
||||
annee_bacs,
|
||||
civilites,
|
||||
statuts,
|
||||
) = graph_parcours(
|
||||
context,
|
||||
formsemestre_id,
|
||||
format="png",
|
||||
@ -1462,7 +1492,7 @@ def formsemestre_graph_parcours(
|
||||
bac=bac,
|
||||
bacspecialite=bacspecialite,
|
||||
annee_bac=annee_bac,
|
||||
sexe=sexe,
|
||||
civilite=civilite,
|
||||
statut=statut,
|
||||
)
|
||||
filename = scu.make_filename("flux " + sem["titreannee"])
|
||||
@ -1477,17 +1507,25 @@ def formsemestre_graph_parcours(
|
||||
else:
|
||||
op = ""
|
||||
url = urllib.quote(
|
||||
"formsemestre_graph_parcours?formsemestre_id=%s&%sbac=%s&bacspecialite=%s&sexe=%s&statut=%s&format="
|
||||
% (formsemestre_id, op, bac, bacspecialite, sexe, statut)
|
||||
"formsemestre_graph_parcours?formsemestre_id=%s&%sbac=%s&bacspecialite=%s&civilite=%s&statut=%s&format="
|
||||
% (formsemestre_id, op, bac, bacspecialite, civilite, statut)
|
||||
)
|
||||
doc, etuds, bacs, bacspecialites, annee_bacs, sexes, statuts = graph_parcours(
|
||||
(
|
||||
doc,
|
||||
etuds,
|
||||
bacs,
|
||||
bacspecialites,
|
||||
annee_bacs,
|
||||
civilites,
|
||||
statuts,
|
||||
) = graph_parcours(
|
||||
context,
|
||||
formsemestre_id,
|
||||
only_primo=only_primo,
|
||||
bac=bac,
|
||||
bacspecialite=bacspecialite,
|
||||
annee_bac=annee_bac,
|
||||
sexe=sexe,
|
||||
civilite=civilite,
|
||||
statut=statut,
|
||||
)
|
||||
|
||||
@ -1507,12 +1545,12 @@ def formsemestre_graph_parcours(
|
||||
bac=bac,
|
||||
bacspecialite=bacspecialite,
|
||||
annee_bac=annee_bac,
|
||||
sexe=sexe,
|
||||
civilite=civilite,
|
||||
statut=statut,
|
||||
bacs=bacs,
|
||||
bacspecialites=bacspecialites,
|
||||
annee_bacs=annee_bacs,
|
||||
sexes=sexes,
|
||||
civilites=civilites,
|
||||
statuts=statuts,
|
||||
percent=0,
|
||||
),
|
||||
|
@ -33,7 +33,6 @@ import time
|
||||
import datetime
|
||||
import psycopg2
|
||||
|
||||
# from notesdb import *
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from TrivialFormulator import TrivialFormulator, TF
|
||||
@ -258,9 +257,7 @@ def do_evaluation_upload_xls(context, REQUEST):
|
||||
)
|
||||
raise InvalidNoteValue()
|
||||
# -- check values
|
||||
L, invalids, withoutnotes, absents, tosuppress = _check_notes(
|
||||
notes, E, M["module"]
|
||||
)
|
||||
L, invalids, withoutnotes, absents, _ = _check_notes(notes, E, M["module"])
|
||||
if len(invalids):
|
||||
diag.append(
|
||||
"Erreur: la feuille contient %d notes invalides</p>" % len(invalids)
|
||||
@ -339,7 +336,7 @@ def do_evaluation_set_missing(
|
||||
if not NotesDB.has_key(etudid): # pas de note
|
||||
notes.append((etudid, value))
|
||||
# Check value
|
||||
L, invalids, withoutnotes, absents, tosuppress = _check_notes(notes, E, M["module"])
|
||||
L, invalids, _, _, _ = _check_notes(notes, E, M["module"])
|
||||
diag = ""
|
||||
if len(invalids):
|
||||
diag = "Valeur %s invalide" % value
|
||||
@ -368,9 +365,7 @@ def do_evaluation_set_missing(
|
||||
)
|
||||
# ok
|
||||
comment = "Initialisation notes manquantes"
|
||||
nb_changed, nb_suppress, existing_decisions = _notes_add(
|
||||
context, authuser, evaluation_id, L, comment
|
||||
)
|
||||
nb_changed, _, _ = _notes_add(context, authuser, evaluation_id, L, comment)
|
||||
# news
|
||||
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=E["moduleimpl_id"])[0]
|
||||
mod = context.do_module_list(args={"module_id": M["module_id"]})[0]
|
||||
@ -479,7 +474,7 @@ def _notes_add(context, uid, evaluation_id, notes, comment=None, do_it=True):
|
||||
psycopg2.Timestamp, time.localtime()[:6]
|
||||
) # datetime.datetime.now().isoformat()
|
||||
# Verifie inscription et valeur note
|
||||
inscrits = {}.fromkeys(
|
||||
_ = {}.fromkeys(
|
||||
sco_groups.do_evaluation_listeetuds_groups(
|
||||
context, evaluation_id, getallstudents=True, include_dems=True
|
||||
)
|
||||
@ -806,10 +801,10 @@ def feuille_saisie_notes(context, evaluation_id, group_ids=[], REQUEST=None):
|
||||
)
|
||||
groups = sco_groups.listgroups(context, groups_infos.group_ids)
|
||||
gr_title_filename = sco_groups.listgroups_filename(groups)
|
||||
gr_title = sco_groups.listgroups_abbrev(groups)
|
||||
# gr_title = sco_groups.listgroups_abbrev(groups)
|
||||
if None in [g["group_name"] for g in groups]: # tous les etudiants
|
||||
getallstudents = True
|
||||
gr_title = "tous"
|
||||
# gr_title = "tous"
|
||||
gr_title_filename = "tous"
|
||||
else:
|
||||
getallstudents = False
|
||||
@ -954,9 +949,15 @@ def saisie_notes(context, evaluation_id, group_ids=[], REQUEST=None):
|
||||
H.append("""</td></tr></table></div>""")
|
||||
|
||||
# Le formulaire de saisie des notes:
|
||||
form = _form_saisie_notes(context, E, M, groups_infos.group_ids, REQUEST=REQUEST)
|
||||
destination = "%s/Notes/moduleimpl_status?moduleimpl_id=%s" % (
|
||||
context.ScoURL(),
|
||||
E["moduleimpl_id"],
|
||||
)
|
||||
form = _form_saisie_notes(
|
||||
context, E, M, groups_infos.group_ids, destination=destination, REQUEST=REQUEST
|
||||
)
|
||||
if form is None:
|
||||
return "" # redirect
|
||||
return REQUEST.RESPONSE.redirect(destination)
|
||||
H.append(form)
|
||||
#
|
||||
H.append("</div>") # /saisie_notes
|
||||
@ -1046,7 +1047,7 @@ def _get_sorted_etuds(context, E, etudids, formsemestre_id):
|
||||
return etuds
|
||||
|
||||
|
||||
def _form_saisie_notes(context, E, M, group_ids, REQUEST=None):
|
||||
def _form_saisie_notes(context, E, M, group_ids, destination="", REQUEST=None):
|
||||
"""Formulaire HTML saisie des notes dans l'évaluation E du moduleimpl M
|
||||
pour les groupes indiqués.
|
||||
|
||||
@ -1126,7 +1127,13 @@ def _form_saisie_notes(context, E, M, group_ids, REQUEST=None):
|
||||
for group_info in e["groups"]:
|
||||
etud_classes.append(group_info["group_id"])
|
||||
|
||||
label = '<span class="%s">' % classdem + e["nomprenom"] + "</span>"
|
||||
label = (
|
||||
'<span class="%s">' % classdem
|
||||
+ e["civilite_str"]
|
||||
+ " "
|
||||
+ scolars.format_nomprenom(e, reverse=True)
|
||||
+ "</span>"
|
||||
)
|
||||
|
||||
# Historique des saisies de notes:
|
||||
if not disabled:
|
||||
@ -1181,11 +1188,6 @@ def _form_saisie_notes(context, E, M, group_ids, REQUEST=None):
|
||||
)
|
||||
# H.append('''<div id="sco_msg" class="head_message"></div>''')
|
||||
|
||||
destination = "%s/Notes/moduleimpl_status?moduleimpl_id=%s" % (
|
||||
context.ScoURL(),
|
||||
M["moduleimpl_id"],
|
||||
)
|
||||
|
||||
tf = TF(
|
||||
destination,
|
||||
REQUEST.form,
|
||||
@ -1196,7 +1198,6 @@ def _form_saisie_notes(context, E, M, group_ids, REQUEST=None):
|
||||
)
|
||||
H.append(tf.getform()) # check and init
|
||||
if tf.canceled():
|
||||
REQUEST.RESPONSE.redirect(destination)
|
||||
return None
|
||||
elif (not tf.submitted()) or not tf.result:
|
||||
# ajout formularie saisie notes manquantes
|
||||
@ -1218,7 +1219,6 @@ def _form_saisie_notes(context, E, M, group_ids, REQUEST=None):
|
||||
else:
|
||||
# form submission
|
||||
# rien à faire
|
||||
REQUEST.RESPONSE.redirect(destination)
|
||||
return None
|
||||
|
||||
|
||||
@ -1240,11 +1240,9 @@ def save_note(
|
||||
if not can_edit_notes(context, authuser, E["moduleimpl_id"]):
|
||||
result["status"] = "unauthorized"
|
||||
else:
|
||||
L, invalids, withoutnotes, absents, tosuppress = _check_notes(
|
||||
[(etudid, value)], E, Mod
|
||||
)
|
||||
L, _, _, _, _ = _check_notes([(etudid, value)], E, Mod)
|
||||
if L:
|
||||
nbchanged, nbsuppress, existing_decisions = _notes_add(
|
||||
nbchanged, _, existing_decisions = _notes_add(
|
||||
context, authuser, evaluation_id, L, comment=comment, do_it=True
|
||||
)
|
||||
sco_news.add(
|
||||
|
@ -39,8 +39,8 @@ sem_set_list(context)
|
||||
|
||||
"""
|
||||
|
||||
from sco_utils import *
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
import sco_formsemestre
|
||||
from sco_formsemestre import ApoEtapeVDI
|
||||
@ -49,9 +49,10 @@ import sco_etape_apogee
|
||||
from sco_etape_bilan import EtapeBilan
|
||||
import sco_portal_apogee
|
||||
from gen_tables import GenTable
|
||||
from sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
_semset_editor = EditableTable(
|
||||
_semset_editor = ndb.EditableTable(
|
||||
"notes_semset", "semset_id", ("semset_id", "title", "annee_scolaire", "sem_id")
|
||||
)
|
||||
|
||||
@ -81,7 +82,7 @@ class SemSet(dict):
|
||||
self["title"] = L[0]["title"]
|
||||
self["annee_scolaire"] = L[0]["annee_scolaire"]
|
||||
self["sem_id"] = L[0]["sem_id"]
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT formsemestre_id FROM notes_semset_formsemestre WHERE semset_id = %(semset_id)s",
|
||||
{"semset_id": semset_id},
|
||||
@ -150,7 +151,7 @@ class SemSet(dict):
|
||||
% (formsemestre_id, self.semset_id)
|
||||
)
|
||||
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
self.context,
|
||||
"INSERT INTO notes_semset_formsemestre (formsemestre_id, semset_id) VALUES (%(formsemestre_id)s, %(semset_id)s)",
|
||||
{"formsemestre_id": formsemestre_id, "semset_id": self.semset_id},
|
||||
@ -158,7 +159,7 @@ class SemSet(dict):
|
||||
self.load_sems() # update our list
|
||||
|
||||
def remove(self, formsemestre_id):
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
self.context,
|
||||
"DELETE FROM notes_semset_formsemestre WHERE semset_id=%(semset_id)s AND formsemestre_id=%(formsemestre_id)s",
|
||||
{"formsemestre_id": formsemestre_id, "semset_id": self.semset_id},
|
||||
@ -416,7 +417,7 @@ def semset_page(context, format="html", REQUEST=None):
|
||||
"""
|
||||
semsets = get_semsets_list(context)
|
||||
for s in semsets:
|
||||
s["suppress"] = icontag(
|
||||
s["suppress"] = scu.icontag(
|
||||
"delete_small_img", border="0", alt="supprimer", title="Supprimer"
|
||||
)
|
||||
s["_suppress_target"] = "do_semset_delete?semset_id=%s" % (s["semset_id"])
|
||||
@ -478,7 +479,7 @@ def semset_page(context, format="html", REQUEST=None):
|
||||
]
|
||||
H.append(tab.html())
|
||||
|
||||
annee_courante = int(AnneeScolaire(REQUEST))
|
||||
annee_courante = int(scu.AnneeScolaire(REQUEST))
|
||||
menu_annee = "\n".join(
|
||||
[
|
||||
'<option value="%s">%s</option>' % (i, i)
|
||||
|
@ -31,9 +31,11 @@
|
||||
import time
|
||||
import pprint
|
||||
|
||||
from sco_utils import ScoEtudInscrit, annee_scolaire_debut, log, ScoValueError
|
||||
import sco_utils as scu
|
||||
from sco_permissions import ScoEtudInscrit
|
||||
from sco_exceptions import ScoValueError
|
||||
from notesdb import ScoDocCursor
|
||||
|
||||
from notes_log import log
|
||||
import sco_portal_apogee
|
||||
import sco_inscr_passage
|
||||
import scolars
|
||||
@ -111,7 +113,7 @@ def formsemestre_synchro_etuds(
|
||||
|
||||
if anneeapogee == None: # année d'inscription par défaut
|
||||
anneeapogee = str(
|
||||
annee_scolaire_debut(sem["annee_debut"], sem["mois_debut_ord"])
|
||||
scu.annee_scolaire_debut(sem["annee_debut"], sem["mois_debut_ord"])
|
||||
)
|
||||
|
||||
if type(etuds) == type(""):
|
||||
@ -406,7 +408,7 @@ def list_synch(context, sem, anneeapogee=None):
|
||||
etud = etudsapo_ident[key]
|
||||
|
||||
etud["etudid"] = ""
|
||||
etud["sexe"] = etud.get(
|
||||
etud["civilite"] = etud.get(
|
||||
"sexe", etud.get("gender", "")
|
||||
) # la cle 'sexe' est prioritaire sur 'gender'
|
||||
etud["inscrit"] = is_inscrit # checkbox state
|
||||
@ -543,16 +545,14 @@ def formsemestre_synchro_etuds_help(context, sem):
|
||||
)
|
||||
|
||||
|
||||
def gender2sex(gender):
|
||||
"""Le portail code en 'M', 'F', et ScoDoc en 'MR', 'MME'
|
||||
Les F sont ici codées en MME
|
||||
"""
|
||||
if gender == "M":
|
||||
return "MR"
|
||||
elif gender == "F":
|
||||
return "MME"
|
||||
log('gender2sex: invalid value "%s", defaulting to "M"' % gender)
|
||||
return "MR"
|
||||
def gender2civilite(gender):
|
||||
"""Le portail code en 'M', 'F', et ScoDoc en 'M', 'F', 'X'"""
|
||||
if gender == "M" or gender == "F" or gender == "X":
|
||||
return gender
|
||||
elif not gender:
|
||||
return "X"
|
||||
log('gender2civilite: invalid value "%s", defaulting to "X"' % gender)
|
||||
return "X" # "X" en général n'est pas affiché, donc bon choix si invalide
|
||||
|
||||
|
||||
def get_opt_str(etud, k):
|
||||
@ -596,7 +596,7 @@ def do_import_etuds_from_portal(context, sem, a_importer, etudsapo_ident, REQUES
|
||||
"prenom": etud["prenom"].strip(),
|
||||
# Les champs suivants sont facultatifs (pas toujours renvoyés par le portail)
|
||||
"code_ine": etud.get("ine", "").strip(),
|
||||
"sexe": gender2sex(etud["gender"].strip()),
|
||||
"civilite": gender2civilite(etud["gender"].strip()),
|
||||
"etape": etud.get("etape", None),
|
||||
"email": etud.get("mail", "").strip(),
|
||||
"emailperso": etud.get("mailperso", "").strip(),
|
||||
@ -736,9 +736,9 @@ def do_import_etud_admission(
|
||||
if x:
|
||||
args[sco_field] = x
|
||||
# Champs spécifiques:
|
||||
sexe = gender2sex(etud["gender"].strip())
|
||||
if sexe:
|
||||
args["sexe"] = sexe
|
||||
civilite = gender2civilite(etud["gender"].strip())
|
||||
if civilite:
|
||||
args["civilite"] = civilite
|
||||
|
||||
scolars.identite_edit_nocheck(cnx, args)
|
||||
|
||||
@ -791,7 +791,9 @@ def formsemestre_import_etud_admission(
|
||||
# Essaie de recuperer les etudiants des étapes, car
|
||||
# la requete get_inscrits_etape est en général beaucoup plus
|
||||
# rapide que les requetes individuelles get_etud_apogee
|
||||
anneeapogee = str(annee_scolaire_debut(sem["annee_debut"], sem["mois_debut_ord"]))
|
||||
anneeapogee = str(
|
||||
scu.annee_scolaire_debut(sem["annee_debut"], sem["mois_debut_ord"])
|
||||
)
|
||||
apo_etuds = {} # nip : etud apo
|
||||
for etape in sem["etapes"]:
|
||||
etudsapo = sco_portal_apogee.get_inscrits_etape(
|
||||
|
@ -34,9 +34,13 @@
|
||||
Pour l'UI, voir https://goodies.pixabay.com/jquery/tag-editor/demo.html
|
||||
"""
|
||||
|
||||
from sco_utils import *
|
||||
from notesdb import *
|
||||
import types
|
||||
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
from sco_exceptions import ScoValueError, AccessDenied
|
||||
from sco_permissions import ScoEditFormationTags, ScoChangeFormation
|
||||
|
||||
# Opérations à implementer:
|
||||
# + liste des modules des formations de code donné (formation_code) avec ce tag
|
||||
@ -66,7 +70,7 @@ class ScoTag:
|
||||
self.title = title.strip()
|
||||
if not self.title:
|
||||
raise ScoValueError("invalid empty tag")
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT * FROM " + self.tag_table + " WHERE title = %(title)s",
|
||||
{"title": self.title},
|
||||
@ -77,8 +81,10 @@ class ScoTag:
|
||||
# Create new tag:
|
||||
log("creating new tag: %s" % self.title)
|
||||
cnx = context.GetDBConnexion()
|
||||
oid = DBInsertDict(cnx, self.tag_table, {"title": self.title}, commit=True)
|
||||
self.tag_id = SimpleDictFetch(
|
||||
oid = ndb.DBInsertDict(
|
||||
cnx, self.tag_table, {"title": self.title}, commit=True
|
||||
)
|
||||
self.tag_id = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT tag_id FROM " + self.tag_table + " WHERE oid=%(oid)s",
|
||||
{"oid": oid},
|
||||
@ -94,7 +100,7 @@ class ScoTag:
|
||||
This object should not be used after this call !
|
||||
"""
|
||||
args = {"tag_id": self.tag_id}
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
self.context,
|
||||
"DELETE FROM " + self.tag_table + " t WHERE t.tag_id = %(tag_id)s",
|
||||
args,
|
||||
@ -103,7 +109,7 @@ class ScoTag:
|
||||
def tag_object(self, object_id):
|
||||
"""Associate tag to given object"""
|
||||
args = {self.obj_colname: object_id, "tag_id": self.tag_id}
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
self.context,
|
||||
"SELECT * FROM "
|
||||
+ self.assoc_table
|
||||
@ -117,7 +123,7 @@ class ScoTag:
|
||||
if not r:
|
||||
log("tag %s with %s" % (object_id, self.title))
|
||||
cnx = self.context.GetDBConnexion()
|
||||
DBInsertDict(cnx, self.assoc_table, args, commit=True)
|
||||
ndb.DBInsertDict(cnx, self.assoc_table, args, commit=True)
|
||||
|
||||
def remove_tag_from_object(self, object_id):
|
||||
"""Remove tag from module.
|
||||
@ -126,7 +132,7 @@ class ScoTag:
|
||||
"""
|
||||
log("removing tag %s from %s" % (self.title, object_id))
|
||||
args = {"object_id": object_id, "tag_id": self.tag_id}
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
self.context,
|
||||
"DELETE FROM "
|
||||
+ self.assoc_table
|
||||
@ -135,7 +141,7 @@ class ScoTag:
|
||||
+ " = %(object_id)s AND a.tag_id = %(tag_id)s",
|
||||
args,
|
||||
)
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
self.context,
|
||||
"""SELECT * FROM notes_modules_tags mt WHERE tag_id = %(tag_id)s
|
||||
""",
|
||||
@ -143,7 +149,7 @@ class ScoTag:
|
||||
)
|
||||
if not r:
|
||||
# tag no more used, delete
|
||||
SimpleQuery(
|
||||
ndb.SimpleQuery(
|
||||
self.context,
|
||||
"""DELETE FROM notes_tags t WHERE t.tag_id = %(tag_id)s""",
|
||||
args,
|
||||
@ -162,7 +168,7 @@ class ModuleTag(ScoTag):
|
||||
args = {"tag_id": self.tag_id}
|
||||
if not formation_code:
|
||||
# tous les modules de toutes les formations !
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
self.context,
|
||||
"SELECT "
|
||||
+ self.obj_colname
|
||||
@ -174,7 +180,7 @@ class ModuleTag(ScoTag):
|
||||
else:
|
||||
args["formation_code"] = formation_code
|
||||
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
self.context,
|
||||
"""SELECT mt.module_id
|
||||
FROM notes_modules_tags mt, notes_modules m, notes_formations f
|
||||
@ -194,22 +200,22 @@ class ModuleTag(ScoTag):
|
||||
def module_tag_search(context, term, REQUEST=None):
|
||||
"""List all used tag names (for auto-completion)"""
|
||||
# restrict charset to avoid injections
|
||||
if not ALPHANUM_EXP.match(term.decode(SCO_ENCODING)):
|
||||
if not scu.ALPHANUM_EXP.match(term.decode(scu.SCO_ENCODING)):
|
||||
data = []
|
||||
else:
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"SELECT title FROM notes_tags WHERE title LIKE %(term)s",
|
||||
{"term": term + "%"},
|
||||
)
|
||||
data = [x["title"] for x in r]
|
||||
|
||||
return sendJSON(REQUEST, data)
|
||||
return scu.sendJSON(REQUEST, data)
|
||||
|
||||
|
||||
def module_tag_list(context, module_id=""):
|
||||
"""les noms de tags associés à ce module"""
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""SELECT t.title
|
||||
FROM notes_modules_tags mt, notes_tags t
|
||||
@ -237,7 +243,7 @@ def module_tag_set(context, module_id="", taglist=[], REQUEST=None):
|
||||
#
|
||||
if not taglist:
|
||||
taglist = []
|
||||
elif type(taglist) == StringType:
|
||||
elif type(taglist) == types.StringType:
|
||||
taglist = taglist.split(",")
|
||||
taglist = [t.strip() for t in taglist]
|
||||
log("module_tag_set: module_id=%s taglist=%s" % (module_id, taglist))
|
||||
|
127
sco_trombino.py
127
sco_trombino.py
@ -28,16 +28,29 @@
|
||||
"""Photos: trombinoscopes
|
||||
"""
|
||||
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except:
|
||||
from StringIO import StringIO
|
||||
from cStringIO import StringIO
|
||||
from zipfile import ZipFile, BadZipfile
|
||||
import xml
|
||||
import tempfile
|
||||
import reportlab
|
||||
from reportlab.lib.units import cm, mm
|
||||
from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
|
||||
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Frame, PageBreak
|
||||
from reportlab.platypus import Table, TableStyle, Image, KeepInFrame
|
||||
from reportlab.platypus.flowables import Flowable
|
||||
from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate
|
||||
from reportlab.lib.pagesizes import A4, landscape
|
||||
from reportlab.lib import styles
|
||||
from reportlab.lib.colors import Color
|
||||
from reportlab.lib import colors
|
||||
from PIL import Image as PILImage
|
||||
|
||||
from notes_log import log
|
||||
from sco_utils import *
|
||||
import sco_utils as scu
|
||||
import sco_pdf
|
||||
from sco_pdf import SU
|
||||
from sco_exceptions import ScoValueError
|
||||
from TrivialFormulator import TrivialFormulator
|
||||
import scolars
|
||||
import sco_photos
|
||||
import sco_formsemestre
|
||||
@ -45,10 +58,8 @@ import sco_groups
|
||||
import sco_groups_view
|
||||
import sco_portal_apogee
|
||||
import htmlutils
|
||||
from sco_pdf import *
|
||||
import ImportScolars
|
||||
import sco_excel
|
||||
from reportlab.lib import colors
|
||||
|
||||
|
||||
def trombino(
|
||||
@ -165,8 +176,7 @@ def check_local_photos_availability(context, groups_infos, REQUEST, format=""):
|
||||
"""
|
||||
nb_missing = 0
|
||||
for t in groups_infos.members:
|
||||
etudid = t["etudid"]
|
||||
url = sco_photos.etud_photo_url(
|
||||
_ = sco_photos.etud_photo_url(
|
||||
context, t, REQUEST=REQUEST
|
||||
) # -> copy distant files if needed
|
||||
if not sco_photos.etud_photo_is_local(context, t):
|
||||
@ -327,13 +337,7 @@ def _trombino_pdf(context, groups_infos, REQUEST):
|
||||
[img],
|
||||
[
|
||||
Paragraph(
|
||||
SU(
|
||||
scolars.format_sexe(t["sexe"])
|
||||
+ " "
|
||||
+ scolars.format_prenom(t["prenom"])
|
||||
+ " "
|
||||
+ scolars.format_nom(t["nom"])
|
||||
),
|
||||
SU(scolars.format_nomprenom(t)),
|
||||
StyleSheet["Normal"],
|
||||
)
|
||||
],
|
||||
@ -366,7 +370,7 @@ def _trombino_pdf(context, groups_infos, REQUEST):
|
||||
# Build document
|
||||
document = BaseDocTemplate(report)
|
||||
document.addPageTemplates(
|
||||
ScolarsPageTemplate(
|
||||
sco_pdf.ScolarsPageTemplate(
|
||||
document,
|
||||
context=context,
|
||||
preferences=context.get_preferences(sem["formsemestre_id"]),
|
||||
@ -375,7 +379,7 @@ def _trombino_pdf(context, groups_infos, REQUEST):
|
||||
document.build(objects)
|
||||
data = report.getvalue()
|
||||
|
||||
return sendPDFFile(REQUEST, data, filename)
|
||||
return scu.sendPDFFile(REQUEST, data, filename)
|
||||
|
||||
|
||||
# --------------------- Sur une idée de l'IUT d'Orléans:
|
||||
@ -385,8 +389,8 @@ def _listeappel_photos_pdf(context, groups_infos, REQUEST):
|
||||
sem = groups_infos.formsemestre # suppose 1 seul semestre
|
||||
|
||||
PHOTOWIDTH = 2 * cm
|
||||
COLWIDTH = 3.6 * cm
|
||||
ROWS_PER_PAGE = 26 # XXX should be in ScoDoc preferences
|
||||
# COLWIDTH = 3.6 * cm
|
||||
# ROWS_PER_PAGE = 26 # XXX should be in ScoDoc preferences
|
||||
|
||||
StyleSheet = styles.getSampleStyleSheet()
|
||||
report = StringIO() # in-memory document, no disk file
|
||||
@ -412,13 +416,7 @@ def _listeappel_photos_pdf(context, groups_infos, REQUEST):
|
||||
t = groups_infos.members[i]
|
||||
img = _get_etud_platypus_image(context, t, image_width=PHOTOWIDTH)
|
||||
txt = Paragraph(
|
||||
SU(
|
||||
scolars.format_sexe(t["sexe"])
|
||||
+ " "
|
||||
+ scolars.format_prenom(t["prenom"])
|
||||
+ " "
|
||||
+ scolars.format_nom(t["nom"])
|
||||
),
|
||||
SU(scolars.format_nomprenom(t)),
|
||||
StyleSheet["Normal"],
|
||||
)
|
||||
if currow:
|
||||
@ -449,7 +447,7 @@ def _listeappel_photos_pdf(context, groups_infos, REQUEST):
|
||||
# Build document
|
||||
document = BaseDocTemplate(report)
|
||||
document.addPageTemplates(
|
||||
ScolarsPageTemplate(
|
||||
sco_pdf.ScolarsPageTemplate(
|
||||
document,
|
||||
context,
|
||||
preferences=context.get_preferences(sem["formsemestre_id"]),
|
||||
@ -458,72 +456,7 @@ def _listeappel_photos_pdf(context, groups_infos, REQUEST):
|
||||
document.build(objects)
|
||||
data = report.getvalue()
|
||||
|
||||
return sendPDFFile(REQUEST, data, filename)
|
||||
|
||||
objects = []
|
||||
StyleSheet = styles.getSampleStyleSheet()
|
||||
report = StringIO() # in-memory document, no disk file
|
||||
filename = ("trombino-%s.pdf" % ng).replace(
|
||||
" ", "_"
|
||||
) # XXX should sanitize this filename
|
||||
objects.append(
|
||||
Paragraph(SU("Liste " + sem["titreannee"] + " " + ng), StyleSheet["Heading3"])
|
||||
)
|
||||
PHOTOWIDTH = 3 * cm
|
||||
COLWIDTH = 3.6 * cm
|
||||
|
||||
L = [] # cells
|
||||
n = 0
|
||||
currow = []
|
||||
for t in T:
|
||||
n = n + 1
|
||||
img = _get_etud_platypus_image(context, t, image_width=2 * cm)
|
||||
currow += [
|
||||
Paragraph(
|
||||
SU(
|
||||
scolars.format_sexe(t["sexe"])
|
||||
+ " "
|
||||
+ scolars.format_prenom(t["prenom"])
|
||||
+ " "
|
||||
+ scolars.format_nom(t["nom"])
|
||||
),
|
||||
StyleSheet["Normal"],
|
||||
),
|
||||
"", # empty cell (signature ou autre info a remplir sur papier)
|
||||
img,
|
||||
]
|
||||
|
||||
if not L:
|
||||
table = Paragraph(SU("Aucune photo à exporter !"), StyleSheet["Normal"])
|
||||
else:
|
||||
table = Table(
|
||||
L,
|
||||
colWidths=[COLWIDTH] * 7,
|
||||
style=TableStyle(
|
||||
[
|
||||
("VALIGN", (0, 0), (-1, -1), "TOP"),
|
||||
("GRID", (0, 0), (2, -1), 0.25, colors.grey),
|
||||
("GRID", (2, 0), (-1, -1), 0.25, colors.red), # <<<
|
||||
]
|
||||
),
|
||||
)
|
||||
objects.append(table)
|
||||
|
||||
# Réduit sur une page
|
||||
objects = [KeepInFrame(0, 0, objects, mode="shrink")]
|
||||
|
||||
# --- Build document
|
||||
document = BaseDocTemplate(report)
|
||||
document.addPageTemplates(
|
||||
ScolarsPageTemplate(
|
||||
document,
|
||||
context=context,
|
||||
preferences=context.get_preferences(sem["formsemestre_id"]),
|
||||
)
|
||||
)
|
||||
document.build(objects)
|
||||
data = report.getvalue()
|
||||
return sendPDFFile(REQUEST, data, filename)
|
||||
return scu.sendPDFFile(REQUEST, data, filename)
|
||||
|
||||
|
||||
# --------------------- Upload des photos de tout un groupe
|
||||
@ -614,7 +547,7 @@ def photos_import_files(
|
||||
def callback(context, etud, data, filename, REQUEST):
|
||||
sco_photos.store_photo(context, etud, data, REQUEST)
|
||||
|
||||
r = zip_excel_import_files(
|
||||
zip_excel_import_files(
|
||||
context, xlsfile, zipfile, REQUEST, callback, filename_title, page_title
|
||||
)
|
||||
return REQUEST.RESPONSE.redirect(back_url + "&head_message=photos%20 importees")
|
||||
@ -638,7 +571,7 @@ def zip_excel_import_files(
|
||||
exceldata = xlsfile.read()
|
||||
if not exceldata:
|
||||
raise ScoValueError("Fichier excel vide ou invalide")
|
||||
diag, data = sco_excel.Excel_to_list(exceldata)
|
||||
_, data = sco_excel.Excel_to_list(exceldata)
|
||||
if not data: # probably a bug
|
||||
raise ScoValueError("Fichier excel vide !")
|
||||
# on doit avoir une colonne etudid et une colonne filename_title ('fichier_photo')
|
||||
@ -657,7 +590,7 @@ def zip_excel_import_files(
|
||||
fn = fn.replace("\\", "/") # not sure if this is necessary ?
|
||||
fn = fn.strip()
|
||||
if lowercase:
|
||||
fn = strlower(fn)
|
||||
fn = scu.strlower(fn)
|
||||
fn = fn.split("/")[-1] # use only last component, not directories
|
||||
return fn
|
||||
|
||||
|
@ -38,8 +38,8 @@ from zipfile import ZipFile, BadZipfile
|
||||
import xml
|
||||
import tempfile
|
||||
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
from sco_utils import *
|
||||
import sco_abs
|
||||
import scolars
|
||||
import sco_photos
|
||||
@ -283,7 +283,7 @@ def pdf_trombino_tours(
|
||||
document.build(objects)
|
||||
data = report.getvalue()
|
||||
|
||||
return sendPDFFile(REQUEST, data, filename)
|
||||
return scu.sendPDFFile(REQUEST, data, filename)
|
||||
|
||||
|
||||
# Feuille d'absences en pdf avec photos:
|
||||
@ -477,4 +477,4 @@ def pdf_feuille_releve_absences(
|
||||
document.build(objects)
|
||||
data = report.getvalue()
|
||||
|
||||
return sendPDFFile(REQUEST, data, filename)
|
||||
return scu.sendPDFFile(REQUEST, data, filename)
|
||||
|
@ -54,14 +54,17 @@ Solution proposée (nov 2014):
|
||||
|
||||
"""
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
import notesdb as ndb
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
import sco_formsemestre
|
||||
import sco_moduleimpl
|
||||
import sco_edit_ue
|
||||
import sco_saisie_notes
|
||||
import sco_codes_parcours
|
||||
from TrivialFormulator import TrivialFormulator, tf_error_message
|
||||
from sco_permissions import ScoImplement
|
||||
from sco_exceptions import AccessDenied, ScoValueError
|
||||
|
||||
|
||||
def external_ue_create(
|
||||
@ -69,7 +72,7 @@ def external_ue_create(
|
||||
formsemestre_id,
|
||||
titre="",
|
||||
acronyme="",
|
||||
ue_type=UE_STANDARD,
|
||||
ue_type=sco_codes_parcours.UE_STANDARD,
|
||||
ects=0.0,
|
||||
REQUEST=None,
|
||||
):
|
||||
@ -162,7 +165,7 @@ def external_ue_inscrit_et_note(
|
||||
description="note externe",
|
||||
)
|
||||
# Saisie des notes
|
||||
nbchanged, nbsuppress, existing_decisions = sco_saisie_notes._notes_add(
|
||||
_, _, _ = sco_saisie_notes._notes_add(
|
||||
context,
|
||||
REQUEST.AUTHENTICATED_USER,
|
||||
evaluation_id,
|
||||
@ -178,7 +181,7 @@ def get_existing_external_ue(context, formation_id):
|
||||
|
||||
def get_external_moduleimpl_id(context, formsemestre_id, ue_id):
|
||||
"moduleimpl correspondant à l'UE externe indiquée de ce formsemestre"
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""
|
||||
SELECT moduleimpl_id FROM notes_moduleimpl mi, notes_modules mo
|
||||
@ -235,7 +238,7 @@ def external_ue_create_form(context, formsemestre_id, etudid, REQUEST=None):
|
||||
parcours = sco_codes_parcours.get_parcours_from_code(Fo["type_parcours"])
|
||||
ue_types = parcours.ALLOWED_UE_TYPES
|
||||
ue_types.sort()
|
||||
ue_types_names = [UE_TYPE_NAME[k] for k in ue_types]
|
||||
ue_types_names = [sco_codes_parcours.UE_TYPE_NAME[k] for k in ue_types]
|
||||
ue_types = [str(x) for x in ue_types]
|
||||
|
||||
if existing_external_ue:
|
||||
|
@ -35,7 +35,7 @@ Pour une évaluation:
|
||||
- historique: table notes_notes_log
|
||||
|
||||
saisie de notes == saisir ou supprimer une ou plusieurs notes (mêmes date et uid)
|
||||
/!\ tolérance sur les dates (200ms ?)
|
||||
! tolérance sur les dates (200ms ?)
|
||||
Chaque saisie affecte ou remplace une ou plusieurs notes.
|
||||
|
||||
Opérations:
|
||||
@ -48,12 +48,13 @@ Opérations:
|
||||
import datetime
|
||||
from intervals import intervalmap
|
||||
|
||||
from sco_utils import *
|
||||
from notesdb import *
|
||||
import sco_utils as scu
|
||||
import notesdb as ndb
|
||||
from notes_log import log
|
||||
from gen_tables import GenTable
|
||||
import sco_formsemestre
|
||||
import sco_moduleimpl
|
||||
import VERSION
|
||||
|
||||
# deux notes (de même uid) sont considérées comme de la même opération si
|
||||
# elles sont séparées de moins de 2*tolerance:
|
||||
@ -121,7 +122,7 @@ def list_operations(context, evaluation_id):
|
||||
|
||||
Ops = []
|
||||
for uid in NotesDates.keys():
|
||||
for (t0, t1), notes in NotesDates[uid].items():
|
||||
for (t0, _), notes in NotesDates[uid].items():
|
||||
Op = NotesOperation(
|
||||
evaluation_id=evaluation_id,
|
||||
date=t0,
|
||||
@ -166,7 +167,7 @@ def formsemestre_list_saisies_notes(
|
||||
):
|
||||
"""Table listant toutes les operations de saisies de notes, dans toutes les evaluations du semestre."""
|
||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||
r = SimpleDictFetch(
|
||||
r = ndb.SimpleDictFetch(
|
||||
context,
|
||||
"""select i.nom, n.*, mod.titre, e.description, e.jour from notes_notes n, notes_evaluation e, notes_moduleimpl m, notes_modules mod, identite i where m.moduleimpl_id = e.moduleimpl_id and m.module_id = mod.module_id and e.evaluation_id=n.evaluation_id and i.etudid=n.etudid and m.formsemestre_id=%(formsemestre_id)s order by date desc""",
|
||||
{"formsemestre_id": formsemestre_id},
|
||||
@ -201,7 +202,7 @@ def formsemestre_list_saisies_notes(
|
||||
caption="Saisies de notes dans %s" % sem["titreannee"],
|
||||
preferences=context.get_preferences(formsemestre_id),
|
||||
base_url="%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id),
|
||||
origin="Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + "",
|
||||
origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
|
||||
)
|
||||
return tab.make_page(context, format=format, REQUEST=REQUEST)
|
||||
|
||||
@ -212,7 +213,7 @@ def get_note_history(context, evaluation_id, etudid, REQUEST=None, fmt=""):
|
||||
[ { 'value', 'date', 'comment', 'uid' } ]
|
||||
"""
|
||||
cnx = context.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
|
||||
# Valeur courante
|
||||
cursor.execute(
|
||||
@ -242,7 +243,7 @@ def get_note_history(context, evaluation_id, etudid, REQUEST=None, fmt=""):
|
||||
x["user_name"] = context.Users.user_info(x["uid"])["nomcomplet"]
|
||||
|
||||
if fmt == "json":
|
||||
return sendJSON(REQUEST, history)
|
||||
return scu.sendJSON(REQUEST, history)
|
||||
else:
|
||||
return history
|
||||
|
||||
|
@ -29,8 +29,11 @@
|
||||
""" Verification version logiciel vs version "stable" sur serveur
|
||||
N'effectue pas la mise à jour automatiquement, mais permet un affichage d'avertissement.
|
||||
"""
|
||||
import sco_utils
|
||||
from sco_utils import *
|
||||
import datetime
|
||||
import re
|
||||
|
||||
import sco_utils as scu
|
||||
from notes_log import log
|
||||
|
||||
# Appel renvoyant la subversion "stable"
|
||||
# La notion de "stable" est juste là pour éviter d'afficher trop frequemment
|
||||
@ -46,7 +49,9 @@ def get_last_stable_version():
|
||||
(do not wait server answer more than 3 seconds)
|
||||
"""
|
||||
global _LAST_UP_TO_DATE_REQUEST
|
||||
ans = query_portal(GET_VER_URL, msg="ScoDoc version server", timeout=3) # sco_utils
|
||||
ans = scu.query_portal(
|
||||
GET_VER_URL, msg="ScoDoc version server", timeout=3
|
||||
) # sco_utils
|
||||
if ans:
|
||||
ans = ans.strip()
|
||||
_LAST_UP_TO_DATE_REQUEST = datetime.datetime.now()
|
||||
@ -76,7 +81,7 @@ def is_up_to_date(context):
|
||||
# return _UP_TO_DATE, _UP_TO_DATE_MSG
|
||||
|
||||
# last_stable_ver = get_last_stable_version()
|
||||
# cur_ver = sco_utils.get_scodoc_version()
|
||||
# cur_ver = scu.get_svn_version(context.file_path) # in sco_utils
|
||||
# cur_ver2 = cur_ver
|
||||
# cur_ver_num = -1
|
||||
# # Convert versions to integers:
|
||||
|
69
sco_utils.py
69
sco_utils.py
@ -28,30 +28,22 @@
|
||||
|
||||
""" Common definitions
|
||||
"""
|
||||
import pdb
|
||||
import os, sys, copy, re
|
||||
import pprint
|
||||
import traceback
|
||||
from types import (
|
||||
StringType,
|
||||
IntType,
|
||||
FloatType,
|
||||
UnicodeType,
|
||||
ListType,
|
||||
TupleType,
|
||||
InstanceType,
|
||||
)
|
||||
import operator, bisect
|
||||
import collections
|
||||
import os
|
||||
import sys
|
||||
import copy
|
||||
import re
|
||||
import bisect
|
||||
import types
|
||||
import numbers
|
||||
import thread
|
||||
import urllib
|
||||
import urllib2
|
||||
import socket
|
||||
import xml.sax.saxutils
|
||||
import xml, xml.dom.minidom
|
||||
import time, datetime, cgi
|
||||
import mx
|
||||
import time
|
||||
import datetime
|
||||
import json
|
||||
|
||||
# XML generation package (apt-get install jaxml)
|
||||
import jaxml
|
||||
|
||||
try:
|
||||
import six
|
||||
@ -59,25 +51,16 @@ try:
|
||||
STRING_TYPES = six.string_types
|
||||
except ImportError:
|
||||
# fallback for very old ScoDoc instances
|
||||
STRING_TYPES = StringType
|
||||
STRING_TYPES = types.StringType
|
||||
|
||||
from PIL import Image as PILImage
|
||||
|
||||
# XML generation package (apt-get install jaxml)
|
||||
import jaxml
|
||||
|
||||
import json
|
||||
|
||||
from VERSION import SCOVERSION
|
||||
import VERSION
|
||||
|
||||
from SuppressAccents import suppression_diacritics
|
||||
from sco_exceptions import *
|
||||
from sco_permissions import *
|
||||
from TrivialFormulator import TrivialFormulator, TF, tf_error_message
|
||||
from notes_log import log, logCallStack
|
||||
|
||||
from sco_codes_parcours import *
|
||||
from notes_log import log
|
||||
from sco_codes_parcours import NOTES_TOLERANCE, CODES_EXPL
|
||||
|
||||
# ----- CALCUL ET PRESENTATION DES NOTES
|
||||
NOTES_PRECISION = 1e-4 # evite eventuelles erreurs d'arrondis
|
||||
@ -140,7 +123,7 @@ def fmt_note(val, note_max=None, keep_numeric=False):
|
||||
return "EXC" # excuse, note neutralise
|
||||
if val == NOTES_ATTENTE:
|
||||
return "ATT" # attente, note neutralisee
|
||||
if type(val) == FloatType or type(val) == IntType:
|
||||
if type(val) == types.FloatType or type(val) == types.IntType:
|
||||
if note_max != None and note_max > 0:
|
||||
val = val * 20.0 / note_max
|
||||
if keep_numeric:
|
||||
@ -369,7 +352,7 @@ def unescape_html_dict(d):
|
||||
indices = range(len(d))
|
||||
for k in indices:
|
||||
v = d[k]
|
||||
if type(v) == StringType:
|
||||
if type(v) == types.StringType:
|
||||
d[k] = unescape_html(v)
|
||||
elif isiterable(v):
|
||||
unescape_html_dict(v)
|
||||
@ -414,11 +397,11 @@ def simple_dictlist2xml(dictlist, doc=None, tagname=None, quote=False):
|
||||
raise ValueError("invalid empty tagname !")
|
||||
if not doc:
|
||||
doc = jaxml.XML_document(encoding=SCO_ENCODING)
|
||||
scalar_types = [StringType, UnicodeType, IntType, FloatType]
|
||||
scalar_types = [types.StringType, types.UnicodeType, types.IntType, types.FloatType]
|
||||
for d in dictlist:
|
||||
doc._push()
|
||||
if (
|
||||
type(d) == InstanceType or type(d) in scalar_types
|
||||
type(d) == types.InstanceType or type(d) in scalar_types
|
||||
): # pour ApoEtapeVDI et listes de chaines
|
||||
getattr(doc, tagname)(code=str(d))
|
||||
else:
|
||||
@ -435,7 +418,7 @@ def simple_dictlist2xml(dictlist, doc=None, tagname=None, quote=False):
|
||||
[(k, v) for (k, v) in d.items() if type(v) in scalar_types]
|
||||
)
|
||||
getattr(doc, tagname)(**d_scalar)
|
||||
d_list = dict([(k, v) for (k, v) in d.items() if type(v) == ListType])
|
||||
d_list = dict([(k, v) for (k, v) in d.items() if type(v) == types.ListType])
|
||||
if d_list:
|
||||
for (k, v) in d_list.items():
|
||||
simple_dictlist2xml(v, doc=doc, tagname=k, quote=quote)
|
||||
@ -547,15 +530,15 @@ class ScoDocJSONEncoder(json.JSONEncoder):
|
||||
def default(self, o): # pylint: disable=E0202
|
||||
import sco_formsemestre
|
||||
|
||||
# horrible hack pour encoder les dates mx
|
||||
# ScoDoc 7.22 n'utilise plus mx:
|
||||
if str(type(o)) == "<type 'mx.DateTime.DateTime'>":
|
||||
log("Warning: mx.DateTime object detected !")
|
||||
return o.strftime("%Y-%m-%dT%H:%M:%S")
|
||||
if isinstance(o, (datetime.date, datetime.datetime)):
|
||||
return o.isoformat()
|
||||
elif isinstance(o, sco_formsemestre.ApoEtapeVDI):
|
||||
return str(o)
|
||||
else:
|
||||
log("not mx: %s" % type(o))
|
||||
return json.JSONEncoder.default(self, o)
|
||||
|
||||
|
||||
@ -567,7 +550,7 @@ def sendJSON(REQUEST, data):
|
||||
|
||||
|
||||
def sendXML(REQUEST, data, tagname=None, force_outer_xml_tag=True):
|
||||
if type(data) != ListType:
|
||||
if type(data) != types.ListType:
|
||||
data = [data] # always list-of-dicts
|
||||
if force_outer_xml_tag:
|
||||
root_tagname = tagname + "_list"
|
||||
@ -702,7 +685,7 @@ if WITH_PYDOT:
|
||||
junk_graph = pydot.Dot("junk")
|
||||
junk_graph.add_node(pydot.Node("a"))
|
||||
n = junk_graph.get_node("a")
|
||||
if type(n) == type([]):
|
||||
if type(n) == type([]): # "modern" pydot
|
||||
|
||||
def pydot_get_node(g, name):
|
||||
r = g.get_node(name)
|
||||
@ -711,7 +694,7 @@ if WITH_PYDOT:
|
||||
else:
|
||||
return r[0]
|
||||
|
||||
else:
|
||||
else: # very old pydot
|
||||
|
||||
def pydot_get_node(g, name):
|
||||
return g.get_node(name)
|
||||
@ -757,7 +740,7 @@ def scodoc_html2txt(html):
|
||||
|
||||
def is_valid_mail(email):
|
||||
"""True if well-formed email address"""
|
||||
return re.match("^.+@.+\..{2,3}$", email)
|
||||
return re.match(r"^.+@.+\..{2,3}$", email)
|
||||
|
||||
|
||||
ICONSIZES = {} # name : (width, height) cache image sizes
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
"""Imports et configuration des composants Zope
|
||||
"""
|
||||
# Avoid pylint warnings when linting without Zope
|
||||
# pylint: skip-file
|
||||
|
||||
# Allows code linting on platforms without Zope:
|
||||
# pylint: disable=import-error
|
||||
|
79
scolars.py
79
scolars.py
@ -98,7 +98,7 @@ def format_etud_ident(etud):
|
||||
else:
|
||||
etud["nom_usuel"] = ""
|
||||
etud["prenom"] = format_prenom(etud["prenom"])
|
||||
etud["sexe"] = format_sexe(etud["sexe"])
|
||||
etud["civilite_str"] = format_civilite(etud["civilite"])
|
||||
# Nom à afficher:
|
||||
if etud["nom_usuel"]:
|
||||
etud["nom_disp"] = etud["nom_usuel"]
|
||||
@ -108,10 +108,12 @@ def format_etud_ident(etud):
|
||||
etud["nom_disp"] = etud["nom"]
|
||||
|
||||
etud["nomprenom"] = format_nomprenom(etud) # M. Pierre DUPONT
|
||||
if etud["sexe"] == "M.":
|
||||
if etud["civilite"] == "M":
|
||||
etud["ne"] = ""
|
||||
else:
|
||||
elif etud["civilite"] == "F":
|
||||
etud["ne"] = "e"
|
||||
else: # 'X'
|
||||
etud["ne"] = "(e)"
|
||||
# Mail à utiliser pour les envois vers l'étudiant:
|
||||
# choix qui pourrait être controé par une preference
|
||||
# ici priorité au mail institutionnel:
|
||||
@ -124,15 +126,22 @@ def force_uppercase(s):
|
||||
return s
|
||||
|
||||
|
||||
def format_nomprenom(etud):
|
||||
"formatte sexe/nom/prenom pour affichages"
|
||||
return " ".join(
|
||||
[format_sexe(etud["sexe"]), format_prenom(etud["prenom"]), etud["nom_disp"]]
|
||||
)
|
||||
def format_nomprenom(etud, reverse=False):
|
||||
"""Formatte civilité/nom/prenom pour affichages: "M. Pierre Dupont"
|
||||
Si reverse, "Dupont Pierre", sans civilité.
|
||||
"""
|
||||
nom = etud.get("nom_disp", "") or etud.get("nom_usuel", "") or etud["nom"]
|
||||
prenom = format_prenom(etud["prenom"])
|
||||
civilite = format_civilite(etud["civilite"])
|
||||
if reverse:
|
||||
fs = [nom, prenom]
|
||||
else:
|
||||
fs = [civilite, prenom, nom]
|
||||
return " ".join([x for x in fs if x])
|
||||
|
||||
|
||||
def format_prenom(s):
|
||||
"formatte prenom etudiant pour affichage"
|
||||
"Formatte prenom etudiant pour affichage"
|
||||
if not s:
|
||||
return ""
|
||||
frags = s.split()
|
||||
@ -159,22 +168,33 @@ def format_nom(s, uppercase=True):
|
||||
return format_prenom(s)
|
||||
|
||||
|
||||
def format_sexe(sexe):
|
||||
sexe = scu.strlower(sexe)
|
||||
if sexe == "mr" or sexe == "m." or sexe == "m":
|
||||
return "M."
|
||||
else:
|
||||
return "Mme"
|
||||
def input_civilite(s):
|
||||
"""Converts external representation of civilite to internal:
|
||||
'M', 'F', or 'X' (and nothing else).
|
||||
Raises valueError if conversion fails.
|
||||
"""
|
||||
s = scu.strupper(s).strip()
|
||||
if s in ("M", "M.", "MR", "H"):
|
||||
return "M"
|
||||
elif s in ("F", "MLLE", "MLLE.", "MELLE", "MME"):
|
||||
return "F"
|
||||
elif s == "X" or not s:
|
||||
return "X"
|
||||
raise ValueError("valeur invalide pour la civilité: %s" % s)
|
||||
|
||||
|
||||
def normalize_sexe(sexe):
|
||||
"returns 'MR' ou 'MME'"
|
||||
sexe = scu.strupper(sexe).strip()
|
||||
if sexe in ("M.", "M", "MR", "H"):
|
||||
return "MR"
|
||||
elif sexe in ("MLLE", "MLLE.", "MELLE", "MME", "F"):
|
||||
return "MME"
|
||||
raise ValueError("valeur invalide pour le sexe: %s" % sexe)
|
||||
def format_civilite(civilite):
|
||||
"""returns 'M.' ou 'Mme' ou '' (pour le genre neutre,
|
||||
personne ne souhaitant pas d'affichage)
|
||||
"""
|
||||
try:
|
||||
return {
|
||||
"M": "M.",
|
||||
"F": "Mme",
|
||||
"X": "",
|
||||
}[civilite]
|
||||
except KeyError:
|
||||
raise ValueError("valeur invalide pour la civilité: %s" % civilite)
|
||||
|
||||
|
||||
def format_lycee(nomlycee):
|
||||
@ -238,7 +258,7 @@ _identiteEditor = EditableTable(
|
||||
"nom",
|
||||
"nom_usuel",
|
||||
"prenom",
|
||||
"sexe",
|
||||
"civilite", # 'M", "F", or "X"
|
||||
"date_naissance",
|
||||
"lieu_naissance",
|
||||
"dept_naissance",
|
||||
@ -254,10 +274,10 @@ _identiteEditor = EditableTable(
|
||||
input_formators={
|
||||
"nom": force_uppercase,
|
||||
"prenom": force_uppercase,
|
||||
"sexe": force_uppercase,
|
||||
"civilite": input_civilite,
|
||||
"date_naissance": DateDMYtoISO,
|
||||
},
|
||||
output_formators={"date_naissance": DateISOtoDMY, "sexe": normalize_sexe},
|
||||
output_formators={"date_naissance": DateISOtoDMY},
|
||||
convert_null_outputs_to_empty=True,
|
||||
allow_set_id=True, # car on specifie le code Apogee a la creation
|
||||
)
|
||||
@ -266,13 +286,14 @@ identite_delete = _identiteEditor.delete
|
||||
|
||||
|
||||
def identite_list(cnx, *a, **kw):
|
||||
"list, add 'annee_naissance'"
|
||||
"""List, adding on the fly 'annee_naissance' and 'civilite_str' (M., Mme, "")."""
|
||||
objs = _identiteEditor.list(cnx, *a, **kw)
|
||||
for o in objs:
|
||||
if o["date_naissance"]:
|
||||
o["annee_naissance"] = int(o["date_naissance"].split("/")[2])
|
||||
else:
|
||||
o["annee_naissance"] = o["date_naissance"]
|
||||
o["civilite_str"] = format_civilite(o["civilite"])
|
||||
return objs
|
||||
|
||||
|
||||
@ -369,7 +390,6 @@ def identite_edit(cnx, args, context=None, REQUEST=None):
|
||||
if notify_to:
|
||||
# etat AVANT edition pour envoyer diffs
|
||||
before = identite_list(cnx, {"etudid": args["etudid"]})[0]
|
||||
before["sexe"] = format_sexe(before["sexe"])
|
||||
|
||||
identite_edit_nocheck(cnx, args)
|
||||
|
||||
@ -377,7 +397,6 @@ def identite_edit(cnx, args, context=None, REQUEST=None):
|
||||
if notify_to:
|
||||
etud = context.getEtudInfo(etudid=args["etudid"], filled=True)[0]
|
||||
after = identite_list(cnx, {"etudid": args["etudid"]})[0]
|
||||
after["sexe"] = format_sexe(after["sexe"])
|
||||
notify_etud_change(
|
||||
context,
|
||||
notify_to,
|
||||
@ -409,7 +428,7 @@ def notify_etud_change(context, email_addr, etud, before, after, subject):
|
||||
"""
|
||||
txt = [
|
||||
"Code NIP:" + etud["code_nip"],
|
||||
"Genre: " + etud["sexe"],
|
||||
"Civilité: " + etud["civilite_str"],
|
||||
"Nom: " + etud["nom"],
|
||||
"Prénom: " + etud["prenom"],
|
||||
"Etudid: " + etud["etudid"],
|
||||
|
14
scolog.py
14
scolog.py
@ -26,9 +26,11 @@
|
||||
##############################################################################
|
||||
|
||||
|
||||
import pdb, os, sys
|
||||
from sco_exceptions import *
|
||||
from notesdb import *
|
||||
import pdb
|
||||
import os
|
||||
import sys
|
||||
|
||||
import notesdb as ndb
|
||||
from notes_log import retreive_request
|
||||
|
||||
|
||||
@ -46,8 +48,8 @@ def logdb(REQUEST=None, cnx=None, method=None, etudid=None, msg=None, commit=Tru
|
||||
else:
|
||||
args = {"authenticated_user": None, "remote_addr": None, "remote_host": None}
|
||||
args.update({"method": method, "etudid": etudid, "msg": msg})
|
||||
quote_dict(args)
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
ndb.quote_dict(args)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"insert into scolog (authenticated_user,remote_addr,remote_host,method,etudid,msg) values (%(authenticated_user)s,%(remote_addr)s,%(remote_host)s,%(method)s,%(etudid)s,%(msg)s)",
|
||||
args,
|
||||
@ -58,7 +60,7 @@ def logdb(REQUEST=None, cnx=None, method=None, etudid=None, msg=None, commit=Tru
|
||||
|
||||
def loglist(cnx, method=None, authenticated_user=None):
|
||||
"""List of events logged for these method and user"""
|
||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"select * from scolog where method=%(method)s and authenticated_user=%(authenticated_user)s",
|
||||
{"method": method, "authenticated_user": authenticated_user},
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user