Compare commits

...

20 Commits

Author SHA1 Message Date
IDK
dc4bfe4d2e Merge ScoDoc 7.23
Merge branch 'master' of https://scodoc.org/git/viennet/ScoDoc into ScoDoc8
2021-02-13 23:18:32 +01:00
a50a9eb8e8 Merge pull request 'nosex' (#66) from nosex into master
Reviewed-on: https://scodoc.org/git/viennet/ScoDoc/pulls/66
2021-02-13 22:12:56 +01:00
54771c8303 Nom avant prenom sur formulaire saisie notes + deco+ + linted css. 2021-02-13 22:06:03 +01:00
91bb62587a Closes #11 2021-02-13 21:28:59 +01:00
2f4edc48dc 7.23 / pylint pv jury 2021-02-13 19:20:21 +01:00
8f02f16442 Handling of neutral genders.
Closes #65
2021-02-13 17:28:55 +01:00
IDK
8d7ec2faea Fix all redirects for Flask compatibility 2021-02-07 15:31:35 +01:00
IDK
154e7bf3e8 Replaced Zope URL1 and URL2 2021-02-07 09:10:26 +01:00
IDK
860ca5d8f7 pylint 2021-02-05 22:16:30 +01:00
031c877afb pylint 2021-02-05 21:35:21 +01:00
c8c58e54c4 Fix: controle affichage code et date naissance sur PV jury pdf 2021-02-05 21:34:26 +01:00
IDK
de7d66e8e8 Fix: bug display selected students on export apo 2021-02-05 19:06:42 +01:00
IDK
6d17f030e2 removed old mxDateTime 2021-02-05 18:21:34 +01:00
IDK
66be2a41c9 test absences 2021-02-04 23:16:18 +01:00
IDK
2835777ea6 Changed sco_utils import 2021-02-04 20:02:44 +01:00
IDK
284257e5e1 code cleaning 2021-02-03 22:13:03 +01:00
IDK
aefd14b420 refactoring: notesdb usage 2021-02-03 22:00:41 +01:00
IDK
b86c815b02 pylinting 2021-02-02 14:49:49 +01:00
IDK
1576a64ccd pylinting 2021-02-01 23:54:46 +01:00
a4173e1877 Fix bulletins legacy + refactoring 2021-02-01 16:23:11 +01:00
108 changed files with 2184 additions and 1745 deletions

View File

@ -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)

View File

@ -9,7 +9,7 @@
v 1.2
"""
from types import *
from types import BooleanType, StringType
def TrivialFormulator(
@ -44,7 +44,7 @@ def TrivialFormulator(
-1 cancel (if cancelbutton specified)
HTML form: html string (form to insert in your web page)
values: None or, when the form is submitted and correctly filled,
a dictionnary with the requeted values.
a dictionnary with the requeted values.
formdescription: sequence [ (field, description), ... ]
where description is a dict with following (optional) keys:
default : default value for this field ('')
@ -63,7 +63,7 @@ def TrivialFormulator(
withcheckbox: if true, place a checkbox at the left of the input
elem. Checked items will be returned in 'tf-checked'
attributes: a liste of strings to put in the HTML form element
template: HTML template for element
template: HTML template for element
HTML elements:
input_type : 'text', 'textarea', 'password',
'radio', 'menu', 'checkbox',
@ -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

View File

@ -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

View File

@ -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é&nbsp;:
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é&nbsp;:
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é&nbsp;:
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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>&copy; Emmanuel Viennet 1997-2020</p>
<p>&copy; 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&amp;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):&nbsp;</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(

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -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"

View File

@ -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>"""
)

View File

@ -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/>&nbsp;") # /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/>

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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 }}

View File

@ -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)

View File

@ -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(

View File

@ -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)

View File

@ -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,14 +59,14 @@ 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 :
- resultats: {tag: { etudid: (note_moy, somme_coff), ...} , ...}
- rang
- statistiques
Redéfinition :
- get_etudids() : les etudids des étudiants non défaillants ni démissionnaires
"""
@ -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]
# -----------------------------------------------------------------------------
@ -154,7 +155,7 @@ class SemestreTag(pe_tagtable.TableTag):
Renvoie le dictionnaire ainsi construit.
Rq: choix fait de repérer les modules par rapport à leur modimpl_id (valable uniquement pour un semestre), car
correspond à la majorité des calculs de moyennes pour les étudiants
correspond à la majorité des calculs de moyennes pour les étudiants
(seuls ceux qui ont capitalisé des ue auront un régime de calcul différent).
"""
tagdict = {}
@ -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é,
@ -313,10 +314,10 @@ class SemestreTag(pe_tagtable.TableTag):
# -----------------------------------------------------------------------------
def get_listesNotesEtCoeffsTagEtudiant(self, tag, etudid):
"""Renvoie un triplet (notes, coeffs_norm, ponderations) où notes, coeff_norm et ponderation désignent trois listes
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). """
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)."""
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
)
@ -471,14 +472,15 @@ def comp_coeff_pond(coeffs, ponderations):
# -----------------------------------------------------------------------------
def get_moduleimpl(nt, modimpl_id):
"""Renvoie l'objet modimpl dont l'id est modimpl_id fourni dans la note table nt,
en utilisant l'attribut nt._modimpls"""
en utilisant l'attribut nt._modimpls"""
modimplids = [
modimpl["moduleimpl_id"] for modimpl in nt._modimpls
] # 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)]

View File

@ -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

View File

@ -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))
# ************************************************************************

View File

@ -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": {

View File

@ -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"

View File

@ -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

View File

@ -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)

View File

@ -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">

View File

@ -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)

View File

@ -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...

View File

@ -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)

View File

@ -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"] = "&nbsp;" + 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&amp;etudid=%s&amp;format=pdf&amp;version=%s"
% (formsemestre_id, etudid, version),
ICON_PDF,
scu.ICON_PDF,
)
)
H.append("""</tr></table>""")

View File

@ -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
),

View File

@ -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"]),
)
)
#

View File

@ -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)

View File

@ -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"
)

View File

@ -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

View File

@ -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

View File

@ -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"],

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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":

View File

@ -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(

View File

@ -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 (

View File

@ -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},

View File

@ -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,
)

View File

@ -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",

View File

@ -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

View File

@ -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:

View File

@ -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()

View File

@ -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 = []

View File

@ -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

View File

@ -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,
"&amp;types_parcours=".join([str(x) for s in types_parcours]),
"&amp;types_parcours=".join([str(x) for x in types_parcours]),
)
if format != "html":
return tab.make_page(

View File

@ -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",

View File

@ -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",

View File

@ -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">

View File

@ -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)

View File

@ -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&amp;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))
)

View File

@ -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 = {}

View File

@ -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

View File

@ -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 += "&amp;sortcol=" + sortcol
if desturl:
desturl += "&amp;desturl=" + desturl
REQUEST.RESPONSE.redirect(adr)
# if desturl:
# desturl += "&amp;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

View File

@ -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

View File

@ -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(

View File

@ -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):

View File

@ -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",

View File

@ -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)

View File

@ -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&amp;export_cat_xls=%s">%s</a>&nbsp;'
% (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

View File

@ -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&amp;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 = "&amp;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:

View File

@ -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
)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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&amp;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&amp;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&amp;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&amp;etudid=%(etudid)s&amp;formsemestre_id=%(last_formsemestre_id)s&amp;desturl=ficheEtud?etudid=%(etudid)s">récapitulatif parcours</a>)"""
% info

View File

@ -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()]

View File

@ -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):
)
+ "&amp;".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)

View File

@ -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

View File

@ -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)

View File

@ -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&amp;formsemestre_id="
+ self.formsemestre_id
dest_url + "&head_message=Préférences modifiées"
)
elif destination == "again":
return REQUEST.RESPONSE.redirect(

View File

@ -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"],

View File

@ -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():

View File

@ -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,

View File

@ -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)

View File

@ -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&amp;percent=%s&amp;bac=%s&amp;bacspecialite=%s&amp;sexe=%s"
% (REQUEST.URL0, formsemestre_id, percent, bac, bacspecialite, sexe)
"%s?formsemestre_id=%s&amp;percent=%s&amp;bac=%s&amp;bacspecialite=%s&amp;civilite=%s"
% (REQUEST.URL0, formsemestre_id, percent, bac, bacspecialite, civilite)
)
if only_primo:
tab.base_url += "&amp;only_primo=on"
@ -695,8 +709,8 @@ def formsemestre_suivi_cohorte(
base_url = REQUEST.URL0
burl = (
"%s?formsemestre_id=%s&amp;bac=%s&amp;bacspecialite=%s&amp;sexe=%s&amp;statut=%s"
% (base_url, formsemestre_id, bac, bacspecialite, sexe, statut)
"%s?formsemestre_id=%s&amp;bac=%s&amp;bacspecialite=%s&amp;civilite=%s&amp;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(
"""&nbsp; Genre: <select name="sexe" onchange="javascript: submit(this);">
"""&nbsp; 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&amp;%sbac=%s&amp;bacspecialite=%s&amp;sexe=%s&amp;statut=%s&amp;format="
% (formsemestre_id, op, bac, bacspecialite, sexe, statut)
"formsemestre_graph_parcours?formsemestre_id=%s&amp;%sbac=%s&amp;bacspecialite=%s&amp;civilite=%s&amp;statut=%s&amp;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,
),

View File

@ -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(

View File

@ -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)

View File

@ -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(

View File

@ -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))

View File

@ -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 + "&amp;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

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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"],

View File

@ -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