forked from ScoDoc/ScoDoc
Merge branch 'master' into code_apogee_multiples
This commit is contained in:
commit
891b87185e
@ -28,10 +28,16 @@
|
|||||||
""" Importation des etudiants à partir de fichiers CSV
|
""" 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 *
|
import sco_utils as scu
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import scolars
|
import scolars
|
||||||
import sco_formsemestre
|
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_news import NEWS_INSCR, NEWS_NOTE, NEWS_FORM, NEWS_SEM, NEWS_MISC
|
||||||
from sco_formsemestre_inscriptions import do_formsemestre_inscription_with_modules
|
from sco_formsemestre_inscriptions import do_formsemestre_inscription_with_modules
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
|
from sco_exceptions import (
|
||||||
|
AccessDenied,
|
||||||
|
FormatError,
|
||||||
|
ScoException,
|
||||||
|
ScoValueError,
|
||||||
|
ScoInvalidDateError,
|
||||||
|
ScoLockedFormError,
|
||||||
|
ScoGenError,
|
||||||
|
)
|
||||||
|
|
||||||
# format description (relative to Product directory))
|
# format description (relative to Product directory))
|
||||||
FORMAT_FILE = "misc/format_import_etudiants.txt"
|
FORMAT_FILE = "misc/format_import_etudiants.txt"
|
||||||
@ -93,7 +108,7 @@ ADMISSION_MODIFIABLE_FIELDS = (
|
|||||||
def sco_import_format(with_codesemestre=True):
|
def sco_import_format(with_codesemestre=True):
|
||||||
"returns tuples (Attribut, Type, Table, AllowNulls, Description)"
|
"returns tuples (Attribut, Type, Table, AllowNulls, Description)"
|
||||||
r = []
|
r = []
|
||||||
for l in open(SCO_SRCDIR + "/" + FORMAT_FILE):
|
for l in open(scu.SCO_SRCDIR + "/" + FORMAT_FILE):
|
||||||
l = l.strip()
|
l = l.strip()
|
||||||
if l and l[0] != "#":
|
if l and l[0] != "#":
|
||||||
fs = l.split(";")
|
fs = l.split(";")
|
||||||
@ -152,10 +167,10 @@ def sco_import_generate_excel_sample(
|
|||||||
titles = []
|
titles = []
|
||||||
titlesStyles = []
|
titlesStyles = []
|
||||||
for l in fmt:
|
for l in fmt:
|
||||||
name = strlower(l[0])
|
name = scu.strlower(l[0])
|
||||||
if (not with_codesemestre) and name == "codesemestre":
|
if (not with_codesemestre) and name == "codesemestre":
|
||||||
continue # pas de colonne 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
|
continue # table non demandée
|
||||||
if name in exclude_cols:
|
if name in exclude_cols:
|
||||||
continue # colonne exclue
|
continue # colonne exclue
|
||||||
@ -192,7 +207,7 @@ def sco_import_generate_excel_sample(
|
|||||||
)
|
)
|
||||||
l.append(etud["partitionsgroupes"])
|
l.append(etud["partitionsgroupes"])
|
||||||
else:
|
else:
|
||||||
key = strlower(field).split()[0]
|
key = scu.strlower(field).split()[0]
|
||||||
l.append(etud.get(key, ""))
|
l.append(etud.get(key, ""))
|
||||||
lines.append(l)
|
lines.append(l)
|
||||||
else:
|
else:
|
||||||
@ -224,7 +239,7 @@ def students_import_excel(
|
|||||||
if formsemestre_id:
|
if formsemestre_id:
|
||||||
dest = "formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
dest = "formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||||
else:
|
else:
|
||||||
dest = REQUEST.URL1
|
dest = context.NotesURL()
|
||||||
H = [context.sco_header(REQUEST, page_title="Import etudiants")]
|
H = [context.sco_header(REQUEST, page_title="Import etudiants")]
|
||||||
H.append("<ul>")
|
H.append("<ul>")
|
||||||
for d in diag:
|
for d in diag:
|
||||||
@ -249,7 +264,7 @@ def scolars_import_excel_file(
|
|||||||
"""
|
"""
|
||||||
log("scolars_import_excel_file: formsemestre_id=%s" % formsemestre_id)
|
log("scolars_import_excel_file: formsemestre_id=%s" % formsemestre_id)
|
||||||
cnx = context.GetDBConnexion(autocommit=False)
|
cnx = context.GetDBConnexion(autocommit=False)
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
annee_courante = time.localtime()[0]
|
annee_courante = time.localtime()[0]
|
||||||
always_require_ine = context.get_preference("always_require_ine")
|
always_require_ine = context.get_preference("always_require_ine")
|
||||||
exceldata = datafile.read()
|
exceldata = datafile.read()
|
||||||
@ -265,7 +280,7 @@ def scolars_import_excel_file(
|
|||||||
titles = {}
|
titles = {}
|
||||||
fmt = sco_import_format()
|
fmt = sco_import_format()
|
||||||
for l in fmt:
|
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 (
|
if (
|
||||||
(not formsemestre_id) or (tit != "codesemestre")
|
(not formsemestre_id) or (tit != "codesemestre")
|
||||||
) and tit not in exclude_cols:
|
) and tit not in exclude_cols:
|
||||||
@ -274,7 +289,7 @@ def scolars_import_excel_file(
|
|||||||
# log("titles=%s" % titles)
|
# log("titles=%s" % titles)
|
||||||
# remove quotes, downcase and keep only 1st word
|
# remove quotes, downcase and keep only 1st word
|
||||||
try:
|
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:
|
except:
|
||||||
raise ScoValueError("Titres de colonnes invalides (ou vides ?)")
|
raise ScoValueError("Titres de colonnes invalides (ou vides ?)")
|
||||||
# log("excel: fs='%s'\ndata=%s" % (str(fs), str(data)))
|
# log("excel: fs='%s'\ndata=%s" % (str(fs), str(data)))
|
||||||
@ -351,22 +366,22 @@ def scolars_import_excel_file(
|
|||||||
% (val, linenum, titleslist[i])
|
% (val, linenum, titleslist[i])
|
||||||
)
|
)
|
||||||
# xxx Ad-hoc checks (should be in format description)
|
# xxx Ad-hoc checks (should be in format description)
|
||||||
if strlower(titleslist[i]) == "sexe":
|
if scu.strlower(titleslist[i]) == "sexe":
|
||||||
try:
|
try:
|
||||||
val = scolars.normalize_sexe(val)
|
val = scolars.input_civilite(val)
|
||||||
except:
|
except:
|
||||||
raise ScoValueError(
|
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])
|
% (val, linenum, titleslist[i])
|
||||||
)
|
)
|
||||||
# Excel date conversion:
|
# Excel date conversion:
|
||||||
if strlower(titleslist[i]) == "date_naissance":
|
if scu.strlower(titleslist[i]) == "date_naissance":
|
||||||
if val:
|
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))
|
val = sco_excel.xldate_as_datetime(float(val))
|
||||||
# INE
|
# INE
|
||||||
if (
|
if (
|
||||||
strlower(titleslist[i]) == "code_ine"
|
scu.strlower(titleslist[i]) == "code_ine"
|
||||||
and always_require_ine
|
and always_require_ine
|
||||||
and not val
|
and not val
|
||||||
):
|
):
|
||||||
@ -423,7 +438,7 @@ def scolars_import_excel_file(
|
|||||||
log("scolars_import_excel_file: aborting transaction !")
|
log("scolars_import_excel_file: aborting transaction !")
|
||||||
# Nota: db transaction is sometimes partly commited...
|
# Nota: db transaction is sometimes partly commited...
|
||||||
# here we try to remove all created students
|
# 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:
|
for etudid in created_etudids:
|
||||||
log("scolars_import_excel_file: deleting etudid=%s" % etudid)
|
log("scolars_import_excel_file: deleting etudid=%s" % etudid)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
@ -500,11 +515,11 @@ def _import_one_student(
|
|||||||
# Admissions
|
# Admissions
|
||||||
args["etudid"] = etudid
|
args["etudid"] = etudid
|
||||||
args["annee"] = annee_courante
|
args["annee"] = annee_courante
|
||||||
adm_id = scolars.admission_create(cnx, args)
|
_ = scolars.admission_create(cnx, args)
|
||||||
# Adresse
|
# Adresse
|
||||||
args["typeadresse"] = "domicile"
|
args["typeadresse"] = "domicile"
|
||||||
args["description"] = "(infos admission)"
|
args["description"] = "(infos admission)"
|
||||||
adresse_id = scolars.adresse_create(cnx, args)
|
_ = scolars.adresse_create(cnx, args)
|
||||||
# Inscription au semestre
|
# Inscription au semestre
|
||||||
args["etat"] = "I" # etat insc. semestre
|
args["etat"] = "I" # etat insc. semestre
|
||||||
if formsemestre_id:
|
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
|
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):
|
def adm_convert_text(v):
|
||||||
if type(v) == FloatType:
|
if type(v) == types.FloatType:
|
||||||
return "{:g}".format(v) # evite "1.0"
|
return "{:g}".format(v) # evite "1.0"
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
|
||||||
def adm_convert_int(v):
|
def adm_convert_int(v):
|
||||||
if type(v) != IntType and not v:
|
if type(v) != types.IntType and not v:
|
||||||
return None
|
return None
|
||||||
return int(float(v)) # accept "10.0"
|
return int(float(v)) # accept "10.0"
|
||||||
|
|
||||||
|
|
||||||
def adm_convert_real(v):
|
def adm_convert_real(v):
|
||||||
if type(v) != FloatType and not v:
|
if type(v) != types.FloatType and not v:
|
||||||
return None
|
return None
|
||||||
return float(v)
|
return float(v)
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
v 1.2
|
v 1.2
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from types import *
|
from types import BooleanType, StringType
|
||||||
|
|
||||||
|
|
||||||
def TrivialFormulator(
|
def TrivialFormulator(
|
||||||
@ -44,7 +44,7 @@ def TrivialFormulator(
|
|||||||
-1 cancel (if cancelbutton specified)
|
-1 cancel (if cancelbutton specified)
|
||||||
HTML form: html string (form to insert in your web page)
|
HTML form: html string (form to insert in your web page)
|
||||||
values: None or, when the form is submitted and correctly filled,
|
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), ... ]
|
formdescription: sequence [ (field, description), ... ]
|
||||||
where description is a dict with following (optional) keys:
|
where description is a dict with following (optional) keys:
|
||||||
default : default value for this field ('')
|
default : default value for this field ('')
|
||||||
@ -63,7 +63,7 @@ def TrivialFormulator(
|
|||||||
withcheckbox: if true, place a checkbox at the left of the input
|
withcheckbox: if true, place a checkbox at the left of the input
|
||||||
elem. Checked items will be returned in 'tf-checked'
|
elem. Checked items will be returned in 'tf-checked'
|
||||||
attributes: a liste of strings to put in the HTML form element
|
attributes: a liste of strings to put in the HTML form element
|
||||||
template: HTML template for element
|
template: HTML template for element
|
||||||
HTML elements:
|
HTML elements:
|
||||||
input_type : 'text', 'textarea', 'password',
|
input_type : 'text', 'textarea', 'password',
|
||||||
'radio', 'menu', 'checkbox',
|
'radio', 'menu', 'checkbox',
|
||||||
@ -368,9 +368,6 @@ class TF:
|
|||||||
idx = 0
|
idx = 0
|
||||||
for idx in range(len(self.formdescription)):
|
for idx in range(len(self.formdescription)):
|
||||||
(field, descr) = self.formdescription[idx]
|
(field, descr) = self.formdescription[idx]
|
||||||
nextitemname = None
|
|
||||||
if idx < len(self.formdescription) - 2:
|
|
||||||
nextitemname = self.formdescription[idx + 1][0]
|
|
||||||
if descr.get("readonly", False):
|
if descr.get("readonly", False):
|
||||||
R.append(self._ReadOnlyElement(field, descr))
|
R.append(self._ReadOnlyElement(field, descr))
|
||||||
continue
|
continue
|
||||||
@ -682,7 +679,6 @@ class TF:
|
|||||||
"Generate HTML for an element, read-only"
|
"Generate HTML for an element, read-only"
|
||||||
R = []
|
R = []
|
||||||
title = descr.get("title", field.capitalize())
|
title = descr.get("title", field.capitalize())
|
||||||
withcheckbox = descr.get("withcheckbox", False)
|
|
||||||
input_type = descr.get("input_type", "text")
|
input_type = descr.get("input_type", "text")
|
||||||
klass = descr.get("cssclass", "")
|
klass = descr.get("cssclass", "")
|
||||||
klass = " " + klass
|
klass = " " + klass
|
||||||
@ -764,6 +760,6 @@ def tf_error_message(msg):
|
|||||||
if type(msg) == StringType:
|
if type(msg) == StringType:
|
||||||
msg = [msg]
|
msg = [msg]
|
||||||
return (
|
return (
|
||||||
'<ul class="tf-msg"><li class="tf-msg">%s</li></ul>'
|
'<ul class="tf-msg"><li id="errorMessage" class="tf-msg">%s</li></ul>'
|
||||||
% '</li><li class="tf-msg">'.join(msg)
|
% '</li><li class="tf-msg">'.join(msg)
|
||||||
)
|
)
|
||||||
|
14
VERSION.py
14
VERSION.py
@ -1,15 +1,23 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "7.20a"
|
SCOVERSION = "7.25m"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
SCONEWS = """
|
SCONEWS = """
|
||||||
|
<h4>Année 2021</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Version mobile (en test)</li>
|
||||||
|
<li>Évaluations de type "deuxième session"</li>
|
||||||
|
<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>
|
<h4>Année 2020</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Corrections d'erreurs, améliorations saise absences< et affichage bulletins</li>
|
<li>Corrections d'erreurs, améliorations saisie 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>Enregistrement de semestres extérieurs</li>
|
||||||
<li>Améliorations PV de Jury</li>
|
<li>Améliorations PV de Jury</li>
|
||||||
<li>Contributions J.-M. Place: aide au diagnostic problèmes export Apogée
|
<li>Contributions J.-M. Place: aide au diagnostic problèmes export Apogée
|
||||||
|
917
ZAbsences.py
917
ZAbsences.py
File diff suppressed because it is too large
Load Diff
1421
ZEntreprises.py
1421
ZEntreprises.py
File diff suppressed because it is too large
Load Diff
202
ZScoDoc.py
202
ZScoDoc.py
@ -31,35 +31,59 @@
|
|||||||
Chaque departement est géré par un ZScolar sous ZScoDoc.
|
Chaque departement est géré par un ZScolar sous ZScoDoc.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import time, string, glob, re, inspect
|
import time
|
||||||
import urllib, urllib2, cgi, xml
|
import datetime
|
||||||
|
import string
|
||||||
|
import glob
|
||||||
|
import re
|
||||||
|
import inspect
|
||||||
|
import urllib
|
||||||
|
import urllib2
|
||||||
|
import cgi
|
||||||
|
import xml
|
||||||
|
|
||||||
try:
|
from cStringIO import StringIO
|
||||||
from cStringIO import StringIO
|
|
||||||
except:
|
|
||||||
from StringIO import StringIO
|
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
import os.path, glob
|
import os.path
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
from email.MIMEMultipart import ( # pylint: disable=no-name-in-module,import-error
|
||||||
from email.MIMEText import MIMEText
|
MIMEMultipart,
|
||||||
from email.MIMEBase import MIMEBase
|
)
|
||||||
from email.Header import Header
|
from email.MIMEText import MIMEText # pylint: disable=no-name-in-module,import-error
|
||||||
from email import Encoders
|
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
|
||||||
|
|
||||||
from sco_zope import *
|
from sco_zope import * # pylint: disable=unused-wildcard-import
|
||||||
|
|
||||||
#
|
|
||||||
try:
|
try:
|
||||||
import Products.ZPsycopgDA.DA as ZopeDA
|
import Products.ZPsycopgDA.DA as ZopeDA
|
||||||
except:
|
except:
|
||||||
import ZPsycopgDA.DA as ZopeDA # interp.py
|
import ZPsycopgDA.DA as ZopeDA # interp.py
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
|
import VERSION
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_find_etud
|
import sco_find_etud
|
||||||
from ZScoUsers import pwdFascistCheck
|
import sco_users
|
||||||
|
from sco_permissions import (
|
||||||
|
ScoView,
|
||||||
|
ScoEnsView,
|
||||||
|
ScoImplement,
|
||||||
|
ScoChangeFormation,
|
||||||
|
ScoObservateur,
|
||||||
|
ScoEtudInscrit,
|
||||||
|
ScoEtudChangeGroups,
|
||||||
|
ScoEtudChangeAdr,
|
||||||
|
ScoEtudSupprAnnotations,
|
||||||
|
ScoEditAllEvals,
|
||||||
|
ScoEditAllNotes,
|
||||||
|
ScoEditFormationTags,
|
||||||
|
ScoEditApo,
|
||||||
|
ScoSuperAdmin,
|
||||||
|
)
|
||||||
|
from sco_exceptions import ScoValueError, ScoLockedFormError, ScoGenError, AccessDenied
|
||||||
|
|
||||||
|
|
||||||
class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Implicit):
|
class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Implicit):
|
||||||
@ -77,13 +101,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
manage_options = (
|
manage_options = (
|
||||||
({"label": "Contents", "action": "manage_main"},)
|
({"label": "Contents", "action": "manage_main"},)
|
||||||
+ PropertyManager.manage_options # add the 'Properties' tab
|
+ PropertyManager.manage_options # add the 'Properties' tab
|
||||||
+ (
|
+ ({"label": "View", "action": "index_html"},)
|
||||||
# this line is kept as an example with the files :
|
|
||||||
# dtml/manage_editZScolarForm.dtml
|
|
||||||
# html/ZScolar-edit.stx
|
|
||||||
# {'label': 'Properties', 'action': 'manage_editForm',},
|
|
||||||
{"label": "View", "action": "index_html"},
|
|
||||||
)
|
|
||||||
+ Item.manage_options # add the 'Undo' & 'Owner' tab
|
+ Item.manage_options # add the 'Undo' & 'Owner' tab
|
||||||
+ RoleManager.manage_options # add the 'Security' tab
|
+ RoleManager.manage_options # add the 'Security' tab
|
||||||
)
|
)
|
||||||
@ -111,7 +129,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
def _check_users_folder(self, REQUEST=None):
|
def _check_users_folder(self, REQUEST=None):
|
||||||
"""Vérifie UserFolder et le crée s'il le faut"""
|
"""Vérifie UserFolder et le crée s'il le faut"""
|
||||||
try:
|
try:
|
||||||
udb = self.UsersDB
|
_ = self.UsersDB
|
||||||
return "<!-- uf ok -->"
|
return "<!-- uf ok -->"
|
||||||
except:
|
except:
|
||||||
e = self._check_admin_perm(REQUEST)
|
e = self._check_admin_perm(REQUEST)
|
||||||
@ -164,11 +182,11 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
pass
|
pass
|
||||||
# add missing getAuthFailedMessage (bug in exUserFolder ?)
|
# add missing getAuthFailedMessage (bug in exUserFolder ?)
|
||||||
try:
|
try:
|
||||||
x = self.getAuthFailedMessage
|
_ = self.getAuthFailedMessage
|
||||||
except:
|
except:
|
||||||
log("adding getAuthFailedMessage to Zope install")
|
log("adding getAuthFailedMessage to Zope install")
|
||||||
parent = self.aq_parent
|
parent = self.aq_parent
|
||||||
from OFS.DTMLMethod import addDTMLMethod
|
from OFS.DTMLMethod import addDTMLMethod # pylint: disable=import-error
|
||||||
|
|
||||||
addDTMLMethod(parent, "getAuthFailedMessage", file="Identification")
|
addDTMLMethod(parent, "getAuthFailedMessage", file="Identification")
|
||||||
|
|
||||||
@ -187,7 +205,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
da = ZopeDA.Connection(
|
da = ZopeDA.Connection(
|
||||||
oid,
|
oid,
|
||||||
"Cnx bd utilisateurs",
|
"Cnx bd utilisateurs",
|
||||||
SCO_DEFAULT_SQL_USERS_CNX,
|
scu.SCO_DEFAULT_SQL_USERS_CNX,
|
||||||
False,
|
False,
|
||||||
check=1,
|
check=1,
|
||||||
tilevel=2,
|
tilevel=2,
|
||||||
@ -207,7 +225,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
raise AccessDenied("vous n'avez pas le droit d'effectuer cette opération")
|
raise AccessDenied("vous n'avez pas le droit d'effectuer cette opération")
|
||||||
log("trying to change admin password")
|
log("trying to change admin password")
|
||||||
# 1-- check strong password
|
# 1-- check strong password
|
||||||
if pwdFascistCheck(password) != None:
|
if not sco_users.is_valid_password(password):
|
||||||
log("refusing weak password")
|
log("refusing weak password")
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"change_admin_user_form?message=Mot%20de%20passe%20trop%20simple,%20recommencez"
|
"change_admin_user_form?message=Mot%20de%20passe%20trop%20simple,%20recommencez"
|
||||||
@ -255,16 +273,32 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
|
|
||||||
security.declareProtected("View", "list_depts")
|
security.declareProtected("View", "list_depts")
|
||||||
|
|
||||||
def list_depts(self, REQUEST=None):
|
def list_depts(self, viewable=True, format=None, REQUEST=None):
|
||||||
"""List departments folders
|
"""List departments
|
||||||
(returns a list of Zope folders containing a ZScolar instance)
|
If viewable, list only depts viewable the current user.
|
||||||
"""
|
"""
|
||||||
|
authuser = REQUEST.AUTHENTICATED_USER
|
||||||
|
viewable = int(viewable)
|
||||||
|
return scu.sendResult(
|
||||||
|
REQUEST,
|
||||||
|
[
|
||||||
|
d.id
|
||||||
|
for d in self._list_depts()
|
||||||
|
if (not viewable) or authuser.has_permission(ScoView, d.Scolarite)
|
||||||
|
],
|
||||||
|
name="depts",
|
||||||
|
format=format,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _list_depts(self, REQUEST=None): # not published
|
||||||
|
# List departments folders
|
||||||
|
# (returns a list of Zope folders containing a ZScolar instance)
|
||||||
folders = self.objectValues("Folder")
|
folders = self.objectValues("Folder")
|
||||||
# select folders with Scolarite object:
|
# select folders with Scolarite object:
|
||||||
r = []
|
r = []
|
||||||
for folder in folders:
|
for folder in folders:
|
||||||
try:
|
try:
|
||||||
s = folder.Scolarite
|
_ = folder.Scolarite
|
||||||
r.append(folder)
|
r.append(folder)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@ -309,7 +343,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
if e:
|
if e:
|
||||||
return e
|
return e
|
||||||
|
|
||||||
if not force and DeptId not in [x.id for x in self.list_depts()]:
|
if not force and DeptId not in [x.id for x in self._list_depts()]:
|
||||||
raise ValueError("nom de departement invalide")
|
raise ValueError("nom de departement invalide")
|
||||||
|
|
||||||
self.manage_delObjects(ids=[DeptId])
|
self.manage_delObjects(ids=[DeptId])
|
||||||
@ -317,8 +351,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
return (
|
return (
|
||||||
"<p>Département "
|
"<p>Département "
|
||||||
+ DeptId
|
+ DeptId
|
||||||
+ """ supprimé du serveur web (la base de données n'est pas affectée)!</p><p><a href="%s">Continuer</a></p>"""
|
+ """ supprimé du serveur web (la base de données n'est pas affectée)!</p><p><a href="/ScoDoc">Continuer</a></p>"""
|
||||||
% REQUEST.URL1
|
|
||||||
)
|
)
|
||||||
|
|
||||||
_top_level_css = """
|
_top_level_css = """
|
||||||
@ -362,10 +395,10 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
def scodoc_top_html_header(self, REQUEST, page_title="ScoDoc"):
|
def scodoc_top_html_header(self, REQUEST, page_title="ScoDoc"):
|
||||||
H = [
|
H = [
|
||||||
self._html_begin
|
self._html_begin
|
||||||
% {"page_title": "ScoDoc: bienvenue", "encoding": SCO_ENCODING},
|
% {"page_title": "ScoDoc: bienvenue", "encoding": scu.SCO_ENCODING},
|
||||||
self._top_level_css,
|
self._top_level_css,
|
||||||
"""</head><body class="gtrcontent" id="gtrcontent">""",
|
"""</head><body class="gtrcontent" id="gtrcontent">""",
|
||||||
CUSTOM_HTML_HEADER_CNX,
|
scu.CUSTOM_HTML_HEADER_CNX,
|
||||||
]
|
]
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
@ -374,7 +407,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
def index_html(self, REQUEST=None, message=None):
|
def index_html(self, REQUEST=None, message=None):
|
||||||
"""Top level page for ScoDoc"""
|
"""Top level page for ScoDoc"""
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = REQUEST.AUTHENTICATED_USER
|
||||||
deptList = self.list_depts()
|
deptList = self._list_depts()
|
||||||
self._fix_users_folder() # fix our exUserFolder
|
self._fix_users_folder() # fix our exUserFolder
|
||||||
isAdmin = not self._check_admin_perm(REQUEST)
|
isAdmin = not self._check_admin_perm(REQUEST)
|
||||||
try:
|
try:
|
||||||
@ -382,14 +415,14 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
except:
|
except:
|
||||||
admin_password_initialized = "0"
|
admin_password_initialized = "0"
|
||||||
if isAdmin and admin_password_initialized != "1":
|
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!"
|
"ScoDoc/change_admin_user_form?message=Le%20mot%20de%20passe%20administrateur%20doit%20etre%20change%20!"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Si l'URL indique que l'on est dans un folder, affiche page login du departement
|
# Si l'URL indique que l'on est dans un folder, affiche page login du departement
|
||||||
try:
|
try:
|
||||||
deptfoldername = REQUEST.URL0.split("ScoDoc")[1].split("/")[1]
|
deptfoldername = REQUEST.URL0.split("ScoDoc")[1].split("/")[1]
|
||||||
if deptfoldername in [x.id for x in self.list_depts()]:
|
if deptfoldername in [x.id for x in self._list_depts()]:
|
||||||
return self.index_dept(deptfoldername=deptfoldername, REQUEST=REQUEST)
|
return self.index_dept(deptfoldername=deptfoldername, REQUEST=REQUEST)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@ -436,7 +469,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
dest_folder = "/Scolarite"
|
dest_folder = "/Scolarite"
|
||||||
else:
|
else:
|
||||||
dest_folder = ""
|
dest_folder = ""
|
||||||
for deptFolder in self.list_depts():
|
for deptFolder in self._list_depts():
|
||||||
if authuser.has_permission(ScoView, deptFolder.Scolarite):
|
if authuser.has_permission(ScoView, deptFolder.Scolarite):
|
||||||
link_cls = "link_accessible"
|
link_cls = "link_accessible"
|
||||||
else:
|
else:
|
||||||
@ -471,6 +504,11 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
% REQUEST.BASE0
|
% REQUEST.BASE0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Lien expérimental temporaire:
|
||||||
|
H.append(
|
||||||
|
'<p><a href="/ScoDoc/static/mobile">Version mobile (expérimentale, à vos risques et périls)</a></p>'
|
||||||
|
)
|
||||||
|
|
||||||
H.append(
|
H.append(
|
||||||
"""
|
"""
|
||||||
<div id="scodoc_attribution">
|
<div id="scodoc_attribution">
|
||||||
@ -478,7 +516,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
E. Viennet (Université Paris 13).</p>
|
E. Viennet (Université Paris 13).</p>
|
||||||
</div>
|
</div>
|
||||||
</div>"""
|
</div>"""
|
||||||
% (SCO_WEBSITE,)
|
% (scu.SCO_WEBSITE,)
|
||||||
)
|
)
|
||||||
|
|
||||||
H.append("""</body></html>""")
|
H.append("""</body></html>""")
|
||||||
@ -591,20 +629,21 @@ E. Viennet (Université Paris 13).</p>
|
|||||||
<link HREF="/ScoDoc/static/css/scodoc.css" rel="stylesheet" type="text/css"/>
|
<link HREF="/ScoDoc/static/css/scodoc.css" rel="stylesheet" type="text/css"/>
|
||||||
|
|
||||||
</head><body>%s""" % (
|
</head><body>%s""" % (
|
||||||
SCO_ENCODING,
|
scu.SCO_ENCODING,
|
||||||
CUSTOM_HTML_HEADER_CNX,
|
scu.CUSTOM_HTML_HEADER_CNX,
|
||||||
)
|
)
|
||||||
|
|
||||||
security.declareProtected("View", "standard_html_footer")
|
security.declareProtected("View", "standard_html_footer")
|
||||||
|
|
||||||
def standard_html_footer(self, REQUEST=None):
|
def standard_html_footer(self, REQUEST=None):
|
||||||
|
"""Le pied de page HTML de la page d'accueil."""
|
||||||
return """<p class="footer">
|
return """<p class="footer">
|
||||||
Problème de connexion (identifiant, mot de passe): <em>contacter votre responsable ou chef de département</em>.</p>
|
Problème de connexion (identifiant, mot de passe): <em>contacter votre responsable ou chef de département</em>.</p>
|
||||||
<p>Problèmes et suggestions sur le logiciel: <a href="mailto:%s">%s</a></p>
|
<p>Problèmes et suggestions sur le logiciel: <a href="mailto:%s">%s</a></p>
|
||||||
<p><em>ScoDoc est un logiciel libre développé par Emmanuel Viennet.</em></p>
|
<p><em>ScoDoc est un logiciel libre développé par Emmanuel Viennet.</em></p>
|
||||||
</body></html>""" % (
|
</body></html>""" % (
|
||||||
SCO_USERS_LIST,
|
scu.SCO_USERS_LIST,
|
||||||
SCO_USERS_LIST,
|
scu.SCO_USERS_LIST,
|
||||||
)
|
)
|
||||||
|
|
||||||
# sendEmail is not used through the web
|
# sendEmail is not used through the web
|
||||||
@ -642,15 +681,13 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
|||||||
def standard_error_message(
|
def standard_error_message(
|
||||||
self,
|
self,
|
||||||
error_value=None,
|
error_value=None,
|
||||||
error_message=None,
|
error_message=None, # unused ?
|
||||||
error_type=None,
|
error_type=None,
|
||||||
error_traceback=None,
|
error_traceback=None,
|
||||||
error_tb=None,
|
error_tb=None,
|
||||||
**kv
|
**kv
|
||||||
):
|
):
|
||||||
"Recuperation des exceptions Zope"
|
"Recuperation des exceptions Zope"
|
||||||
sco_exc_mail = SCO_EXC_MAIL
|
|
||||||
sco_dev_mail = SCO_DEV_MAIL
|
|
||||||
# neat (or should I say dirty ?) hack to get REQUEST
|
# neat (or should I say dirty ?) hack to get REQUEST
|
||||||
# in fact, our caller (probably SimpleItem.py) has the REQUEST variable
|
# in fact, our caller (probably SimpleItem.py) has the REQUEST variable
|
||||||
# that we'd like to use for our logs, but does not pass it as an argument.
|
# that we'd like to use for our logs, but does not pass it as an argument.
|
||||||
@ -663,9 +700,6 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
|||||||
# Authentication uses exceptions, pass them up
|
# Authentication uses exceptions, pass them up
|
||||||
HTTP_X_FORWARDED_FOR = REQUEST.get("HTTP_X_FORWARDED_FOR", "")
|
HTTP_X_FORWARDED_FOR = REQUEST.get("HTTP_X_FORWARDED_FOR", "")
|
||||||
if error_type == "LoginRequired":
|
if error_type == "LoginRequired":
|
||||||
# raise 'LoginRequired', '' # copied from exuserFolder (beurk, old style exception...)
|
|
||||||
# if REQUEST:
|
|
||||||
# REQUEST.response.setStatus( 401, "Unauthorized") # ??????
|
|
||||||
log("LoginRequired from %s" % HTTP_X_FORWARDED_FOR)
|
log("LoginRequired from %s" % HTTP_X_FORWARDED_FOR)
|
||||||
self.login_page = error_value
|
self.login_page = error_value
|
||||||
return error_value
|
return error_value
|
||||||
@ -676,6 +710,14 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
|||||||
log("exception caught: %s" % error_type)
|
log("exception caught: %s" % error_type)
|
||||||
log(traceback.format_exc())
|
log(traceback.format_exc())
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"error_type": error_type,
|
||||||
|
"error_value": error_value,
|
||||||
|
"error_tb": error_tb,
|
||||||
|
"sco_exc_mail": scu.SCO_EXC_MAIL,
|
||||||
|
"sco_dev_mail": scu.SCO_DEV_MAIL,
|
||||||
|
}
|
||||||
|
|
||||||
if error_type == "ScoGenError":
|
if error_type == "ScoGenError":
|
||||||
return "<p>" + str(error_value) + "</p>"
|
return "<p>" + str(error_value) + "</p>"
|
||||||
elif error_type in ("ScoValueError", "FormatError"):
|
elif error_type in ("ScoValueError", "FormatError"):
|
||||||
@ -713,11 +755,11 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
|||||||
</p>
|
</p>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
</table> """
|
</table> """
|
||||||
% vars()
|
% params
|
||||||
)
|
)
|
||||||
# display error traceback (? may open a security risk via xss attack ?)
|
# display error traceback (? may open a security risk via xss attack ?)
|
||||||
# log('exc B')
|
# log('exc B')
|
||||||
txt_html = self._report_request(REQUEST, fmt="html")
|
params["txt_html"] = self._report_request(REQUEST, fmt="html")
|
||||||
H.append(
|
H.append(
|
||||||
"""<h4 class="scodoc">Zope Traceback (à envoyer par mail à <a href="mailto:%(sco_dev_mail)s">%(sco_dev_mail)s</a>)</h4><div style="background-color: rgb(153,153,204); border: 1px;">
|
"""<h4 class="scodoc">Zope Traceback (à envoyer par mail à <a href="mailto:%(sco_dev_mail)s">%(sco_dev_mail)s</a>)</h4><div style="background-color: rgb(153,153,204); border: 1px;">
|
||||||
%(error_tb)s
|
%(error_tb)s
|
||||||
@ -728,7 +770,7 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
|||||||
|
|
||||||
<p>Merci de votre patience !</p>
|
<p>Merci de votre patience !</p>
|
||||||
"""
|
"""
|
||||||
% vars()
|
% params
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
H.append(self.standard_html_footer(REQUEST))
|
H.append(self.standard_html_footer(REQUEST))
|
||||||
@ -737,14 +779,14 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# --- Mail:
|
# --- Mail:
|
||||||
error_traceback_txt = scodoc_html2txt(error_tb)
|
params["error_traceback_txt"] = scu.scodoc_html2txt(error_tb)
|
||||||
txt = (
|
txt = (
|
||||||
"""
|
"""
|
||||||
ErrorType: %(error_type)s
|
ErrorType: %(error_type)s
|
||||||
|
|
||||||
%(error_traceback_txt)s
|
%(error_traceback_txt)s
|
||||||
"""
|
"""
|
||||||
% vars()
|
% params
|
||||||
)
|
)
|
||||||
|
|
||||||
self.send_debug_alert(txt, REQUEST=REQUEST)
|
self.send_debug_alert(txt, REQUEST=REQUEST)
|
||||||
@ -755,25 +797,29 @@ ErrorType: %(error_type)s
|
|||||||
|
|
||||||
def _report_request(self, REQUEST, fmt="txt"):
|
def _report_request(self, REQUEST, fmt="txt"):
|
||||||
"""string describing current request for bug reports"""
|
"""string describing current request for bug reports"""
|
||||||
AUTHENTICATED_USER = REQUEST.get("AUTHENTICATED_USER", "")
|
|
||||||
dt = time.asctime()
|
|
||||||
URL = REQUEST.get("URL", "")
|
|
||||||
QUERY_STRING = REQUEST.get("QUERY_STRING", "")
|
QUERY_STRING = REQUEST.get("QUERY_STRING", "")
|
||||||
if QUERY_STRING:
|
if QUERY_STRING:
|
||||||
QUERY_STRING = "?" + QUERY_STRING
|
QUERY_STRING = "?" + QUERY_STRING
|
||||||
METHOD = REQUEST.get("REQUEST_METHOD", "")
|
|
||||||
|
|
||||||
if fmt == "txt":
|
if fmt == "txt":
|
||||||
REFERER = REQUEST.get("HTTP_REFERER", "")
|
REFERER = REQUEST.get("HTTP_REFERER", "")
|
||||||
HTTP_USER_AGENT = REQUEST.get("HTTP_USER_AGENT", "")
|
HTTP_USER_AGENT = REQUEST.get("HTTP_USER_AGENT", "")
|
||||||
else:
|
else:
|
||||||
REFERER = "na"
|
REFERER = "na"
|
||||||
HTTP_USER_AGENT = "na"
|
HTTP_USER_AGENT = "na"
|
||||||
form = REQUEST.get("form", "")
|
|
||||||
HTTP_X_FORWARDED_FOR = REQUEST.get("HTTP_X_FORWARDED_FOR", "")
|
|
||||||
svn_version = get_svn_version(self.file_path)
|
|
||||||
SCOVERSION = VERSION.SCOVERSION
|
|
||||||
|
|
||||||
|
params = dict(
|
||||||
|
AUTHENTICATED_USER=REQUEST.get("AUTHENTICATED_USER", ""),
|
||||||
|
dt=time.asctime(),
|
||||||
|
URL=REQUEST.get("URL", ""),
|
||||||
|
QUERY_STRING=QUERY_STRING,
|
||||||
|
METHOD=REQUEST.get("REQUEST_METHOD", ""),
|
||||||
|
REFERER=REFERER,
|
||||||
|
HTTP_USER_AGENT=HTTP_USER_AGENT,
|
||||||
|
form=REQUEST.get("form", ""),
|
||||||
|
HTTP_X_FORWARDED_FOR=REQUEST.get("HTTP_X_FORWARDED_FOR", ""),
|
||||||
|
svn_version=scu.get_svn_version(self.file_path),
|
||||||
|
SCOVERSION=VERSION.SCOVERSION,
|
||||||
|
)
|
||||||
txt = (
|
txt = (
|
||||||
"""
|
"""
|
||||||
Version: %(SCOVERSION)s
|
Version: %(SCOVERSION)s
|
||||||
@ -789,7 +835,7 @@ Agent: %(HTTP_USER_AGENT)s
|
|||||||
|
|
||||||
subversion: %(svn_version)s
|
subversion: %(svn_version)s
|
||||||
"""
|
"""
|
||||||
% vars()
|
% params
|
||||||
)
|
)
|
||||||
if fmt == "html":
|
if fmt == "html":
|
||||||
txt = txt.replace("\n", "<br/>")
|
txt = txt.replace("\n", "<br/>")
|
||||||
@ -801,7 +847,7 @@ subversion: %(svn_version)s
|
|||||||
|
|
||||||
def send_debug_alert(self, txt, REQUEST=None):
|
def send_debug_alert(self, txt, REQUEST=None):
|
||||||
"""Send an alert email (bug report) to ScoDoc developpers"""
|
"""Send an alert email (bug report) to ScoDoc developpers"""
|
||||||
if not SCO_EXC_MAIL:
|
if not scu.SCO_EXC_MAIL:
|
||||||
log("send_debug_alert: email disabled")
|
log("send_debug_alert: email disabled")
|
||||||
return
|
return
|
||||||
if REQUEST:
|
if REQUEST:
|
||||||
@ -810,13 +856,13 @@ subversion: %(svn_version)s
|
|||||||
else:
|
else:
|
||||||
URL = "send_debug_alert"
|
URL = "send_debug_alert"
|
||||||
msg = MIMEMultipart()
|
msg = MIMEMultipart()
|
||||||
subj = Header("[scodoc] exc %s" % URL, SCO_ENCODING)
|
subj = Header("[scodoc] exc %s" % URL, scu.SCO_ENCODING)
|
||||||
msg["Subject"] = subj
|
msg["Subject"] = subj
|
||||||
recipients = [SCO_EXC_MAIL]
|
recipients = [scu.SCO_EXC_MAIL]
|
||||||
msg["To"] = " ,".join(recipients)
|
msg["To"] = " ,".join(recipients)
|
||||||
msg["From"] = "scodoc-alert"
|
msg["From"] = "scodoc-alert"
|
||||||
msg.epilogue = ""
|
msg.epilogue = ""
|
||||||
msg.attach(MIMEText(txt, "plain", SCO_ENCODING))
|
msg.attach(MIMEText(txt, "plain", scu.SCO_ENCODING))
|
||||||
self.sendEmailFromException(msg)
|
self.sendEmailFromException(msg)
|
||||||
log("Sent mail alert:\n" + txt)
|
log("Sent mail alert:\n" + txt)
|
||||||
|
|
||||||
@ -843,7 +889,7 @@ subversion: %(svn_version)s
|
|||||||
% self.absolute_url(),
|
% self.absolute_url(),
|
||||||
]
|
]
|
||||||
|
|
||||||
deptList = [x.id for x in self.list_depts()] # definis dans Zope
|
deptList = [x.id for x in self._list_depts()] # definis dans Zope
|
||||||
deptIds = set(self._list_depts_ids()) # definis sur le filesystem
|
deptIds = set(self._list_depts_ids()) # definis sur le filesystem
|
||||||
existingDepts = set(deptList)
|
existingDepts = set(deptList)
|
||||||
addableDepts = deptIds - existingDepts
|
addableDepts = deptIds - existingDepts
|
||||||
@ -852,7 +898,7 @@ subversion: %(svn_version)s
|
|||||||
# aucun departement defini: aide utilisateur
|
# aucun departement defini: aide utilisateur
|
||||||
H.append("<p>Aucun département à ajouter !</p>")
|
H.append("<p>Aucun département à ajouter !</p>")
|
||||||
else:
|
else:
|
||||||
H.append("""<form action="create_dept"><select name="DeptId"/>""")
|
H.append("""<form action="create_dept" id="CreateDpt"><select name="DeptId"/>""")
|
||||||
for deptId in addableDepts:
|
for deptId in addableDepts:
|
||||||
H.append("""<option value="%s">%s</option>""" % (deptId, deptId))
|
H.append("""<option value="%s">%s</option>""" % (deptId, deptId))
|
||||||
H.append(
|
H.append(
|
||||||
@ -869,10 +915,10 @@ subversion: %(svn_version)s
|
|||||||
(le site peut donc être recréé sans perte de données).
|
(le site peut donc être recréé sans perte de données).
|
||||||
</p>
|
</p>
|
||||||
<form action="delete_dept">
|
<form action="delete_dept">
|
||||||
<select name="DeptId">
|
<select name="DeptId" id= "DeleteDept">
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
for deptFolder in self.list_depts():
|
for deptFolder in self._list_depts():
|
||||||
H.append(
|
H.append(
|
||||||
'<option value="%s">%s</option>' % (deptFolder.id, deptFolder.id)
|
'<option value="%s">%s</option>' % (deptFolder.id, deptFolder.id)
|
||||||
)
|
)
|
||||||
@ -890,7 +936,7 @@ subversion: %(svn_version)s
|
|||||||
"""Liste de id de departements definis par create_dept.sh
|
"""Liste de id de departements definis par create_dept.sh
|
||||||
(fichiers depts/*.cfg)
|
(fichiers depts/*.cfg)
|
||||||
"""
|
"""
|
||||||
filenames = glob.glob(SCODOC_VAR_DIR + "/config/depts/*.cfg")
|
filenames = glob.glob(scu.SCODOC_VAR_DIR + "/config/depts/*.cfg")
|
||||||
ids = [os.path.split(os.path.splitext(f)[0])[1] for f in filenames]
|
ids = [os.path.split(os.path.splitext(f)[0])[1] for f in filenames]
|
||||||
return ids
|
return ids
|
||||||
|
|
||||||
@ -907,7 +953,7 @@ subversion: %(svn_version)s
|
|||||||
"""Returns the dept id (eg "GEII") of an etud (identified by etudid, INE or NIP in REQUEST).
|
"""Returns the dept id (eg "GEII") of an etud (identified by etudid, INE or NIP in REQUEST).
|
||||||
Warning: This function is inefficient and its result should be cached.
|
Warning: This function is inefficient and its result should be cached.
|
||||||
"""
|
"""
|
||||||
depts = self.list_depts()
|
depts = self._list_depts()
|
||||||
depts_etud = [] # liste des depts où l'etud est defini
|
depts_etud = [] # liste des depts où l'etud est defini
|
||||||
for dept in depts:
|
for dept in depts:
|
||||||
etuds = dept.Scolarite.getEtudInfo(REQUEST=REQUEST)
|
etuds = dept.Scolarite.getEtudInfo(REQUEST=REQUEST)
|
||||||
@ -947,5 +993,5 @@ def manage_addZScoDoc(self, id="ScoDoc", title="Site ScoDoc", REQUEST=None):
|
|||||||
) # ne cree (presque rien), tout se passe lors du 1er accès
|
) # ne cree (presque rien), tout se passe lors du 1er accès
|
||||||
self._setObject(id, zscodoc)
|
self._setObject(id, zscodoc)
|
||||||
if REQUEST is not None:
|
if REQUEST is not None:
|
||||||
REQUEST.RESPONSE.redirect("%s/manage_workspace" % REQUEST.URL1)
|
REQUEST.RESPONSE.redirect("/ScoDoc/manage_workspace")
|
||||||
return id
|
return id
|
||||||
|
169
ZScoUsers.py
169
ZScoUsers.py
@ -27,45 +27,45 @@
|
|||||||
|
|
||||||
""" Gestion des utilisateurs (table SQL pour Zope User Folder)
|
""" Gestion des utilisateurs (table SQL pour Zope User Folder)
|
||||||
"""
|
"""
|
||||||
import string, re
|
import string
|
||||||
|
import re
|
||||||
import time
|
import time
|
||||||
import md5, base64
|
import md5
|
||||||
|
import base64
|
||||||
|
import jaxml
|
||||||
|
|
||||||
|
from sco_zope import * # pylint: disable=unused-wildcard-import
|
||||||
from sco_zope import *
|
|
||||||
|
|
||||||
# ---------------
|
# ---------------
|
||||||
|
import sco_utils as scu
|
||||||
import notesdb
|
import notesdb as ndb
|
||||||
from notesdb import *
|
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from scolog import logdb
|
from scolog import logdb
|
||||||
from sco_utils import *
|
|
||||||
from scolars import format_prenom, format_nom
|
from scolars import format_prenom, format_nom
|
||||||
import sco_import_users, sco_excel
|
import sco_import_users
|
||||||
from TrivialFormulator import TrivialFormulator, TF
|
import sco_excel
|
||||||
|
from TrivialFormulator import TrivialFormulator, TF, tf_error_message
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
import scolars
|
import scolars
|
||||||
import sco_cache
|
import sco_cache
|
||||||
|
import sco_users
|
||||||
# ----------------- password checking
|
from sco_permissions import (
|
||||||
import cracklib
|
ScoEditAllEvals,
|
||||||
|
ScoEditAllNotes,
|
||||||
|
ScoImplement,
|
||||||
def pwdFascistCheck(cleartxt):
|
ScoSuperAdmin,
|
||||||
"returns None if OK"
|
ScoUsersAdmin,
|
||||||
if (
|
ScoUsersView,
|
||||||
hasattr(CONFIG, "MIN_PASSWORD_LENGTH")
|
ScoView,
|
||||||
and CONFIG.MIN_PASSWORD_LENGTH > 0
|
)
|
||||||
and len(cleartxt) < CONFIG.MIN_PASSWORD_LENGTH
|
from sco_exceptions import (
|
||||||
):
|
AccessDenied,
|
||||||
return True # invalid
|
ScoException,
|
||||||
try:
|
ScoValueError,
|
||||||
x = cracklib.FascistCheck(cleartxt)
|
ScoInvalidDateError,
|
||||||
return None
|
ScoLockedFormError,
|
||||||
except ValueError as e:
|
ScoGenError,
|
||||||
return str(e)
|
)
|
||||||
|
|
||||||
|
|
||||||
# ---------------
|
# ---------------
|
||||||
# cache global: chaque instance, repérée par son URL, a un cache
|
# cache global: chaque instance, repérée par son URL, a un cache
|
||||||
@ -105,26 +105,12 @@ class ZScoUsers(
|
|||||||
self.id = id
|
self.id = id
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
||||||
# The form used to edit this object
|
|
||||||
def manage_editZScousers(self, title, RESPONSE=None):
|
|
||||||
"Changes the instance values"
|
|
||||||
self.title = title
|
|
||||||
self._p_changed = 1
|
|
||||||
RESPONSE.redirect("manage_editForm")
|
|
||||||
|
|
||||||
# Ajout (dans l'instance) d'un dtml modifiable par Zope
|
|
||||||
def defaultDocFile(self, id, title, file):
|
|
||||||
f = open(file_path + "/dtml-editable/" + file + ".dtml")
|
|
||||||
file = f.read()
|
|
||||||
f.close()
|
|
||||||
self.manage_addDTMLMethod(id, title, file)
|
|
||||||
|
|
||||||
# Connexion to SQL database of users:
|
# Connexion to SQL database of users:
|
||||||
|
|
||||||
# Ugly but necessary during transition out of Zope:
|
# Ugly but necessary during transition out of Zope:
|
||||||
_db_cnx_string = "dbname=SCOUSERS port=5432"
|
_db_cnx_string = "dbname=SCOUSERS port=5432"
|
||||||
security.declareProtected("Change DTML Documents", "GetUsersDBConnexion")
|
security.declareProtected("Change DTML Documents", "GetUsersDBConnexion")
|
||||||
GetUsersDBConnexion = notesdb.GetUsersDBConnexion
|
GetUsersDBConnexion = ndb.GetUsersDBConnexion
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@ -157,7 +143,7 @@ class ZScoUsers(
|
|||||||
|
|
||||||
if authuser.has_permission(ScoUsersAdmin, self):
|
if authuser.has_permission(ScoUsersAdmin, self):
|
||||||
H.append(
|
H.append(
|
||||||
'<p><a href="create_user_form" class="stdlink">Ajouter un utilisateur</a>'
|
'<p><a id="creer_Utilisateur" href="create_user_form" class="stdlink">Ajouter un utilisateur</a>'
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
' <a href="import_users_form" class="stdlink">Importer des utilisateurs</a></p>'
|
' <a href="import_users_form" class="stdlink">Importer des utilisateurs</a></p>'
|
||||||
@ -193,7 +179,7 @@ class ZScoUsers(
|
|||||||
F = self.sco_footer(REQUEST)
|
F = self.sco_footer(REQUEST)
|
||||||
return "\n".join(H) + F
|
return "\n".join(H) + F
|
||||||
|
|
||||||
_userEditor = EditableTable(
|
_userEditor = ndb.EditableTable(
|
||||||
"sco_users",
|
"sco_users",
|
||||||
"user_id",
|
"user_id",
|
||||||
(
|
(
|
||||||
@ -211,12 +197,12 @@ class ZScoUsers(
|
|||||||
"date_expiration",
|
"date_expiration",
|
||||||
),
|
),
|
||||||
output_formators={
|
output_formators={
|
||||||
"date_modif_passwd": DateISOtoDMY,
|
"date_modif_passwd": ndb.DateISOtoDMY,
|
||||||
"date_expiration": DateISOtoDMY,
|
"date_expiration": ndb.DateISOtoDMY,
|
||||||
},
|
},
|
||||||
input_formators={
|
input_formators={
|
||||||
"date_modif_passwd": DateDMYtoISO,
|
"date_modif_passwd": ndb.DateDMYtoISO,
|
||||||
"date_expiration": DateDMYtoISO,
|
"date_expiration": ndb.DateDMYtoISO,
|
||||||
},
|
},
|
||||||
sortkey="nom",
|
sortkey="nom",
|
||||||
filter_nulls=False,
|
filter_nulls=False,
|
||||||
@ -248,12 +234,12 @@ class ZScoUsers(
|
|||||||
u = self._user_list(args={"user_name": user_name})[0]
|
u = self._user_list(args={"user_name": user_name})[0]
|
||||||
if u["status"] == "old" and u["roles"] and u["roles"][0] != "-":
|
if u["status"] == "old" and u["roles"] and u["roles"][0] != "-":
|
||||||
roles = ["-" + r for r in u["roles"].split(",")]
|
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.acl_users.scodoc_editUser(cursor, user_name, roles=roles)
|
||||||
self.get_userlist_cache().inval_cache()
|
self.get_userlist_cache().inval_cache()
|
||||||
elif not u["status"] and u["roles"] and u["roles"][0] == "-":
|
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] == "-")]
|
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.acl_users.scodoc_editUser(cursor, user_name, roles=roles)
|
||||||
self.get_userlist_cache().inval_cache()
|
self.get_userlist_cache().inval_cache()
|
||||||
|
|
||||||
@ -275,7 +261,7 @@ class ZScoUsers(
|
|||||||
|
|
||||||
security.declareProtected(ScoUsersAdmin, "user_info")
|
security.declareProtected(ScoUsersAdmin, "user_info")
|
||||||
|
|
||||||
def user_info(self, user_name=None, user=None):
|
def user_info(self, user_name=None, user=None, format=None, REQUEST=None):
|
||||||
"""Donne infos sur l'utilisateur (qui peut ne pas etre dans notre base).
|
"""Donne infos sur l'utilisateur (qui peut ne pas etre dans notre base).
|
||||||
Si user_name est specifie, interroge la BD. Sinon, user doit etre un dict.
|
Si user_name est specifie, interroge la BD. Sinon, user doit etre un dict.
|
||||||
"""
|
"""
|
||||||
@ -299,7 +285,7 @@ class ZScoUsers(
|
|||||||
"nom_fmt": user_name,
|
"nom_fmt": user_name,
|
||||||
"nomcomplet": user_name,
|
"nomcomplet": user_name,
|
||||||
"nomplogin": user_name,
|
"nomplogin": user_name,
|
||||||
"nomnoacc": suppress_accents(user_name),
|
"nomnoacc": scu.suppress_accents(user_name),
|
||||||
"passwd_temp": 0,
|
"passwd_temp": 0,
|
||||||
"status": "",
|
"status": "",
|
||||||
"date_expiration": None,
|
"date_expiration": None,
|
||||||
@ -320,7 +306,7 @@ class ZScoUsers(
|
|||||||
else:
|
else:
|
||||||
n = user_name
|
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
|
# nomprenom est le nom capitalisé suivi de l'initiale du prénom
|
||||||
info["nomprenom"] = (n + " " + prenom_abbrv).strip()
|
info["nomprenom"] = (n + " " + prenom_abbrv).strip()
|
||||||
# prenomnom est l'initiale du prénom suivie du nom
|
# prenomnom est l'initiale du prénom suivie du nom
|
||||||
@ -332,11 +318,11 @@ class ZScoUsers(
|
|||||||
info["nomcomplet"] = info["prenom_fmt"] + " " + info["nom_fmt"]
|
info["nomcomplet"] = info["prenom_fmt"] + " " + info["nom_fmt"]
|
||||||
# nomplogin est le nom en majuscules suivi du prénom et du login
|
# nomplogin est le nom en majuscules suivi du prénom et du login
|
||||||
# e.g. Dupont Pierre (dupont)
|
# 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
|
# 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
|
return scu.sendResult(REQUEST, info, name="user", format=format)
|
||||||
|
|
||||||
def _can_handle_passwd(self, authuser, user_name, allow_admindepts=False):
|
def _can_handle_passwd(self, authuser, user_name, allow_admindepts=False):
|
||||||
"""true if authuser can see or change passwd of user_name.
|
"""true if authuser can see or change passwd of user_name.
|
||||||
@ -372,16 +358,12 @@ class ZScoUsers(
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _is_valid_passwd(self, passwd):
|
|
||||||
"check if passwd is secure enough"
|
|
||||||
return not pwdFascistCheck(passwd)
|
|
||||||
|
|
||||||
def do_change_password(self, user_name, password):
|
def do_change_password(self, user_name, password):
|
||||||
user = self._user_list(args={"user_name": user_name})
|
user = self._user_list(args={"user_name": user_name})
|
||||||
assert len(user) == 1, "database inconsistency: len(r)=%d" % len(r)
|
assert len(user) == 1, "database inconsistency: len(user)=%d" % len(user)
|
||||||
# should not occur, already tested in _can_handle_passwd
|
# should not occur, already tested in _can_handle_passwd
|
||||||
cnx = self.GetUsersDBConnexion() # en mode autocommit
|
cnx = self.GetUsersDBConnexion() # en mode autocommit
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"update sco_users set date_modif_passwd=now(), passwd_temp=0 where user_name=%(user_name)s",
|
"update sco_users set date_modif_passwd=now(), passwd_temp=0 where user_name=%(user_name)s",
|
||||||
{"user_name": user_name},
|
{"user_name": user_name},
|
||||||
@ -408,7 +390,7 @@ class ZScoUsers(
|
|||||||
# access denied
|
# access denied
|
||||||
log(
|
log(
|
||||||
"change_password: access denied (authuser=%s, user_name=%s, ip=%s)"
|
"change_password: access denied (authuser=%s, user_name=%s, ip=%s)"
|
||||||
% (authuser, user_name, REQUEST.REMOTE_ADDR)
|
% (REQUEST.AUTHENTICATED_USER, user_name, REQUEST.REMOTE_ADDR)
|
||||||
)
|
)
|
||||||
raise AccessDenied(
|
raise AccessDenied(
|
||||||
"vous n'avez pas la permission de changer ce mot de passe"
|
"vous n'avez pas la permission de changer ce mot de passe"
|
||||||
@ -421,7 +403,7 @@ class ZScoUsers(
|
|||||||
% user_name
|
% user_name
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if not self._is_valid_passwd(password):
|
if not sco_users.is_valid_password(password):
|
||||||
H.append(
|
H.append(
|
||||||
"""<p><b>ce mot de passe n\'est pas assez compliqué !</b><br/>(oui, il faut un mot de passe vraiment compliqué !)</p>
|
"""<p><b>ce mot de passe n\'est pas assez compliqué !</b><br/>(oui, il faut un mot de passe vraiment compliqué !)</p>
|
||||||
<p><a href="form_change_password?user_name=%s" class="stdlink">Recommencer</a></p>
|
<p><a href="form_change_password?user_name=%s" class="stdlink">Recommencer</a></p>
|
||||||
@ -452,7 +434,7 @@ class ZScoUsers(
|
|||||||
<meta http-equiv="Content-Type" content="text/html; charset=%s" />
|
<meta http-equiv="Content-Type" content="text/html; charset=%s" />
|
||||||
<body><h1>Mot de passe changé !</h1>
|
<body><h1>Mot de passe changé !</h1>
|
||||||
"""
|
"""
|
||||||
% (SCO_ENCODING, SCO_ENCODING)
|
% (scu.SCO_ENCODING, scu.SCO_ENCODING)
|
||||||
+ "\n".join(H)
|
+ "\n".join(H)
|
||||||
+ '<a href="%s" class="stdlink">Continuer</a></body></html>'
|
+ '<a href="%s" class="stdlink">Continuer</a></body></html>'
|
||||||
% self.ScoURL()
|
% self.ScoURL()
|
||||||
@ -541,7 +523,7 @@ class ZScoUsers(
|
|||||||
if authuser.has_permission(ScoUsersAdmin, self):
|
if authuser.has_permission(ScoUsersAdmin, self):
|
||||||
H.append(
|
H.append(
|
||||||
"""
|
"""
|
||||||
<li><a class="stdlink" href="create_user_form?user_name=%(user_name)s&edit=1">modifier/déactiver ce compte</a></li>
|
<li><a class="stdlink" href="create_user_form?user_name=%(user_name)s&edit=1">modifier/déactiver ce compte</a></li>
|
||||||
<li><a class="stdlink" href="delete_user_form?user_name=%(user_name)s">supprimer cet utilisateur</a> <em>(à n'utiliser qu'en cas d'erreur !)</em></li>
|
<li><a class="stdlink" href="delete_user_form?user_name=%(user_name)s">supprimer cet utilisateur</a> <em>(à n'utiliser qu'en cas d'erreur !)</em></li>
|
||||||
"""
|
"""
|
||||||
% info[0]
|
% info[0]
|
||||||
@ -571,7 +553,7 @@ class ZScoUsers(
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
for p in scoperms:
|
for p in scoperms:
|
||||||
permname, value = p[:2]
|
permname, _ = p[:2]
|
||||||
if thisuser.has_permission(permname, self):
|
if thisuser.has_permission(permname, self):
|
||||||
b = "oui"
|
b = "oui"
|
||||||
else:
|
else:
|
||||||
@ -810,11 +792,12 @@ class ZScoUsers(
|
|||||||
descr,
|
descr,
|
||||||
initvalues=initvalues,
|
initvalues=initvalues,
|
||||||
submitlabel=submitlabel,
|
submitlabel=submitlabel,
|
||||||
|
cancelbutton="Annuler",
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + "\n" + tf[1] + F
|
return "\n".join(H) + "\n" + tf[1] + F
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
return REQUEST.RESPONSE.redirect(self.UsersURL())
|
||||||
else:
|
else:
|
||||||
vals = tf[2]
|
vals = tf[2]
|
||||||
roles = set(vals["roles"]).intersection(editable_roles)
|
roles = set(vals["roles"]).intersection(editable_roles)
|
||||||
@ -904,7 +887,7 @@ class ZScoUsers(
|
|||||||
"""Les deux mots de passes ne correspondent pas !"""
|
"""Les deux mots de passes ne correspondent pas !"""
|
||||||
)
|
)
|
||||||
return "\n".join(H) + msg + "\n" + tf[1] + F
|
return "\n".join(H) + msg + "\n" + tf[1] + F
|
||||||
if not self._is_valid_passwd(vals["passwd"]):
|
if not sco_users.is_valid_password(vals["passwd"]):
|
||||||
msg = tf_error_message(
|
msg = tf_error_message(
|
||||||
"""Mot de passe trop simple, recommencez !"""
|
"""Mot de passe trop simple, recommencez !"""
|
||||||
)
|
)
|
||||||
@ -938,7 +921,7 @@ class ZScoUsers(
|
|||||||
|
|
||||||
# Des noms/prénoms semblables existent ?
|
# Des noms/prénoms semblables existent ?
|
||||||
cnx = self.GetUsersDBConnexion()
|
cnx = self.GetUsersDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"select * from sco_users where lower(nom) ~ %(nom)s and lower(prenom) ~ %(prenom)s;",
|
"select * from sco_users where lower(nom) ~ %(nom)s and lower(prenom) ~ %(prenom)s;",
|
||||||
{"nom": nom.lower().strip(), "prenom": prenom.lower().strip()},
|
{"nom": nom.lower().strip(), "prenom": prenom.lower().strip()},
|
||||||
@ -1015,7 +998,7 @@ class ZScoUsers(
|
|||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + "</li></ol>" + help + F
|
return "\n".join(H) + tf[1] + "</li></ol>" + help + F
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
return REQUEST.RESPONSE.redirect(self.UsersURL())
|
||||||
else:
|
else:
|
||||||
# IMPORT
|
# IMPORT
|
||||||
diag = sco_import_users.import_excel_file(
|
diag = sco_import_users.import_excel_file(
|
||||||
@ -1024,7 +1007,9 @@ class ZScoUsers(
|
|||||||
H = [head]
|
H = [head]
|
||||||
H.append("<p>Import excel: %s</p>" % diag)
|
H.append("<p>Import excel: %s</p>" % diag)
|
||||||
H.append("<p>OK, import terminé !</p>")
|
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
|
return "\n".join(H) + help + F
|
||||||
|
|
||||||
security.declareProtected(ScoUsersAdmin, "import_users_generate_excel_sample")
|
security.declareProtected(ScoUsersAdmin, "import_users_generate_excel_sample")
|
||||||
@ -1039,13 +1024,13 @@ class ZScoUsers(
|
|||||||
def create_user(self, args, REQUEST=None):
|
def create_user(self, args, REQUEST=None):
|
||||||
"creation utilisateur zope"
|
"creation utilisateur zope"
|
||||||
cnx = self.GetUsersDBConnexion()
|
cnx = self.GetUsersDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
passwd = args["passwd"]
|
passwd = args["passwd"]
|
||||||
args["passwd"] = "undefined"
|
args["passwd"] = "undefined"
|
||||||
if "passwd2" in args:
|
if "passwd2" in args:
|
||||||
del args["passwd2"]
|
del args["passwd2"]
|
||||||
log("create_user: args=%s" % args) # log apres supr. du mot de passe !
|
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() # >
|
self.get_userlist_cache().inval_cache() # >
|
||||||
|
|
||||||
# call exUserFolder to set passwd
|
# call exUserFolder to set passwd
|
||||||
@ -1055,7 +1040,7 @@ class ZScoUsers(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if REQUEST:
|
if REQUEST:
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
return REQUEST.RESPONSE.redirect(self.UsersURL())
|
||||||
|
|
||||||
security.declareProtected(ScoUsersAdmin, "delete_user_form")
|
security.declareProtected(ScoUsersAdmin, "delete_user_form")
|
||||||
|
|
||||||
@ -1083,11 +1068,15 @@ class ZScoUsers(
|
|||||||
% user_name,
|
% user_name,
|
||||||
dest_url="",
|
dest_url="",
|
||||||
REQUEST=REQUEST,
|
REQUEST=REQUEST,
|
||||||
cancel_url=REQUEST.URL1,
|
cancel_url=self.UsersURL(),
|
||||||
parameters={"user_name": user_name},
|
parameters={"user_name": user_name},
|
||||||
)
|
)
|
||||||
self._user_delete(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")
|
||||||
|
|
||||||
def list_users(
|
def list_users(
|
||||||
self,
|
self,
|
||||||
@ -1133,15 +1122,15 @@ class ZScoUsers(
|
|||||||
|
|
||||||
# Convert dates to ISO if XML output
|
# Convert dates to ISO if XML output
|
||||||
if format == "xml" and u["date_modif_passwd"] != "NA":
|
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
|
# Convert date_expiration and date_modif_passwd to ISO to ease sorting
|
||||||
if u["date_expiration"]:
|
if u["date_expiration"]:
|
||||||
u["date_expiration_iso"] = DateDMYtoISO(u["date_expiration"])
|
u["date_expiration_iso"] = ndb.DateDMYtoISO(u["date_expiration"])
|
||||||
else:
|
else:
|
||||||
u["date_expiration_iso"] = ""
|
u["date_expiration_iso"] = ""
|
||||||
if u["date_modif_passwd"]:
|
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:
|
else:
|
||||||
u["date_modif_passwd_iso"] = ""
|
u["date_modif_passwd_iso"] = ""
|
||||||
|
|
||||||
@ -1235,13 +1224,13 @@ class ZScoUsers(
|
|||||||
"""Returns XML list of users with name (nomplogin) starting with start.
|
"""Returns XML list of users with name (nomplogin) starting with start.
|
||||||
Used for forms auto-completion."""
|
Used for forms auto-completion."""
|
||||||
userlist = self.get_userlist(dept=dept)
|
userlist = self.get_userlist(dept=dept)
|
||||||
start = suppression_diacritics(unicode(start, "utf-8"))
|
start = scu.suppression_diacritics(unicode(start, "utf-8"))
|
||||||
start = strlower(str(start))
|
start = scu.strlower(str(start))
|
||||||
|
|
||||||
userlist = [user for user in userlist if user["nomnoacc"].startswith(start)]
|
userlist = [user for user in userlist if user["nomnoacc"].startswith(start)]
|
||||||
if REQUEST:
|
if REQUEST:
|
||||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||||
doc = jaxml.XML_document(encoding=SCO_ENCODING)
|
doc = jaxml.XML_document(encoding=scu.SCO_ENCODING)
|
||||||
doc.results()
|
doc.results()
|
||||||
for user in userlist[:limit]:
|
for user in userlist[:limit]:
|
||||||
doc._push()
|
doc._push()
|
||||||
@ -1276,8 +1265,8 @@ Il devra ensuite se connecter et le changer.
|
|||||||
)
|
)
|
||||||
self.reset_password(user_name=user_name, REQUEST=REQUEST)
|
self.reset_password(user_name=user_name, REQUEST=REQUEST)
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
REQUEST.URL1
|
self.UsersURL()
|
||||||
+ "?head_message=mot%20de%20passe%20de%20"
|
+ r"?head_message=mot%20de%20passe%20de%20"
|
||||||
+ user_name
|
+ user_name
|
||||||
+ "%20reinitialise"
|
+ "%20reinitialise"
|
||||||
)
|
)
|
||||||
@ -1302,14 +1291,14 @@ Il devra ensuite se connecter et le changer.
|
|||||||
log("reset_password: %s" % user_name)
|
log("reset_password: %s" % user_name)
|
||||||
# Check that user has valid mail
|
# Check that user has valid mail
|
||||||
info = self.user_info(user_name=user_name)
|
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")
|
raise Exception("pas de mail valide associé à l'utilisateur")
|
||||||
# Generate random password
|
# Generate random password
|
||||||
password = sco_import_users.generate_password()
|
password = sco_import_users.generate_password()
|
||||||
self.do_change_password(user_name, password)
|
self.do_change_password(user_name, password)
|
||||||
# Flag it as temporary:
|
# Flag it as temporary:
|
||||||
cnx = self.GetUsersDBConnexion()
|
cnx = self.GetUsersDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
ui = {"user_name": user_name}
|
ui = {"user_name": user_name}
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"update sco_users set passwd_temp=1 where user_name='%(user_name)s'" % ui
|
"update sco_users set passwd_temp=1 where user_name='%(user_name)s'" % ui
|
||||||
|
492
ZScolar.py
492
ZScolar.py
@ -30,8 +30,15 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import time, string, glob, re
|
import time
|
||||||
import urllib, urllib2, cgi, xml
|
import string
|
||||||
|
import glob
|
||||||
|
import re
|
||||||
|
import urllib
|
||||||
|
import urllib2
|
||||||
|
import cgi
|
||||||
|
import xml
|
||||||
|
import jaxml
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
@ -41,7 +48,7 @@ from zipfile import ZipFile
|
|||||||
import thread
|
import thread
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
|
||||||
from sco_zope import *
|
from sco_zope import * # pylint: disable=unused-wildcard-import
|
||||||
|
|
||||||
|
|
||||||
# ---------------
|
# ---------------
|
||||||
@ -53,18 +60,46 @@ log("restarting...")
|
|||||||
log("ZScolar home=%s" % file_path)
|
log("ZScolar home=%s" % file_path)
|
||||||
|
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
import notesdb
|
import notesdb as ndb
|
||||||
from notesdb import *
|
|
||||||
from scolog import logdb
|
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 scolars
|
||||||
|
import sco_codes_parcours
|
||||||
import sco_preferences
|
import sco_preferences
|
||||||
import sco_formations
|
import sco_formations
|
||||||
from scolars import (
|
from scolars import (
|
||||||
format_nom,
|
format_nom,
|
||||||
format_prenom,
|
format_prenom,
|
||||||
format_sexe,
|
format_civilite,
|
||||||
format_lycee,
|
format_lycee,
|
||||||
format_lycee_from_code,
|
format_lycee_from_code,
|
||||||
)
|
)
|
||||||
@ -87,8 +122,10 @@ import ZNotes
|
|||||||
import ZAbsences
|
import ZAbsences
|
||||||
import ZEntreprises
|
import ZEntreprises
|
||||||
import ZScoUsers
|
import ZScoUsers
|
||||||
import sco_modalites
|
|
||||||
|
# import sco_modalites
|
||||||
import ImportScolars
|
import ImportScolars
|
||||||
|
import sco_abs
|
||||||
import sco_portal_apogee
|
import sco_portal_apogee
|
||||||
import sco_synchro_etuds
|
import sco_synchro_etuds
|
||||||
import sco_page_etud
|
import sco_page_etud
|
||||||
@ -108,9 +145,9 @@ import sco_dump_db
|
|||||||
|
|
||||||
from VERSION import SCOVERSION, SCONEWS
|
from VERSION import SCOVERSION, SCONEWS
|
||||||
|
|
||||||
if hasattr(CONFIG, "ABSOLUTE_URL") and CONFIG.ABSOLUTE_URL:
|
if hasattr(scu.CONFIG, "ABSOLUTE_URL") and scu.CONFIG.ABSOLUTE_URL:
|
||||||
log("ScoDoc: ABSOLUTE_URL='%s'" % CONFIG.ABSOLUTE_URL)
|
log("ScoDoc: ABSOLUTE_URL='%s'" % scu.CONFIG.ABSOLUTE_URL)
|
||||||
log("ScoDoc: using encoding %s" % SCO_ENCODING)
|
log("ScoDoc: using encoding %s" % scu.SCO_ENCODING)
|
||||||
|
|
||||||
# import essai_cas
|
# import essai_cas
|
||||||
|
|
||||||
@ -132,13 +169,7 @@ class ZScolar(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
manage_options = (
|
manage_options = (
|
||||||
({"label": "Contents", "action": "manage_main"},)
|
({"label": "Contents", "action": "manage_main"},)
|
||||||
+ PropertyManager.manage_options # add the 'Properties' tab
|
+ PropertyManager.manage_options # add the 'Properties' tab
|
||||||
+ (
|
+ ({"label": "View", "action": "index_html"},)
|
||||||
# this line is kept as an example with the files :
|
|
||||||
# dtml/manage_editZScolarForm.dtml
|
|
||||||
# html/ZScolar-edit.stx
|
|
||||||
# {'label': 'Properties', 'action': 'manage_editForm',},
|
|
||||||
{"label": "View", "action": "index_html"},
|
|
||||||
)
|
|
||||||
+ Item.manage_options # add the 'Undo' & 'Owner' tab
|
+ Item.manage_options # add the 'Undo' & 'Owner' tab
|
||||||
+ RoleManager.manage_options # add the 'Security' tab
|
+ RoleManager.manage_options # add the 'Security' tab
|
||||||
)
|
)
|
||||||
@ -151,17 +182,7 @@ class ZScolar(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
self.title = title
|
self.title = title
|
||||||
self._db_cnx_string = db_cnx_string
|
self._db_cnx_string = db_cnx_string
|
||||||
self._cnx = None
|
self._cnx = None
|
||||||
# --- add editable DTML documents:
|
|
||||||
# self.defaultDocFile('sidebar_dept',
|
|
||||||
# 'barre gauche (partie haute)',
|
|
||||||
# 'sidebar_dept')
|
|
||||||
|
|
||||||
# --- add DB connector
|
|
||||||
# id = 'DB'
|
|
||||||
# da = ZopeDA.Connection(
|
|
||||||
# id, 'DB connector', db_cnx_string, False,
|
|
||||||
# check=1, tilevel=2, encoding='utf-8')
|
|
||||||
# self._setObject(id, da)
|
|
||||||
# --- add Scousers instance
|
# --- add Scousers instance
|
||||||
id = "Users"
|
id = "Users"
|
||||||
obj = ZScoUsers.ZScoUsers(id, "Gestion utilisateurs zope")
|
obj = ZScoUsers.ZScoUsers(id, "Gestion utilisateurs zope")
|
||||||
@ -183,11 +204,13 @@ class ZScolar(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
self.manage_addProperty("roles_initialized", "0", "string")
|
self.manage_addProperty("roles_initialized", "0", "string")
|
||||||
|
|
||||||
# The for used to edit this object
|
# The for used to edit this object
|
||||||
def manage_editZScolar(self, title, RESPONSE=None):
|
security.declareProtected(ScoView, "manage_editZScolar")
|
||||||
|
|
||||||
|
def manage_editZScolar(self, title, REQUEST=None):
|
||||||
"Changes the instance values"
|
"Changes the instance values"
|
||||||
self.title = title
|
self.title = title
|
||||||
self._p_changed = 1
|
self._p_changed = 1
|
||||||
RESPONSE.redirect("manage_editForm")
|
return REQUEST.RESPONSE.redirect("manage_editForm")
|
||||||
|
|
||||||
def _setup_initial_roles_and_permissions(self):
|
def _setup_initial_roles_and_permissions(self):
|
||||||
"""Initialize roles and permissions
|
"""Initialize roles and permissions
|
||||||
@ -209,8 +232,10 @@ class ZScolar(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
H.append(r)
|
H.append(r)
|
||||||
ok = False
|
ok = False
|
||||||
|
|
||||||
for permission in Sco_Default_Permissions.keys():
|
for permission in sco_permissions.Sco_Default_Permissions.keys():
|
||||||
roles = [r + DeptId for r in Sco_Default_Permissions[permission]]
|
roles = [
|
||||||
|
r + DeptId for r in sco_permissions.Sco_Default_Permissions[permission]
|
||||||
|
]
|
||||||
roles.append("Manager")
|
roles.append("Manager")
|
||||||
log("granting '%s' to %s" % (permission, roles))
|
log("granting '%s' to %s" % (permission, roles))
|
||||||
try:
|
try:
|
||||||
@ -254,7 +279,7 @@ class ZScolar(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
<head>
|
<head>
|
||||||
<title>Programme DUT R&T</title>
|
<title>Programme DUT TEST</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<meta http-equiv="Content-Style-Type" content="text/css" />
|
<meta http-equiv="Content-Style-Type" content="text/css" />
|
||||||
<meta name="LANG" content="fr" />
|
<meta name="LANG" content="fr" />
|
||||||
@ -269,65 +294,70 @@ class ZScolar(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<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>
|
<tt>
|
||||||
<span class="locked">[verrouillé]</span>
|
REQUEST.URL=%s<br/>
|
||||||
|
REQUEST.URL0=%s<br/>
|
||||||
|
</tt>
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
"""
|
""" % (
|
||||||
return (
|
REQUEST.URL,
|
||||||
self.sco_header(REQUEST)
|
REQUEST.URL0,
|
||||||
+ """<div class="xp">%s</div>""" % x
|
|
||||||
+ self.sco_footer(REQUEST)
|
|
||||||
)
|
)
|
||||||
b = "<p>Hello, World !</p><br/>"
|
# return (
|
||||||
raise ValueError("essai exception")
|
# self.sco_header(REQUEST)
|
||||||
|
# + """<div class="xp">%s</div>""" % x
|
||||||
|
# + self.sco_footer(REQUEST)
|
||||||
|
# )
|
||||||
|
# b = "<p>Hello, World !</p><br/>"
|
||||||
|
# raise ValueError("essai exception")
|
||||||
# raise ScoValueError('essai exception !', dest_url='totoro', REQUEST=REQUEST)
|
# 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")
|
# cursor.execute("select * from notes_formations")
|
||||||
# b += str(cursor.fetchall())
|
# b += str(cursor.fetchall())
|
||||||
# b = self.Notes.gloups()
|
# b = self.Notes.gloups()
|
||||||
# raise NoteProcessError('test exception !')
|
# raise NoteProcessError('test exception !')
|
||||||
|
|
||||||
# essai: liste des permissions
|
# essai: liste des permissions
|
||||||
from AccessControl import getSecurityManager
|
# from AccessControl import getSecurityManager # pylint: disable=import-error
|
||||||
from AccessControl.Permission import Permission
|
# from AccessControl.Permission import Permission # pylint: disable=import-error
|
||||||
|
|
||||||
permissions = self.ac_inherited_permissions(1)
|
# permissions = self.ac_inherited_permissions(1)
|
||||||
scoperms = [p for p in permissions if p[0][:3] == "Sco"]
|
# scoperms = [p for p in permissions if p[0][:3] == "Sco"]
|
||||||
# H.append( str(self.aq_parent.aq_parent.permission_settings()) )
|
# # H.append( str(self.aq_parent.aq_parent.permission_settings()) )
|
||||||
# H.append('<p>perms: %s</p>'%str(scoperms))
|
# # H.append('<p>perms: %s</p>'%str(scoperms))
|
||||||
# H.append('<p>valid_roles: %s</p>'%str(self.valid_roles()))
|
# # 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)))
|
# # H.append('<p>ac_inherited_permissions=%s</p>'%str(self.ac_inherited_permissions(1)))
|
||||||
def collect_roles(context, rd):
|
# def collect_roles(context, rd):
|
||||||
for p in scoperms:
|
# for p in scoperms:
|
||||||
name, value = p[:2]
|
# name, value = p[:2]
|
||||||
P = Permission(name, value, context)
|
# P = Permission(name, value, context)
|
||||||
roles = list(P.getRoles())
|
# roles = list(P.getRoles())
|
||||||
if rd.has_key(name):
|
# if rd.has_key(name):
|
||||||
rd[name] += roles
|
# rd[name] += roles
|
||||||
else:
|
# else:
|
||||||
rd[name] = roles
|
# rd[name] = roles
|
||||||
if hasattr(context, "aq_parent"):
|
# if hasattr(context, "aq_parent"):
|
||||||
collect_roles(context.aq_parent, rd)
|
# collect_roles(context.aq_parent, rd)
|
||||||
|
|
||||||
b = ""
|
# b = ""
|
||||||
rd = {}
|
# rd = {}
|
||||||
collect_roles(self, rd)
|
# collect_roles(self, rd)
|
||||||
b = "<p>" + str(rd) + "</p>"
|
# b = "<p>" + str(rd) + "</p>"
|
||||||
|
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
# authuser = REQUEST.AUTHENTICATED_USER
|
||||||
for p in scoperms:
|
# for p in scoperms:
|
||||||
permname, value = p[:2]
|
# permname, _ = p[:2]
|
||||||
b += "<p>" + permname + " : "
|
# b += "<p>" + permname + " : "
|
||||||
if authuser.has_permission(permname, self):
|
# if authuser.has_permission(permname, self):
|
||||||
b += "yes"
|
# b += "yes"
|
||||||
else:
|
# else:
|
||||||
b += "no"
|
# b += "no"
|
||||||
b += "</p>"
|
# b += "</p>"
|
||||||
b += "<p>xxx</p><hr><p>" + str(self.aq_parent.aq_parent)
|
# 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:
|
# essais calendriers:
|
||||||
security.declareProtected(ScoView, "experimental_calendar")
|
security.declareProtected(ScoView, "experimental_calendar")
|
||||||
@ -338,11 +368,43 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
security.declareProtected(ScoView, "ScoURL")
|
security.declareProtected(ScoView, "ScoURL")
|
||||||
|
|
||||||
def ScoURL(self):
|
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
|
# absolute_url is the classic Zope method
|
||||||
# The avoid the burden of configuring a proxy zope object, we offer
|
# The avoid the burden of configuring a proxy zope object, we offer
|
||||||
# a custom configuration via scodoc_config
|
# 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 AbsencesURL(self):
|
||||||
|
"""URL of Absences"""
|
||||||
|
return self.ScoURL() + "/Absences"
|
||||||
|
|
||||||
|
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")
|
security.declareProtected(ScoView, "sco_header")
|
||||||
sco_header = html_sco_header.sco_header
|
sco_header = html_sco_header.sco_header
|
||||||
@ -361,7 +423,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
return self._db_cnx_string
|
return self._db_cnx_string
|
||||||
|
|
||||||
security.declareProtected(ScoSuperAdmin, "GetDBConnexion")
|
security.declareProtected(ScoSuperAdmin, "GetDBConnexion")
|
||||||
GetDBConnexion = notesdb.GetDBConnexion
|
GetDBConnexion = ndb.GetDBConnexion
|
||||||
|
|
||||||
# A enlever après re-ecriture de ZEntreprises.py
|
# A enlever après re-ecriture de ZEntreprises.py
|
||||||
security.declareProtected(ScoView, "TrivialFormulator")
|
security.declareProtected(ScoView, "TrivialFormulator")
|
||||||
@ -404,10 +466,10 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
"version info"
|
"version info"
|
||||||
H = [
|
H = [
|
||||||
"""<h2>Système de gestion scolarité</h2>
|
"""<h2>Système de gestion scolarité</h2>
|
||||||
<p>© Emmanuel Viennet 1997-2020</p>
|
<p>© Emmanuel Viennet 1997-2021</p>
|
||||||
<p>Version %s (subversion %s)</p>
|
<p>Version %s (subversion %s)</p>
|
||||||
"""
|
"""
|
||||||
% (SCOVERSION, get_svn_version(file_path))
|
% (SCOVERSION, scu.get_svn_version(file_path))
|
||||||
]
|
]
|
||||||
H.append(
|
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>'
|
'<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>'
|
||||||
@ -415,7 +477,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("<h2>Dernières évolutions</h2>" + SCONEWS)
|
||||||
H.append(
|
H.append(
|
||||||
'<div class="about-logo">'
|
'<div class="about-logo">'
|
||||||
+ icontag("borgne_img")
|
+ scu.icontag("borgne_img")
|
||||||
+ " <em>Au pays des aveugles...</em></div>"
|
+ " <em>Au pays des aveugles...</em></div>"
|
||||||
)
|
)
|
||||||
d = ""
|
d = ""
|
||||||
@ -429,12 +491,12 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
if format == "html" or format == "pdf":
|
if format == "html" or format == "pdf":
|
||||||
raise ScoValueError(msg)
|
raise ScoValueError(msg)
|
||||||
elif format == "xml":
|
elif format == "xml":
|
||||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||||
doc = jaxml.XML_document(encoding=SCO_ENCODING)
|
doc = jaxml.XML_document(encoding=scu.SCO_ENCODING)
|
||||||
doc.error(msg=msg)
|
doc.error(msg=msg)
|
||||||
return repr(doc)
|
return repr(doc)
|
||||||
elif format == "json":
|
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
|
return "undefined" # XXX voir quoi faire en cas d'erreur json
|
||||||
else:
|
else:
|
||||||
raise ValueError("ScoErrorResponse: invalid format")
|
raise ValueError("ScoErrorResponse: invalid format")
|
||||||
@ -529,7 +591,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
page_title="Opérations sur %(nomprenom)s" % etud,
|
page_title="Opérations sur %(nomprenom)s" % etud,
|
||||||
html_title="<h2>Opérations effectuées sur l'étudiant %(nomprenom)s</h2>"
|
html_title="<h2>Opérations effectuées sur l'étudiant %(nomprenom)s</h2>"
|
||||||
% etud,
|
% 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>'
|
html_next_section='<ul><li><a href="ficheEtud?etudid=%(etudid)s">fiche de %(nomprenom)s</a></li></ul>'
|
||||||
% etud,
|
% etud,
|
||||||
preferences=self.get_preferences(),
|
preferences=self.get_preferences(),
|
||||||
@ -537,10 +599,12 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
|
|
||||||
return tab.make_page(self, format=format, REQUEST=REQUEST)
|
return tab.make_page(self, format=format, REQUEST=REQUEST)
|
||||||
|
|
||||||
|
security.declareProtected(ScoView, "listScoLog")
|
||||||
|
|
||||||
def listScoLog(self, etudid):
|
def listScoLog(self, etudid):
|
||||||
"liste des operations effectuees sur cet etudiant"
|
"liste des operations effectuees sur cet etudiant"
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"select * from scolog where etudid=%(etudid)s ORDER BY DATE DESC",
|
"select * from scolog where etudid=%(etudid)s ORDER BY DATE DESC",
|
||||||
{"etudid": etudid},
|
{"etudid": etudid},
|
||||||
@ -555,7 +619,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
|
|
||||||
def rssnews(self, REQUEST=None):
|
def rssnews(self, REQUEST=None):
|
||||||
"rss feed"
|
"rss feed"
|
||||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||||
return sco_news.scolar_news_summary_rss(
|
return sco_news.scolar_news_summary_rss(
|
||||||
self, "Nouvelles de " + self.get_preference("DeptName"), self.ScoURL()
|
self, "Nouvelles de " + self.get_preference("DeptName"), self.ScoURL()
|
||||||
)
|
)
|
||||||
@ -592,7 +656,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
# calcule dates 1er jour semaine pour absences
|
# calcule dates 1er jour semaine pour absences
|
||||||
try:
|
try:
|
||||||
if with_absences:
|
if with_absences:
|
||||||
first_monday = ZAbsences.ddmmyyyy(sem["date_debut"]).prev_monday()
|
first_monday = sco_abs.ddmmyyyy(sem["date_debut"]).prev_monday()
|
||||||
FA = [] # formulaire avec menu saisi absences
|
FA = [] # formulaire avec menu saisi absences
|
||||||
FA.append(
|
FA.append(
|
||||||
'<td><form action="Absences/SignaleAbsenceGrSemestre" method="get">'
|
'<td><form action="Absences/SignaleAbsenceGrSemestre" method="get">'
|
||||||
@ -610,12 +674,12 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
FA.append('<input type="submit" value="Saisir absences du" />')
|
FA.append('<input type="submit" value="Saisir absences du" />')
|
||||||
FA.append('<select name="datedebut" class="noprint">')
|
FA.append('<select name="datedebut" class="noprint">')
|
||||||
date = first_monday
|
date = first_monday
|
||||||
for jour in self.Absences.day_names():
|
for jour in sco_abs.day_names(self):
|
||||||
FA.append('<option value="%s">%s</option>' % (date, jour))
|
FA.append('<option value="%s">%s</option>' % (date, jour))
|
||||||
date = date.next()
|
date = date.next()
|
||||||
FA.append("</select>")
|
FA.append("</select>")
|
||||||
FA.append(
|
FA.append(
|
||||||
'<a href="Absences/EtatAbsencesGr?group_ids=%%(group_id)s&debut=%(date_debut)s&fin=%(date_fin)s">état</a>'
|
'<a href="Absences/EtatAbsencesGr?group_ids=%%(group_id)s&debut=%(date_debut)s&fin=%(date_fin)s">état</a>'
|
||||||
% sem
|
% sem
|
||||||
)
|
)
|
||||||
FA.append("</form></td>")
|
FA.append("</form></td>")
|
||||||
@ -651,8 +715,8 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
"""<td>
|
"""<td>
|
||||||
<a href="%(url)s/groups_view?group_ids=%(group_id)s">%(label)s</a>
|
<a href="%(url)s/groups_view?group_ids=%(group_id)s">%(label)s</a>
|
||||||
</td><td>
|
</td><td>
|
||||||
(<a href="%(url)s/groups_view?group_ids=%(group_id)s&format=xls">format tableur</a>)
|
(<a href="%(url)s/groups_view?group_ids=%(group_id)s&format=xls">format tableur</a>)
|
||||||
<a href="%(url)s/groups_view?curtab=tab-photos&group_ids=%(group_id)s&etat=I">Photos</a>
|
<a href="%(url)s/groups_view?curtab=tab-photos&group_ids=%(group_id)s&etat=I">Photos</a>
|
||||||
</td>"""
|
</td>"""
|
||||||
% group
|
% group
|
||||||
)
|
)
|
||||||
@ -665,13 +729,13 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
H.append("</table>")
|
H.append("</table>")
|
||||||
else:
|
else:
|
||||||
H.append('<p class="help indent">Aucun groupe dans cette partition')
|
H.append('<p class="help indent">Aucun groupe dans cette partition')
|
||||||
if self.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if sco_groups.can_change_groups(self, REQUEST, formsemestre_id):
|
||||||
H.append(
|
H.append(
|
||||||
' (<a href="affectGroups?partition_id=%s" class="stdlink">créer</a>)'
|
' (<a href="affectGroups?partition_id=%s" class="stdlink">créer</a>)'
|
||||||
% partition["partition_id"]
|
% partition["partition_id"]
|
||||||
)
|
)
|
||||||
H.append("</p>")
|
H.append("</p>")
|
||||||
if self.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if sco_groups.can_change_groups(self, REQUEST, formsemestre_id):
|
||||||
H.append(
|
H.append(
|
||||||
'<h4><a href="editPartitionForm?formsemestre_id=%s">Ajouter une partition</a></h4>'
|
'<h4><a href="editPartitionForm?formsemestre_id=%s">Ajouter une partition</a></h4>'
|
||||||
% formsemestre_id
|
% formsemestre_id
|
||||||
@ -716,7 +780,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
# -------------------------- INFOS SUR ETUDIANTS --------------------------
|
# -------------------------- INFOS SUR ETUDIANTS --------------------------
|
||||||
security.declareProtected(ScoView, "getEtudInfo")
|
security.declareProtected(ScoView, "getEtudInfo")
|
||||||
|
|
||||||
def getEtudInfo(self, etudid=False, code_nip=False, filled=False, REQUEST=None):
|
def getEtudInfo(self, etudid=False, code_nip=False, filled=False, REQUEST=None, format=None):
|
||||||
"""infos sur un etudiant pour utilisation en Zope DTML
|
"""infos sur un etudiant pour utilisation en Zope DTML
|
||||||
On peut specifier etudid
|
On peut specifier etudid
|
||||||
ou bien cherche dans REQUEST.form: etudid, code_nip, code_ine
|
ou bien cherche dans REQUEST.form: etudid, code_nip, code_ine
|
||||||
@ -727,9 +791,13 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
args = make_etud_args(etudid=etudid, code_nip=code_nip, REQUEST=REQUEST)
|
args = make_etud_args(etudid=etudid, code_nip=code_nip, REQUEST=REQUEST)
|
||||||
etud = scolars.etudident_list(cnx, args=args)
|
etud = scolars.etudident_list(cnx, args=args)
|
||||||
|
|
||||||
if filled:
|
if filled:
|
||||||
self.fillEtudsInfo(etud)
|
self.fillEtudsInfo(etud)
|
||||||
return etud
|
if format is None:
|
||||||
|
return etud
|
||||||
|
else:
|
||||||
|
return scu.sendResult(REQUEST, etud, name="etud", format=format)
|
||||||
|
|
||||||
security.declareProtected(ScoView, "search_etud_in_dept")
|
security.declareProtected(ScoView, "search_etud_in_dept")
|
||||||
search_etud_in_dept = sco_find_etud.search_etud_in_dept
|
search_etud_in_dept = sco_find_etud.search_etud_in_dept
|
||||||
@ -764,14 +832,11 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
# Semestres dans lesquel il est inscrit
|
# Semestres dans lesquel il est inscrit
|
||||||
ins = self.Notes.do_formsemestre_inscription_list({"etudid": etudid})
|
ins = self.Notes.do_formsemestre_inscription_list({"etudid": etudid})
|
||||||
etud["ins"] = ins
|
etud["ins"] = ins
|
||||||
now = time.strftime("%Y-%m-%d")
|
|
||||||
sems = []
|
sems = []
|
||||||
cursem = None # semestre "courant" ou il est inscrit
|
cursem = None # semestre "courant" ou il est inscrit
|
||||||
for i in ins:
|
for i in ins:
|
||||||
sem = sco_formsemestre.get_formsemestre(self, i["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(self, i["formsemestre_id"])
|
||||||
debut = DateDMYtoISO(sem["date_debut"])
|
if sco_formsemestre.sem_est_courant(self, sem):
|
||||||
fin = DateDMYtoISO(sem["date_fin"])
|
|
||||||
if debut <= now and now <= fin:
|
|
||||||
cursem = sem
|
cursem = sem
|
||||||
curi = i
|
curi = i
|
||||||
sem["ins"] = i
|
sem["ins"] = i
|
||||||
@ -859,18 +924,19 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
"nom": "?",
|
"nom": "?",
|
||||||
"nom_usuel": "",
|
"nom_usuel": "",
|
||||||
"prenom": "?",
|
"prenom": "?",
|
||||||
"sexe": "?",
|
"civilite": "?",
|
||||||
|
"sexe": "?", # for backward compat
|
||||||
"email": "?",
|
"email": "?",
|
||||||
"emailperso": "",
|
"emailperso": "",
|
||||||
"error": "code etudiant inconnu",
|
"error": "code etudiant inconnu",
|
||||||
}
|
}
|
||||||
return sendResult(
|
return scu.sendResult(
|
||||||
REQUEST, d, name="etudiant", format=format, force_outer_xml_tag=False
|
REQUEST, d, name="etudiant", format=format, force_outer_xml_tag=False
|
||||||
)
|
)
|
||||||
d = {}
|
d = {}
|
||||||
etud = etuds[0]
|
etud = etuds[0]
|
||||||
self.fillEtudsInfo([etud])
|
self.fillEtudsInfo([etud])
|
||||||
etud["date_naissance_iso"] = DateDMYtoISO(etud["date_naissance"])
|
etud["date_naissance_iso"] = ndb.DateDMYtoISO(etud["date_naissance"])
|
||||||
for a in (
|
for a in (
|
||||||
"etudid",
|
"etudid",
|
||||||
"code_nip",
|
"code_nip",
|
||||||
@ -878,7 +944,6 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
"nom",
|
"nom",
|
||||||
"nom_usuel",
|
"nom_usuel",
|
||||||
"prenom",
|
"prenom",
|
||||||
"sexe",
|
|
||||||
"nomprenom",
|
"nomprenom",
|
||||||
"email",
|
"email",
|
||||||
"emailperso",
|
"emailperso",
|
||||||
@ -898,8 +963,12 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
"codelycee",
|
"codelycee",
|
||||||
"date_naissance_iso",
|
"date_naissance_iso",
|
||||||
):
|
):
|
||||||
d[a] = quote_xml_attr(etud[a])
|
d[a] = scu.quote_xml_attr(etud[a])
|
||||||
d["photo_url"] = quote_xml_attr(sco_photos.etud_photo_url(self, etud))
|
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"]
|
sem = etud["cursem"]
|
||||||
if sem:
|
if sem:
|
||||||
@ -908,10 +977,10 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
{
|
{
|
||||||
"current": "1",
|
"current": "1",
|
||||||
"formsemestre_id": sem["formsemestre_id"],
|
"formsemestre_id": sem["formsemestre_id"],
|
||||||
"date_debut": DateDMYtoISO(sem["date_debut"]),
|
"date_debut": ndb.DateDMYtoISO(sem["date_debut"]),
|
||||||
"date_fin": DateDMYtoISO(sem["date_fin"]),
|
"date_fin": ndb.DateDMYtoISO(sem["date_fin"]),
|
||||||
"etat": quote_xml_attr(sem["ins"]["etat"]),
|
"etat": scu.quote_xml_attr(sem["ins"]["etat"]),
|
||||||
"groupes": quote_xml_attr(
|
"groupes": scu.quote_xml_attr(
|
||||||
etud["groupes"]
|
etud["groupes"]
|
||||||
), # slt pour semestre courant
|
), # slt pour semestre courant
|
||||||
}
|
}
|
||||||
@ -923,20 +992,22 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
d["insemestre"].append(
|
d["insemestre"].append(
|
||||||
{
|
{
|
||||||
"formsemestre_id": sem["formsemestre_id"],
|
"formsemestre_id": sem["formsemestre_id"],
|
||||||
"date_debut": DateDMYtoISO(sem["date_debut"]),
|
"date_debut": ndb.DateDMYtoISO(sem["date_debut"]),
|
||||||
"date_fin": DateDMYtoISO(sem["date_fin"]),
|
"date_fin": ndb.DateDMYtoISO(sem["date_fin"]),
|
||||||
"etat": quote_xml_attr(sem["ins"]["etat"]),
|
"etat": scu.quote_xml_attr(sem["ins"]["etat"]),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
log("etud_info (%gs)" % (time.time() - t0))
|
log("etud_info (%gs)" % (time.time() - t0))
|
||||||
return sendResult(
|
return scu.sendResult(
|
||||||
REQUEST, d, name="etudiant", format=format, force_outer_xml_tag=False
|
REQUEST, d, name="etudiant", format=format, force_outer_xml_tag=False
|
||||||
)
|
)
|
||||||
|
|
||||||
security.declareProtected(ScoView, "XMLgetEtudInfos")
|
security.declareProtected(ScoView, "XMLgetEtudInfos")
|
||||||
XMLgetEtudInfos = etud_info # old name, deprecated
|
XMLgetEtudInfos = etud_info # old name, deprecated
|
||||||
|
|
||||||
|
security.declareProtected(ScoView, "isPrimoEtud")
|
||||||
|
|
||||||
def isPrimoEtud(self, etud, sem):
|
def isPrimoEtud(self, etud, sem):
|
||||||
"""Determine si un (filled) etud a ete inscrit avant ce semestre.
|
"""Determine si un (filled) etud a ete inscrit avant ce semestre.
|
||||||
Regarde la liste des semestres dans lesquels l'étudiant est inscrit
|
Regarde la liste des semestres dans lesquels l'étudiant est inscrit
|
||||||
@ -971,7 +1042,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
def _descr_situation_etud(self, etudid, ne=""):
|
def _descr_situation_etud(self, etudid, ne=""):
|
||||||
"""chaine decrivant la situation actuelle de l'etudiant"""
|
"""chaine decrivant la situation actuelle de l'etudiant"""
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
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;",
|
"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},
|
{"etudid": etudid},
|
||||||
@ -1063,7 +1134,7 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
logdb(REQUEST, cnx, method="addAnnotation", etudid=etudid)
|
logdb(REQUEST, cnx, method="addAnnotation", etudid=etudid)
|
||||||
REQUEST.RESPONSE.redirect("ficheEtud?etudid=" + etudid)
|
return REQUEST.RESPONSE.redirect("ficheEtud?etudid=" + etudid)
|
||||||
|
|
||||||
security.declareProtected(ScoView, "canSuppressAnnotation")
|
security.declareProtected(ScoView, "canSuppressAnnotation")
|
||||||
|
|
||||||
@ -1102,8 +1173,8 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
logdb(REQUEST, cnx, method="SuppressAnnotation", etudid=etudid)
|
logdb(REQUEST, cnx, method="SuppressAnnotation", etudid=etudid)
|
||||||
scolars.etud_annotations_delete(cnx, annotation_id)
|
scolars.etud_annotations_delete(cnx, annotation_id)
|
||||||
|
|
||||||
REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"ficheEtud?etudid=%s&head_message=Annotation%%20supprimée" % (etudid)
|
"ficheEtud?etudid=%s&head_message=Annotation%%20supprimée" % (etudid)
|
||||||
)
|
)
|
||||||
|
|
||||||
security.declareProtected(ScoEtudChangeAdr, "formChangeCoordonnees")
|
security.declareProtected(ScoEtudChangeAdr, "formChangeCoordonnees")
|
||||||
@ -1161,99 +1232,18 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
initvalues=adr,
|
initvalues=adr,
|
||||||
submitlabel="Valider le formulaire",
|
submitlabel="Valider le formulaire",
|
||||||
)
|
)
|
||||||
|
dest_url = self.ScoURL() + "/ficheEtud?etudid=" + etudid
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return header + "\n".join(H) + tf[1] + self.sco_footer(REQUEST)
|
return header + "\n".join(H) + tf[1] + self.sco_footer(REQUEST)
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
return REQUEST.RESPONSE.redirect(dest_url)
|
||||||
else:
|
else:
|
||||||
if adrs:
|
if adrs:
|
||||||
scolars.adresse_edit(cnx, args=tf[2], context=self)
|
scolars.adresse_edit(cnx, args=tf[2], context=self)
|
||||||
else:
|
else:
|
||||||
scolars.adresse_create(cnx, args=tf[2])
|
scolars.adresse_create(cnx, args=tf[2])
|
||||||
logdb(REQUEST, cnx, method="changeCoordonnees", etudid=etudid)
|
logdb(REQUEST, cnx, method="changeCoordonnees", etudid=etudid)
|
||||||
REQUEST.RESPONSE.redirect("ficheEtud?etudid=" + etudid)
|
return REQUEST.RESPONSE.redirect(dest_url)
|
||||||
|
|
||||||
security.declareProtected(ScoView, "formChangeGroup")
|
|
||||||
|
|
||||||
def formChangeGroup(self, formsemestre_id, etudid, REQUEST):
|
|
||||||
"changement groupe etudiant dans semestre"
|
|
||||||
if not self.Notes.can_change_groups(REQUEST, formsemestre_id):
|
|
||||||
raise ScoValueError(
|
|
||||||
"Vous n'avez pas le droit d'effectuer cette opération !"
|
|
||||||
)
|
|
||||||
cnx = self.GetDBConnexion()
|
|
||||||
etud = self.getEtudInfo(etudid=etudid, filled=1, REQUEST=REQUEST)[0]
|
|
||||||
sem = sco_formsemestre.do_formsemestre_list(self, formsemestre_id)
|
|
||||||
ins = self.Notes.do_formsemestre_inscription_list(
|
|
||||||
{"etudid": etudid, "formsemestre_id": formsemestre_id}
|
|
||||||
)[0]
|
|
||||||
#
|
|
||||||
# -- check lock
|
|
||||||
sem = sco_formsemestre.get_formsemestre(self, formsemestre_id)
|
|
||||||
if sem["etat"] != "1":
|
|
||||||
raise ScoValueError("Modification impossible: semestre verrouille")
|
|
||||||
#
|
|
||||||
etud["semtitre"] = sem["titremois"]
|
|
||||||
H = [
|
|
||||||
'<h2><font color="#FF0000">Changement de groupe de</font> %(nomprenom)s (semestre %(semtitre)s)</h2><p>'
|
|
||||||
% etud
|
|
||||||
]
|
|
||||||
header = self.sco_header(
|
|
||||||
REQUEST, page_title="Changement de groupe de %(nomprenom)s" % etud
|
|
||||||
)
|
|
||||||
# Liste des groupes existants
|
|
||||||
raise NotImplementedError # XXX utiliser form_group_choice ou supprimer completement ?
|
|
||||||
#
|
|
||||||
H.append("""<form action="doChangeGroup" method="get" name="cg">""")
|
|
||||||
|
|
||||||
H.append(
|
|
||||||
"""<input type="hidden" name="etudid" value="%s">
|
|
||||||
<input type="hidden" name="formsemestre_id" value="%s">
|
|
||||||
<p>
|
|
||||||
(attention, vérifier que les groupes sont compatibles, selon votre organisation)
|
|
||||||
</p>
|
|
||||||
<script type="text/javascript">
|
|
||||||
function tweakmenu( gname ) {
|
|
||||||
var gr = document.cg.newgroupname.value;
|
|
||||||
if (!gr) {
|
|
||||||
alert("nom de groupe vide !");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var menutd = document.getElementById(gname);
|
|
||||||
var newopt = document.createElement('option');
|
|
||||||
newopt.value = gr;
|
|
||||||
var textopt = document.createTextNode(gr);
|
|
||||||
newopt.appendChild(textopt);
|
|
||||||
menutd.appendChild(newopt);
|
|
||||||
var msg = document.getElementById("groupemsg");
|
|
||||||
msg.appendChild( document.createTextNode("groupe " + gr + " créé; ") );
|
|
||||||
document.cg.newgroupname.value = "";
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<p>Créer un nouveau groupe:
|
|
||||||
<input type="text" id="newgroupname" size="8"/>
|
|
||||||
<input type="button" onClick="tweakmenu( 'groupetd' );" value="créer groupe de %s"/>
|
|
||||||
<input type="button" onClick="tweakmenu( 'groupeanglais' );" value="créer groupe de %s"/>
|
|
||||||
<input type="button" onClick="tweakmenu( 'groupetp' );" value="créer groupe de %s"/>
|
|
||||||
</p>
|
|
||||||
<p id="groupemsg" style="font-style: italic;"></p>
|
|
||||||
|
|
||||||
<input type="submit" value="Changer de groupe">
|
|
||||||
<input type="button" value="Annuler" onClick="window.location='%s'">
|
|
||||||
|
|
||||||
</form>"""
|
|
||||||
% (
|
|
||||||
etudid,
|
|
||||||
formsemestre_id,
|
|
||||||
sem["nomgroupetd"],
|
|
||||||
sem["nomgroupeta"],
|
|
||||||
sem["nomgroupetp"],
|
|
||||||
REQUEST.URL1,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return header + "\n".join(H) + self.sco_footer(REQUEST)
|
|
||||||
|
|
||||||
# --- Gestion des groupes:
|
# --- Gestion des groupes:
|
||||||
security.declareProtected(ScoView, "affectGroups")
|
security.declareProtected(ScoView, "affectGroups")
|
||||||
@ -1366,6 +1356,7 @@ function tweakmenu( gname ) {
|
|||||||
submitlabel="Valider",
|
submitlabel="Valider",
|
||||||
cancelbutton="Annuler",
|
cancelbutton="Annuler",
|
||||||
)
|
)
|
||||||
|
dest_url = self.ScoURL() + "/ficheEtud?etudid=" + etud["etudid"]
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return (
|
return (
|
||||||
"\n".join(H)
|
"\n".join(H)
|
||||||
@ -1375,16 +1366,12 @@ function tweakmenu( gname ) {
|
|||||||
+ self.sco_footer(REQUEST)
|
+ self.sco_footer(REQUEST)
|
||||||
)
|
)
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(dest_url)
|
||||||
REQUEST.URL1 + "/ficheEtud?etudid=" + etud["etudid"]
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
data = tf[2]["photofile"].read()
|
data = tf[2]["photofile"].read()
|
||||||
status, diag = sco_photos.store_photo(self, etud, data, REQUEST=REQUEST)
|
status, diag = sco_photos.store_photo(self, etud, data, REQUEST=REQUEST)
|
||||||
if status != 0:
|
if status != 0:
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(dest_url)
|
||||||
self.ScoURL() + "/ficheEtud?etudid=" + etud["etudid"]
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
H.append('<p class="warning">Erreur:' + diag + "</p>")
|
H.append('<p class="warning">Erreur:' + diag + "</p>")
|
||||||
return "\n".join(H) + self.sco_footer(REQUEST)
|
return "\n".join(H) + self.sco_footer(REQUEST)
|
||||||
@ -1406,7 +1393,7 @@ function tweakmenu( gname ) {
|
|||||||
sco_photos.suppress_photo(self, etud, REQUEST=REQUEST)
|
sco_photos.suppress_photo(self, etud, REQUEST=REQUEST)
|
||||||
|
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
REQUEST.URL1 + "/ficheEtud?etudid=" + etud["etudid"]
|
self.ScoURL() + "/ficheEtud?etudid=" + etud["etudid"]
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -1443,7 +1430,6 @@ function tweakmenu( gname ) {
|
|||||||
operation_method="",
|
operation_method="",
|
||||||
):
|
):
|
||||||
"Formulaire démission ou défaillance Etudiant"
|
"Formulaire démission ou défaillance Etudiant"
|
||||||
cnx = self.GetDBConnexion()
|
|
||||||
etud = self.getEtudInfo(etudid=etudid, filled=1, REQUEST=REQUEST)[0]
|
etud = self.getEtudInfo(etudid=etudid, filled=1, REQUEST=REQUEST)[0]
|
||||||
sem = sco_formsemestre.get_formsemestre(self, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(self, formsemestre_id)
|
||||||
if sem["etat"] != "1":
|
if sem["etat"] != "1":
|
||||||
@ -1467,7 +1453,7 @@ function tweakmenu( gname ) {
|
|||||||
"""<form action="%s" method="get">
|
"""<form action="%s" method="get">
|
||||||
<b>Date de la %s (J/M/AAAA): </b>
|
<b>Date de la %s (J/M/AAAA): </b>
|
||||||
"""
|
"""
|
||||||
% (operation_method, strlower(operation_name))
|
% (operation_method, scu.strlower(operation_name))
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
"""
|
"""
|
||||||
@ -1503,7 +1489,7 @@ function tweakmenu( gname ) {
|
|||||||
etudid,
|
etudid,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
event_date=event_date,
|
event_date=event_date,
|
||||||
etat_new=DEF,
|
etat_new=sco_codes_parcours.DEF,
|
||||||
operation_method="defailleEtudiant",
|
operation_method="defailleEtudiant",
|
||||||
event_type="DEFAILLANCE",
|
event_type="DEFAILLANCE",
|
||||||
REQUEST=REQUEST,
|
REQUEST=REQUEST,
|
||||||
@ -1581,7 +1567,7 @@ function tweakmenu( gname ) {
|
|||||||
dialog_confirmed=dialog_confirmed,
|
dialog_confirmed=dialog_confirmed,
|
||||||
args=args,
|
args=args,
|
||||||
operation_name="défaillance",
|
operation_name="défaillance",
|
||||||
etat_current=DEF,
|
etat_current=sco_codes_parcours.DEF,
|
||||||
etat_new="I",
|
etat_new="I",
|
||||||
operation_method="cancelDef",
|
operation_method="cancelDef",
|
||||||
event_type="DEFAILLANCE",
|
event_type="DEFAILLANCE",
|
||||||
@ -1637,7 +1623,7 @@ function tweakmenu( gname ) {
|
|||||||
args=ins, formsemestre_id=formsemestre_id
|
args=ins, formsemestre_id=formsemestre_id
|
||||||
)
|
)
|
||||||
logdb(REQUEST, cnx, method=operation_method, etudid=etudid)
|
logdb(REQUEST, cnx, method=operation_method, etudid=etudid)
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"delete from scolar_events where etudid=%(etudid)s and formsemestre_id=%(formsemestre_id)s and event_type='"
|
"delete from scolar_events where etudid=%(etudid)s and formsemestre_id=%(formsemestre_id)s and event_type='"
|
||||||
+ event_type
|
+ event_type
|
||||||
@ -1665,7 +1651,6 @@ function tweakmenu( gname ) {
|
|||||||
"Le formulaire HTML"
|
"Le formulaire HTML"
|
||||||
H = [self.sco_header(REQUEST, init_jquery_ui=True)]
|
H = [self.sco_header(REQUEST, init_jquery_ui=True)]
|
||||||
F = self.sco_footer(REQUEST)
|
F = self.sco_footer(REQUEST)
|
||||||
AUTHENTICATED_USER = REQUEST.AUTHENTICATED_USER
|
|
||||||
etudid = REQUEST.form.get("etudid", None)
|
etudid = REQUEST.form.get("etudid", None)
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
descr = []
|
descr = []
|
||||||
@ -1700,12 +1685,14 @@ function tweakmenu( gname ) {
|
|||||||
# recuperation infos Apogee
|
# recuperation infos Apogee
|
||||||
# Si on a le code NIP, fait juste une requete, sinon tente de rechercher par nom
|
# 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)
|
# (la recherche par nom ne fonctionne plus à Paris 13)
|
||||||
code_nip = initvalues.get("code_nip", "")
|
# XXX A terminer
|
||||||
if code_nip:
|
# code_nip = initvalues.get("code_nip", "")
|
||||||
try:
|
# if code_nip:
|
||||||
info = sco_portal_apogee.get_etud_apogee(self, code_nip)
|
# try:
|
||||||
except ValueError:
|
# infos = sco_portal_apogee.get_etud_apogee(self, code_nip)
|
||||||
pass # XXX a terminer
|
# except ValueError:
|
||||||
|
# infos = None
|
||||||
|
# pass # XXX a terminer
|
||||||
nom = REQUEST.form.get("nom", None)
|
nom = REQUEST.form.get("nom", None)
|
||||||
if nom is None:
|
if nom is None:
|
||||||
nom = initvalues.get("nom", None)
|
nom = initvalues.get("nom", None)
|
||||||
@ -1768,15 +1755,19 @@ function tweakmenu( gname ) {
|
|||||||
("nom_usuel", {"size": 25, "title": "Nom usuel", "allow_null": True}),
|
("nom_usuel", {"size": 25, "title": "Nom usuel", "allow_null": True}),
|
||||||
(
|
(
|
||||||
"prenom",
|
"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",
|
"input_type": "menu",
|
||||||
"labels": ["H", "F"],
|
"labels": ["Homme", "Femme", "Autre/neutre"],
|
||||||
"allowed_values": ["MR", "MME"],
|
"allowed_values": ["M", "F", "X"],
|
||||||
"title": "Genre",
|
"title": "Civilité",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -1869,7 +1860,7 @@ function tweakmenu( gname ) {
|
|||||||
{
|
{
|
||||||
"input_type": "menu",
|
"input_type": "menu",
|
||||||
"title": "Voie d'admission",
|
"title": "Voie d'admission",
|
||||||
"allowed_values": TYPES_ADMISSION,
|
"allowed_values": scu.TYPES_ADMISSION,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -2102,7 +2093,7 @@ function tweakmenu( gname ) {
|
|||||||
"billet_absence",
|
"billet_absence",
|
||||||
"identite",
|
"identite",
|
||||||
]
|
]
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
for table in tables:
|
for table in tables:
|
||||||
cursor.execute("delete from %s where etudid=%%(etudid)s" % table, etud)
|
cursor.execute("delete from %s where etudid=%%(etudid)s" % table, etud)
|
||||||
cnx.commit()
|
cnx.commit()
|
||||||
@ -2110,7 +2101,9 @@ function tweakmenu( gname ) {
|
|||||||
to_inval = [s["formsemestre_id"] for s in etud["sems"]]
|
to_inval = [s["formsemestre_id"] for s in etud["sems"]]
|
||||||
if to_inval:
|
if to_inval:
|
||||||
self.Notes._inval_cache(formsemestre_id_list=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")
|
security.declareProtected(ScoEtudInscrit, "check_group_apogee")
|
||||||
|
|
||||||
@ -2123,7 +2116,7 @@ function tweakmenu( gname ) {
|
|||||||
XXX A re-écrire pour API 2: prendre liste dans l'étape et vérifier à partir de cela.
|
XXX A re-écrire pour API 2: prendre liste dans l'étape et vérifier à partir de cela.
|
||||||
"""
|
"""
|
||||||
etat = etat or None
|
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
|
self, group_id, etat=etat
|
||||||
)
|
)
|
||||||
formsemestre_id = group["formsemestre_id"]
|
formsemestre_id = group["formsemestre_id"]
|
||||||
@ -2229,8 +2222,8 @@ function tweakmenu( gname ) {
|
|||||||
% (
|
% (
|
||||||
REQUEST.URL0,
|
REQUEST.URL0,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
strnone(group_id),
|
scu.strnone(group_id),
|
||||||
strnone(etat),
|
scu.strnone(etat),
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -2248,8 +2241,8 @@ function tweakmenu( gname ) {
|
|||||||
% (
|
% (
|
||||||
REQUEST.URL0,
|
REQUEST.URL0,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
strnone(group_id),
|
scu.strnone(group_id),
|
||||||
strnone(etat),
|
scu.strnone(etat),
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -2262,8 +2255,13 @@ function tweakmenu( gname ) {
|
|||||||
"formulaire import xls"
|
"formulaire import xls"
|
||||||
if formsemestre_id:
|
if formsemestre_id:
|
||||||
sem = sco_formsemestre.get_formsemestre(self.Notes, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(self.Notes, formsemestre_id)
|
||||||
|
dest_url = (
|
||||||
|
self.ScoURL()
|
||||||
|
+ "/formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
sem = None
|
sem = None
|
||||||
|
dest_url = self.ScoURL()
|
||||||
if sem and sem["etat"] != "1":
|
if sem and sem["etat"] != "1":
|
||||||
raise ScoValueError("Modification impossible: semestre verrouille")
|
raise ScoValueError("Modification impossible: semestre verrouille")
|
||||||
H = [
|
H = [
|
||||||
@ -2379,7 +2377,7 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
|
|||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + "</li></ol>" + "\n".join(S) + F
|
return "\n".join(H) + tf[1] + "</li></ol>" + "\n".join(S) + F
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
return REQUEST.RESPONSE.redirect(dest_url)
|
||||||
else:
|
else:
|
||||||
return ImportScolars.students_import_excel(
|
return ImportScolars.students_import_excel(
|
||||||
self,
|
self,
|
||||||
@ -2428,7 +2426,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):
|
def form_students_import_infos_admissions(self, REQUEST, formsemestre_id=None):
|
||||||
"formulaire import xls"
|
"formulaire import xls"
|
||||||
sem = sco_formsemestre.get_formsemestre(self.Notes, formsemestre_id)
|
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = REQUEST.AUTHENTICATED_USER
|
||||||
F = self.sco_footer(REQUEST)
|
F = self.sco_footer(REQUEST)
|
||||||
if not authuser.has_permission(ScoEtudInscrit, self):
|
if not authuser.has_permission(ScoEtudInscrit, self):
|
||||||
@ -2517,7 +2514,11 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
|
|||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + help_text + F
|
return "\n".join(H) + tf[1] + help_text + F
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
return REQUEST.RESPONSE.redirect(
|
||||||
|
self.ScoURL()
|
||||||
|
+ "/formsemestre_status?formsemestre_id="
|
||||||
|
+ formsemestre_id
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return self._students_import_admission(
|
return self._students_import_admission(
|
||||||
tf[2]["csvfile"],
|
tf[2]["csvfile"],
|
||||||
@ -2598,7 +2599,6 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
|
|||||||
def stat_bac(self, formsemestre_id):
|
def stat_bac(self, formsemestre_id):
|
||||||
"Renvoie statistisques sur nb d'etudiants par bac"
|
"Renvoie statistisques sur nb d'etudiants par bac"
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
sem = sco_formsemestre.get_formsemestre(self, formsemestre_id)
|
|
||||||
ins = self.Notes.do_formsemestre_inscription_list(
|
ins = self.Notes.do_formsemestre_inscription_list(
|
||||||
args={"formsemestre_id": formsemestre_id}
|
args={"formsemestre_id": formsemestre_id}
|
||||||
)
|
)
|
||||||
@ -2727,23 +2727,23 @@ def manage_addZScolarForm(context, DeptId, REQUEST=None):
|
|||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + context.standard_html_footer(context)
|
return "\n".join(H) + tf[1] + context.standard_html_footer(context)
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
return REQUEST.RESPONSE.redirect("/ScoDoc")
|
||||||
else:
|
else:
|
||||||
DeptId = tf[2]["DeptId"].strip()
|
DeptId = tf[2]["DeptId"].strip()
|
||||||
db_cnx_string = tf[2]["db_cnx_string"].strip()
|
db_cnx_string = tf[2]["db_cnx_string"].strip()
|
||||||
# default connexion string
|
# default connexion string
|
||||||
if not db_cnx_string:
|
if not db_cnx_string:
|
||||||
db_name = "SCO" + DeptId.upper()
|
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_cnx_string = "user=%s dbname=%s port=%s" % (
|
||||||
db_user,
|
db_user,
|
||||||
db_name,
|
db_name,
|
||||||
SCO_DEFAULT_SQL_PORT,
|
scu.SCO_DEFAULT_SQL_PORT,
|
||||||
)
|
)
|
||||||
# vérifie que la bd existe et possede le meme nom de dept.
|
# vérifie que la bd existe et possede le meme nom de dept.
|
||||||
try:
|
try:
|
||||||
cnx = psycopg2.connect(db_cnx_string)
|
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'")
|
cursor.execute("select * from sco_prefs where name='DeptName'")
|
||||||
except:
|
except:
|
||||||
return _simple_error_page(
|
return _simple_error_page(
|
||||||
@ -2776,7 +2776,7 @@ def _simple_error_page(context, msg, DeptId=None):
|
|||||||
H = [context.standard_html_header(context), "<h2>Erreur !</h2>", "<p>", msg, "</p>"]
|
H = [context.standard_html_header(context), "<h2>Erreur !</h2>", "<p>", msg, "</p>"]
|
||||||
if DeptId:
|
if DeptId:
|
||||||
H.append(
|
H.append(
|
||||||
'<p><a href="delete_dept?DeptId=%s&force=1">Supprimer le dossier %s</a>(très recommandé !)</p>'
|
'<p><a href="delete_dept?DeptId=%s&force=1">Supprimer le dossier %s</a>(très recommandé !)</p>'
|
||||||
% (DeptId, DeptId)
|
% (DeptId, DeptId)
|
||||||
)
|
)
|
||||||
H.append(context.standard_html_footer(context))
|
H.append(context.standard_html_footer(context))
|
||||||
|
@ -251,8 +251,8 @@ class exUserFolder(Folder,BasicUserFolder,BasicGroupFolderMixin,
|
|||||||
('Manager',)),
|
('Manager',)),
|
||||||
|
|
||||||
('View', ('manage_changePassword',
|
('View', ('manage_changePassword',
|
||||||
'manage_forgotPassword', 'docLogin','docLoginRedirect',
|
'manage_forgotPassword','docLoginRedirect',
|
||||||
'docLogout', 'logout', 'DialogHeader',
|
'logout', 'DialogHeader',
|
||||||
'DialogFooter', 'manage_signupUser',
|
'DialogFooter', 'manage_signupUser',
|
||||||
'MessageDialog', 'redirectToLogin','manage_changeProps'),
|
'MessageDialog', 'redirectToLogin','manage_changeProps'),
|
||||||
('Anonymous', 'Authenticated', 'Manager')),
|
('Anonymous', 'Authenticated', 'Manager')),
|
||||||
@ -269,7 +269,7 @@ class exUserFolder(Folder,BasicUserFolder,BasicGroupFolderMixin,
|
|||||||
('Access contents information', ('hasProperty', 'propertyIds',
|
('Access contents information', ('hasProperty', 'propertyIds',
|
||||||
'propertyValues','propertyItems',
|
'propertyValues','propertyItems',
|
||||||
'getProperty', 'getPropertyType',
|
'getProperty', 'getPropertyType',
|
||||||
'propertyMap', 'docLogin','docLoginRedirect',
|
'propertyMap', 'docLoginRedirect',
|
||||||
'DialogHeader', 'DialogFooter',
|
'DialogHeader', 'DialogFooter',
|
||||||
'MessageDialog', 'redirectToLogin',),
|
'MessageDialog', 'redirectToLogin',),
|
||||||
('Anonymous', 'Authenticated', 'Manager')),
|
('Anonymous', 'Authenticated', 'Manager')),
|
||||||
|
18
__init__.py
18
__init__.py
@ -27,8 +27,6 @@
|
|||||||
|
|
||||||
from ZScolar import ZScolar, manage_addZScolarForm, manage_addZScolar
|
from ZScolar import ZScolar, manage_addZScolarForm, manage_addZScolar
|
||||||
|
|
||||||
# from ZNotes import ZNotes, manage_addZNotesForm, manage_addZNotes
|
|
||||||
|
|
||||||
from ZScoDoc import ZScoDoc, manage_addZScoDoc
|
from ZScoDoc import ZScoDoc, manage_addZScoDoc
|
||||||
|
|
||||||
# from sco_zope import *
|
# from sco_zope import *
|
||||||
@ -53,23 +51,7 @@ def initialize(context):
|
|||||||
icon="static/icons/sco_icon.png",
|
icon="static/icons/sco_icon.png",
|
||||||
)
|
)
|
||||||
|
|
||||||
# context.registerHelp()
|
|
||||||
# context.registerHelpTitle("ZScolar")
|
|
||||||
|
|
||||||
# --- ZScoDoc
|
# --- ZScoDoc
|
||||||
context.registerClass(
|
context.registerClass(
|
||||||
ZScoDoc, constructors=(manage_addZScoDoc,), icon="static/icons/sco_icon.png"
|
ZScoDoc, constructors=(manage_addZScoDoc,), icon="static/icons/sco_icon.png"
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- ZNotes
|
|
||||||
# context.registerClass(
|
|
||||||
# ZNotes,
|
|
||||||
# constructors = (
|
|
||||||
# manage_addZNotesForm,
|
|
||||||
# manage_addZNotes
|
|
||||||
# ),
|
|
||||||
# icon = 'static/icons/notes_icon.png'
|
|
||||||
# )
|
|
||||||
|
|
||||||
# context.registerHelp()
|
|
||||||
# context.registerHelpTitle("ZNotes")
|
|
||||||
|
@ -45,9 +45,16 @@ def bonus_iutv(notes_sport, coefs, infos=None):
|
|||||||
return bonus
|
return bonus
|
||||||
|
|
||||||
|
|
||||||
def bonus_iut_stdenis(notes_sport, coefs, infos=None):
|
def bonus_direct(notes_sport, coefs, infos=None):
|
||||||
"""Semblable à bonus_iutv mais sans coefficients et total limité à 0.5 points.
|
"""Un bonus direct et sans chichis: les points sont directement ajoutés à la moyenne générale.
|
||||||
|
Les coefficients sont ignorés: tous les points de bonus sont sommés.
|
||||||
|
(rappel: la note est ramenée sur 20 avant application).
|
||||||
"""
|
"""
|
||||||
|
return sum(notes_sport)
|
||||||
|
|
||||||
|
|
||||||
|
def bonus_iut_stdenis(notes_sport, coefs, infos=None):
|
||||||
|
"""Semblable à bonus_iutv mais sans coefficients et total limité à 0.5 points."""
|
||||||
points = sum([x - 10 for x in notes_sport if x > 10]) # points au dessus de 10
|
points = sum([x - 10 for x in notes_sport if x > 10]) # points au dessus de 10
|
||||||
bonus = points * 0.05 # ou / 20
|
bonus = points * 0.05 # ou / 20
|
||||||
return min(bonus, 0.5) # bonus limité à 1/2 point
|
return min(bonus, 0.5) # bonus limité à 1/2 point
|
||||||
@ -62,7 +69,7 @@ def bonus_colmar(notes_sport, coefs, infos=None):
|
|||||||
sur 20 obtenus dans chacune des matières optionnelles sont cumulés
|
sur 20 obtenus dans chacune des matières optionnelles sont cumulés
|
||||||
dans la limite de 10 points. 5% de ces points cumulés s'ajoutent à
|
dans la limite de 10 points. 5% de ces points cumulés s'ajoutent à
|
||||||
la moyenne générale du semestre déjà obtenue par l'étudiant.
|
la moyenne générale du semestre déjà obtenue par l'étudiant.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# les coefs sont ignorés
|
# les coefs sont ignorés
|
||||||
points = sum([x - 10 for x in notes_sport if x > 10])
|
points = sum([x - 10 for x in notes_sport if x > 10])
|
||||||
@ -73,7 +80,7 @@ def bonus_colmar(notes_sport, coefs, infos=None):
|
|||||||
|
|
||||||
def bonus_iutva(notes_sport, coefs, infos=None):
|
def bonus_iutva(notes_sport, coefs, infos=None):
|
||||||
"""Calcul bonus modules optionels (sport, culture), règle IUT Ville d'Avray
|
"""Calcul bonus modules optionels (sport, culture), règle IUT Ville d'Avray
|
||||||
|
|
||||||
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
Les étudiants de l'IUT peuvent suivre des enseignements optionnels
|
||||||
de l'Université Paris 10 (C2I) non rattachés à une unité d'enseignement.
|
de l'Université Paris 10 (C2I) non rattachés à une unité d'enseignement.
|
||||||
Si la note est >= 10 et < 12, bonus de 0.1 point
|
Si la note est >= 10 et < 12, bonus de 0.1 point
|
||||||
@ -93,42 +100,13 @@ def bonus_iutva(notes_sport, coefs, infos=None):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
# XXX Inutilisé (mai 2020) ? à confirmer avant suppression XXX
|
|
||||||
# def bonus_iut1grenoble_v0(notes_sport, coefs, infos=None):
|
|
||||||
# """Calcul bonus sport IUT Grenoble sur la moyenne générale
|
|
||||||
#
|
|
||||||
# La note de sport de nos étudiants va de 0 à 5 points.
|
|
||||||
# Chaque point correspond à un % qui augmente la moyenne de chaque UE et la moyenne générale.
|
|
||||||
# Par exemple : note de sport 2/5 : chaque UE sera augmentée de 2%, ainsi que la moyenne générale.
|
|
||||||
#
|
|
||||||
# Calcul ici du bonus sur moyenne générale et moyennes d'UE non capitalisées.
|
|
||||||
# """
|
|
||||||
# # les coefs sont ignorés
|
|
||||||
# # notes de 0 à 5
|
|
||||||
# points = sum([x for x in notes_sport])
|
|
||||||
# factor = (points / 4.0) / 100.0
|
|
||||||
# bonus = infos["moy"] * factor
|
|
||||||
# # Modifie les moyennes de toutes les UE:
|
|
||||||
# for ue_id in infos["moy_ues"]:
|
|
||||||
# ue_status = infos["moy_ues"][ue_id]
|
|
||||||
# if ue_status["sum_coefs"] > 0:
|
|
||||||
# # modifie moyenne UE ds semestre courant
|
|
||||||
# ue_status["cur_moy_ue"] = ue_status["cur_moy_ue"] * (1.0 + factor)
|
|
||||||
# if not ue_status["is_capitalized"]:
|
|
||||||
# # si non capitalisee, modifie moyenne prise en compte
|
|
||||||
# ue_status["moy"] = ue_status["cur_moy_ue"]
|
|
||||||
#
|
|
||||||
# # open('/tmp/log','a').write( pprint.pformat(ue_status) + '\n\n' )
|
|
||||||
# return bonus
|
|
||||||
|
|
||||||
|
|
||||||
def bonus_iut1grenoble_2017(notes_sport, coefs, infos=None):
|
def bonus_iut1grenoble_2017(notes_sport, coefs, infos=None):
|
||||||
"""Calcul bonus sport IUT Grenoble sur la moyenne générale (version 2017)
|
"""Calcul bonus sport IUT Grenoble sur la moyenne générale (version 2017)
|
||||||
|
|
||||||
La note de sport de nos étudiants va de 0 à 5 points.
|
La note de sport de nos étudiants va de 0 à 5 points.
|
||||||
Chaque point correspond à un % qui augmente la moyenne de chaque UE et la moyenne générale.
|
Chaque point correspond à un % qui augmente la moyenne de chaque UE et la moyenne générale.
|
||||||
Par exemple : note de sport 2/5 : la moyenne générale sera augmentée de 2%.
|
Par exemple : note de sport 2/5 : la moyenne générale sera augmentée de 2%.
|
||||||
|
|
||||||
Calcul ici du bonus sur moyenne générale
|
Calcul ici du bonus sur moyenne générale
|
||||||
"""
|
"""
|
||||||
# les coefs sont ignorés
|
# les coefs sont ignorés
|
||||||
@ -162,14 +140,14 @@ def bonus_lille(notes_sport, coefs, infos=None):
|
|||||||
def bonus_iutlh(notes_sport, coefs, infos=None):
|
def bonus_iutlh(notes_sport, coefs, infos=None):
|
||||||
"""Calcul bonus sport IUT du Havre sur moyenne générale et UE
|
"""Calcul bonus sport IUT du Havre sur moyenne générale et UE
|
||||||
|
|
||||||
La note de sport de nos étudiants va de 0 à 20 points.
|
La note de sport de nos étudiants va de 0 à 20 points.
|
||||||
m2=m1*(1+0.005*((10-N1)+(10-N2))
|
m2=m1*(1+0.005*((10-N1)+(10-N2))
|
||||||
m2 : Nouvelle moyenne de l'unité d'enseignement si note de sport et/ou de langue supérieure à 10
|
m2 : Nouvelle moyenne de l'unité d'enseignement si note de sport et/ou de langue supérieure à 10
|
||||||
m1 : moyenne de l'unité d'enseignement avant bonification
|
m1 : moyenne de l'unité d'enseignement avant bonification
|
||||||
N1 : note de sport si supérieure à 10
|
N1 : note de sport si supérieure à 10
|
||||||
N2 : note de seconde langue si supérieure à 10
|
N2 : note de seconde langue si supérieure à 10
|
||||||
Par exemple : sport 15/20 et langue 12/20 : chaque UE sera multipliée par 1+0.005*7, ainsi que la moyenne générale.
|
Par exemple : sport 15/20 et langue 12/20 : chaque UE sera multipliée par 1+0.005*7, ainsi que la moyenne générale.
|
||||||
Calcul ici de la moyenne générale et moyennes d'UE non capitalisées.
|
Calcul ici de la moyenne générale et moyennes d'UE non capitalisées.
|
||||||
"""
|
"""
|
||||||
# les coefs sont ignorés
|
# les coefs sont ignorés
|
||||||
points = sum([x - 10 for x in notes_sport if x > 10])
|
points = sum([x - 10 for x in notes_sport if x > 10])
|
||||||
@ -205,8 +183,8 @@ def bonus_tours(notes_sport, coefs, infos=None):
|
|||||||
def bonus_iutr(notes_sport, coefs, infos=None):
|
def bonus_iutr(notes_sport, coefs, infos=None):
|
||||||
"""Calcul du bonus , regle de l'IUT de Roanne (contribuée par Raphael C., nov 2012)
|
"""Calcul du bonus , regle de l'IUT de Roanne (contribuée par Raphael C., nov 2012)
|
||||||
|
|
||||||
Le bonus est compris entre 0 et 0.35 point.
|
Le bonus est compris entre 0 et 0.35 point.
|
||||||
cette procédure modifie la moyenne de chaque UE capitalisable.
|
cette procédure modifie la moyenne de chaque UE capitalisable.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# modifie les moyennes de toutes les UE:
|
# modifie les moyennes de toutes les UE:
|
||||||
@ -260,7 +238,7 @@ def bonus_saint_etienne(notes_sport, coefs, infos=None):
|
|||||||
"""IUT de Saint-Etienne (jan 2014)
|
"""IUT de Saint-Etienne (jan 2014)
|
||||||
Nous avons différents types de bonification
|
Nous avons différents types de bonification
|
||||||
bonfication Sport / Associations
|
bonfication Sport / Associations
|
||||||
coopératives de département / Bureau Des Étudiants
|
coopératives de département / Bureau Des Étudiants
|
||||||
/ engagement citoyen / Langues optionnelles
|
/ engagement citoyen / Langues optionnelles
|
||||||
Nous ajoutons sur le bulletin une bonification qui varie entre 0,1 et 0,3 ou 0,35 pour chaque item
|
Nous ajoutons sur le bulletin une bonification qui varie entre 0,1 et 0,3 ou 0,35 pour chaque item
|
||||||
la bonification totale ne doit pas excéder les 0,6 point.
|
la bonification totale ne doit pas excéder les 0,6 point.
|
||||||
@ -278,9 +256,9 @@ def bonus_saint_etienne(notes_sport, coefs, infos=None):
|
|||||||
|
|
||||||
|
|
||||||
def bonus_iutTarbes(notes_sport, coefs, infos=None):
|
def bonus_iutTarbes(notes_sport, coefs, infos=None):
|
||||||
"""Calcul bonus modules optionnels
|
"""Calcul bonus modules optionnels
|
||||||
(sport, Langues, action sociale, Théâtre), règle IUT Tarbes
|
(sport, Langues, action sociale, Théâtre), règle IUT Tarbes
|
||||||
Les coefficients ne sont pas pris en compte,
|
Les coefficients ne sont pas pris en compte,
|
||||||
seule la meilleure note est prise en compte
|
seule la meilleure note est prise en compte
|
||||||
le 1/30ème des points au-dessus de 10 sur 20 est retenu et s'ajoute à
|
le 1/30ème des points au-dessus de 10 sur 20 est retenu et s'ajoute à
|
||||||
la moyenne générale du semestre déjà obtenue par l'étudiant.
|
la moyenne générale du semestre déjà obtenue par l'étudiant.
|
||||||
@ -408,7 +386,7 @@ def bonus_iutbethune(notes_sport, coefs, infos=None):
|
|||||||
def bonus_demo(notes_sport, coefs, infos=None):
|
def bonus_demo(notes_sport, coefs, infos=None):
|
||||||
"""Fausse fonction "bonus" pour afficher les informations disponibles
|
"""Fausse fonction "bonus" pour afficher les informations disponibles
|
||||||
et aider les développeurs.
|
et aider les développeurs.
|
||||||
Les informations sont placées dans le fichier /tmp/scodoc_bonus.log
|
Les informations sont placées dans le fichier /tmp/scodoc_bonus.log
|
||||||
qui est ECRASE à chaque appel.
|
qui est ECRASE à chaque appel.
|
||||||
*** Ne pas utiliser en production !!! ***
|
*** Ne pas utiliser en production !!! ***
|
||||||
"""
|
"""
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
# Version majeure de Debian (..., 9, 10)
|
# Version majeure de Debian (..., 9, 10)
|
||||||
debian_version=$(cat /etc/debian_version)
|
debian_version=$(cat /etc/debian_version)
|
||||||
debian_version=${debian_version%%.*}
|
debian_version=${debian_version%%.*}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
echo
|
||||||
|
echo "Erreur: $1"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
# Fix path
|
# Fix path
|
||||||
export PATH="${PATH}":/usr/sbin:/sbin
|
export PATH="${PATH}":/usr/sbin:/sbin
|
||||||
@ -12,7 +18,8 @@ umask 0022
|
|||||||
|
|
||||||
export SCODOC_DIR=/opt/scodoc/Products/ScoDoc
|
export SCODOC_DIR=/opt/scodoc/Products/ScoDoc
|
||||||
|
|
||||||
export SCODOC_VAR_DIR=$(realpath "$SCODOC_DIR/../../var/scodoc")
|
SCODOC_VAR_DIR=$(realpath -L "$SCODOC_DIR/../../var/scodoc") || die "can't set SCODOC_VAR_DIR"
|
||||||
|
export SCODOC_VAR_DIR
|
||||||
# = /opt/scodoc/var/scodoc
|
# = /opt/scodoc/var/scodoc
|
||||||
export SCODOC_VERSION_DIR="${SCODOC_VAR_DIR}/config/version"
|
export SCODOC_VERSION_DIR="${SCODOC_VAR_DIR}/config/version"
|
||||||
export SCODOC_LOGOS_DIR="${SCODOC_VAR_DIR}/config/logos"
|
export SCODOC_LOGOS_DIR="${SCODOC_VAR_DIR}/config/logos"
|
||||||
@ -24,22 +31,24 @@ export POSTGRES_SUPERUSER=postgres
|
|||||||
export POSTGRES_USER=www-data
|
export POSTGRES_USER=www-data
|
||||||
|
|
||||||
# psql command: if various versions installed, force the one we want:
|
# psql command: if various versions installed, force the one we want:
|
||||||
if [ ${debian_version} = "10" ]
|
if [ "${debian_version}" = "10" ]
|
||||||
then
|
then
|
||||||
PSQL=/usr/lib/postgresql/11/bin/psql
|
PSQL=/usr/lib/postgresql/11/bin/psql
|
||||||
elif [ ${debian_version} = "9" ]
|
export POSTGRES_SERVICE="postgresql@11-main.service"
|
||||||
|
elif [ "${debian_version}" = "9" ]
|
||||||
then
|
then
|
||||||
PSQL=/usr/lib/postgresql/9.6/bin/psql
|
PSQL=/usr/lib/postgresql/9.6/bin/psql
|
||||||
elif [ ${debian_version} = "8" ]
|
export POSTGRES_SERVICE="postgresql"
|
||||||
|
elif [ "${debian_version}" = "8" ]
|
||||||
then
|
then
|
||||||
PSQL=/usr/lib/postgresql/9.4/bin/psql
|
PSQL=/usr/lib/postgresql/9.4/bin/psql
|
||||||
elif [ ${debian_version} = "7" ]
|
elif [ "${debian_version}" = "7" ]
|
||||||
then
|
then
|
||||||
PSQL=/usr/lib/postgresql/9.1/bin/psql
|
PSQL=/usr/lib/postgresql/9.1/bin/psql
|
||||||
elif [ ${debian_version} = "5" ]
|
elif [ "${debian_version}" = "5" ]
|
||||||
then
|
then
|
||||||
PSQL=/usr/lib/postgresql/8.3/bin/psql
|
PSQL=/usr/lib/postgresql/8.3/bin/psql
|
||||||
elif [ ${debian_version} = "6" ]
|
elif [ "${debian_version}" = "6" ]
|
||||||
then
|
then
|
||||||
PSQL=/usr/lib/postgresql/8.4/bin/psql
|
PSQL=/usr/lib/postgresql/8.4/bin/psql
|
||||||
else
|
else
|
||||||
@ -53,7 +62,7 @@ fi
|
|||||||
export POSTGRES_PORT=5432
|
export POSTGRES_PORT=5432
|
||||||
|
|
||||||
# Utilise par le script de reset du mot de passe:
|
# Utilise par le script de reset du mot de passe:
|
||||||
if [ ${debian_version} -ge "7" ]
|
if [ "${debian_version}" -ge "7" ]
|
||||||
then
|
then
|
||||||
export ZOPE_VERSION=2.13
|
export ZOPE_VERSION=2.13
|
||||||
else
|
else
|
||||||
|
@ -8,7 +8,13 @@ source utils.sh
|
|||||||
check_uid_root $0
|
check_uid_root $0
|
||||||
|
|
||||||
echo 'Installation du demarrage automatique de ScoDoc (systemd)'
|
echo 'Installation du demarrage automatique de ScoDoc (systemd)'
|
||||||
cp $SCODOC_DIR/config/etc/scodoc.service /etc/systemd/system
|
|
||||||
|
# La variable POSTGRES_SERVICE doit être positionnée dans config.sh
|
||||||
|
# suivant la version de Debian et de postgresql
|
||||||
|
[ -z "${POSTGRES_SERVICE}" ] && die "incompatible Debian version"
|
||||||
|
|
||||||
|
cat "$SCODOC_DIR/config/etc/scodoc.service" | sed 's/{{postgresql}}/'"${POSTGRES_SERVICE}"'/g' > /etc/systemd/system/scodoc.service
|
||||||
|
|
||||||
systemctl enable scodoc.service
|
systemctl enable scodoc.service
|
||||||
|
|
||||||
echo "A partir de maintenant, utiliser"
|
echo "A partir de maintenant, utiliser"
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
# E. Viennet, Juin 2008
|
# E. Viennet, Juin 2008
|
||||||
#
|
#
|
||||||
|
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
source config.sh
|
source config.sh
|
||||||
source utils.sh
|
source utils.sh
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
# ScoDoc: suppression d'un departement
|
# ScoDoc: suppression d'un departement
|
||||||
#
|
#
|
||||||
# Ce script supprime la base de donnees ScoDoc d'un departement
|
# Ce script supprime la base de donnees ScoDoc d'un departement
|
||||||
# *** le departement doit au prealable avoir <EFBFBD>t<EFBFBD> supprime via l'interface web ! ***
|
# *** le departement doit au prealable avoir été supprime via l'interface web ! ***
|
||||||
#
|
#
|
||||||
# Ne fonctionne que pour les configurations "standards" (dbname=xxx)
|
# Ne fonctionne que pour les configurations "standards" (dbname=xxx)
|
||||||
#
|
#
|
||||||
# Il doit <EFBFBD>tre lanc<6E> par l'utilisateur unix root dans le repertoire .../config
|
# Il doit être lancé par l'utilisateur unix root dans le repertoire .../config
|
||||||
# ^^^^^^^^^^^^^^^^^^^^^
|
# ^^^^^^^^^^^^^^^^^^^^^
|
||||||
# E. Viennet, Sept 2008
|
# E. Viennet, Sept 2008
|
||||||
#
|
#
|
||||||
@ -17,7 +17,7 @@
|
|||||||
source config.sh
|
source config.sh
|
||||||
source utils.sh
|
source utils.sh
|
||||||
|
|
||||||
check_uid_root $0
|
check_uid_root "$0"
|
||||||
usage() {
|
usage() {
|
||||||
echo "$0 [-n DEPT]"
|
echo "$0 [-n DEPT]"
|
||||||
echo "(default to interactive mode)"
|
echo "(default to interactive mode)"
|
||||||
@ -59,11 +59,16 @@ then
|
|||||||
scodocctl stop
|
scodocctl stop
|
||||||
|
|
||||||
# suppression de la base postgres
|
# suppression de la base postgres
|
||||||
db_name=$(cat "$cfg_pathname" | sed '/^dbname=*/!d; s///;q')
|
db_name=$(sed '/^dbname=*/!d; s///;q' < "$cfg_pathname")
|
||||||
echo "suppression de la base postgres $db_name"
|
if su -c "psql -lt" "$POSTGRES_SUPERUSER" | cut -d \| -f 1 | grep -wq "$db_name"
|
||||||
su -c "dropdb $db_name" "$POSTGRES_SUPERUSER" || terminate "ne peux supprimer base de donnees $db_name"
|
then
|
||||||
|
echo "Suppression de la base postgres $db_name ..."
|
||||||
|
su -c "dropdb $db_name" "$POSTGRES_SUPERUSER" || terminate "ne peux supprimer base de donnees $db_name"
|
||||||
|
else
|
||||||
|
echo "la base postgres $db_name n'existe pas."
|
||||||
|
fi
|
||||||
# suppression du fichier de config
|
# suppression du fichier de config
|
||||||
/bin/rm -f "$cfg_pathname" || terminate "ne peux supprimer $cfg_pathname"
|
/bin/rm -f "$cfg_pathname" || terminate "Ne peux supprimer $cfg_pathname"
|
||||||
# relance ScoDoc
|
# relance ScoDoc
|
||||||
if [ "$interactive" = 1 ]
|
if [ "$interactive" = 1 ]
|
||||||
then
|
then
|
||||||
@ -76,6 +81,8 @@ then
|
|||||||
fi
|
fi
|
||||||
exit 0
|
exit 0
|
||||||
else
|
else
|
||||||
echo 'Erreur: pas de configuration trouvee pour "'"$DEPT"'"'
|
echo 'Attention: pas de configuration trouvee pour "'"$DEPT"'"'
|
||||||
exit 1
|
echo " fichier cherché: $cfg_pathname"
|
||||||
|
echo " => ne fait rien."
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
# ScoDoc7 service
|
# ScoDoc7 service
|
||||||
# Zope based
|
# Zope based
|
||||||
# Depends on postgresql
|
# Depends on {{postgresql}} (replaced by installation script by
|
||||||
# => is restarted when postgresql restarts
|
# postgresql@11-main.service on Debian 10
|
||||||
|
# postgresql on Debian <= 9
|
||||||
|
# => is restarted when {{postgresql}} restarts
|
||||||
#
|
#
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=ScoDoc 7 service
|
Description=ScoDoc 7 service
|
||||||
After=network.target postgresql@11-main.service
|
After=network.target {{postgresql}}
|
||||||
Requires=postgresql@11-main.service
|
Requires={{postgresql}}
|
||||||
PartOf=postgresql@11-main.service
|
PartOf={{postgresql}}
|
||||||
StartLimitIntervalSec=0
|
StartLimitIntervalSec=0
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
@ -21,4 +23,4 @@ ExecStop=/opt/scodoc/bin/zopectl stop
|
|||||||
ExecReload=/opt/scodoc/bin/zopectl restart
|
ExecReload=/opt/scodoc/bin/zopectl restart
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=postgresql@11-main.service
|
WantedBy={{postgresql}}
|
||||||
|
64
config/fix_bug70_db.py
Normal file
64
config/fix_bug70_db.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Fix bug #70
|
||||||
|
|
||||||
|
Utiliser comme:
|
||||||
|
scotests/scointeractive.sh DEPT config/fix_bug70_db.py
|
||||||
|
|
||||||
|
"""
|
||||||
|
context = context.Notes # pylint: disable=undefined-variable
|
||||||
|
REQUEST = REQUEST # pylint: disable=undefined-variable
|
||||||
|
import scotests.sco_fake_gen as sco_fake_gen # pylint: disable=import-error
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import sco_utils
|
||||||
|
import notesdb
|
||||||
|
import sco_formsemestre
|
||||||
|
import sco_formsemestre_edit
|
||||||
|
import sco_moduleimpl
|
||||||
|
|
||||||
|
G = sco_fake_gen.ScoFake(context.Notes)
|
||||||
|
|
||||||
|
|
||||||
|
def fix_formsemestre_formation_bug70(formsemestre_id):
|
||||||
|
"""Le bug #70 a pu entrainer des incohérences
|
||||||
|
lors du clonage avorté de semestres.
|
||||||
|
Cette fonction réassocie le semestre à la formation
|
||||||
|
à laquelle appartiennent ses modulesimpls.
|
||||||
|
2021-04-23
|
||||||
|
"""
|
||||||
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
|
cursor = notesdb.SimpleQuery(
|
||||||
|
context,
|
||||||
|
"""SELECT m.formation_id
|
||||||
|
FROM notes_modules m, notes_moduleimpl mi
|
||||||
|
WHERE mi.module_id = m.module_id
|
||||||
|
AND mi.formsemestre_id = %(formsemestre_id)s
|
||||||
|
""",
|
||||||
|
{"formsemestre_id": formsemestre_id},
|
||||||
|
)
|
||||||
|
modimpls_formations = set([x[0] for x in cursor])
|
||||||
|
if len(modimpls_formations) > 1:
|
||||||
|
# this is should not occur
|
||||||
|
G.log(
|
||||||
|
"Warning: fix_formsemestre_formation_bug70: modules from several formations in sem %s"
|
||||||
|
% formsemestre_id
|
||||||
|
)
|
||||||
|
elif len(modimpls_formations) == 1:
|
||||||
|
modimpls_formation_id = modimpls_formations.pop()
|
||||||
|
if modimpls_formation_id != sem["formation_id"]:
|
||||||
|
# Bug #70: fix
|
||||||
|
G.log("fix_formsemestre_formation_bug70: fixing %s" % formsemestre_id)
|
||||||
|
sem["formation_id"] = modimpls_formation_id
|
||||||
|
context.do_formsemestre_edit(sem, html_quote=False)
|
||||||
|
|
||||||
|
|
||||||
|
formsemestre_ids = [
|
||||||
|
x[0]
|
||||||
|
for x in notesdb.SimpleQuery(
|
||||||
|
context, "SELECT formsemestre_id FROM notes_formsemestre", {}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
for formsemestre_id in formsemestre_ids:
|
||||||
|
fix_formsemestre_formation_bug70(formsemestre_id)
|
@ -32,11 +32,13 @@ fi
|
|||||||
chgrp www-data $SCODOC_DIR $SCODOC_DIR/ZopeProducts/*
|
chgrp www-data $SCODOC_DIR $SCODOC_DIR/ZopeProducts/*
|
||||||
chmod g+w $SCODOC_DIR $SCODOC_DIR/ZopeProducts/*
|
chmod g+w $SCODOC_DIR $SCODOC_DIR/ZopeProducts/*
|
||||||
|
|
||||||
chgrp -R www-data "${SCODOC_VAR_DIR}"/photos
|
if [ -d "${SCODOC_VAR_DIR}"/photos ]; then
|
||||||
chmod -R g+w "${SCODOC_VAR_DIR}"/photos
|
chgrp -R www-data "${SCODOC_VAR_DIR}"/photos
|
||||||
|
chmod -R g+w "${SCODOC_VAR_DIR}"/photos
|
||||||
|
fi
|
||||||
|
|
||||||
if [ ! -e "${SCODOC_VERSION_DIR}" ]; then
|
if [ ! -e "${SCODOC_VERSION_DIR}" ]; then
|
||||||
mkdir "${SCODOC_VERSION_DIR}"
|
mkdir -p "${SCODOC_VERSION_DIR}"
|
||||||
chown www-data.www-data "${SCODOC_VERSION_DIR}"
|
chown www-data.www-data "${SCODOC_VERSION_DIR}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -96,8 +98,6 @@ apt-get -y install python-cracklib # was python-crack
|
|||||||
apt-get -y install python-icalendar
|
apt-get -y install python-icalendar
|
||||||
apt-get -y install python-requests
|
apt-get -y install python-requests
|
||||||
|
|
||||||
apt-get -y install python-egenix-mxtools python-egenix-mxdatetime
|
|
||||||
|
|
||||||
|
|
||||||
# ------------
|
# ------------
|
||||||
SVNVERSION=$(cd ..; svnversion)
|
SVNVERSION=$(cd ..; svnversion)
|
||||||
@ -220,9 +220,7 @@ read ans
|
|||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
# ScoDoc 7.19+ uses systemd
|
# ScoDoc 7.19+ uses systemd
|
||||||
echo 'Installation du demarrage automatique de ScoDoc (systemd)'
|
$SCODOC_DIR/config/configure_systemd.sh
|
||||||
cp $SCODOC_DIR/config/etc/scodoc.service /etc/systemd/system
|
|
||||||
systemctl enable scodoc.service
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
@ -583,27 +583,6 @@ for dept in get_depts():
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
# add etape_apo2
|
|
||||||
check_field(
|
|
||||||
cnx,
|
|
||||||
"notes_formsemestre",
|
|
||||||
"etape_apo2",
|
|
||||||
["alter table notes_formsemestre add column etape_apo2 text"],
|
|
||||||
)
|
|
||||||
# add etape_apo3
|
|
||||||
check_field(
|
|
||||||
cnx,
|
|
||||||
"notes_formsemestre",
|
|
||||||
"etape_apo3",
|
|
||||||
["alter table notes_formsemestre add column etape_apo3 text"],
|
|
||||||
)
|
|
||||||
# add etape_apo4
|
|
||||||
check_field(
|
|
||||||
cnx,
|
|
||||||
"notes_formsemestre",
|
|
||||||
"etape_apo4",
|
|
||||||
["alter table notes_formsemestre add column etape_apo4 text"],
|
|
||||||
)
|
|
||||||
# add publish_incomplete
|
# add publish_incomplete
|
||||||
check_field(
|
check_field(
|
||||||
cnx,
|
cnx,
|
||||||
@ -1070,6 +1049,21 @@ for dept in get_depts():
|
|||||||
"etape",
|
"etape",
|
||||||
["alter table notes_formsemestre_inscription add column etape text"],
|
["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:
|
# Add here actions to performs after upgrades:
|
||||||
cnx.commit()
|
cnx.commit()
|
||||||
cnx.close()
|
cnx.close()
|
||||||
|
29
config/postupgrade.py
Executable file → Normal file
29
config/postupgrade.py
Executable file → Normal file
@ -1,4 +1,5 @@
|
|||||||
#!/opt/zope213/bin/python
|
#!/opt/zope213/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
ScoDoc post-upgrade script.
|
ScoDoc post-upgrade script.
|
||||||
@ -11,21 +12,22 @@ _before_ upgrading the database.
|
|||||||
E. Viennet, June 2008
|
E. Viennet, June 2008
|
||||||
Mar 2017: suppress upgrade of very old Apache configs
|
Mar 2017: suppress upgrade of very old Apache configs
|
||||||
Aug 2020: move photos to .../var/scodoc/
|
Aug 2020: move photos to .../var/scodoc/
|
||||||
|
Apr 2021: bug #70
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import glob
|
import glob
|
||||||
import shutil
|
import shutil
|
||||||
from scodocutils import log, SCODOC_DIR, SCODOC_VAR_DIR, SCODOC_LOGOS_DIR
|
from scodocutils import log, SCODOC_DIR, SCODOC_VAR_DIR, SCODOC_LOGOS_DIR, SCO_TMPDIR
|
||||||
|
|
||||||
if os.getuid() != 0:
|
if os.getuid() != 0:
|
||||||
log('postupgrade.py: must be run as root')
|
log("postupgrade.py: must be run as root")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# ---
|
# ---
|
||||||
# Migrate photos (2020-08-16, svn 1908)
|
# Migrate photos (2020-08-16, svn 1908)
|
||||||
old_photo_dir = os.path.join(SCODOC_DIR, "static", "photos")
|
old_photo_dir = os.path.join(SCODOC_DIR, "static", "photos")
|
||||||
photo_dirs = glob.glob( old_photo_dir + "/F*")
|
photo_dirs = glob.glob(old_photo_dir + "/F*")
|
||||||
if photo_dirs:
|
if photo_dirs:
|
||||||
log("Moving photos to new <var> directory...")
|
log("Moving photos to new <var> directory...")
|
||||||
shutil.move(old_photo_dir, SCODOC_VAR_DIR)
|
shutil.move(old_photo_dir, SCODOC_VAR_DIR)
|
||||||
@ -33,7 +35,7 @@ if photo_dirs:
|
|||||||
# Migrate depts (2020-08-17, svn 1909)
|
# Migrate depts (2020-08-17, svn 1909)
|
||||||
|
|
||||||
old_depts_dir = os.path.join(SCODOC_DIR, "config", "depts")
|
old_depts_dir = os.path.join(SCODOC_DIR, "config", "depts")
|
||||||
cfg_files = glob.glob( old_depts_dir + "/*.cfg")
|
cfg_files = glob.glob(old_depts_dir + "/*.cfg")
|
||||||
depts_dir = os.path.join(SCODOC_VAR_DIR, "config/depts/")
|
depts_dir = os.path.join(SCODOC_VAR_DIR, "config/depts/")
|
||||||
for cfg in cfg_files:
|
for cfg in cfg_files:
|
||||||
log("Moving %s to new <var> directory..." % cfg)
|
log("Moving %s to new <var> directory..." % cfg)
|
||||||
@ -41,7 +43,7 @@ for cfg in cfg_files:
|
|||||||
|
|
||||||
# Move logos
|
# Move logos
|
||||||
if not os.path.exists(SCODOC_LOGOS_DIR):
|
if not os.path.exists(SCODOC_LOGOS_DIR):
|
||||||
old_logos = os.path.join(SCODOC_DIR,"logos")
|
old_logos = os.path.join(SCODOC_DIR, "logos")
|
||||||
if os.path.exists(old_logos):
|
if os.path.exists(old_logos):
|
||||||
log("Moving logos to new <var> directory...")
|
log("Moving logos to new <var> directory...")
|
||||||
dest = os.path.normpath(os.path.join(SCODOC_LOGOS_DIR, ".."))
|
dest = os.path.normpath(os.path.join(SCODOC_LOGOS_DIR, ".."))
|
||||||
@ -50,10 +52,23 @@ if not os.path.exists(SCODOC_LOGOS_DIR):
|
|||||||
log("Warning: logos directory is missing (%s)" % SCODOC_LOGOS_DIR)
|
log("Warning: logos directory is missing (%s)" % SCODOC_LOGOS_DIR)
|
||||||
|
|
||||||
# Move dept-specific logos
|
# Move dept-specific logos
|
||||||
for d in glob.glob( SCODOC_DIR + "/logos_*" ):
|
for d in glob.glob(SCODOC_DIR + "/logos_*"):
|
||||||
log("Moving %s to %s" % (d, SCODOC_LOGOS_DIR))
|
log("Moving %s to %s" % (d, SCODOC_LOGOS_DIR))
|
||||||
shutil.move(d, SCODOC_LOGOS_DIR)
|
shutil.move(d, SCODOC_LOGOS_DIR)
|
||||||
|
|
||||||
|
# Fix bug #70
|
||||||
|
depts = [
|
||||||
|
os.path.splitext(os.path.basename(f))[0] for f in glob.glob(depts_dir + "/*.cfg")
|
||||||
|
]
|
||||||
|
for dept in depts:
|
||||||
|
fixed_filename = SCO_TMPDIR + "/.%s_bug70_fixed" % dept
|
||||||
|
if not os.path.exists(fixed_filename):
|
||||||
|
log("fixing #70 on %s" % dept)
|
||||||
|
os.system("../scotests/scointeractive.sh -x %s config/fix_bug70_db.py" % dept)
|
||||||
|
# n'essaie qu'une fois, même en cas d'échec
|
||||||
|
f = open(fixed_filename, "a")
|
||||||
|
f.close()
|
||||||
|
|
||||||
# Continue here...
|
# Continue here...
|
||||||
|
|
||||||
# ---
|
# ---
|
||||||
|
@ -51,7 +51,7 @@ then
|
|||||||
fi
|
fi
|
||||||
chown root "$DEST"
|
chown root "$DEST"
|
||||||
|
|
||||||
# Zope DB and ScoDoc archives:
|
# Zope DB, ScoDoc archives, configuration, photos, etc.
|
||||||
echo "Copying var/ ..."
|
echo "Copying var/ ..."
|
||||||
cp -rp "$INSTANCE_DIR/var" "$DEST"
|
cp -rp "$INSTANCE_DIR/var" "$DEST"
|
||||||
|
|
||||||
|
8
config/scodocutils.py
Normal file → Executable file
8
config/scodocutils.py
Normal file → Executable file
@ -9,6 +9,12 @@ import sys, os, psycopg2, glob, subprocess, traceback, time
|
|||||||
|
|
||||||
sys.path.append("..")
|
sys.path.append("..")
|
||||||
|
|
||||||
|
# INSTANCE_HOME est nécessaire pour sco_utils.py
|
||||||
|
# note: avec le python 2.7 de Zope2, l'import de pyscopg2 change
|
||||||
|
# INSTANCE_HOME dans l'environnement !
|
||||||
|
# Ici on le fixe à la "bonne" valeur pour ScoDoc7.
|
||||||
|
os.environ["INSTANCE_HOME"] = "/opt/scodoc"
|
||||||
|
|
||||||
|
|
||||||
def log(msg):
|
def log(msg):
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
@ -24,8 +30,10 @@ SCODOC_VAR_DIR = os.environ.get("SCODOC_VAR_DIR", "")
|
|||||||
if not SCODOC_VAR_DIR:
|
if not SCODOC_VAR_DIR:
|
||||||
log("Error: environment variable SCODOC_VAR_DIR is not defined")
|
log("Error: environment variable SCODOC_VAR_DIR is not defined")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
SCO_TMPDIR = os.path.join(SCODOC_VAR_DIR, "tmp")
|
||||||
SCODOC_LOGOS_DIR = os.environ.get("SCODOC_LOGOS_DIR", "")
|
SCODOC_LOGOS_DIR = os.environ.get("SCODOC_LOGOS_DIR", "")
|
||||||
|
|
||||||
|
|
||||||
def get_dept_cnx_str(dept):
|
def get_dept_cnx_str(dept):
|
||||||
"db cnx string for dept"
|
"db cnx string for dept"
|
||||||
f = os.path.join(SCODOC_VAR_DIR, "config", "depts", dept + ".cfg")
|
f = os.path.join(SCODOC_VAR_DIR, "config", "depts", dept + ".cfg")
|
||||||
|
19
config/upgrade.sh
Executable file → Normal file
19
config/upgrade.sh
Executable file → Normal file
@ -14,7 +14,7 @@ cd /opt/scodoc/Products/ScoDoc/config
|
|||||||
source config.sh
|
source config.sh
|
||||||
source utils.sh
|
source utils.sh
|
||||||
|
|
||||||
check_uid_root $0
|
check_uid_root "$0"
|
||||||
|
|
||||||
if [ -z "$SCODOC_UPGRADE_RUNNING" ]
|
if [ -z "$SCODOC_UPGRADE_RUNNING" ]
|
||||||
then
|
then
|
||||||
@ -23,7 +23,8 @@ fi
|
|||||||
|
|
||||||
# Upgrade svn working copy if possible
|
# Upgrade svn working copy if possible
|
||||||
svnver=$(svn --version --quiet)
|
svnver=$(svn --version --quiet)
|
||||||
if [[ ${svnver} > "1.7" ]]
|
# shellcheck disable=SC2072
|
||||||
|
if [[ ${svnver} > "1.7" ]]
|
||||||
then
|
then
|
||||||
(cd "$SCODOC_DIR"; find . -name .svn -type d -exec dirname {} \; | xargs svn upgrade)
|
(cd "$SCODOC_DIR"; find . -name .svn -type d -exec dirname {} \; | xargs svn upgrade)
|
||||||
fi
|
fi
|
||||||
@ -63,7 +64,7 @@ CMD="curl --fail --connect-timeout 5 --silent http://scodoc.iutv.univ-paris13.fr
|
|||||||
#echo $CMD
|
#echo $CMD
|
||||||
SVERSION="$(${CMD})"
|
SVERSION="$(${CMD})"
|
||||||
|
|
||||||
if [ $? == 0 ]; then
|
if [ "$?" == 0 ]; then
|
||||||
#echo "answer=${SVERSION}"
|
#echo "answer=${SVERSION}"
|
||||||
echo "${SVERSION}" > "${SCODOC_VERSION_DIR}"/scodoc.sn
|
echo "${SVERSION}" > "${SCODOC_VERSION_DIR}"/scodoc.sn
|
||||||
else
|
else
|
||||||
@ -72,13 +73,13 @@ fi
|
|||||||
|
|
||||||
|
|
||||||
# Check that no Zope "access" file has been forgotten in the way:
|
# Check that no Zope "access" file has been forgotten in the way:
|
||||||
if [ -e $SCODOC_DIR/../../access ]
|
if [ -e "$SCODOC_DIR"/../../access ]
|
||||||
then
|
then
|
||||||
mv $SCODOC_DIR/../../access $SCODOC_DIR/../../access.bak
|
mv "$SCODOC_DIR"/../../access "$SCODOC_DIR"/../../access.bak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Fix some permissions which may have been altered in the way:
|
# Fix some permissions which may have been altered in the way:
|
||||||
chsh -s /bin/sh $POSTGRES_USER # www-data, nologin in Debian 9
|
chsh -s /bin/sh "$POSTGRES_USER" # www-data, nologin in Debian 9
|
||||||
chown root.www-data "$SCODOC_DIR" # important to create .pyc
|
chown root.www-data "$SCODOC_DIR" # important to create .pyc
|
||||||
chmod 775 "${SCODOC_DIR}"
|
chmod 775 "${SCODOC_DIR}"
|
||||||
chmod a+r "$SCODOC_DIR"/*.py
|
chmod a+r "$SCODOC_DIR"/*.py
|
||||||
@ -119,6 +120,10 @@ then
|
|||||||
/opt/zope213/bin/pip install requests
|
/opt/zope213/bin/pip install requests
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# upgrade old dateutil (check version manually to speedup)
|
||||||
|
v=$(/opt/zope213/bin/python -c "import dateutil; print dateutil.__version__")
|
||||||
|
[[ "$v" < "2.8.1" ]] && /opt/zope213/bin/pip install --upgrade python-dateutil
|
||||||
|
|
||||||
# Ensure www-data can duplicate databases (for dumps)
|
# Ensure www-data can duplicate databases (for dumps)
|
||||||
su -c $'psql -c \'alter role "www-data" with CREATEDB;\'' "$POSTGRES_SUPERUSER"
|
su -c $'psql -c \'alter role "www-data" with CREATEDB;\'' "$POSTGRES_SUPERUSER"
|
||||||
#'
|
#'
|
||||||
@ -128,7 +133,7 @@ echo "Executing post-upgrade script..."
|
|||||||
"$SCODOC_DIR"/config/postupgrade.py
|
"$SCODOC_DIR"/config/postupgrade.py
|
||||||
|
|
||||||
echo "Executing post-upgrade database script..."
|
echo "Executing post-upgrade database script..."
|
||||||
su -c "$SCODOC_DIR/config/postupgrade-db.py" $POSTGRES_USER
|
su -c "$SCODOC_DIR/config/postupgrade-db.py" "$POSTGRES_USER"
|
||||||
|
|
||||||
#
|
#
|
||||||
echo
|
echo
|
||||||
|
28
csv2rules.py
28
csv2rules.py
@ -45,7 +45,27 @@ HEAD = """# -*- coding: utf-8 -*-
|
|||||||
#
|
#
|
||||||
# Command: %s %s
|
# 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'
|
rules_source_file='%s'
|
||||||
|
|
||||||
@ -55,15 +75,15 @@ rules_source_file='%s'
|
|||||||
sourcefile,
|
sourcefile,
|
||||||
)
|
)
|
||||||
|
|
||||||
from sco_codes_parcours import *
|
import sco_utils as scu
|
||||||
|
|
||||||
|
|
||||||
def _fmt(s):
|
def _fmt(s):
|
||||||
if not s:
|
if not s:
|
||||||
return None
|
return None
|
||||||
if strlower(s) in ("ok", "oui", "o", "y", "yes"):
|
if scu.strlower(s) in ("ok", "oui", "o", "y", "yes"):
|
||||||
return True
|
return True
|
||||||
if strlower(s) in ("no", "non"):
|
if scu.strlower(s) in ("no", "non"):
|
||||||
return False
|
return False
|
||||||
if s == "*":
|
if s == "*":
|
||||||
return ALL
|
return ALL
|
||||||
|
24
debug.py
24
debug.py
@ -32,10 +32,13 @@ nt = context.Notes._getNotesCache().get_NotesTable(context.Notes, formsemestre_i
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
import pdb
|
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 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
|
from gen_tables import GenTable
|
||||||
import sco_archives
|
import sco_archives
|
||||||
@ -54,18 +57,24 @@ import sco_bulletins_xml
|
|||||||
# Prend le premier departement comme context
|
# Prend le premier departement comme context
|
||||||
|
|
||||||
|
|
||||||
def go(app, n=0):
|
def go(app, n=0, verbose=True):
|
||||||
context = app.ScoDoc.objectValues("Folder")[n].Scolarite
|
context = app.ScoDoc.objectValues("Folder")[n].Scolarite
|
||||||
print("context in dept ", context.DeptId())
|
if verbose:
|
||||||
|
print("context in dept ", context.DeptId())
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
def go_dept(app, dept):
|
def go_dept(app, dept, verbose=True):
|
||||||
objs = app.ScoDoc.objectValues("Folder")
|
objs = app.ScoDoc.objectValues("Folder")
|
||||||
for o in objs:
|
for o in objs:
|
||||||
context = o.Scolarite
|
try:
|
||||||
|
context = o.Scolarite
|
||||||
|
except AttributeError:
|
||||||
|
# ignore other folders, like old "icons"
|
||||||
|
continue
|
||||||
if context.DeptId() == dept:
|
if context.DeptId() == dept:
|
||||||
print("context in dept ", context.DeptId())
|
if verbose:
|
||||||
|
print("context in dept ", context.DeptId())
|
||||||
return context
|
return context
|
||||||
raise ValueError("dep %s not found" % dept)
|
raise ValueError("dep %s not found" % dept)
|
||||||
|
|
||||||
@ -106,7 +115,6 @@ class DummyRequest:
|
|||||||
self.AUTHENTICATED_USER = FakeUser("admin")
|
self.AUTHENTICATED_USER = FakeUser("admin")
|
||||||
self.form = {}
|
self.form = {}
|
||||||
self.URL = "http://scodoc/"
|
self.URL = "http://scodoc/"
|
||||||
self.URL1 = self.URL
|
|
||||||
self.URL0 = self.URL
|
self.URL0 = self.URL
|
||||||
self.BASE0 = "localhost"
|
self.BASE0 = "localhost"
|
||||||
self.REMOTE_HOST = "localhost"
|
self.REMOTE_HOST = "localhost"
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
<dtml-var "entreprise_header(REQUEST=REQUEST)">
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set( 'E', do_entreprise_list( args={ 'entreprise_id' : entreprise_id } )[0])">
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set( 'curtime', ZopeTime().strftime('%d/%m/%Y') )">
|
|
||||||
<dtml-call "REQUEST.set( 'link_create_corr', make_link_create_corr(entreprise_id) )">
|
|
||||||
<dtml-call "REQUEST.set( 'correspondants',
|
|
||||||
do_entreprise_correspondant_listnames( args={ 'entreprise_id' : entreprise_id }) )">
|
|
||||||
<dtml-if "len(correspondants) == 0">
|
|
||||||
<dtml-call "REQUEST.set( 'correspondants', [ ('inconnu','') ])">
|
|
||||||
</dtml-if>
|
|
||||||
|
|
||||||
<h2 class="entreprise_contact">Nouveau "contact" avec l'entreprise <dtml-var "E['nom']"></h2>
|
|
||||||
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set('tf', TrivialFormulator( URL0, REQUEST.form,
|
|
||||||
(
|
|
||||||
('entreprise_id', { 'input_type' : 'hidden', 'default' : entreprise_id }),
|
|
||||||
|
|
||||||
('type_contact', { 'input_type' : 'menu', 'title' : 'Objet',
|
|
||||||
'allowed_values' : ('Prospection', 'Stage étudiant',
|
|
||||||
'Contrat Apprentissage DUT GTR1',
|
|
||||||
'Contrat Apprentissage DUT GTR2',
|
|
||||||
'Contrat Apprentissage Licence SQRT',
|
|
||||||
'Projet', 'Autre' ),
|
|
||||||
'default' : 'Stage étudiant'
|
|
||||||
}),
|
|
||||||
|
|
||||||
('date', { 'size' : 12, 'title' : 'Date du contact (j/m/a)', 'allow_null' : False,
|
|
||||||
'default': curtime }),
|
|
||||||
|
|
||||||
('entreprise_corresp_id', { 'input_type' : 'menu', 'title' : 'Correspondant entreprise',
|
|
||||||
'explanation' : link_create_corr, 'allow_null' : True,
|
|
||||||
'labels' : [ x[0] for x in correspondants ],
|
|
||||||
'allowed_values' : [ x[1] for x in correspondants ] }),
|
|
||||||
|
|
||||||
('etudiant', { 'size' : 16, 'title' : 'Etudiant concerné', 'allow_null' : True,
|
|
||||||
'explanation' : 'nom (si pas ambigu) ou code' }),
|
|
||||||
('enseignant', { 'size' : 16, 'title' : 'Enseignant (tuteur)', 'allow_null' : True }),
|
|
||||||
('description', { 'input_type' : 'textarea', 'rows' : 3, 'cols': 40, 'title' : 'Description' }),
|
|
||||||
|
|
||||||
),
|
|
||||||
cancelbutton='Annuler',
|
|
||||||
submitlabel = 'Ajouter ce contact', readonly = REQUEST['_read_only']
|
|
||||||
))">
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set( 'etudok', do_entreprise_check_etudiant(etudiant) )">
|
|
||||||
|
|
||||||
<dtml-if "(tf[0] == 0) or (etudok[0] == 0)">
|
|
||||||
<dtml-if "etudok[0] == 0">
|
|
||||||
<p class="entreprise_warning"><dtml-var "etudok[1]"></p>
|
|
||||||
</dtml-if>
|
|
||||||
<dtml-var "tf[1]">
|
|
||||||
<dtml-elif "tf[0] == -1">
|
|
||||||
<dtml-call "RESPONSE.redirect( URL1 )">
|
|
||||||
<dtml-else>
|
|
||||||
<dtml-call "tf[2].update( { 'etudid' : etudok[1] })">
|
|
||||||
<dtml-var "REQUEST.set( 'matiere_id', do_entreprise_contact_create( tf[2] ) )">
|
|
||||||
<dtml-call "RESPONSE.redirect( URL1 )">
|
|
||||||
</dtml-if tf>
|
|
||||||
|
|
||||||
<dtml-var "entreprise_footer(REQUEST=REQUEST)">
|
|
@ -1,27 +0,0 @@
|
|||||||
<dtml-var "entreprise_header(REQUEST=REQUEST)">
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set( 'F', do_entreprise_contact_list( args={ 'entreprise_contact_id' : entreprise_contact_id } )[0])">
|
|
||||||
|
|
||||||
<h2>Suppression du contact</h2>
|
|
||||||
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set('tf', TrivialFormulator( URL0, REQUEST.form,
|
|
||||||
( ('entreprise_contact_id', { 'input_type' : 'hidden' }),
|
|
||||||
),
|
|
||||||
initvalues = F,
|
|
||||||
submitlabel = 'Confirmer la suppression',
|
|
||||||
cancelbutton = 'Annuler', readonly = REQUEST['_read_only']
|
|
||||||
))">
|
|
||||||
|
|
||||||
<dtml-if "tf[0] == 0">
|
|
||||||
<dtml-var "tf[1]">
|
|
||||||
<dtml-else>
|
|
||||||
<dtml-if "tf[0] == -1">
|
|
||||||
<dtml-call "RESPONSE.redirect( URL1 )">
|
|
||||||
<dtml-else>
|
|
||||||
<dtml-call "do_entreprise_contact_delete( F['entreprise_contact_id'] )">
|
|
||||||
<dtml-call "RESPONSE.redirect(URL1)">
|
|
||||||
</dtml-if>
|
|
||||||
</dtml-if>
|
|
||||||
|
|
||||||
<dtml-var "entreprise_footer(REQUEST=REQUEST)">
|
|
@ -1,62 +0,0 @@
|
|||||||
<dtml-call "REQUEST.set( 'F', do_entreprise_contact_list( args={ 'entreprise_contact_id' : entreprise_contact_id } )[0])">
|
|
||||||
<dtml-call "REQUEST.set( 'entreprise_id', F['entreprise_id'])">
|
|
||||||
<dtml-call "REQUEST.set( 'link_create_corr', make_link_create_corr(F['entreprise_id']) )">
|
|
||||||
<dtml-call "REQUEST.set( 'E', do_entreprise_list( args={ 'entreprise_id' : F['entreprise_id'] } )[0])">
|
|
||||||
<dtml-call "REQUEST.set( 'correspondants',
|
|
||||||
do_entreprise_correspondant_listnames( args={ 'entreprise_id' : F['entreprise_id'] })+ [ ('inconnu','') ])">
|
|
||||||
|
|
||||||
<dtml-var "entreprise_header(REQUEST=REQUEST)">
|
|
||||||
<h2 class="entreprise_contact"><dtml-var title_or_id></h2>
|
|
||||||
|
|
||||||
|
|
||||||
<h3>Contact avec entreprise <dtml-var "E['nom']"></h3>
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set('tf', TrivialFormulator( URL0, REQUEST.form,
|
|
||||||
( ('entreprise_contact_id', { 'default' : entreprise_contact_id, 'input_type' : 'hidden' }),
|
|
||||||
|
|
||||||
('entreprise_id', { 'input_type' : 'hidden', 'default' : F['entreprise_id'] }),
|
|
||||||
|
|
||||||
('type_contact', { 'input_type' : 'menu', 'title' : 'Objet',
|
|
||||||
'allowed_values' : ('Prospection', 'Stage étudiant', 'Contrat Apprentissage', 'Projet', 'Autre' ),
|
|
||||||
}),
|
|
||||||
|
|
||||||
('date', { 'size' : 12, 'title' : 'Date du contact (j/m/a)', 'allow_null' : False }),
|
|
||||||
|
|
||||||
('entreprise_corresp_id', { 'input_type' : 'menu', 'title' : 'Correspondant entreprise',
|
|
||||||
'explanation' : link_create_corr,
|
|
||||||
'allow_null' : True,
|
|
||||||
'labels' : [ x[0] for x in correspondants ],
|
|
||||||
'allowed_values' : [ x[1] for x in correspondants ] }),
|
|
||||||
|
|
||||||
('etudiant', { 'size' : 16, 'title' : 'Etudiant concerné', 'allow_null' : True,
|
|
||||||
'default' : F['etudid'],
|
|
||||||
'explanation' : 'nom (si pas ambigu) ou code' }),
|
|
||||||
('enseignant', { 'size' : 16, 'title' : 'Enseignant (tuteur)', 'allow_null' : True }),
|
|
||||||
('description', { 'input_type' : 'textarea', 'rows' : 3, 'cols': 40, 'title' : 'Description' }),
|
|
||||||
),
|
|
||||||
cancelbutton = 'Annuler',
|
|
||||||
initvalues = F,
|
|
||||||
submitlabel = 'Modifier les valeurs', readonly = REQUEST['_read_only']
|
|
||||||
))">
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set( 'etudok', do_entreprise_check_etudiant(etudiant) )">
|
|
||||||
|
|
||||||
<dtml-if "(tf[0] == 0) or (etudok[0] == 0)">
|
|
||||||
<dtml-if "etudok[0] == 0">
|
|
||||||
<p class="entreprise_warning"><dtml-var "etudok[1]"></p>
|
|
||||||
</dtml-if>
|
|
||||||
|
|
||||||
<dtml-var "tf[1]">
|
|
||||||
<dtml-unless "REQUEST['_read_only']">
|
|
||||||
<p class="entreprise_descr"><a class="entreprise_delete" href="entreprise_contact_delete?entreprise_contact_id=<dtml-var entreprise_contact_id>">Supprimer ce contact</a> </p>
|
|
||||||
</dtml-unless>
|
|
||||||
<dtml-elif "tf[0] == -1">
|
|
||||||
<dtml-call "RESPONSE.redirect( URL1 )" >
|
|
||||||
<dtml-else>
|
|
||||||
<dtml-call "tf[2].update( { 'etudid' : etudok[1] })">
|
|
||||||
<dtml-call "do_entreprise_contact_edit( tf[2] )">
|
|
||||||
<dtml-call "RESPONSE.redirect( URL1 + '/entreprise_contact_list?entreprise_id=' + str(F['entreprise_id']) )" >
|
|
||||||
</dtml-if>
|
|
||||||
|
|
||||||
|
|
||||||
<dtml-var "entreprise_footer(REQUEST=REQUEST)">
|
|
@ -1,54 +0,0 @@
|
|||||||
<dtml-var "entreprise_header(REQUEST=REQUEST)">
|
|
||||||
|
|
||||||
<dtml-if entreprise_id>
|
|
||||||
<dtml-call "REQUEST.set( 'E', do_entreprise_list( args={ 'entreprise_id' : entreprise_id } )[0])">
|
|
||||||
<dtml-call "REQUEST.set( 'C', do_entreprise_contact_list( args={ 'entreprise_id' : entreprise_id }) )">
|
|
||||||
|
|
||||||
<h2 class="entreprise_contact">Listes des contacts avec l'entreprise <dtml-var "E['nom']"> </h2>
|
|
||||||
|
|
||||||
<dtml-else>
|
|
||||||
<h2 class="entreprise_contact">Listes des contacts</h2>
|
|
||||||
<dtml-call "REQUEST.set( 'C', do_entreprise_contact_list( args={ }))">
|
|
||||||
</dtml-if entreprise_id>
|
|
||||||
|
|
||||||
<table class="contact_list">
|
|
||||||
|
|
||||||
<tr><th>Date</th><th>Objet</th><dtml-unless entreprise_id><th>Entreprise</th></dtml-unless><th>Etudiant</th><th>Description</th></tr>
|
|
||||||
|
|
||||||
<dtml-in "C">
|
|
||||||
<dtml-let F="_['sequence-item']">
|
|
||||||
<dtml-call "REQUEST.set( 'Ec', do_entreprise_list( args={ 'entreprise_id' : F['entreprise_id'] } )[0])">
|
|
||||||
|
|
||||||
<tr class="<dtml-if sequence-odd>contact_list_odd<dtml-else>contact_list_even</dtml-if>">
|
|
||||||
|
|
||||||
<td><a class="contact_edit" href="entreprise_contact_edit?entreprise_contact_id=<dtml-var "F['entreprise_contact_id']">">
|
|
||||||
<dtml-var "F['date']">
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td class="contact_descr"><dtml-var "F['type_contact']"></td>
|
|
||||||
<dtml-unless entreprise_id><td class="contact_descr"><dtml-var "Ec['nom']"></td></dtml-unless>
|
|
||||||
<td class="contact_descr">
|
|
||||||
<dtml-if "F['etudid']">
|
|
||||||
<dtml-in "getEtudInfo(etudid=F['etudid'],filled=1)" mapping>
|
|
||||||
<a href="<dtml-var ScoURL>/ficheEtud?etudid=<dtml-var "F['etudid']">"><dtml-var nomprenom></a>
|
|
||||||
</dtml-in>
|
|
||||||
</dtml-if etudid>
|
|
||||||
</td>
|
|
||||||
<td class="contact_descr"><dtml-var "F['description']"></td>
|
|
||||||
</tr>
|
|
||||||
</dtml-let F>
|
|
||||||
|
|
||||||
<dtml-else>
|
|
||||||
<tr><td colspan="4"><font color="red"><em>Aucun contact !</em></font></td></tr>
|
|
||||||
</dtml-in>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<dtml-unless "REQUEST['_read_only']">
|
|
||||||
<dtml-if entreprise_id>
|
|
||||||
<p class="entreprise_create">
|
|
||||||
<a class="entreprise_create" href="entreprise_contact_create?entreprise_id=<dtml-var "E['entreprise_id']">">nouveau "contact"</a>
|
|
||||||
</p>
|
|
||||||
</dtml-if>
|
|
||||||
</dtml-unless>
|
|
||||||
|
|
||||||
<dtml-var "entreprise_footer(REQUEST=REQUEST)">
|
|
@ -1,43 +0,0 @@
|
|||||||
<dtml-var "entreprise_header(REQUEST=REQUEST)">
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set( 'UE', do_entreprise_list( args={ 'entreprise_id' : entreprise_id } )[0])">
|
|
||||||
|
|
||||||
|
|
||||||
<h2 class="entreprise_correspondant"><dtml-var title_or_id> dans l'entreprise <dtml-var "UE['nom']"></h2>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set('tf', TrivialFormulator( URL0, REQUEST.form,
|
|
||||||
( ('entreprise_id', { 'input_type' : 'hidden', 'default' : entreprise_id }),
|
|
||||||
('civilite', { 'input_type' : 'menu',
|
|
||||||
'labels' : [ 'M.', 'Mme' ], 'allowed_values' : [ 'M.', 'Mme' ] }),
|
|
||||||
('nom', { 'size' : 25, 'title' : 'Nom', 'allow_null' : False }),
|
|
||||||
('prenom', { 'size' : 25, 'title' : 'Prénom' }),
|
|
||||||
('fonction', { 'input_type' : 'menu',
|
|
||||||
'allowed_values' : ('Directeur', 'RH', 'Resp. Administratif', 'Tuteur', 'Autre'),
|
|
||||||
'default' : 'Tuteur',
|
|
||||||
'explanation' : 'fonction via à vis de l\'IUT' }),
|
|
||||||
('phone1', { 'size' : 14, 'title' : 'Téléphone 1', }),
|
|
||||||
('phone2', { 'size' : 14, 'title' : 'Téléphone 2', }),
|
|
||||||
('mobile', { 'size' : 14, 'title' : 'Tél. mobile', }),
|
|
||||||
('fax', { 'size' : 14, 'title' : 'Fax', }),
|
|
||||||
('mail1', { 'size' : 25, 'title' : 'e-mail', }),
|
|
||||||
('mail2', { 'size' : 25, 'title' : 'e-mail 2', }),
|
|
||||||
|
|
||||||
('note', { 'input_type' : 'textarea', 'rows' : 3, 'cols': 40, 'title' : 'Note' }),
|
|
||||||
|
|
||||||
),
|
|
||||||
cancelbutton='Annuler',
|
|
||||||
submitlabel = 'Ajouter ce correspondant', readonly = REQUEST['_read_only']
|
|
||||||
))">
|
|
||||||
|
|
||||||
<dtml-if "tf[0] == 0">
|
|
||||||
<dtml-var "tf[1]">
|
|
||||||
<dtml-else>
|
|
||||||
<dtml-var "REQUEST.set( 'matiere_id', do_entreprise_correspondant_create( tf[2] ) )">
|
|
||||||
|
|
||||||
<dtml-call "RESPONSE.redirect( URL1 )">
|
|
||||||
|
|
||||||
</dtml-if>
|
|
||||||
|
|
||||||
<dtml-var "entreprise_footer(REQUEST=REQUEST)">
|
|
@ -1,27 +0,0 @@
|
|||||||
<dtml-var "entreprise_header(REQUEST=REQUEST)">
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set( 'F', do_entreprise_correspondant_list( args={ 'entreprise_corresp_id' : entreprise_corresp_id } )[0])">
|
|
||||||
|
|
||||||
<h2>Suppression du correspondant <dtml-var "F['nom']"> <dtml-var "F['prenom']"></h2>
|
|
||||||
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set('tf', TrivialFormulator( URL0, REQUEST.form,
|
|
||||||
( ('entreprise_corresp_id', { 'input_type' : 'hidden' }),
|
|
||||||
),
|
|
||||||
initvalues = F,
|
|
||||||
submitlabel = 'Confirmer la suppression',
|
|
||||||
cancelbutton = 'Annuler', readonly = REQUEST['_read_only']
|
|
||||||
))">
|
|
||||||
|
|
||||||
<dtml-if "tf[0] == 0">
|
|
||||||
<dtml-var "tf[1]">
|
|
||||||
<dtml-else>
|
|
||||||
<dtml-if "tf[0] == -1">
|
|
||||||
<dtml-call "RESPONSE.redirect( URL1 )">
|
|
||||||
<dtml-else>
|
|
||||||
<dtml-call "do_entreprise_correspondant_delete( F['entreprise_corresp_id'] )">
|
|
||||||
<dtml-call "RESPONSE.redirect(URL1)">
|
|
||||||
</dtml-if>
|
|
||||||
</dtml-if>
|
|
||||||
|
|
||||||
<dtml-var "entreprise_footer(REQUEST=REQUEST)">
|
|
@ -1,41 +0,0 @@
|
|||||||
<dtml-call "REQUEST.set( 'F', do_entreprise_correspondant_list( args={ 'entreprise_corresp_id' : entreprise_corresp_id } )[0])">
|
|
||||||
<dtml-call "REQUEST.set( 'entreprise_id', F['entreprise_id'])">
|
|
||||||
|
|
||||||
<dtml-var "entreprise_header(REQUEST=REQUEST)">
|
|
||||||
<h2 class="entreprise_correspondant"><dtml-var title_or_id></h2>
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set('tf', TrivialFormulator( URL0, REQUEST.form,
|
|
||||||
( ('entreprise_corresp_id', { 'default' : entreprise_corresp_id, 'input_type' : 'hidden' }),
|
|
||||||
('civilite', { 'input_type' : 'menu',
|
|
||||||
'labels' : [ 'M.', 'Mme' ], 'allowed_values' : [ 'M.', 'Mme' ] }),
|
|
||||||
('nom', { 'size' : 25, 'title' : 'Nom', 'allow_null' : False }),
|
|
||||||
('prenom', { 'size' : 25, 'title' : 'Prénom' }),
|
|
||||||
('fonction', { 'input_type' : 'menu',
|
|
||||||
'allowed_values' : ('Directeur', 'RH', 'Resp. Administratif', 'Tuteur', 'Autre'),
|
|
||||||
'explanation' : 'fonction via à vis de l\'IUT' }),
|
|
||||||
('phone1', { 'size' : 14, 'title' : 'Téléphone 1', }),
|
|
||||||
('phone2', { 'size' : 14, 'title' : 'Téléphone 2', }),
|
|
||||||
('mobile', { 'size' : 14, 'title' : 'Tél. mobile', }),
|
|
||||||
('fax', { 'size' : 14, 'title' : 'Fax', }),
|
|
||||||
('mail1', { 'size' : 25, 'title' : 'e-mail', }),
|
|
||||||
('mail2', { 'size' : 25, 'title' : 'e-mail 2', }),
|
|
||||||
|
|
||||||
('note', { 'input_type' : 'textarea', 'rows' : 3, 'cols': 40, 'title' : 'Note' }),
|
|
||||||
),
|
|
||||||
cancelbutton = 'Annuler',
|
|
||||||
initvalues = F,
|
|
||||||
submitlabel = 'Modifier les valeurs', readonly = REQUEST['_read_only']
|
|
||||||
))">
|
|
||||||
|
|
||||||
<dtml-if "tf[0] == 0">
|
|
||||||
<dtml-var "tf[1]">
|
|
||||||
<dtml-elif "tf[0] == -1">
|
|
||||||
<dtml-call "RESPONSE.redirect( REQUEST.HTTP_REFERER )" >
|
|
||||||
<dtml-call "RESPONSE.redirect( URL1 + '/entreprise_correspondant_list?entreprise_id=' + str(F['entreprise_id']) )" >
|
|
||||||
<dtml-else>
|
|
||||||
<dtml-call "do_entreprise_correspondant_edit( tf[2] )">
|
|
||||||
<dtml-call "RESPONSE.redirect( URL1 + '/entreprise_correspondant_list?entreprise_id=' + str(F['entreprise_id']) )" >
|
|
||||||
</dtml-if>
|
|
||||||
|
|
||||||
|
|
||||||
<dtml-var "entreprise_footer(REQUEST=REQUEST)">
|
|
@ -1,52 +0,0 @@
|
|||||||
<dtml-var "entreprise_header(REQUEST=REQUEST)">
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set( 'E', do_entreprise_list( args={ 'entreprise_id' : entreprise_id } )[0])">
|
|
||||||
|
|
||||||
<h2>Listes des correspondants dans l'entreprise <dtml-var "E['nom']"> </h2>
|
|
||||||
|
|
||||||
<table class="corr_list">
|
|
||||||
|
|
||||||
<tr><th>Nom</th><th>Entreprise</th><th>Fonction</th><th>Téléphone</th><th>Mail</th><th>Note</th></tr>
|
|
||||||
|
|
||||||
<dtml-in "do_entreprise_correspondant_list( args={ 'entreprise_id' : entreprise_id })">
|
|
||||||
<dtml-let F="_['sequence-item']">
|
|
||||||
|
|
||||||
<tr class="<dtml-if sequence-odd>corr_list_odd<dtml-else>corr_list_even</dtml-if>">
|
|
||||||
|
|
||||||
<td><a class="corr_edit" href="entreprise_correspondant_edit?entreprise_corresp_id=<dtml-var "F['entreprise_corresp_id']">">
|
|
||||||
<dtml-if "F['nom']"><dtml-var "F['nom'].lower().capitalize()"></dtml-if>
|
|
||||||
<dtml-if "F['prenom']"> <dtml-var "F['prenom'].lower().capitalize()"></dtml-if>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td class="corr_descr"><dtml-var "E['nom']"></td>
|
|
||||||
|
|
||||||
<td class="corr_descr"><dtml-var "F['fonction']"></td>
|
|
||||||
|
|
||||||
<td class="corr_descr">
|
|
||||||
<dtml-if "F['phone1']"><dtml-var "F['phone1']"></dtml-if>
|
|
||||||
<dtml-if "F['phone2']"> / <dtml-var "F['phone2']"></dtml-if>
|
|
||||||
<dtml-if "F['mobile']"> / <dtml-var "F['mobile']"></dtml-if>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td class="corr_descr">
|
|
||||||
<dtml-if "F['mail1']"> <a href="mailto:<dtml-var "F['mail1']">"><dtml-var "F['mail1']"></a></dtml-if>
|
|
||||||
<dtml-if "F['mail1']"> <br> <a href="mailto:<dtml-var "F['mail2']">"><dtml-var "F['mail2']"></a></dtml-if>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td class="corr_descr"><dtml-var "F['note']"></td>
|
|
||||||
|
|
||||||
<td class="corr_descr"><a class="corr_delete" href="entreprise_correspondant_edit?entreprise_corresp_id=<dtml-var "F['entreprise_corresp_id']">">modifier</a> </td>
|
|
||||||
<td class="corr_descr"><a class="corr_delete" href="entreprise_correspondant_delete?entreprise_corresp_id=<dtml-var "F['entreprise_corresp_id']">">supprimer</a> </td>
|
|
||||||
</tr>
|
|
||||||
</dtml-let>
|
|
||||||
<dtml-else>
|
|
||||||
<tr><td colspan="4"><font color="red"><em>Aucun correspondant dans cette entreprise !</em></font></td></tr>
|
|
||||||
</dtml-in>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p class="entreprise_create"><a class="entreprise_create" href="<dtml-var "URL1 + '/entreprise_correspondant_create?entreprise_id=' + entreprise_id">">
|
|
||||||
Ajouter un correspondant dans l'entreprise <dtml-var "E['nom']"> </a><p>
|
|
||||||
|
|
||||||
|
|
||||||
<dtml-var "entreprise_footer(REQUEST=REQUEST)">
|
|
@ -1,60 +0,0 @@
|
|||||||
<dtml-var "entreprise_header(REQUEST=REQUEST)">
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set( 'F', do_entreprise_list( args={ 'entreprise_id' : entreprise_id } )[0])">
|
|
||||||
|
|
||||||
|
|
||||||
<h2>Suppression de l'entreprise <dtml-var "F['nom']"> </h2>
|
|
||||||
|
|
||||||
<p class="entreprise_warning">Attention: supression définitive de l'entreprise, de ses correspondants et contacts.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set( 'Cl', do_entreprise_correspondant_list( args={ 'entreprise_id' : entreprise_id }))">
|
|
||||||
|
|
||||||
<dtml-if "len(Cl)">
|
|
||||||
<h3>Correspondants dans l'entreprise <dtml-var "F['nom']"> (seront <em>supprimés</em>):</h3>
|
|
||||||
<ul>
|
|
||||||
<dtml-in Cl>
|
|
||||||
<dtml-let c="_['sequence-item']">
|
|
||||||
<li><dtml-if "c['nom']"><dtml-var "c['nom'].lower().capitalize()"></dtml-if>
|
|
||||||
<dtml-if "c['prenom']"> <dtml-var "c['prenom'].lower().capitalize()"></dtml-if>
|
|
||||||
(<dtml-var "c['fonction']">)
|
|
||||||
</li>
|
|
||||||
</dtml-let c>
|
|
||||||
</dtml-in Cl>
|
|
||||||
</ul>
|
|
||||||
</dtml-if Cl>
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set( 'Cts', do_entreprise_contact_list( args={ 'entreprise_id' : entreprise_id }))">
|
|
||||||
<dtml-if "len(Cts)">
|
|
||||||
<h3>Contacts avec l'entreprise <dtml-var "F['nom']"> (seront <em>supprimés</em>):</h3>
|
|
||||||
<ul>
|
|
||||||
<dtml-in Cts>
|
|
||||||
<dtml-let c="_['sequence-item']">
|
|
||||||
<li><dtml-if "c['date']"><dtml-var "c['date']"></dtml-if>
|
|
||||||
<dtml-if "c['description']">(<dtml-var "c['description']">)</dtml-if>
|
|
||||||
</li>
|
|
||||||
</dtml-let c>
|
|
||||||
</dtml-in Cts>
|
|
||||||
</ul>
|
|
||||||
</dtml-if Cts>
|
|
||||||
|
|
||||||
<dtml-call "REQUEST.set('tf', TrivialFormulator( URL0, REQUEST.form,
|
|
||||||
( ('entreprise_id', { 'input_type' : 'hidden' }),
|
|
||||||
),
|
|
||||||
initvalues = F,
|
|
||||||
submitlabel = 'Confirmer la suppression',
|
|
||||||
cancelbutton = 'Annuler', readonly = REQUEST['_read_only']
|
|
||||||
))">
|
|
||||||
|
|
||||||
<dtml-if "tf[0] == 0">
|
|
||||||
<dtml-var "tf[1]">
|
|
||||||
<dtml-else>
|
|
||||||
<dtml-if "tf[0] == -1">
|
|
||||||
<dtml-call "RESPONSE.redirect( URL1 )">
|
|
||||||
<dtml-else>
|
|
||||||
<dtml-call "do_entreprise_delete( F['entreprise_id'] )">
|
|
||||||
<dtml-call "RESPONSE.redirect(URL1)">
|
|
||||||
</dtml-if>
|
|
||||||
</dtml-if>
|
|
||||||
|
|
||||||
<dtml-var "entreprise_footer(REQUEST=REQUEST)">
|
|
@ -1,139 +0,0 @@
|
|||||||
<dtml-var "entreprise_header(REQUEST=REQUEST)">
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
function entsub(event,ourform) {
|
|
||||||
if (event && event.which == 13)
|
|
||||||
ourform.submit();
|
|
||||||
else
|
|
||||||
return true;}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<dtml-if entreprise_page_size>
|
|
||||||
<dtml-call "REQUEST.set( 'entreprise_page_size', int(entreprise_page_size))">
|
|
||||||
<dtml-else>
|
|
||||||
<dtml-call "REQUEST.set( 'entreprise_page_size', 10 )">
|
|
||||||
</dtml-if>
|
|
||||||
|
|
||||||
<h2><dtml-var title_or_id></h2>
|
|
||||||
|
|
||||||
<dtml-comment>
|
|
||||||
<p class="entreprise_warning">
|
|
||||||
Attention: version test préliminaire. Signaler les problèmes à <a href="mailto:viennet@lipn.univ-paris13.fr">Emmanuel</a>
|
|
||||||
</p>
|
|
||||||
</dtml-comment>
|
|
||||||
|
|
||||||
<dtml-unless sort_type><dtml-call "REQUEST.set( 'sort_type', 'nom' )"></dtml-unless>
|
|
||||||
<dtml-call "REQUEST.set( 'sort_on_contact', False )">
|
|
||||||
|
|
||||||
<dtml-if "sort_type=='nom'">
|
|
||||||
<dtml-call "REQUEST.set( 'sort_key', 'nom' )">
|
|
||||||
<dtml-elif "sort_type=='datecontact'">
|
|
||||||
<dtml-call "REQUEST.set( 'sort_on_contact', True )">
|
|
||||||
<dtml-call "REQUEST.set( 'sort_key', None )">
|
|
||||||
<dtml-elif "sort_type=='qualite_relation'">
|
|
||||||
<dtml-call "REQUEST.set( 'sort_key', 'qualite_relation desc, nom asc' )">
|
|
||||||
<dtml-elif "sort_type=='date_creation'">
|
|
||||||
<dtml-call "REQUEST.set( 'sort_key', 'date_creation desc, nom asc' )">
|
|
||||||
<dtml-else>
|
|
||||||
<p class="entreprise_warning">valeur invalide pour 'sort_type' !</p>
|
|
||||||
</dtml-if>
|
|
||||||
|
|
||||||
<dtml-if etud_nom>
|
|
||||||
<dtml-call "REQUEST.set( 'Elist', do_entreprise_list_by_etud( args=REQUEST.form, sort_on_contact=sort_on_contact ) )">
|
|
||||||
<dtml-else>
|
|
||||||
<dtml-call "REQUEST.set( 'Elist', do_entreprise_list( args=REQUEST.form, test='~*', sort_on_contact=sort_on_contact, sortkey=sort_key ) )">
|
|
||||||
</dtml-if>
|
|
||||||
|
|
||||||
<dtml-unless start><dtml-call "REQUEST.set( 'start', 1)"></dtml-unless>
|
|
||||||
|
|
||||||
|
|
||||||
<form action="" method="GET">
|
|
||||||
<table><tr>
|
|
||||||
<th>nom</th><td><input type="text" name="nom" size="12" value="<dtml-if nom><dtml-var nom></dtml-if>" onkeypress="return entsub(event,this.form)"></input></td>
|
|
||||||
<th>ville</th><td><input type="text" name="ville" size="12" value="<dtml-if ville><dtml-var ville></dtml-if>" onkeypress="return entsub(event,this.form)"></input></td>
|
|
||||||
<th>étudiant</th><td><input type="text" name="etud_nom" size="12" value="<dtml-if etud_nom><dtml-var etud_nom></dtml-if>" onkeypress="return entsub(event,this.form)"></input></td>
|
|
||||||
|
|
||||||
<td><input type="submit" value="rechercher"></input></td>
|
|
||||||
<td> </td>
|
|
||||||
<td>Tri par: <select name="sort_type" onchange="this.form.submit()">
|
|
||||||
<option value="nom" <dtml-if "sort_type=='nom'">selected</dtml-if>>nom entreprise</option>
|
|
||||||
<option value="datecontact" <dtml-if "sort_type=='datecontact'">selected</dtml-if>>date dernier contact</option>
|
|
||||||
<option value="qualite_relation" <dtml-if "sort_type=='qualite_relation'">selected</dtml-if>>relation IUT/Entreprise</option>
|
|
||||||
<option value="date_creation" <dtml-if "sort_type=='date_creation'">selected</dtml-if>>date saisie entreprise</option>
|
|
||||||
</select></td>
|
|
||||||
</tr></table>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<table class="entreprise_list">
|
|
||||||
|
|
||||||
<dtml-in Elist size=entreprise_page_size start=start overlap=1>
|
|
||||||
<dtml-if sequence-start>
|
|
||||||
<table class="entreprise_list_title">
|
|
||||||
<tr class="entreprise_list_title"><td class="entreprise_list_title">Entreprises</td>
|
|
||||||
<td class="entreprise_list_title_res">Résultats <b><dtml-var start></b> - <b><dtml-try><dtml-var "_['next-sequence-start-number']"><dtml-except><dtml-var "len(Elist)"></dtml-try></b> sur <b><dtml-var "len(Elist)"> </b>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<table class="entreprise_list">
|
|
||||||
</dtml-if sequence-start>
|
|
||||||
|
|
||||||
<dtml-let F="_['sequence-item']">
|
|
||||||
<dtml-call "REQUEST.set( 'Cl', do_entreprise_correspondant_list( args={ 'entreprise_id' : F['entreprise_id'] }))">
|
|
||||||
<dtml-call "REQUEST.set( 'Ct', do_entreprise_contact_list( args={ 'entreprise_id' : F['entreprise_id'] }))">
|
|
||||||
|
|
||||||
<tr class="<dtml-if sequence-odd>entreprise_list_odd<dtml-else>entreprise_list_even</dtml-if>">
|
|
||||||
|
|
||||||
<td colspan="5" class="entreprise_descr_name"><a class="entreprise_edit" href="entreprise_edit?entreprise_id=<dtml-var "F['entreprise_id']">&start=<dtml-var start>"><dtml-var "F['nom']"></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="<dtml-if sequence-odd>entreprise_list_odd<dtml-else>entreprise_list_even</dtml-if>">
|
|
||||||
<td> </td>
|
|
||||||
<td class="entreprise_descr"><dtml-var "str_abbrev(F['ville'], 22)"></td>
|
|
||||||
<td class="entreprise_descr"><dtml-var "F['secteur']"> </td>
|
|
||||||
|
|
||||||
<td class="entreprise_descr_link">
|
|
||||||
<a class="entreprise_delete" href="entreprise_correspondant_list?entreprise_id=<dtml-var "F['entreprise_id']">"><dtml-var "len(Cl)"> corr.</a>
|
|
||||||
<dtml-if "sort_type=='qualite_relation'"><b><dtml-var "{100:'TB',75:'B',50:'M',25:'!' }.get(F['qualite_relation'],'?')"></b></dtml-if>
|
|
||||||
</td>
|
|
||||||
<td class="entreprise_descr_link"><a class="entreprise_delete" href="entreprise_contact_list?entreprise_id=<dtml-var "F['entreprise_id']">"><dtml-var "len(Ct)"> contacts</a>
|
|
||||||
<dtml-try>(<dtml-var "F['etud_nom']">)<dtml-except></dtml-try>
|
|
||||||
<dtml-try>(<dtml-var "F['date']">)<dtml-except></dtml-try>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
</dtml-let>
|
|
||||||
<dtml-if sequence-end>
|
|
||||||
</table>
|
|
||||||
</dtml-if sequence-end>
|
|
||||||
<dtml-else Elist>
|
|
||||||
<p class="entreprise_warning">Aucune entreprise !</p>
|
|
||||||
</dtml-in>
|
|
||||||
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<form action="setPageSizeCookie" method="GET">
|
|
||||||
<input type="hidden" name="target_url" value="<dtml-var "URL0+'?'+QUERY_STRING">"></input>
|
|
||||||
|
|
||||||
<dtml-in Elist size=entreprise_page_size start=start overlap=1>
|
|
||||||
<dtml-if sequence-start>
|
|
||||||
<dtml-if previous-sequence>
|
|
||||||
<a href="<dtml-var URL><dtml-var sequence-query>start=<dtml-var previous-sequence-start-number>">
|
|
||||||
page précédente</a>
|
|
||||||
</dtml-if previous-sequence>
|
|
||||||
</dtml-if sequence-start>
|
|
||||||
<dtml-if sequence-end>
|
|
||||||
<dtml-if next-sequence>
|
|
||||||
<a href="<dtml-var URL><dtml-var sequence-query>start=<dtml-var next-sequence-start-number>">
|
|
||||||
page suivante</a>
|
|
||||||
</dtml-if next-sequence>
|
|
||||||
</dtml-if sequence-end>
|
|
||||||
</dtml-in Elist>
|
|
||||||
Résultats par page :
|
|
||||||
<select name="entreprise_page_size" onchange="this.form.submit()">
|
|
||||||
<dtml-in "((5,5),(10,10),(15,15),(20,20),(30,30),(50,50),(1000,'Tous'))" prefix="label">
|
|
||||||
<option value="<dtml-var "label_key">" <dtml-if "label_key == entreprise_page_size">selected</dtml-if>><dtml-var label_item></option>
|
|
||||||
</dtml-in>
|
|
||||||
</select>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</p>
|
|
||||||
<dtml-var "entreprise_footer(REQUEST=REQUEST)">
|
|
@ -123,6 +123,7 @@ class GenTable:
|
|||||||
pdf_col_widths=None,
|
pdf_col_widths=None,
|
||||||
xml_outer_tag="table",
|
xml_outer_tag="table",
|
||||||
xml_row_tag="row",
|
xml_row_tag="row",
|
||||||
|
text_with_titles=False, # CSV with header line
|
||||||
text_fields_separator="\t",
|
text_fields_separator="\t",
|
||||||
preferences=None,
|
preferences=None,
|
||||||
):
|
):
|
||||||
@ -173,6 +174,7 @@ class GenTable:
|
|||||||
self.xml_row_tag = xml_row_tag
|
self.xml_row_tag = xml_row_tag
|
||||||
# TEXT parameters
|
# TEXT parameters
|
||||||
self.text_fields_separator = text_fields_separator
|
self.text_fields_separator = text_fields_separator
|
||||||
|
self.text_with_titles = text_with_titles
|
||||||
#
|
#
|
||||||
if preferences:
|
if preferences:
|
||||||
self.preferences = preferences
|
self.preferences = preferences
|
||||||
@ -265,8 +267,7 @@ class GenTable:
|
|||||||
|
|
||||||
def get_titles_list(self):
|
def get_titles_list(self):
|
||||||
"list of titles"
|
"list of titles"
|
||||||
l = []
|
return [self.titles.get(cid, "") for cid in self.columns_ids]
|
||||||
return l + [self.titles.get(cid, "") for cid in self.columns_ids]
|
|
||||||
|
|
||||||
def gen(self, format="html", columns_ids=None):
|
def gen(self, format="html", columns_ids=None):
|
||||||
"""Build representation of the table in the specified format.
|
"""Build representation of the table in the specified format.
|
||||||
@ -444,14 +445,14 @@ class GenTable:
|
|||||||
if self.base_url:
|
if self.base_url:
|
||||||
if self.xls_link:
|
if self.xls_link:
|
||||||
H.append(
|
H.append(
|
||||||
' <a href="%s&format=xls">%s</a>'
|
' <a href="%s&format=xls">%s</a>'
|
||||||
% (self.base_url, scu.ICON_XLS)
|
% (self.base_url, scu.ICON_XLS)
|
||||||
)
|
)
|
||||||
if self.xls_link and self.pdf_link:
|
if self.xls_link and self.pdf_link:
|
||||||
H.append(" ")
|
H.append(" ")
|
||||||
if self.pdf_link:
|
if self.pdf_link:
|
||||||
H.append(
|
H.append(
|
||||||
' <a href="%s&format=pdf">%s</a>'
|
' <a href="%s&format=pdf">%s</a>'
|
||||||
% (self.base_url, scu.ICON_PDF)
|
% (self.base_url, scu.ICON_PDF)
|
||||||
)
|
)
|
||||||
H.append("</p>")
|
H.append("</p>")
|
||||||
@ -479,10 +480,14 @@ class GenTable:
|
|||||||
|
|
||||||
def text(self):
|
def text(self):
|
||||||
"raw text representation of the table"
|
"raw text representation of the table"
|
||||||
|
if self.text_with_titles:
|
||||||
|
headline = [self.get_titles_list()]
|
||||||
|
else:
|
||||||
|
headline = []
|
||||||
return "\n".join(
|
return "\n".join(
|
||||||
[
|
[
|
||||||
self.text_fields_separator.join([x for x in line])
|
self.text_fields_separator.join([x for x in line])
|
||||||
for line in self.get_data_list()
|
for line in headline + self.get_data_list()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -534,14 +539,6 @@ class GenTable:
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
pdf_style_list += self.pdf_table_style
|
pdf_style_list += self.pdf_table_style
|
||||||
# log('len(Pt)=%s' % len(Pt))
|
|
||||||
# log( 'line lens=%s' % [ len(x) for x in Pt ] )
|
|
||||||
# log( 'style=\n%s' % pdf_style_list)
|
|
||||||
# col_min = min([x[1][0] for x in pdf_style_list])
|
|
||||||
# col_max = max([x[2][0] for x in pdf_style_list])
|
|
||||||
# lin_min = min([x[1][1] for x in pdf_style_list])
|
|
||||||
# lin_max = max([x[2][1] for x in pdf_style_list])
|
|
||||||
# log('col_min=%s col_max=%s lin_min=%s lin_max=%s' % (col_min, col_max, lin_min, lin_max))
|
|
||||||
T = Table(Pt, repeatRows=1, colWidths=self.pdf_col_widths, style=pdf_style_list)
|
T = Table(Pt, repeatRows=1, colWidths=self.pdf_col_widths, style=pdf_style_list)
|
||||||
|
|
||||||
objects = []
|
objects = []
|
||||||
@ -693,7 +690,7 @@ class SeqGenTable:
|
|||||||
|
|
||||||
def excel(self):
|
def excel(self):
|
||||||
"""Export des genTables dans un unique fichier excel avec plusieurs feuilles tagguées"""
|
"""Export des genTables dans un unique fichier excel avec plusieurs feuilles tagguées"""
|
||||||
book = sco_excel.Workbook() # Le fichier xls en devenir
|
book = sco_excel.Workbook() # pylint: disable=no-member
|
||||||
for (_, gt) in self.genTables.items():
|
for (_, gt) in self.genTables.items():
|
||||||
gt.excel(wb=book) # Ecrit dans un fichier excel
|
gt.excel(wb=book) # Ecrit dans un fichier excel
|
||||||
return book.savetostr()
|
return book.savetostr()
|
||||||
|
@ -25,7 +25,9 @@
|
|||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from sco_utils import *
|
import cgi
|
||||||
|
|
||||||
|
import sco_utils as scu
|
||||||
from sco_formsemestre_status import formsemestre_page_title
|
from sco_formsemestre_status import formsemestre_page_title
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -95,7 +97,7 @@ def sco_header(
|
|||||||
"page_title": page_title or context.title_or_id(),
|
"page_title": page_title or context.title_or_id(),
|
||||||
"no_side_bar": no_side_bar,
|
"no_side_bar": no_side_bar,
|
||||||
"ScoURL": context.ScoURL(),
|
"ScoURL": context.ScoURL(),
|
||||||
"encoding": SCO_ENCODING,
|
"encoding": scu.SCO_ENCODING,
|
||||||
"titrebandeau_mkup": "<td>" + titrebandeau + "</td>",
|
"titrebandeau_mkup": "<td>" + titrebandeau + "</td>",
|
||||||
"authuser": str(REQUEST.AUTHENTICATED_USER),
|
"authuser": str(REQUEST.AUTHENTICATED_USER),
|
||||||
}
|
}
|
||||||
@ -224,7 +226,7 @@ def sco_header(
|
|||||||
|
|
||||||
# Body et bandeau haut:
|
# Body et bandeau haut:
|
||||||
H.append("""<body %(bodyOnLoad_mkup)s>""" % params)
|
H.append("""<body %(bodyOnLoad_mkup)s>""" % params)
|
||||||
H.append(CUSTOM_HTML_HEADER)
|
H.append(scu.CUSTOM_HTML_HEADER)
|
||||||
#
|
#
|
||||||
if not no_side_bar:
|
if not no_side_bar:
|
||||||
H.append(context.sidebar(REQUEST))
|
H.append(context.sidebar(REQUEST))
|
||||||
@ -258,4 +260,6 @@ def sco_header(
|
|||||||
|
|
||||||
def sco_footer(context, REQUEST=None):
|
def sco_footer(context, REQUEST=None):
|
||||||
"""Main HTMl pages footer"""
|
"""Main HTMl pages footer"""
|
||||||
return """</div><!-- /gtrcontent -->""" + CUSTOM_HTML_FOOTER + """</body></html>"""
|
return (
|
||||||
|
"""</div><!-- /gtrcontent -->""" + scu.CUSTOM_HTML_FOOTER + """</body></html>"""
|
||||||
|
)
|
||||||
|
@ -25,8 +25,14 @@
|
|||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from ZAbsences import getAbsSemEtud
|
from sco_abs import getAbsSemEtud
|
||||||
|
from sco_permissions import (
|
||||||
|
ScoUsersAdmin,
|
||||||
|
ScoUsersView,
|
||||||
|
ScoChangePreferences,
|
||||||
|
ScoAbsChange,
|
||||||
|
)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Génération de la "sidebar" (marge gauche des pages HTML)
|
Génération de la "sidebar" (marge gauche des pages HTML)
|
||||||
@ -36,16 +42,22 @@ Génération de la "sidebar" (marge gauche des pages HTML)
|
|||||||
def sidebar_common(context, REQUEST=None):
|
def sidebar_common(context, REQUEST=None):
|
||||||
"partie commune a toutes les sidebar"
|
"partie commune a toutes les sidebar"
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = REQUEST.AUTHENTICATED_USER
|
||||||
params = {"ScoURL": context.ScoURL(), "authuser": str(authuser)}
|
params = {
|
||||||
|
"ScoURL": context.ScoURL(),
|
||||||
|
"UsersURL": context.UsersURL(),
|
||||||
|
"NotesURL": context.NotesURL(),
|
||||||
|
"AbsencesURL": context.AbsencesURL(),
|
||||||
|
"authuser": str(authuser),
|
||||||
|
}
|
||||||
H = [
|
H = [
|
||||||
'<a class="scodoc_title" href="about">ScoDoc</a>',
|
'<a class="scodoc_title" href="about">ScoDoc</a>',
|
||||||
'<div id="authuser"><a id="authuserlink" href="%(ScoURL)s/Users/userinfo">%(authuser)s</a><br/><a id="deconnectlink" href="%(ScoURL)s/acl_users/logout">déconnexion</a></div>'
|
'<div id="authuser"><a id="authuserlink" href="%(ScoURL)s/Users/userinfo">%(authuser)s</a><br/><a id="deconnectlink" href="%(ScoURL)s/acl_users/logout">déconnexion</a></div>'
|
||||||
% params,
|
% params,
|
||||||
context.sidebar_dept(REQUEST),
|
context.sidebar_dept(REQUEST),
|
||||||
"""<h2 class="insidebar">Scolarité</h2>
|
"""<h2 class="insidebar">Scolarité</h2>
|
||||||
<a href="%(ScoURL)s" class="sidebar">Semestres</a> <br/>
|
<a id="SemestresLink" href="%(ScoURL)s" class="sidebar">Semestres</a> <br/>
|
||||||
<a href="%(ScoURL)s/Notes" class="sidebar">Programmes</a> <br/>
|
<a id="ProgrammesLink" href="%(NotesURL)s" class="sidebar">Programmes</a> <br/>
|
||||||
<a href="%(ScoURL)s/Absences" class="sidebar">Absences</a> <br/>
|
<a id="AbsnecesLink" href="%(AbsencesURL)s" class="sidebar">Absences</a> <br/>
|
||||||
"""
|
"""
|
||||||
% params,
|
% params,
|
||||||
]
|
]
|
||||||
@ -54,19 +66,12 @@ def sidebar_common(context, REQUEST=None):
|
|||||||
ScoUsersView, context
|
ScoUsersView, context
|
||||||
):
|
):
|
||||||
H.append(
|
H.append(
|
||||||
"""<a href="%(ScoURL)s/Users" class="sidebar">Utilisateurs</a> <br/>"""
|
"""<a id="utilisateurs_Vue" href="%(UsersURL)s" class="sidebar">Utilisateurs</a> <br/>""" % params
|
||||||
% params
|
|
||||||
)
|
|
||||||
|
|
||||||
if 0: # XXX experimental
|
|
||||||
H.append(
|
|
||||||
"""<a href="%(ScoURL)s/Notes/Services" class="sidebar">Services</a> <br/>"""
|
|
||||||
% params
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if authuser.has_permission(ScoChangePreferences, context):
|
if authuser.has_permission(ScoChangePreferences, context):
|
||||||
H.append(
|
H.append(
|
||||||
"""<a href="%(ScoURL)s/edit_preferences" class="sidebar">Paramétrage</a> <br/>"""
|
"""<a id="preferences_Edit" href="%(ScoURL)s/edit_preferences" class="sidebar">Paramétrage</a> <br/>"""
|
||||||
% params
|
% params
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -76,14 +81,14 @@ def sidebar_common(context, REQUEST=None):
|
|||||||
def sidebar(context, REQUEST=None):
|
def sidebar(context, REQUEST=None):
|
||||||
"Main HTML page sidebar"
|
"Main HTML page sidebar"
|
||||||
# rewritten from legacy DTML code
|
# 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)]
|
H = ['<div class="sidebar">', sidebar_common(context, REQUEST)]
|
||||||
|
|
||||||
H.append(
|
H.append(
|
||||||
"""<div class="box-chercheetud">Chercher étudiant:<br/>
|
"""<div class="box-chercheetud">Chercher étudiant:<br/>
|
||||||
<form id="form-chercheetud" action="%(ScoURL)s/search_etud_in_dept">
|
<form method="get" id="form-chercheetud" action="%(ScoURL)s/search_etud_in_dept">
|
||||||
<div><input type="text" size="12" id="in-expnom" name="expnom"></input></div>
|
<div><input type="text" size="12" id="in-expnom" name="expnom" spellcheck="false"></input></div>
|
||||||
</form></div>
|
</form></div>
|
||||||
<div class="etud-insidebar">
|
<div class="etud-insidebar">
|
||||||
"""
|
"""
|
||||||
@ -97,8 +102,9 @@ def sidebar(context, REQUEST=None):
|
|||||||
# compte les absences du semestre en cours
|
# compte les absences du semestre en cours
|
||||||
H.append(
|
H.append(
|
||||||
"""<h2 id="insidebar-etud"><a href="%(ScoURL)s/ficheEtud?etudid=%(etudid)s" class="sidebar">
|
"""<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>
|
</h2>
|
||||||
|
<p id="euid">%(etudid)s</p>
|
||||||
<b>Absences</b>"""
|
<b>Absences</b>"""
|
||||||
% params
|
% params
|
||||||
)
|
)
|
||||||
@ -118,21 +124,21 @@ def sidebar(context, REQUEST=None):
|
|||||||
if REQUEST.AUTHENTICATED_USER.has_permission(ScoAbsChange, context):
|
if REQUEST.AUTHENTICATED_USER.has_permission(ScoAbsChange, context):
|
||||||
H.append(
|
H.append(
|
||||||
"""
|
"""
|
||||||
<li> <a href="%(ScoURL)s/Absences/SignaleAbsenceEtud?etudid=%(etudid)s">Ajouter</a></li>
|
<li> <a id="ajout_Absence" href="%(ScoURL)s/Absences/SignaleAbsenceEtud?etudid=%(etudid)s">Ajouter</a></li>
|
||||||
<li> <a href="%(ScoURL)s/Absences/JustifAbsenceEtud?etudid=%(etudid)s">Justifier</a></li>
|
<li> <a id="justifier_Absence" href="%(ScoURL)s/Absences/JustifAbsenceEtud?etudid=%(etudid)s">Justifier</a></li>
|
||||||
<li> <a href="%(ScoURL)s/Absences/AnnuleAbsenceEtud?etudid=%(etudid)s">Supprimer</a></li>
|
<li> <a id="supprimer_Absence" href="%(ScoURL)s/Absences/AnnuleAbsenceEtud?etudid=%(etudid)s">Supprimer</a></li>
|
||||||
"""
|
"""
|
||||||
% params
|
% params
|
||||||
)
|
)
|
||||||
if context.get_preference("handle_billets_abs"):
|
if context.get_preference("handle_billets_abs"):
|
||||||
H.append(
|
H.append(
|
||||||
"""<li> <a href="%(ScoURL)s/Absences/listeBilletsEtud?etudid=%(etudid)s">Billets</a></li>"""
|
"""<li> <a id="afficher_Billets" href="%(ScoURL)s/Absences/listeBilletsEtud?etudid=%(etudid)s">Billets</a></li>"""
|
||||||
% params
|
% params
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
"""
|
"""
|
||||||
<li> <a href="%(ScoURL)s/Absences/CalAbs?etudid=%(etudid)s">Calendrier</a></li>
|
<li> <a id="afficher_Calendrier" href="%(ScoURL)s/Absences/CalAbs?etudid=%(etudid)s">Calendrier</a></li>
|
||||||
<li> <a href="%(ScoURL)s/Absences/ListeAbsEtud?etudid=%(etudid)s">Liste</a></li>
|
<li> <a id="afficher_Liste_Absence" href="%(ScoURL)s/Absences/ListeAbsEtud?etudid=%(etudid)s">Liste</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
"""
|
"""
|
||||||
% params
|
% params
|
||||||
@ -142,7 +148,7 @@ def sidebar(context, REQUEST=None):
|
|||||||
# ---------
|
# ---------
|
||||||
H.append("</div><br/> ") # /etud-insidebar
|
H.append("</div><br/> ") # /etud-insidebar
|
||||||
# Logo
|
# 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('<div class="logo-insidebar"><div class="logo-logo">%s<br/>' % scologo_img)
|
||||||
H.append(
|
H.append(
|
||||||
"""<a href="%(ScoURL)s/about" class="sidebar">A propos</a><br/>
|
"""<a href="%(ScoURL)s/about" class="sidebar">A propos</a><br/>
|
||||||
|
58
htmlutils.py
58
htmlutils.py
@ -28,6 +28,8 @@
|
|||||||
"""Various HTML generation functions
|
"""Various HTML generation functions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import listhistogram
|
||||||
|
|
||||||
|
|
||||||
def horizontal_bargraph(value, mark):
|
def horizontal_bargraph(value, mark):
|
||||||
"""html drawing an horizontal bar and a mark
|
"""html drawing an horizontal bar and a mark
|
||||||
@ -42,9 +44,6 @@ def horizontal_bargraph(value, mark):
|
|||||||
return tmpl % {"value": int(value), "mark": int(mark)}
|
return tmpl % {"value": int(value), "mark": int(mark)}
|
||||||
|
|
||||||
|
|
||||||
import listhistogram
|
|
||||||
|
|
||||||
|
|
||||||
def histogram_notes(notes):
|
def histogram_notes(notes):
|
||||||
"HTML code drawing histogram"
|
"HTML code drawing histogram"
|
||||||
if not notes:
|
if not notes:
|
||||||
@ -70,3 +69,56 @@ def histogram_notes(notes):
|
|||||||
)
|
)
|
||||||
D.append("</ul></li></ul>")
|
D.append("</ul></li></ul>")
|
||||||
return "\n".join(D)
|
return "\n".join(D)
|
||||||
|
|
||||||
|
|
||||||
|
def make_menu(title, items, css_class="", base_url="", alone=False):
|
||||||
|
"""HTML snippet to render a simple drop down menu.
|
||||||
|
items is a list of dicts:
|
||||||
|
{ 'title' :
|
||||||
|
'url' :
|
||||||
|
'id' :
|
||||||
|
'attr' : "" # optionnal html <a> attributes
|
||||||
|
'enabled' : # True by default
|
||||||
|
'helpmsg' :
|
||||||
|
'submenu' : [ list of sub-items ]
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def gen_menu_items(items):
|
||||||
|
H.append("<ul>")
|
||||||
|
for item in items:
|
||||||
|
if not item.get("enabled", True):
|
||||||
|
cls = ' class="ui-state-disabled"'
|
||||||
|
else:
|
||||||
|
cls = ""
|
||||||
|
the_id = item.get("id", "")
|
||||||
|
if the_id:
|
||||||
|
li_id = 'id="%s" ' % the_id
|
||||||
|
else:
|
||||||
|
li_id = ""
|
||||||
|
if base_url and "url" in item:
|
||||||
|
item["urlq"] = base_url + item["url"]
|
||||||
|
else:
|
||||||
|
item["urlq"] = item.get("url", "#")
|
||||||
|
item["attr"] = item.get("attr", "")
|
||||||
|
submenu = item.get("submenu", None)
|
||||||
|
H.append(
|
||||||
|
"<li "
|
||||||
|
+ li_id
|
||||||
|
+ cls
|
||||||
|
+ '><a href="%(urlq)s" %(attr)s>%(title)s</a>' % item
|
||||||
|
)
|
||||||
|
if submenu:
|
||||||
|
gen_menu_items(submenu)
|
||||||
|
H.append("</li>")
|
||||||
|
H.append("</ul>")
|
||||||
|
|
||||||
|
H = []
|
||||||
|
if alone:
|
||||||
|
H.append('<ul class="sco_dropdown_menu %s">' % css_class)
|
||||||
|
H.append("""<li><a href="#">%s</a>""" % title)
|
||||||
|
gen_menu_items(items)
|
||||||
|
H.append("</li>")
|
||||||
|
if alone:
|
||||||
|
H.append("</ul>")
|
||||||
|
return "".join(H)
|
||||||
|
16
intervals.py
16
intervals.py
@ -173,17 +173,17 @@ if __name__ == "__main__":
|
|||||||
repr(i)
|
repr(i)
|
||||||
== "{[None, 3] => 'My,', [3, 5] => 'Hello', [6, 7] => 'World', [8, 10] => '(Test)', [10, None] => '!'}"
|
== "{[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 (
|
assert (
|
||||||
repr(i)
|
repr(i)
|
||||||
== "{[None, 3] => 'My,', [3, 5] => 'Hello', [5.5, 6] => 'Cruel', [6, 7] => 'World', [8, 10] => '(Test)', [10, None] => '!'}"
|
== "{[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 (
|
assert (
|
||||||
repr(i)
|
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] => '!'}"
|
== "{[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 (
|
assert (
|
||||||
repr(i)
|
repr(i)
|
||||||
== "{[None, 3] => 'My,', [3, 5] => 'Hello', [5.5, 5.9000000000000004] => 'Cruel', [6.5999999999999996, 7] => 'World', [8, 10] => '(Test)', [10, None] => '!'}"
|
== "{[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")
|
print("Test 3 skipped")
|
||||||
else:
|
else:
|
||||||
i = intervalmap()
|
i = intervalmap()
|
||||||
i[: datetime(2005, 10, 24)] = "A"
|
i[: datetime(2005, 10, 24)] = "A" # pylint: disable=invalid-slice-index
|
||||||
i[datetime(2005, 11, 11) : datetime(2005, 11, 17)] = "B"
|
i[
|
||||||
i[datetime(2005, 11, 30) :] = "C"
|
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, 9, 25)] == "A"
|
||||||
assert i[datetime(2005, 10, 23)] == "A"
|
assert i[datetime(2005, 10, 23)] == "A"
|
||||||
assert i[datetime(2005, 10, 26)] == None
|
assert i[datetime(2005, 10, 26)] == None
|
||||||
|
@ -99,8 +99,7 @@ function get_semestre_info($sem, $dept) {
|
|||||||
// Renvoi les informations détaillées d'un semestre
|
// Renvoi les informations détaillées d'un semestre
|
||||||
// Ne nécessite pas d'authentification avec sco_user et sco_pw - Il est possible de choisir le format XML ou JSON.
|
// Ne nécessite pas d'authentification avec sco_user et sco_pw - Il est possible de choisir le format XML ou JSON.
|
||||||
// formsemestre_list
|
// formsemestre_list
|
||||||
// Paramètres (tous optionnels): formsesmestre_id, formation_id, etape_apo, etape_apo2
|
// Paramètres (tous optionnels): formsemestre_id, formation_id, etape_apo
|
||||||
// Coquille dans la doc : formsesmestre_id
|
|
||||||
// Résultat: liste des semestres correspondant.
|
// Résultat: liste des semestres correspondant.
|
||||||
// Exemple: formsemestre_list?format=xml&etape_apo=V1RT
|
// Exemple: formsemestre_list?format=xml&etape_apo=V1RT
|
||||||
global $sco_pw;
|
global $sco_pw;
|
||||||
|
@ -35,6 +35,18 @@ CREATE FUNCTION notes_newid_etud( text ) returns text as '
|
|||||||
as result;
|
as result;
|
||||||
' language SQL;
|
' language SQL;
|
||||||
|
|
||||||
|
-- Fonction pour anonymisation:
|
||||||
|
-- inspirée par https://www.simononsoftware.com/random-string-in-postgresql/
|
||||||
|
CREATE FUNCTION random_text_md5( integer ) returns text
|
||||||
|
LANGUAGE SQL
|
||||||
|
AS $$
|
||||||
|
select upper( substring( (SELECT string_agg(md5(random()::TEXT), '')
|
||||||
|
FROM generate_series(
|
||||||
|
1,
|
||||||
|
CEIL($1 / 32.)::integer)
|
||||||
|
), 1, $1) );
|
||||||
|
$$;
|
||||||
|
|
||||||
-- Preferences
|
-- Preferences
|
||||||
CREATE TABLE sco_prefs (
|
CREATE TABLE sco_prefs (
|
||||||
pref_id text DEFAULT notes_newid('PREF'::text) UNIQUE NOT NULL,
|
pref_id text DEFAULT notes_newid('PREF'::text) UNIQUE NOT NULL,
|
||||||
@ -49,7 +61,7 @@ CREATE TABLE identite (
|
|||||||
etudid text DEFAULT notes_newid_etud('EID'::text) UNIQUE NOT NULL,
|
etudid text DEFAULT notes_newid_etud('EID'::text) UNIQUE NOT NULL,
|
||||||
nom text,
|
nom text,
|
||||||
prenom text,
|
prenom text,
|
||||||
sexe text,
|
civilite text NOT NULL CHECK (civilite IN ('M', 'F', 'X')),
|
||||||
date_naissance date, -- new: date en texte
|
date_naissance date, -- new: date en texte
|
||||||
lieu_naissance text,
|
lieu_naissance text,
|
||||||
dept_naissance text,
|
dept_naissance text,
|
||||||
|
@ -8,7 +8,7 @@ Code_INE; text; identite; 1; code INE;INE
|
|||||||
nom; text; identite; 0; nom de l'etudiant;
|
nom; text; identite; 0; nom de l'etudiant;
|
||||||
nom_usuel; text; identite; 1; nom usuel (si different);
|
nom_usuel; text; identite; 1; nom usuel (si different);
|
||||||
prenom; text; identite; 0; prenom de l'etudiant
|
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)
|
date_naissance;text;identite; 1; date de naissance (jj/mm/aaaa)
|
||||||
lieu_naissance;text;identite; 1; lieu de naissance
|
lieu_naissance;text;identite; 1; lieu de naissance
|
||||||
nationalite; text; identite; 1; nationalite
|
nationalite; text; identite; 1; nationalite
|
||||||
|
18
notes_log.py
18
notes_log.py
@ -1,12 +1,22 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import pdb, os, sys, time, re, inspect
|
import pdb
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
import sys
|
||||||
from email.MIMEText import MIMEText
|
import os
|
||||||
from email.Header import Header
|
import re
|
||||||
|
import inspect
|
||||||
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
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
|
# Simple & stupid file logguer, used only to debug
|
||||||
# (logging to SQL is done in scolog)
|
# (logging to SQL is done in scolog)
|
||||||
|
|
||||||
|
@ -27,27 +27,37 @@
|
|||||||
|
|
||||||
"""Calculs sur les notes et cache des resultats
|
"""Calculs sur les notes et cache des resultats
|
||||||
"""
|
"""
|
||||||
from types import StringType
|
from types import StringType, FloatType
|
||||||
|
import time
|
||||||
import pdb
|
import pdb
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
|
|
||||||
import scolars
|
import scolars
|
||||||
import sco_groups
|
import sco_groups
|
||||||
from notes_log import log, logCallStack
|
from notes_log import log, logCallStack
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
import sco_codes_parcours
|
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 formsemestre_get_etud_capitalisation
|
||||||
from sco_parcours_dut import list_formsemestre_utilisateurs_uecap
|
from sco_parcours_dut import list_formsemestre_utilisateurs_uecap
|
||||||
import sco_parcours_dut
|
import sco_parcours_dut
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
from sco_formsemestre_edit import formsemestre_uecoef_list, formsemestre_uecoef_create
|
from sco_formsemestre import formsemestre_uecoef_list, formsemestre_uecoef_create
|
||||||
|
import sco_moduleimpl
|
||||||
import sco_evaluations
|
import sco_evaluations
|
||||||
import sco_compute_moy
|
import sco_compute_moy
|
||||||
from sco_formulas import NoteVector
|
from sco_formulas import NoteVector
|
||||||
|
from sco_exceptions import (
|
||||||
|
AccessDenied,
|
||||||
|
NoteProcessError,
|
||||||
|
ScoException,
|
||||||
|
ScoValueError,
|
||||||
|
)
|
||||||
|
|
||||||
# Support for old user-written "bonus" functions with 2 args:
|
# 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):
|
def comp_ranks(T):
|
||||||
@ -85,7 +95,9 @@ def get_sem_ues_modimpls(context, formsemestre_id, modimpls=None):
|
|||||||
(utilisé quand on ne peut pas construire nt et faire nt.get_ues())
|
(utilisé quand on ne peut pas construire nt et faire nt.get_ues())
|
||||||
"""
|
"""
|
||||||
if modimpls is None:
|
if modimpls is None:
|
||||||
modimpls = context.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
modimpls = sco_moduleimpl.do_moduleimpl_list(
|
||||||
|
context, formsemestre_id=formsemestre_id
|
||||||
|
)
|
||||||
uedict = {}
|
uedict = {}
|
||||||
for modimpl in modimpls:
|
for modimpl in modimpls:
|
||||||
mod = context.do_module_list(args={"module_id": modimpl["module_id"]})[0]
|
mod = context.do_module_list(args={"module_id": modimpl["module_id"]})[0]
|
||||||
@ -104,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)
|
(nécessaire pour éviter appels récursifs de nt, qui peuvent boucler)
|
||||||
"""
|
"""
|
||||||
infos = SimpleDictFetch(
|
infos = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"""SELECT mod.coefficient
|
"""SELECT mod.coefficient
|
||||||
FROM notes_modules mod, notes_moduleimpl mi, notes_moduleimpl_inscription ins
|
FROM notes_modules mod, notes_moduleimpl mi, notes_moduleimpl_inscription ins
|
||||||
@ -136,7 +148,7 @@ class NotesTable:
|
|||||||
- identdict: { etudid : ident }
|
- identdict: { etudid : ident }
|
||||||
- sem : le formsemestre
|
- sem : le formsemestre
|
||||||
get_table_moyennes_triees: [ (moy_gen, moy_ue1, moy_ue2, ... moy_ues, moy_mod1, ..., moy_modn, etudid) ]
|
get_table_moyennes_triees: [ (moy_gen, moy_ue1, moy_ue2, ... moy_ues, moy_mod1, ..., moy_modn, etudid) ]
|
||||||
(où toutes les valeurs sont soit des nombrs soit des chaines spéciales comme 'NA', 'NI'),
|
(où toutes les valeurs sont soit des nombres soit des chaines spéciales comme 'NA', 'NI'),
|
||||||
incluant les UE de sport
|
incluant les UE de sport
|
||||||
|
|
||||||
- bonus[etudid] : valeur du bonus "sport".
|
- bonus[etudid] : valeur du bonus "sport".
|
||||||
@ -184,7 +196,7 @@ class NotesTable:
|
|||||||
for i in range(len(self.inscrlist)):
|
for i in range(len(self.inscrlist)):
|
||||||
rangalpha[self.inscrlist[i]["etudid"]] = i
|
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 } }
|
# Notes dans les modules { moduleimpl_id : { etudid: note_moyenne_dans_ce_module } }
|
||||||
(
|
(
|
||||||
self._modmoys,
|
self._modmoys,
|
||||||
@ -360,29 +372,28 @@ class NotesTable:
|
|||||||
def get_sexnom(self, etudid):
|
def get_sexnom(self, etudid):
|
||||||
"M. DUPONT"
|
"M. DUPONT"
|
||||||
etud = self.identdict[etudid]
|
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):
|
def get_nom_short(self, etudid):
|
||||||
"formatte nom d'un etud (pour table recap)"
|
"formatte nom d'un etud (pour table recap)"
|
||||||
etud = self.identdict[etudid]
|
etud = self.identdict[etudid]
|
||||||
# Attention aux caracteres multibytes pour decouper les 2 premiers:
|
# Attention aux caracteres multibytes pour decouper les 2 premiers:
|
||||||
return (
|
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):
|
def get_nom_long(self, etudid):
|
||||||
"formatte nom d'un etud: M. Pierre DUPONT"
|
"formatte nom d'un etud: M. Pierre DUPONT"
|
||||||
etud = self.identdict[etudid]
|
etud = self.identdict[etudid]
|
||||||
return " ".join(
|
return scolars.format_nomprenom(etud)
|
||||||
[
|
|
||||||
scolars.format_sexe(etud["sexe"]),
|
|
||||||
scolars.format_prenom(etud["prenom"]),
|
|
||||||
scolars.format_nom(etud["nom_usuel"] or etud["nom"]),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_displayed_etud_code(self, etudid):
|
def get_displayed_etud_code(self, etudid):
|
||||||
'code à afficher sur les listings "anonymes"'
|
'code à afficher sur les listings "anonymes"'
|
||||||
@ -613,7 +624,7 @@ class NotesTable:
|
|||||||
# si 'NI', etudiant non inscrit a ce module
|
# si 'NI', etudiant non inscrit a ce module
|
||||||
if val != "NI":
|
if val != "NI":
|
||||||
est_inscrit = True
|
est_inscrit = True
|
||||||
if modimpl["module"]["module_type"] == MODULE_STANDARD:
|
if modimpl["module"]["module_type"] == scu.MODULE_STANDARD:
|
||||||
coef = modimpl["module"]["coefficient"]
|
coef = modimpl["module"]["coefficient"]
|
||||||
if modimpl["ue"]["type"] != UE_SPORT:
|
if modimpl["ue"]["type"] != UE_SPORT:
|
||||||
notes.append(val, name=modimpl["module"]["code"])
|
notes.append(val, name=modimpl["module"]["code"])
|
||||||
@ -649,7 +660,7 @@ class NotesTable:
|
|||||||
except:
|
except:
|
||||||
# log('comp_etud_moy_ue: exception: val=%s coef=%s' % (val,coef))
|
# log('comp_etud_moy_ue: exception: val=%s coef=%s' % (val,coef))
|
||||||
pass
|
pass
|
||||||
elif modimpl["module"]["module_type"] == MODULE_MALUS:
|
elif modimpl["module"]["module_type"] == scu.MODULE_MALUS:
|
||||||
try:
|
try:
|
||||||
ue_malus += val
|
ue_malus += val
|
||||||
except:
|
except:
|
||||||
@ -669,7 +680,7 @@ class NotesTable:
|
|||||||
moy = sum_notes / sum_coefs
|
moy = sum_notes / sum_coefs
|
||||||
if ue_malus:
|
if ue_malus:
|
||||||
moy -= 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
|
moy_valid = True
|
||||||
else:
|
else:
|
||||||
moy = "NA"
|
moy = "NA"
|
||||||
@ -893,8 +904,10 @@ class NotesTable:
|
|||||||
sum_coefs_ue = 0
|
sum_coefs_ue = 0
|
||||||
for mu in moy_ues.values():
|
for mu in moy_ues.values():
|
||||||
# mu["moy"] can be a number, or "NA", or "ERR" (user-defined UE formulas)
|
# mu["moy"] can be a number, or "NA", or "ERR" (user-defined UE formulas)
|
||||||
if isnumber(mu["moy"]) and (
|
if (
|
||||||
mu["est_inscrit"] or mu["is_capitalized"]
|
(mu["ue"]["type"] != UE_SPORT)
|
||||||
|
and scu.isnumber(mu["moy"])
|
||||||
|
and (mu["est_inscrit"] or mu["is_capitalized"])
|
||||||
):
|
):
|
||||||
coef_ue = mu["ue"]["coefficient"]
|
coef_ue = mu["ue"]["coefficient"]
|
||||||
sum_moy_ue += mu["moy"] * coef_ue
|
sum_moy_ue += mu["moy"] * coef_ue
|
||||||
@ -926,9 +939,11 @@ class NotesTable:
|
|||||||
|
|
||||||
if BONUS_TWO_ARGS:
|
if BONUS_TWO_ARGS:
|
||||||
# backward compat: compute_bonus took only 2 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:
|
else:
|
||||||
bonus = CONFIG.compute_bonus(
|
bonus = scu.CONFIG.compute_bonus(
|
||||||
notes_bonus_gen, coefs_bonus_gen, infos=infos
|
notes_bonus_gen, coefs_bonus_gen, infos=infos
|
||||||
)
|
)
|
||||||
self.bonus[etudid] = bonus
|
self.bonus[etudid] = bonus
|
||||||
@ -1018,7 +1033,7 @@ class NotesTable:
|
|||||||
Si l'étudiant est défaillant, met un code DEF sur toutes les UE
|
Si l'étudiant est défaillant, met un code DEF sur toutes les UE
|
||||||
"""
|
"""
|
||||||
cnx = self.context.GetDBConnexion()
|
cnx = self.context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
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;",
|
"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},
|
{"formsemestre_id": self.formsemestre_id},
|
||||||
@ -1035,7 +1050,7 @@ class NotesTable:
|
|||||||
"code": code,
|
"code": code,
|
||||||
"assidu": assidu,
|
"assidu": assidu,
|
||||||
"compense_formsemestre_id": compense_formsemestre_id,
|
"compense_formsemestre_id": compense_formsemestre_id,
|
||||||
"event_date": DateISOtoDMY(event_date),
|
"event_date": ndb.DateISOtoDMY(event_date),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.decisions_jury = decisions_jury
|
self.decisions_jury = decisions_jury
|
||||||
@ -1084,7 +1099,7 @@ class NotesTable:
|
|||||||
decisions_jury_ues[etudid][ue_id] = {
|
decisions_jury_ues[etudid][ue_id] = {
|
||||||
"code": code,
|
"code": code,
|
||||||
"ects": ects, # 0. si non UE validée ou si mode de calcul different (?)
|
"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
|
self.decisions_jury_ues = decisions_jury_ues
|
||||||
@ -1117,6 +1132,9 @@ class NotesTable:
|
|||||||
|
|
||||||
def sem_has_decisions(self):
|
def sem_has_decisions(self):
|
||||||
"""True si au moins une decision de jury dans ce semestre"""
|
"""True si au moins une decision de jury dans ce semestre"""
|
||||||
|
if [x for x in self.decisions_jury_ues.values() if x]:
|
||||||
|
return True
|
||||||
|
|
||||||
return len([x for x in self.decisions_jury_ues.values() if x]) > 0
|
return len([x for x in self.decisions_jury_ues.values() if x]) > 0
|
||||||
|
|
||||||
def etud_has_decision(self, etudid):
|
def etud_has_decision(self, etudid):
|
||||||
@ -1141,7 +1159,7 @@ class NotesTable:
|
|||||||
ue_capitalisees = { etudid :
|
ue_capitalisees = { etudid :
|
||||||
[{ 'moy':, 'event_date' : ,'formsemestre_id' : }, ...] }
|
[{ 'moy':, 'event_date' : ,'formsemestre_id' : }, ...] }
|
||||||
"""
|
"""
|
||||||
self.ue_capitalisees = DictDefault(defaultvalue=[])
|
self.ue_capitalisees = scu.DictDefault(defaultvalue=[])
|
||||||
cnx = None
|
cnx = None
|
||||||
for etudid in self.get_etudids():
|
for etudid in self.get_etudids():
|
||||||
capital = formsemestre_get_etud_capitalisation(
|
capital = formsemestre_get_etud_capitalisation(
|
||||||
@ -1276,13 +1294,13 @@ class NotesTable:
|
|||||||
(ne compte que les notes en attente dans des évaluation avec coef. non nul).
|
(ne compte que les notes en attente dans des évaluation avec coef. non nul).
|
||||||
"""
|
"""
|
||||||
cnx = self.context.GetDBConnexion()
|
cnx = self.context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
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",
|
"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,
|
"formsemestre_id": self.formsemestre_id,
|
||||||
"etudid": etudid,
|
"etudid": etudid,
|
||||||
"code_attente": NOTES_ATTENTE,
|
"code_attente": scu.NOTES_ATTENTE,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return len(cursor.fetchall()) > 0
|
return len(cursor.fetchall()) > 0
|
||||||
@ -1326,7 +1344,7 @@ class CacheNotesTable:
|
|||||||
# Cache des classeur PDF (bulletins)
|
# Cache des classeur PDF (bulletins)
|
||||||
self.pdfcache = {} # { formsemestre_id : (filename, pdfdoc) }
|
self.pdfcache = {} # { formsemestre_id : (filename, pdfdoc) }
|
||||||
# Listeners:
|
# Listeners:
|
||||||
self.listeners = DictDefault(
|
self.listeners = scu.DictDefault(
|
||||||
defaultvalue={}
|
defaultvalue={}
|
||||||
) # {formsemestre_id : {listener_id : callback }}
|
) # {formsemestre_id : {listener_id : callback }}
|
||||||
|
|
||||||
|
44
notesdb.py
44
notesdb.py
@ -5,10 +5,11 @@ import pdb, os, sys, string
|
|||||||
import traceback
|
import traceback
|
||||||
import psycopg2
|
import psycopg2
|
||||||
import psycopg2.pool
|
import psycopg2.pool
|
||||||
|
import psycopg2.extras
|
||||||
import thread
|
import thread
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from sco_exceptions import *
|
from sco_exceptions import ScoException, ScoValueError, NoteProcessError
|
||||||
from types import *
|
from types import StringType
|
||||||
from cgi import escape
|
from cgi import escape
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
@ -67,16 +68,17 @@ def GetUsersDBConnexion(context, autocommit=True):
|
|||||||
return cnx
|
return cnx
|
||||||
|
|
||||||
|
|
||||||
|
# Nota: on pourrait maintenant utiliser psycopg2.extras.DictCursor
|
||||||
class ScoDocCursor(psycopg2.extensions.cursor):
|
class ScoDocCursor(psycopg2.extensions.cursor):
|
||||||
"""A database cursor emulating some methods of psycopg v1 cursors"""
|
"""A database cursor emulating some methods of psycopg v1 cursors"""
|
||||||
|
|
||||||
def dictfetchall(cursor):
|
def dictfetchall(self):
|
||||||
col_names = [d[0] for d in cursor.description]
|
col_names = [d[0] for d in self.description]
|
||||||
return [dict(zip(col_names, row)) for row in cursor.fetchall()]
|
return [dict(zip(col_names, row)) for row in self.fetchall()]
|
||||||
|
|
||||||
def dictfetchone(cursor):
|
def dictfetchone(self):
|
||||||
col_names = [d[0] for d in cursor.description]
|
col_names = [d[0] for d in self.description]
|
||||||
row = cursor.fetchone()
|
row = self.fetchone()
|
||||||
if row:
|
if row:
|
||||||
return dict(zip(col_names, row))
|
return dict(zip(col_names, row))
|
||||||
else:
|
else:
|
||||||
@ -141,6 +143,8 @@ def DBSelectArgs(
|
|||||||
distinct=True,
|
distinct=True,
|
||||||
aux_tables=[],
|
aux_tables=[],
|
||||||
id_name=None,
|
id_name=None,
|
||||||
|
limit="",
|
||||||
|
offset="",
|
||||||
):
|
):
|
||||||
"""Select * from table where values match dict vals.
|
"""Select * from table where values match dict vals.
|
||||||
Returns cnx, columns_names, list of tuples
|
Returns cnx, columns_names, list of tuples
|
||||||
@ -155,6 +159,12 @@ def DBSelectArgs(
|
|||||||
distinct = " distinct "
|
distinct = " distinct "
|
||||||
else:
|
else:
|
||||||
distinct = ""
|
distinct = ""
|
||||||
|
if limit != "":
|
||||||
|
limit = " LIMIT %d" % limit
|
||||||
|
if not offset:
|
||||||
|
offset = ""
|
||||||
|
if offset != "":
|
||||||
|
offset = " OFFSET %d" % offset
|
||||||
operator = " " + operator + " "
|
operator = " " + operator + " "
|
||||||
# liste des tables (apres "from")
|
# liste des tables (apres "from")
|
||||||
tables = [table] + [x[0] for x in aux_tables]
|
tables = [table] + [x[0] for x in aux_tables]
|
||||||
@ -165,7 +175,7 @@ def DBSelectArgs(
|
|||||||
cond = ""
|
cond = ""
|
||||||
i = 1
|
i = 1
|
||||||
cl = []
|
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))
|
cl.append("T0.%s = T%d.%s" % (id_name, i, aux_id))
|
||||||
i = i + 1
|
i = i + 1
|
||||||
cond += " and ".join(cl)
|
cond += " and ".join(cl)
|
||||||
@ -195,7 +205,17 @@ def DBSelectArgs(
|
|||||||
if cond:
|
if cond:
|
||||||
cond = " where " + cond
|
cond = " where " + cond
|
||||||
#
|
#
|
||||||
req = "select " + distinct + ", ".join(what) + " from " + tables + cond + orderby
|
req = (
|
||||||
|
"select "
|
||||||
|
+ distinct
|
||||||
|
+ ", ".join(what)
|
||||||
|
+ " from "
|
||||||
|
+ tables
|
||||||
|
+ cond
|
||||||
|
+ orderby
|
||||||
|
+ limit
|
||||||
|
+ offset
|
||||||
|
)
|
||||||
# open('/tmp/select.log','a').write( req % vals + '\n' )
|
# open('/tmp/select.log','a').write( req % vals + '\n' )
|
||||||
try:
|
try:
|
||||||
cursor.execute(req, vals)
|
cursor.execute(req, vals)
|
||||||
@ -329,6 +349,8 @@ class EditableTable:
|
|||||||
test="=",
|
test="=",
|
||||||
sortkey=None,
|
sortkey=None,
|
||||||
disable_formatting=False,
|
disable_formatting=False,
|
||||||
|
limit="",
|
||||||
|
offset="",
|
||||||
):
|
):
|
||||||
"returns list of dicts"
|
"returns list of dicts"
|
||||||
# REQLOG.write('%s: %s by %s (%s) %d\n'%(self.table_name,args,sys._getframe(1).f_code.co_name, sys._getframe(2).f_code.co_name, REQN))
|
# REQLOG.write('%s: %s by %s (%s) %d\n'%(self.table_name,args,sys._getframe(1).f_code.co_name, sys._getframe(2).f_code.co_name, REQN))
|
||||||
@ -347,6 +369,8 @@ class EditableTable:
|
|||||||
operator=operator,
|
operator=operator,
|
||||||
aux_tables=self.aux_tables,
|
aux_tables=self.aux_tables,
|
||||||
id_name=self.id_name,
|
id_name=self.id_name,
|
||||||
|
limit=limit,
|
||||||
|
offset=offset,
|
||||||
)
|
)
|
||||||
for r in res:
|
for r in res:
|
||||||
self.format_output(r, disable_formatting=disable_formatting)
|
self.format_output(r, disable_formatting=disable_formatting)
|
||||||
|
@ -30,12 +30,14 @@
|
|||||||
# conçu et développé par Cléo Baras (IUT de Grenoble)
|
# conçu et développé par Cléo Baras (IUT de Grenoble)
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
import os
|
||||||
import codecs
|
import codecs
|
||||||
import re
|
import re
|
||||||
import scolars
|
import scolars
|
||||||
import pe_jurype, pe_tagtable, pe_tools
|
import pe_jurype, pe_tagtable, pe_tools
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
|
from notes_log import log
|
||||||
import scolars
|
import scolars
|
||||||
|
|
||||||
import pe_jurype, pe_tagtable, pe_tools
|
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
|
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)
|
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()
|
un_avis_latex = fid_latex.read()
|
||||||
fid_latex.close()
|
fid_latex.close()
|
||||||
return un_avis_latex
|
return un_avis_latex
|
||||||
@ -72,7 +74,7 @@ def get_code_latex_from_scodoc_preference(
|
|||||||
template_latex = context.get_preference(champ, formsemestre_id)
|
template_latex = context.get_preference(champ, formsemestre_id)
|
||||||
# Conversion du template en unicode:
|
# Conversion du template en unicode:
|
||||||
if template_latex:
|
if template_latex:
|
||||||
template_latex = template_latex.decode(SCO_ENCODING)
|
template_latex = template_latex.decode(scu.SCO_ENCODING)
|
||||||
else:
|
else:
|
||||||
template_latex = u"" # EV: preference non définie (None)
|
template_latex = u"" # EV: preference non définie (None)
|
||||||
|
|
||||||
@ -119,10 +121,14 @@ def comp_latex_parcourstimeline(etudiant, promo, taille=17):
|
|||||||
\\end{parcourstimeline}
|
\\end{parcourstimeline}
|
||||||
"""
|
"""
|
||||||
reslatex = codelatexDebut
|
reslatex = codelatexDebut
|
||||||
reslatex = reslatex.replace("**debut**", etudiant["entree"].decode(SCO_ENCODING))
|
|
||||||
reslatex = reslatex.replace("**fin**", str(etudiant["promo"]).decode(SCO_ENCODING))
|
|
||||||
reslatex = reslatex.replace(
|
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
|
# 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 ?
|
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
|
# Recherche des tags dans le fichier
|
||||||
tags_latex = get_tags_latex(code)
|
tags_latex = get_tags_latex(code)
|
||||||
if DEBUG:
|
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
|
# Interprète et remplace chaque tags latex par les données numériques de l'étudiant (y compris les
|
||||||
# tags "macros" tels que parcourstimeline
|
# tags "macros" tels que parcourstimeline
|
||||||
@ -207,17 +213,16 @@ def get_code_latex_avis_etudiant(
|
|||||||
elif tag_latex == u"bilanParTag":
|
elif tag_latex == u"bilanParTag":
|
||||||
valeur = get_bilanParTag(donnees_etudiant)
|
valeur = get_bilanParTag(donnees_etudiant)
|
||||||
|
|
||||||
# Les tags "simples": par ex. nom, prenom, sexe, ...
|
# Les tags "simples": par ex. nom, prenom, civilite, ...
|
||||||
else:
|
else:
|
||||||
if tag_latex in donnees_etudiant:
|
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**, ...
|
elif tag_latex in prefs: # les champs **NomResponsablePE**, ...
|
||||||
valeur = pe_tools.escape_for_latex(prefs[tag_latex]).decode(
|
valeur = pe_tools.escape_for_latex(prefs[tag_latex]).decode(
|
||||||
SCO_ENCODING
|
scu.SCO_ENCODING
|
||||||
)
|
)
|
||||||
|
|
||||||
# Gestion des pb d'encodage XXX debug
|
# Gestion des pb d'encodage XXX debug
|
||||||
# print(tag_latex, valeur)
|
|
||||||
assert isinstance(tag_latex, unicode)
|
assert isinstance(tag_latex, unicode)
|
||||||
assert isinstance(valeur, 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)
|
exp = re.compile(r"^" + tag_annotation_pe)
|
||||||
|
|
||||||
for a in annotations:
|
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 ?
|
if exp.match(commentaire): # tag en début de commentaire ?
|
||||||
a["comment_u"] = commentaire # unicode, HTML non quoté
|
a["comment_u"] = commentaire # unicode, HTML non quoté
|
||||||
annotationsPE.append(
|
annotationsPE.append(
|
||||||
@ -282,7 +287,6 @@ def str_from_syntheseJury(donnees_etudiant, aggregat, groupe, tag_scodoc, champ)
|
|||||||
for chp in champ
|
for chp in champ
|
||||||
]
|
]
|
||||||
else: # champ = str à priori
|
else: # champ = str à priori
|
||||||
# print(champ)
|
|
||||||
valeur = DONNEE_MANQUANTE
|
valeur = DONNEE_MANQUANTE
|
||||||
if (
|
if (
|
||||||
(aggregat in donnees_etudiant)
|
(aggregat in donnees_etudiant)
|
||||||
@ -316,7 +320,6 @@ def str_from_syntheseJury(donnees_etudiant, aggregat, groupe, tag_scodoc, champ)
|
|||||||
else:
|
else:
|
||||||
valeur = u"%s" % donnees_numeriques[indice_champ]
|
valeur = u"%s" % donnees_numeriques[indice_champ]
|
||||||
|
|
||||||
# print(valeur)
|
|
||||||
return valeur
|
return valeur
|
||||||
|
|
||||||
|
|
||||||
@ -339,7 +342,7 @@ def get_bilanParTag(donnees_etudiant, groupe="groupe"):
|
|||||||
|
|
||||||
lignes = []
|
lignes = []
|
||||||
valeurs = {"note": [], "rang": []}
|
valeurs = {"note": [], "rang": []}
|
||||||
for (indice_aggregat, (aggregat, intitule, ordre)) in enumerate(entete):
|
for (indice_aggregat, (aggregat, intitule, _)) in enumerate(entete):
|
||||||
# print("> " + aggregat)
|
# print("> " + aggregat)
|
||||||
# listeTags = jury.get_allTagForAggregat(aggregat) # les tags de l'aggrégat
|
# listeTags = jury.get_allTagForAggregat(aggregat) # les tags de l'aggrégat
|
||||||
listeTags = [
|
listeTags = [
|
||||||
@ -366,25 +369,20 @@ def get_bilanParTag(donnees_etudiant, groupe="groupe"):
|
|||||||
("\\textit{" + rang + "}") if note else ""
|
("\\textit{" + rang + "}") if note else ""
|
||||||
) # rang masqué si pas de notes
|
) # 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"\\begin{tabular}{|c|" + "|c" * (len(entete)) + "|}\n"
|
||||||
code_latex += u"\\hline \n"
|
code_latex += u"\\hline \n"
|
||||||
code_latex += (
|
code_latex += (
|
||||||
u" & "
|
u" & "
|
||||||
+ " & ".join(
|
+ " & ".join(["\\textbf{" + intitule + "}" for (agg, intitule, _) in entete])
|
||||||
["\\textbf{" + intitule + "}" for (agg, intitule, ordre) in entete]
|
|
||||||
)
|
|
||||||
+ " \\\\ \n"
|
+ " \\\\ \n"
|
||||||
)
|
)
|
||||||
code_latex += u"\\hline"
|
code_latex += u"\\hline"
|
||||||
code_latex += u"\\hline \n"
|
code_latex += u"\\hline \n"
|
||||||
for (i, ligne_val) in enumerate(valeurs["note"]):
|
for (i, ligne_val) in enumerate(valeurs["note"]):
|
||||||
titre = lignes[i] # règle le pb d'encodage
|
titre = lignes[i] # règle le pb d'encodage
|
||||||
# print titre, ligne_val
|
|
||||||
code_latex += (
|
code_latex += (
|
||||||
u"\\textbf{"
|
u"\\textbf{"
|
||||||
+ titre.decode(SCO_ENCODING)
|
+ titre.decode(scu.SCO_ENCODING)
|
||||||
+ u"} & "
|
+ u"} & "
|
||||||
+ " & ".join(ligne_val)
|
+ " & ".join(ligne_val)
|
||||||
+ u"\\\\ \n"
|
+ u"\\\\ \n"
|
||||||
@ -412,9 +410,11 @@ def get_avis_poursuite_par_etudiant(
|
|||||||
if pe_tools.PE_DEBUG:
|
if pe_tools.PE_DEBUG:
|
||||||
pe_tools.pe_print(jury.syntheseJury[etudid]["nom"] + " " + etudid)
|
pe_tools.pe_print(jury.syntheseJury[etudid]["nom"] + " " + etudid)
|
||||||
|
|
||||||
sexe = jury.syntheseJury[etudid]["sexe"].decode(SCO_ENCODING)
|
civilite_str = jury.syntheseJury[etudid]["civilite_str"].decode(scu.SCO_ENCODING)
|
||||||
nom = jury.syntheseJury[etudid]["nom"].replace(" ", "-").decode(SCO_ENCODING)
|
nom = jury.syntheseJury[etudid]["nom"].replace(" ", "-").decode(scu.SCO_ENCODING)
|
||||||
prenom = jury.syntheseJury[etudid]["prenom"].replace(" ", "-").decode(SCO_ENCODING)
|
prenom = (
|
||||||
|
jury.syntheseJury[etudid]["prenom"].replace(" ", "-").decode(scu.SCO_ENCODING)
|
||||||
|
)
|
||||||
|
|
||||||
nom_fichier = (
|
nom_fichier = (
|
||||||
u"avis_poursuite_"
|
u"avis_poursuite_"
|
||||||
@ -429,7 +429,9 @@ def get_avis_poursuite_par_etudiant(
|
|||||||
|
|
||||||
# Entete (commentaire)
|
# Entete (commentaire)
|
||||||
|
|
||||||
contenu_latex = u"%% ---- Etudiant: " + sexe + " " + nom + " " + prenom + u"\n"
|
contenu_latex = (
|
||||||
|
u"%% ---- Etudiant: " + civilite_str + " " + nom + " " + prenom + u"\n"
|
||||||
|
)
|
||||||
|
|
||||||
# les annnotations
|
# les annnotations
|
||||||
annotationPE = get_annotation_PE(
|
annotationPE = get_annotation_PE(
|
||||||
@ -460,11 +462,11 @@ def get_templates_from_distrib(template="avis"):
|
|||||||
|
|
||||||
if template in ["avis", "footer"]:
|
if template in ["avis", "footer"]:
|
||||||
# pas de preference pour le template: utilise fichier du serveur
|
# pas de preference pour le template: utilise fichier du serveur
|
||||||
p = os.path.join(SCO_SRCDIR, pe_local_tmpl)
|
p = os.path.join(scu.SCO_SRCDIR, pe_local_tmpl)
|
||||||
if os.path.exists(p):
|
if os.path.exists(p):
|
||||||
template_latex = get_code_latex_from_modele(p)
|
template_latex = get_code_latex_from_modele(p)
|
||||||
else:
|
else:
|
||||||
p = os.path.join(SCO_SRCDIR, pe_default_tmpl)
|
p = os.path.join(scu.SCO_SRCDIR, pe_default_tmpl)
|
||||||
if os.path.exists(p):
|
if os.path.exists(p):
|
||||||
template_latex = get_code_latex_from_modele(p)
|
template_latex = get_code_latex_from_modele(p)
|
||||||
else:
|
else:
|
||||||
@ -502,7 +504,7 @@ def table_syntheseAnnotationPE(context, syntheseJury, tag_annotation_pe):
|
|||||||
[syntheseJury[etudid]["nbSemestres"] for etudid in etudids]
|
[syntheseJury[etudid]["nbSemestres"] for etudid in etudids]
|
||||||
) # le nombre de semestre le + grand
|
) # le nombre de semestre le + grand
|
||||||
|
|
||||||
infos = ["sexe", "nom", "prenom", "age", "nbSemestres"]
|
infos = ["civilite", "nom", "prenom", "age", "nbSemestres"]
|
||||||
entete = ["etudid"]
|
entete = ["etudid"]
|
||||||
entete.extend(infos)
|
entete.extend(infos)
|
||||||
entete.extend(["P%d" % i for i in range(1, maxParcours + 1)]) # ajout du parcours
|
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:
|
# Les info générales:
|
||||||
row = {
|
row = {
|
||||||
"etudid": etudid,
|
"etudid": etudid,
|
||||||
"sexe": e["sexe"],
|
"civilite": e["civilite"],
|
||||||
"nom": e["nom"],
|
"nom": e["nom"],
|
||||||
"prenom": e["prenom"],
|
"prenom": e["prenom"],
|
||||||
"age": e["age"],
|
"age": e["age"],
|
||||||
@ -534,7 +536,9 @@ def table_syntheseAnnotationPE(context, syntheseJury, tag_annotation_pe):
|
|||||||
annotationPE = get_annotation_PE(
|
annotationPE = get_annotation_PE(
|
||||||
context, etudid, tag_annotation_pe=tag_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)
|
rows.append(row)
|
||||||
|
|
||||||
T = GenTable(
|
T = GenTable(
|
||||||
|
30
pe_jurype.py
30
pe_jurype.py
@ -42,6 +42,7 @@ Created on Fri Sep 9 09:15:05 2016
|
|||||||
# a l'edition d'un jury de poursuites d'etudes
|
# a l'edition d'un jury de poursuites d'etudes
|
||||||
# ----------------------------------------------------------
|
# ----------------------------------------------------------
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
@ -54,10 +55,9 @@ from zipfile import ZipFile, BadZipfile
|
|||||||
import pprint
|
import pprint
|
||||||
|
|
||||||
from gen_tables import GenTable, SeqGenTable
|
from gen_tables import GenTable, SeqGenTable
|
||||||
|
import sco_utils as scu
|
||||||
import sco_codes_parcours # sco_codes_parcours.NEXT -> sem suivant
|
import sco_codes_parcours # sco_codes_parcours.NEXT -> sem suivant
|
||||||
import sco_report
|
import sco_report
|
||||||
from sco_utils import *
|
|
||||||
|
|
||||||
import pe_tagtable, pe_tools, pe_avislatex, pe_semestretag, pe_settag
|
import pe_tagtable, pe_tools, pe_avislatex, pe_semestretag, pe_settag
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ class JuryPE:
|
|||||||
- context : le contexte Zope
|
- context : le contexte Zope
|
||||||
- juryEtudDict : dictionnaire récapitulant les étudiants participant au jury PE (données administratives +
|
- 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 ...
|
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
|
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
|
et ceux qui sont éliminés (abandon, redoublement, ...) pour affichage alternatif
|
||||||
|
|
||||||
@ -450,15 +450,15 @@ class JuryPE:
|
|||||||
end="",
|
end="",
|
||||||
)
|
)
|
||||||
|
|
||||||
if pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 2:
|
# if pe_tools.PE_DEBUG and pe_tools.PE_DEBUG >= 2:
|
||||||
print
|
# print
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------------------------------------------
|
||||||
def est_un_etudiant_reoriente_ou_demissionnaire(self, etudid):
|
def est_un_etudiant_reoriente_ou_demissionnaire(self, etudid):
|
||||||
"""Renvoie True si l'étudiant est réorienté (NAR) ou démissionnaire (DEM)"""
|
"""Renvoie True si l'étudiant est réorienté (NAR) ou démissionnaire (DEM)"""
|
||||||
reponse = False
|
reponse = False
|
||||||
etud = self.get_cache_etudInfo_d_un_etudiant(self.context, etudid)
|
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 (
|
if (
|
||||||
len(set(sco_codes_parcours.CODES_SEM_REO.keys()) & set(parcours.values()))
|
len(set(sco_codes_parcours.CODES_SEM_REO.keys()) & set(parcours.values()))
|
||||||
> 0
|
> 0
|
||||||
@ -812,7 +812,8 @@ class JuryPE:
|
|||||||
self.syntheseJury[etudid] = {
|
self.syntheseJury[etudid] = {
|
||||||
"nom": etudinfo["nom"],
|
"nom": etudinfo["nom"],
|
||||||
"prenom": etudinfo["prenom"],
|
"prenom": etudinfo["prenom"],
|
||||||
"sexe": etudinfo["sexe"],
|
"civilite": etudinfo["civilite"],
|
||||||
|
"civilite_str": etudinfo["civilite_str"],
|
||||||
"age": str(pe_tools.calcul_age(etudinfo["date_naissance"])),
|
"age": str(pe_tools.calcul_age(etudinfo["date_naissance"])),
|
||||||
"lycee": etudinfo["nomlycee"]
|
"lycee": etudinfo["nomlycee"]
|
||||||
+ (
|
+ (
|
||||||
@ -862,13 +863,13 @@ class JuryPE:
|
|||||||
|
|
||||||
def get_dateEntree(self, etudid):
|
def get_dateEntree(self, etudid):
|
||||||
"""Renvoie l'année d'entrée de l'étudiant à l'IUT"""
|
"""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
|
semDeb = self.get_semestresDUT_d_un_etudiant(etudid)[-1] # le 1er sem à l'IUT
|
||||||
return semDeb["annee_debut"]
|
return semDeb["annee_debut"]
|
||||||
|
|
||||||
def get_parcoursIUT(self, etudid):
|
def get_parcoursIUT(self, etudid):
|
||||||
"""Renvoie une liste d'infos sur les semestres du parcours d'un étudiant"""
|
"""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)
|
sems = self.get_semestresDUT_d_un_etudiant(etudid)
|
||||||
|
|
||||||
infos = []
|
infos = []
|
||||||
@ -985,7 +986,7 @@ class JuryPE:
|
|||||||
[self.syntheseJury[etudid]["nbSemestres"] for etudid in etudids]
|
[self.syntheseJury[etudid]["nbSemestres"] for etudid in etudids]
|
||||||
)
|
)
|
||||||
|
|
||||||
infos = ["sexe", "nom", "prenom", "age", "nbSemestres"]
|
infos = ["civilite", "nom", "prenom", "age", "nbSemestres"]
|
||||||
entete = ["etudid"]
|
entete = ["etudid"]
|
||||||
entete.extend(infos)
|
entete.extend(infos)
|
||||||
entete.extend(["P%d" % i for i in range(1, maxParcours + 1)])
|
entete.extend(["P%d" % i for i in range(1, maxParcours + 1)])
|
||||||
@ -1036,7 +1037,7 @@ class JuryPE:
|
|||||||
# Les info générales:
|
# Les info générales:
|
||||||
row = {
|
row = {
|
||||||
"etudid": etudid,
|
"etudid": etudid,
|
||||||
"sexe": e["sexe"],
|
"civilite": e["civilite"],
|
||||||
"nom": e["nom"],
|
"nom": e["nom"],
|
||||||
"prenom": e["prenom"],
|
"prenom": e["prenom"],
|
||||||
"age": e["age"],
|
"age": e["age"],
|
||||||
@ -1073,7 +1074,7 @@ class JuryPE:
|
|||||||
if mode == "singlesheet"
|
if mode == "singlesheet"
|
||||||
else "%s " % (sem)
|
else "%s " % (sem)
|
||||||
)
|
)
|
||||||
row[champ + "note"] = fmt_note(resgroupe[0])
|
row[champ + "note"] = scu.fmt_note(resgroupe[0])
|
||||||
row[champ + "class groupe"] = "%s / %s" % (
|
row[champ + "class groupe"] = "%s / %s" % (
|
||||||
resgroupe[2],
|
resgroupe[2],
|
||||||
resgroupe[3],
|
resgroupe[3],
|
||||||
@ -1083,11 +1084,12 @@ class JuryPE:
|
|||||||
respromo[3],
|
respromo[3],
|
||||||
)
|
)
|
||||||
row[champ + "min/moy/max groupe"] = "%s / %s / %s" % tuple(
|
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])
|
for x in (resgroupe[6], resgroupe[4], resgroupe[5])
|
||||||
)
|
)
|
||||||
row[champ + "min/moy/max promo"] = "%s / %s / %s" % tuple(
|
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)
|
rows.append(row)
|
||||||
|
|
||||||
|
@ -35,8 +35,10 @@ Created on Fri Sep 9 09:15:05 2016
|
|||||||
|
|
||||||
@author: barasc
|
@author: barasc
|
||||||
"""
|
"""
|
||||||
import notes_table
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
from notes_log import log
|
||||||
|
import notes_table
|
||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
import sco_tag_module
|
import sco_tag_module
|
||||||
import sco_utils
|
import sco_utils
|
||||||
@ -57,14 +59,14 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
Attributs supplémentaires :
|
Attributs supplémentaires :
|
||||||
- inscrlist/identdict: étudiants inscrits hors démissionnaires ou défaillants
|
- 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
|
- _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 :
|
Attributs hérités de TableTag :
|
||||||
- nom :
|
- nom :
|
||||||
- resultats: {tag: { etudid: (note_moy, somme_coff), ...} , ...}
|
- resultats: {tag: { etudid: (note_moy, somme_coff), ...} , ...}
|
||||||
- rang
|
- rang
|
||||||
- statistiques
|
- statistiques
|
||||||
|
|
||||||
Redéfinition :
|
Redéfinition :
|
||||||
- get_etudids() : les etudids des étudiants non défaillants ni démissionnaires
|
- get_etudids() : les etudids des étudiants non défaillants ni démissionnaires
|
||||||
"""
|
"""
|
||||||
@ -111,7 +113,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
self.modimpls = [
|
self.modimpls = [
|
||||||
modimpl
|
modimpl
|
||||||
for modimpl in self.nt._modimpls
|
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)
|
] # 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._modimpl_ids = [modimpl['moduleimpl_id'] for modimpl in self._modimpls] # la liste de id des modules (modimpl_id)
|
||||||
self.somme_coeffs = sum(
|
self.somme_coeffs = sum(
|
||||||
@ -136,8 +138,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def get_etudids(self):
|
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]
|
return [etud["etudid"] for etud in self.inscrlist]
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@ -154,7 +155,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
Renvoie le dictionnaire ainsi construit.
|
Renvoie le dictionnaire ainsi construit.
|
||||||
|
|
||||||
Rq: choix fait de repérer les modules par rapport à leur modimpl_id (valable uniquement pour un semestre), car
|
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).
|
(seuls ceux qui ont capitalisé des ue auront un régime de calcul différent).
|
||||||
"""
|
"""
|
||||||
tagdict = {}
|
tagdict = {}
|
||||||
@ -227,7 +228,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def get_noteEtCoeff_modimpl(self, modimpl_id, etudid, profondeur=2):
|
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 :
|
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,
|
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é,
|
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):
|
def get_listesNotesEtCoeffsTagEtudiant(self, tag, etudid):
|
||||||
"""Renvoie un triplet (notes, coeffs_norm, ponderations) où notes, coeff_norm et ponderation désignent trois listes
|
"""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
|
donnant -pour un tag donné- les note, coeff et ponderation de chaque modimpl à prendre en compte dans
|
||||||
le calcul de la moyenne du tag.
|
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 notes et coeff_norm sont extraits grâce à SemestreTag.get_noteEtCoeff_modimpl (donc dans semestre courant ou UE capitalisée).
|
||||||
Les pondérations sont celles déclarées avec le tag (cf. _tagdict). """
|
Les pondérations sont celles déclarées avec le tag (cf. _tagdict)."""
|
||||||
|
|
||||||
notes = []
|
notes = []
|
||||||
coeffs_norm = []
|
coeffs_norm = []
|
||||||
@ -382,7 +383,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
+ (
|
+ (
|
||||||
"%1.5f" % (coeff * self.somme_coeffs)
|
"%1.5f" % (coeff * self.somme_coeffs)
|
||||||
if coeff != None and isinstance(coeff, float)
|
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
|
+ delim
|
||||||
)
|
)
|
||||||
@ -471,14 +472,15 @@ def comp_coeff_pond(coeffs, ponderations):
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def get_moduleimpl(nt, modimpl_id):
|
def get_moduleimpl(nt, modimpl_id):
|
||||||
"""Renvoie l'objet modimpl dont l'id est modimpl_id fourni dans la note table nt,
|
"""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 = [
|
modimplids = [
|
||||||
modimpl["moduleimpl_id"] for modimpl in nt._modimpls
|
modimpl["moduleimpl_id"] for modimpl in nt._modimpls
|
||||||
] # la liste de id des modules (modimpl_id)
|
] # la liste de id des modules (modimpl_id)
|
||||||
if modimpl_id not in modimplids:
|
if modimpl_id not in modimplids:
|
||||||
if SemestreTag.DEBUG:
|
if SemestreTag.DEBUG:
|
||||||
print "SemestreTag.get_moduleimpl( %s ) : le modimpl recherche n'existe pas" % (
|
log(
|
||||||
modimpl_id
|
"SemestreTag.get_moduleimpl( %s ) : le modimpl recherche n'existe pas"
|
||||||
|
% (modimpl_id)
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
return nt._modimpls[modimplids.index(modimpl_id)]
|
return nt._modimpls[modimplids.index(modimpl_id)]
|
||||||
|
@ -36,7 +36,7 @@ Created on Fri Sep 9 09:15:05 2016
|
|||||||
@author: barasc
|
@author: barasc
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pe_tools import *
|
from pe_tools import pe_print, PE_DEBUG
|
||||||
|
|
||||||
import pe_tagtable
|
import pe_tagtable
|
||||||
import pe_semestretag
|
import pe_semestretag
|
||||||
|
@ -210,7 +210,7 @@ class TableTag:
|
|||||||
]
|
]
|
||||||
nb_notes_valides = len(notes_valides)
|
nb_notes_valides = len(notes_valides)
|
||||||
if nb_notes_valides > 0:
|
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))
|
self.statistiques[tag] = (moy, max(notes_valides), min(notes_valides))
|
||||||
|
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
|
10
pe_tools.py
10
pe_tools.py
@ -37,12 +37,14 @@ Created on Thu Sep 8 09:36:33 2016
|
|||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
import operator
|
import operator
|
||||||
import re
|
import re
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
|
from notes_log import log
|
||||||
import notes_table
|
import notes_table
|
||||||
|
|
||||||
PE_DEBUG = 0
|
PE_DEBUG = 0
|
||||||
@ -175,7 +177,7 @@ def add_pe_stuff_to_zip(context, zipfile, ziproot):
|
|||||||
|
|
||||||
Also copy logos
|
Also copy logos
|
||||||
"""
|
"""
|
||||||
PE_AUX_DIR = os.path.join(SCO_SRCDIR, "config/doc_poursuites_etudes")
|
PE_AUX_DIR = os.path.join(scu.SCO_SRCDIR, "config/doc_poursuites_etudes")
|
||||||
distrib_dir = os.path.join(PE_AUX_DIR, "distrib")
|
distrib_dir = os.path.join(PE_AUX_DIR, "distrib")
|
||||||
distrib_pathnames = list_directory_filenames(
|
distrib_pathnames = list_directory_filenames(
|
||||||
distrib_dir
|
distrib_dir
|
||||||
@ -204,7 +206,7 @@ def add_pe_stuff_to_zip(context, zipfile, ziproot):
|
|||||||
# Logos: (add to logos/ directory in zip)
|
# Logos: (add to logos/ directory in zip)
|
||||||
logos_names = ["logo_header.jpg", "logo_footer.jpg"]
|
logos_names = ["logo_header.jpg", "logo_footer.jpg"]
|
||||||
for f in logos_names:
|
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):
|
if os.path.isfile(logo):
|
||||||
add_local_file_to_zip(zipfile, ziproot, logo, "avis/logos/" + f)
|
add_local_file_to_zip(zipfile, ziproot, logo, "avis/logos/" + f)
|
||||||
|
|
||||||
@ -215,7 +217,7 @@ JURY_SYNTHESE_POUR_DEBUG = {
|
|||||||
"EID1810": {
|
"EID1810": {
|
||||||
"nom": "ROUX",
|
"nom": "ROUX",
|
||||||
"entree": "2016",
|
"entree": "2016",
|
||||||
"sexe": "M.",
|
"civilite_str": "M.",
|
||||||
"promo": 2016,
|
"promo": 2016,
|
||||||
"S2": {
|
"S2": {
|
||||||
"groupe": {
|
"groupe": {
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_formsemestre_status
|
import sco_formsemestre_status
|
||||||
@ -44,7 +44,7 @@ from gen_tables import GenTable
|
|||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
|
|
||||||
import pe_tools
|
import pe_tools
|
||||||
from pe_tools import *
|
from pe_tools import PE_LATEX_ENCODING
|
||||||
import pe_tagtable
|
import pe_tagtable
|
||||||
import pe_semestretag
|
import pe_semestretag
|
||||||
import pe_settag
|
import pe_settag
|
||||||
@ -110,7 +110,7 @@ def pe_view_sem_recap(
|
|||||||
# template fourni via le formulaire Web
|
# template fourni via le formulaire Web
|
||||||
if avis_tmpl_file:
|
if avis_tmpl_file:
|
||||||
template_latex = avis_tmpl_file.read()
|
template_latex = avis_tmpl_file.read()
|
||||||
template_latex = template_latex.decode(SCO_ENCODING)
|
template_latex = template_latex.decode(scu.SCO_ENCODING)
|
||||||
else:
|
else:
|
||||||
# template indiqué dans préférences ScoDoc ?
|
# template indiqué dans préférences ScoDoc ?
|
||||||
template_latex = pe_avislatex.get_code_latex_from_scodoc_preference(
|
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
|
# template fourni via le formulaire Web
|
||||||
if footer_tmpl_file:
|
if footer_tmpl_file:
|
||||||
footer_latex = footer_tmpl_file.read()
|
footer_latex = footer_tmpl_file.read()
|
||||||
footer_latex = footer_latex.decode(SCO_ENCODING)
|
footer_latex = footer_latex.decode(scu.SCO_ENCODING)
|
||||||
else:
|
else:
|
||||||
footer_latex = pe_avislatex.get_code_latex_from_scodoc_preference(
|
footer_latex = pe_avislatex.get_code_latex_from_scodoc_preference(
|
||||||
context, formsemestre_id, champ="pe_avis_latex_footer"
|
context, formsemestre_id, champ="pe_avis_latex_footer"
|
||||||
|
633
sco_abs.py
Normal file
633
sco_abs.py
Normal file
@ -0,0 +1,633 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gestion scolarite IUT
|
||||||
|
#
|
||||||
|
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Emmanuel Viennet emmanuel.viennet@viennet.net
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""Fonctions sur les absences
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Anciennement dans ZAbscences.py, séparé pour migration
|
||||||
|
|
||||||
|
import string
|
||||||
|
import datetime
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
import calendar
|
||||||
|
import cgi
|
||||||
|
|
||||||
|
import notesdb
|
||||||
|
from sco_exceptions import ScoValueError, ScoInvalidDateError
|
||||||
|
import sco_formsemestre
|
||||||
|
import sco_compute_moy
|
||||||
|
|
||||||
|
|
||||||
|
def is_work_saturday(context):
|
||||||
|
"Vrai si le samedi est travaillé"
|
||||||
|
return int(context.get_preference("work_saturday"))
|
||||||
|
|
||||||
|
|
||||||
|
def MonthNbDays(month, year):
|
||||||
|
"returns nb of days in month"
|
||||||
|
if month > 7:
|
||||||
|
month = month + 1
|
||||||
|
if month % 2:
|
||||||
|
return 31
|
||||||
|
elif month == 2:
|
||||||
|
if calendar.isleap(year):
|
||||||
|
return 29
|
||||||
|
else:
|
||||||
|
return 28
|
||||||
|
else:
|
||||||
|
return 30
|
||||||
|
|
||||||
|
|
||||||
|
class ddmmyyyy:
|
||||||
|
"""immutable dates"""
|
||||||
|
|
||||||
|
def __init__(self, date=None, fmt="ddmmyyyy", work_saturday=False):
|
||||||
|
self.work_saturday = work_saturday
|
||||||
|
if date is None:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
if fmt == "ddmmyyyy":
|
||||||
|
self.day, self.month, self.year = string.split(date, "/")
|
||||||
|
elif fmt == "iso":
|
||||||
|
self.year, self.month, self.day = string.split(date, "-")
|
||||||
|
else:
|
||||||
|
raise ValueError("invalid format spec. (%s)" % fmt)
|
||||||
|
self.year = string.atoi(self.year)
|
||||||
|
self.month = string.atoi(self.month)
|
||||||
|
self.day = string.atoi(self.day)
|
||||||
|
except:
|
||||||
|
raise ScoValueError("date invalide: %s" % date)
|
||||||
|
# accept years YYYY or YY, uses 1970 as pivot
|
||||||
|
if self.year < 1970:
|
||||||
|
if self.year > 100:
|
||||||
|
raise ScoInvalidDateError("Année invalide: %s" % self.year)
|
||||||
|
if self.year < 70:
|
||||||
|
self.year = self.year + 2000
|
||||||
|
else:
|
||||||
|
self.year = self.year + 1900
|
||||||
|
if self.month < 1 or self.month > 12:
|
||||||
|
raise ScoInvalidDateError("Mois invalide: %s" % self.month)
|
||||||
|
|
||||||
|
if self.day < 1 or self.day > MonthNbDays(self.month, self.year):
|
||||||
|
raise ScoInvalidDateError("Jour invalide: %s" % self.day)
|
||||||
|
|
||||||
|
# weekday in 0-6, where 0 is monday
|
||||||
|
self.weekday = calendar.weekday(self.year, self.month, self.day)
|
||||||
|
|
||||||
|
self.time = time.mktime((self.year, self.month, self.day, 0, 0, 0, 0, 0, 0))
|
||||||
|
|
||||||
|
def iswork(self):
|
||||||
|
"returns true if workable day"
|
||||||
|
if self.work_saturday:
|
||||||
|
nbdays = 6
|
||||||
|
else:
|
||||||
|
nbdays = 5
|
||||||
|
if (
|
||||||
|
self.weekday >= 0 and self.weekday < nbdays
|
||||||
|
): # monday-friday or monday-saturday
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "'%02d/%02d/%04d'" % (self.day, self.month, self.year)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "%02d/%02d/%04d" % (self.day, self.month, self.year)
|
||||||
|
|
||||||
|
def ISO(self):
|
||||||
|
"iso8601 representation of the date"
|
||||||
|
return "%04d-%02d-%02d" % (self.year, self.month, self.day)
|
||||||
|
|
||||||
|
def next(self, days=1):
|
||||||
|
"date for the next day (nota: may be a non workable day)"
|
||||||
|
day = self.day + days
|
||||||
|
month = self.month
|
||||||
|
year = self.year
|
||||||
|
|
||||||
|
while day > MonthNbDays(month, year):
|
||||||
|
day = day - MonthNbDays(month, year)
|
||||||
|
month = month + 1
|
||||||
|
if month > 12:
|
||||||
|
month = 1
|
||||||
|
year = year + 1
|
||||||
|
return self.__class__(
|
||||||
|
"%02d/%02d/%04d" % (day, month, year), work_saturday=self.work_saturday
|
||||||
|
)
|
||||||
|
|
||||||
|
def prev(self, days=1):
|
||||||
|
"date for previous day"
|
||||||
|
day = self.day - days
|
||||||
|
month = self.month
|
||||||
|
year = self.year
|
||||||
|
while day <= 0:
|
||||||
|
month = month - 1
|
||||||
|
if month == 0:
|
||||||
|
month = 12
|
||||||
|
year = year - 1
|
||||||
|
day = day + MonthNbDays(month, year)
|
||||||
|
|
||||||
|
return self.__class__(
|
||||||
|
"%02d/%02d/%04d" % (day, month, year), work_saturday=self.work_saturday
|
||||||
|
)
|
||||||
|
|
||||||
|
def next_monday(self):
|
||||||
|
"date of next monday"
|
||||||
|
return self.next((7 - self.weekday) % 7)
|
||||||
|
|
||||||
|
def prev_monday(self):
|
||||||
|
"date of last monday, but on sunday, pick next monday"
|
||||||
|
if self.weekday == 6:
|
||||||
|
return self.next_monday()
|
||||||
|
else:
|
||||||
|
return self.prev(self.weekday)
|
||||||
|
|
||||||
|
def __cmp__(self, other):
|
||||||
|
"""return a negative integer if self < other,
|
||||||
|
zero if self == other, a positive integer if self > other"""
|
||||||
|
return int(self.time - other.time)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
"we are immutable !"
|
||||||
|
return hash(self.time) ^ hash(str(self))
|
||||||
|
|
||||||
|
|
||||||
|
# d = ddmmyyyy( '21/12/99' )
|
||||||
|
def DateRangeISO(context, date_beg, date_end, workable=1):
|
||||||
|
"""returns list of dates in [date_beg,date_end]
|
||||||
|
workable = 1 => keeps only workable days"""
|
||||||
|
if not date_beg:
|
||||||
|
raise ScoValueError("pas de date spécifiée !")
|
||||||
|
if not date_end:
|
||||||
|
date_end = date_beg
|
||||||
|
r = []
|
||||||
|
work_saturday = is_work_saturday(context)
|
||||||
|
cur = ddmmyyyy(date_beg, work_saturday=work_saturday)
|
||||||
|
end = ddmmyyyy(date_end, work_saturday=work_saturday)
|
||||||
|
while cur <= end:
|
||||||
|
if (not workable) or cur.iswork():
|
||||||
|
r.append(cur)
|
||||||
|
cur = cur.next()
|
||||||
|
|
||||||
|
return map(lambda x: x.ISO(), r)
|
||||||
|
|
||||||
|
|
||||||
|
def day_names(context):
|
||||||
|
"""Returns week day names.
|
||||||
|
If work_saturday property is set, include saturday
|
||||||
|
"""
|
||||||
|
if is_work_saturday(context):
|
||||||
|
return ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"]
|
||||||
|
else:
|
||||||
|
return ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi"]
|
||||||
|
|
||||||
|
|
||||||
|
def next_iso_day(context, date):
|
||||||
|
"return date after date"
|
||||||
|
d = ddmmyyyy(date, fmt="iso", work_saturday=is_work_saturday(context))
|
||||||
|
return d.next().ISO()
|
||||||
|
|
||||||
|
|
||||||
|
def YearTable(
|
||||||
|
context,
|
||||||
|
year,
|
||||||
|
events=[],
|
||||||
|
firstmonth=9,
|
||||||
|
lastmonth=7,
|
||||||
|
halfday=0,
|
||||||
|
dayattributes="",
|
||||||
|
pad_width=8,
|
||||||
|
):
|
||||||
|
"""Generate a calendar table
|
||||||
|
events = list of tuples (date, text, color, href [,halfday])
|
||||||
|
where date is a string in ISO format (yyyy-mm-dd)
|
||||||
|
halfday is boolean (true: morning, false: afternoon)
|
||||||
|
text = text to put in calendar (must be short, 1-5 cars) (optional)
|
||||||
|
if halfday, generate 2 cells per day (morning, afternoon)
|
||||||
|
"""
|
||||||
|
T = [
|
||||||
|
'<table id="maincalendar" class="maincalendar" border="3" cellpadding="1" cellspacing="1" frame="box">'
|
||||||
|
]
|
||||||
|
T.append("<tr>")
|
||||||
|
month = firstmonth
|
||||||
|
while 1:
|
||||||
|
T.append('<td valign="top">')
|
||||||
|
T.append(MonthTableHead(month))
|
||||||
|
T.append(
|
||||||
|
MonthTableBody(
|
||||||
|
month,
|
||||||
|
year,
|
||||||
|
events,
|
||||||
|
halfday,
|
||||||
|
dayattributes,
|
||||||
|
is_work_saturday(context),
|
||||||
|
pad_width=pad_width,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
T.append(MonthTableTail())
|
||||||
|
T.append("</td>")
|
||||||
|
if month == lastmonth:
|
||||||
|
break
|
||||||
|
month = month + 1
|
||||||
|
if month > 12:
|
||||||
|
month = 1
|
||||||
|
year = year + 1
|
||||||
|
T.append("</table>")
|
||||||
|
return string.join(T, "\n")
|
||||||
|
|
||||||
|
|
||||||
|
# ---- BILLETS
|
||||||
|
|
||||||
|
_billet_absenceEditor = notesdb.EditableTable(
|
||||||
|
"billet_absence",
|
||||||
|
"billet_id",
|
||||||
|
(
|
||||||
|
"billet_id",
|
||||||
|
"etudid",
|
||||||
|
"abs_begin",
|
||||||
|
"abs_end",
|
||||||
|
"description",
|
||||||
|
"etat",
|
||||||
|
"entry_date",
|
||||||
|
"justified",
|
||||||
|
),
|
||||||
|
sortkey="entry_date desc",
|
||||||
|
)
|
||||||
|
|
||||||
|
billet_absence_create = _billet_absenceEditor.create
|
||||||
|
billet_absence_delete = _billet_absenceEditor.delete
|
||||||
|
billet_absence_list = _billet_absenceEditor.list
|
||||||
|
billet_absence_edit = _billet_absenceEditor.edit
|
||||||
|
|
||||||
|
# ------ HTML Calendar functions (see YearTable function)
|
||||||
|
|
||||||
|
# MONTH/DAY NAMES:
|
||||||
|
|
||||||
|
MONTHNAMES = (
|
||||||
|
"Janvier",
|
||||||
|
"Février",
|
||||||
|
"Mars",
|
||||||
|
"Avril",
|
||||||
|
"Mai",
|
||||||
|
"Juin",
|
||||||
|
"Juillet",
|
||||||
|
"Aout",
|
||||||
|
"Septembre",
|
||||||
|
"Octobre",
|
||||||
|
"Novembre",
|
||||||
|
"Décembre",
|
||||||
|
)
|
||||||
|
|
||||||
|
MONTHNAMES_ABREV = (
|
||||||
|
"Jan.",
|
||||||
|
"Fév.",
|
||||||
|
"Mars",
|
||||||
|
"Avr.",
|
||||||
|
"Mai ",
|
||||||
|
"Juin",
|
||||||
|
"Juil",
|
||||||
|
"Aout",
|
||||||
|
"Sept",
|
||||||
|
"Oct.",
|
||||||
|
"Nov.",
|
||||||
|
"Déc.",
|
||||||
|
)
|
||||||
|
|
||||||
|
DAYNAMES = ("Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche")
|
||||||
|
|
||||||
|
DAYNAMES_ABREV = ("L", "M", "M", "J", "V", "S", "D")
|
||||||
|
|
||||||
|
# COLORS:
|
||||||
|
|
||||||
|
WHITE = "#FFFFFF"
|
||||||
|
GRAY1 = "#EEEEEE"
|
||||||
|
GREEN3 = "#99CC99"
|
||||||
|
WEEKDAYCOLOR = GRAY1
|
||||||
|
WEEKENDCOLOR = GREEN3
|
||||||
|
|
||||||
|
|
||||||
|
def MonthTableHead(month):
|
||||||
|
color = WHITE
|
||||||
|
return """<table class="monthcalendar" border="0" cellpadding="0" cellspacing="0" frame="box">
|
||||||
|
<tr bgcolor="%s"><td class="calcol" colspan="2" align="center">%s</td></tr>\n""" % (
|
||||||
|
color,
|
||||||
|
MONTHNAMES_ABREV[month - 1],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def MonthTableTail():
|
||||||
|
return "</table>\n"
|
||||||
|
|
||||||
|
|
||||||
|
def MonthTableBody(
|
||||||
|
month, year, events=[], halfday=0, trattributes="", work_saturday=False, pad_width=8
|
||||||
|
):
|
||||||
|
firstday, nbdays = calendar.monthrange(year, month)
|
||||||
|
localtime = time.localtime()
|
||||||
|
current_weeknum = time.strftime("%U", localtime)
|
||||||
|
current_year = localtime[0]
|
||||||
|
T = []
|
||||||
|
# cherche date du lundi de la 1ere semaine de ce mois
|
||||||
|
monday = ddmmyyyy("1/%d/%d" % (month, year))
|
||||||
|
while monday.weekday != 0:
|
||||||
|
monday = monday.prev()
|
||||||
|
|
||||||
|
if work_saturday:
|
||||||
|
weekend = ("D",)
|
||||||
|
else:
|
||||||
|
weekend = ("S", "D")
|
||||||
|
|
||||||
|
if not halfday:
|
||||||
|
for d in range(1, nbdays + 1):
|
||||||
|
weeknum = time.strftime(
|
||||||
|
"%U", time.strptime("%d/%d/%d" % (d, month, year), "%d/%m/%Y")
|
||||||
|
)
|
||||||
|
day = DAYNAMES_ABREV[(firstday + d - 1) % 7]
|
||||||
|
if day in weekend:
|
||||||
|
bgcolor = WEEKENDCOLOR
|
||||||
|
weekclass = "wkend"
|
||||||
|
attrs = ""
|
||||||
|
else:
|
||||||
|
bgcolor = WEEKDAYCOLOR
|
||||||
|
weekclass = "wk" + str(monday).replace("/", "_")
|
||||||
|
attrs = trattributes
|
||||||
|
color = None
|
||||||
|
legend = ""
|
||||||
|
href = ""
|
||||||
|
descr = ""
|
||||||
|
# event this day ?
|
||||||
|
# each event is a tuple (date, text, color, href)
|
||||||
|
# where date is a string in ISO format (yyyy-mm-dd)
|
||||||
|
for ev in events:
|
||||||
|
ev_year = int(ev[0][:4])
|
||||||
|
ev_month = int(ev[0][5:7])
|
||||||
|
ev_day = int(ev[0][8:10])
|
||||||
|
if year == ev_year and month == ev_month and ev_day == d:
|
||||||
|
if ev[1]:
|
||||||
|
legend = ev[1]
|
||||||
|
if ev[2]:
|
||||||
|
color = ev[2]
|
||||||
|
if ev[3]:
|
||||||
|
href = ev[3]
|
||||||
|
if len(ev) > 4 and ev[4]:
|
||||||
|
descr = ev[4]
|
||||||
|
#
|
||||||
|
cc = []
|
||||||
|
if color != None:
|
||||||
|
cc.append('<td bgcolor="%s" class="calcell">' % color)
|
||||||
|
else:
|
||||||
|
cc.append('<td class="calcell">')
|
||||||
|
|
||||||
|
if href:
|
||||||
|
href = 'href="%s"' % href
|
||||||
|
if descr:
|
||||||
|
descr = 'title="%s"' % cgi.escape(descr, quote=True)
|
||||||
|
if href or descr:
|
||||||
|
cc.append("<a %s %s>" % (href, descr))
|
||||||
|
|
||||||
|
if legend or d == 1:
|
||||||
|
if pad_width != None:
|
||||||
|
n = pad_width - len(legend) # pad to 8 cars
|
||||||
|
if n > 0:
|
||||||
|
legend = " " * (n / 2) + legend + " " * ((n + 1) / 2)
|
||||||
|
else:
|
||||||
|
legend = " " # empty cell
|
||||||
|
cc.append(legend)
|
||||||
|
if href or descr:
|
||||||
|
cc.append("</a>")
|
||||||
|
cc.append("</td>")
|
||||||
|
cell = string.join(cc, "")
|
||||||
|
if day == "D":
|
||||||
|
monday = monday.next(7)
|
||||||
|
if (
|
||||||
|
weeknum == current_weeknum
|
||||||
|
and current_year == year
|
||||||
|
and weekclass != "wkend"
|
||||||
|
):
|
||||||
|
weekclass += " currentweek"
|
||||||
|
T.append(
|
||||||
|
'<tr bgcolor="%s" class="%s" %s><td class="calday">%d%s</td>%s</tr>'
|
||||||
|
% (bgcolor, weekclass, attrs, d, day, cell)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Calendar with 2 cells / day
|
||||||
|
for d in range(1, nbdays + 1):
|
||||||
|
weeknum = time.strftime(
|
||||||
|
"%U", time.strptime("%d/%d/%d" % (d, month, year), "%d/%m/%Y")
|
||||||
|
)
|
||||||
|
day = DAYNAMES_ABREV[(firstday + d - 1) % 7]
|
||||||
|
if day in weekend:
|
||||||
|
bgcolor = WEEKENDCOLOR
|
||||||
|
weekclass = "wkend"
|
||||||
|
attrs = ""
|
||||||
|
else:
|
||||||
|
bgcolor = WEEKDAYCOLOR
|
||||||
|
weekclass = "wk" + str(monday).replace("/", "_")
|
||||||
|
attrs = trattributes
|
||||||
|
if (
|
||||||
|
weeknum == current_weeknum
|
||||||
|
and current_year == year
|
||||||
|
and weekclass != "wkend"
|
||||||
|
):
|
||||||
|
weeknum += " currentweek"
|
||||||
|
|
||||||
|
if day == "D":
|
||||||
|
monday = monday.next(7)
|
||||||
|
T.append(
|
||||||
|
'<tr bgcolor="%s" class="wk%s" %s><td class="calday">%d%s</td>'
|
||||||
|
% (bgcolor, weekclass, attrs, d, day)
|
||||||
|
)
|
||||||
|
cc = []
|
||||||
|
for morning in (1, 0):
|
||||||
|
color = None
|
||||||
|
legend = ""
|
||||||
|
href = ""
|
||||||
|
descr = ""
|
||||||
|
for ev in events:
|
||||||
|
ev_year = int(ev[0][:4])
|
||||||
|
ev_month = int(ev[0][5:7])
|
||||||
|
ev_day = int(ev[0][8:10])
|
||||||
|
if ev[4] != None:
|
||||||
|
ev_half = int(ev[4])
|
||||||
|
else:
|
||||||
|
ev_half = 0
|
||||||
|
if (
|
||||||
|
year == ev_year
|
||||||
|
and month == ev_month
|
||||||
|
and ev_day == d
|
||||||
|
and morning == ev_half
|
||||||
|
):
|
||||||
|
if ev[1]:
|
||||||
|
legend = ev[1]
|
||||||
|
if ev[2]:
|
||||||
|
color = ev[2]
|
||||||
|
if ev[3]:
|
||||||
|
href = ev[3]
|
||||||
|
if len(ev) > 5 and ev[5]:
|
||||||
|
descr = ev[5]
|
||||||
|
#
|
||||||
|
if color != None:
|
||||||
|
cc.append('<td bgcolor="%s" class="calcell">' % (color))
|
||||||
|
else:
|
||||||
|
cc.append('<td class="calcell">')
|
||||||
|
if href:
|
||||||
|
href = 'href="%s"' % href
|
||||||
|
if descr:
|
||||||
|
descr = 'title="%s"' % cgi.escape(descr, quote=True)
|
||||||
|
if href or descr:
|
||||||
|
cc.append("<a %s %s>" % (href, descr))
|
||||||
|
if legend or d == 1:
|
||||||
|
n = 3 - len(legend) # pad to 3 cars
|
||||||
|
if n > 0:
|
||||||
|
legend = " " * (n / 2) + legend + " " * ((n + 1) / 2)
|
||||||
|
else:
|
||||||
|
legend = " " # empty cell
|
||||||
|
cc.append(legend)
|
||||||
|
if href or descr:
|
||||||
|
cc.append("</a>")
|
||||||
|
cc.append("</td>\n")
|
||||||
|
T.append(string.join(cc, "") + "</tr>")
|
||||||
|
return string.join(T, "\n")
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Cache absences
|
||||||
|
#
|
||||||
|
# On cache simplement (à la demande) le nombre d'absences de chaque etudiant
|
||||||
|
# dans un semestre donné.
|
||||||
|
# Toute modification du semestre (invalidation) invalide le cache
|
||||||
|
# (simple mécanisme de "listener" sur le cache de semestres)
|
||||||
|
# Toute modification des absences d'un étudiant invalide les caches des semestres
|
||||||
|
# concernés à cette date (en général un seul semestre)
|
||||||
|
#
|
||||||
|
# On ne cache pas la liste des absences car elle est rarement utilisée (calendrier,
|
||||||
|
# absences à une date donnée).
|
||||||
|
#
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
class CAbsSemEtud:
|
||||||
|
"""Comptes d'absences d'un etudiant dans un semestre"""
|
||||||
|
|
||||||
|
def __init__(self, context, sem, etudid):
|
||||||
|
self.context = context
|
||||||
|
self.sem = sem
|
||||||
|
self.etudid = etudid
|
||||||
|
self._loaded = False
|
||||||
|
formsemestre_id = sem["formsemestre_id"]
|
||||||
|
context.Notes._getNotesCache().add_listener(
|
||||||
|
self.invalidate, formsemestre_id, (etudid, formsemestre_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
def CountAbs(self):
|
||||||
|
if not self._loaded:
|
||||||
|
self.load()
|
||||||
|
return self._CountAbs
|
||||||
|
|
||||||
|
def CountAbsJust(self):
|
||||||
|
if not self._loaded:
|
||||||
|
self.load()
|
||||||
|
return self._CountAbsJust
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
"Load state from DB"
|
||||||
|
# log('loading CAbsEtudSem(%s,%s)' % (self.etudid, self.sem['formsemestre_id']))
|
||||||
|
# Reload sem, it may have changed
|
||||||
|
self.sem = sco_formsemestre.get_formsemestre(
|
||||||
|
self.context, self.sem["formsemestre_id"]
|
||||||
|
)
|
||||||
|
debut_sem = notesdb.DateDMYtoISO(self.sem["date_debut"])
|
||||||
|
fin_sem = notesdb.DateDMYtoISO(self.sem["date_fin"])
|
||||||
|
|
||||||
|
self._CountAbs = self.context.Absences.CountAbs(
|
||||||
|
etudid=self.etudid, debut=debut_sem, fin=fin_sem
|
||||||
|
)
|
||||||
|
self._CountAbsJust = self.context.Absences.CountAbsJust(
|
||||||
|
etudid=self.etudid, debut=debut_sem, fin=fin_sem
|
||||||
|
)
|
||||||
|
self._loaded = True
|
||||||
|
|
||||||
|
def invalidate(self, args=None):
|
||||||
|
"Notify me that DB has been modified"
|
||||||
|
# log('invalidate CAbsEtudSem(%s,%s)' % (self.etudid, self.sem['formsemestre_id']))
|
||||||
|
self._loaded = False
|
||||||
|
|
||||||
|
|
||||||
|
# Accès au cache des absences
|
||||||
|
ABS_CACHE_INST = {} # { DeptId : { formsemestre_id : { etudid : CAbsEtudSem } } }
|
||||||
|
|
||||||
|
|
||||||
|
def getAbsSemEtud(context, sem, etudid):
|
||||||
|
AbsSemEtuds = getAbsSemEtuds(context, sem)
|
||||||
|
if not etudid in AbsSemEtuds:
|
||||||
|
AbsSemEtuds[etudid] = CAbsSemEtud(context, sem, etudid)
|
||||||
|
return AbsSemEtuds[etudid]
|
||||||
|
|
||||||
|
|
||||||
|
def getAbsSemEtuds(context, sem):
|
||||||
|
u = context.GetDBConnexionString() # identifie le dept de facon fiable
|
||||||
|
if not u in ABS_CACHE_INST:
|
||||||
|
ABS_CACHE_INST[u] = {}
|
||||||
|
C = ABS_CACHE_INST[u]
|
||||||
|
if sem["formsemestre_id"] not in C:
|
||||||
|
C[sem["formsemestre_id"]] = {}
|
||||||
|
return C[sem["formsemestre_id"]]
|
||||||
|
|
||||||
|
|
||||||
|
def invalidateAbsEtudDate(context, etudid, date):
|
||||||
|
"""Doit etre appelé à chaque modification des absences pour cet étudiant et cette date.
|
||||||
|
Invalide cache absence et PDF bulletins si nécessaire.
|
||||||
|
date: date au format ISO
|
||||||
|
"""
|
||||||
|
# Semestres a cette date:
|
||||||
|
etud = context.getEtudInfo(etudid=etudid, filled=True)[0]
|
||||||
|
sems = [
|
||||||
|
sem
|
||||||
|
for sem in etud["sems"]
|
||||||
|
if sem["date_debut_iso"] <= date and sem["date_fin_iso"] >= date
|
||||||
|
]
|
||||||
|
|
||||||
|
# Invalide les PDF et les abscences:
|
||||||
|
for sem in sems:
|
||||||
|
# Inval cache bulletin et/ou note_table
|
||||||
|
if sco_compute_moy.formsemestre_expressions_use_abscounts(
|
||||||
|
context, sem["formsemestre_id"]
|
||||||
|
):
|
||||||
|
pdfonly = False # seules certaines formules utilisent les absences
|
||||||
|
else:
|
||||||
|
pdfonly = (
|
||||||
|
True # efface toujours le PDF car il affiche en général les absences
|
||||||
|
)
|
||||||
|
|
||||||
|
context.Notes._inval_cache(
|
||||||
|
pdfonly=pdfonly, formsemestre_id=sem["formsemestre_id"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Inval cache compteurs absences:
|
||||||
|
AbsSemEtuds = getAbsSemEtuds(context, sem)
|
||||||
|
if etudid in AbsSemEtuds:
|
||||||
|
AbsSemEtuds[etudid].invalidate()
|
@ -31,14 +31,17 @@
|
|||||||
|
|
||||||
Il suffit d'appeler abs_notify() après chaque ajout d'absence.
|
Il suffit d'appeler abs_notify() après chaque ajout d'absence.
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
|
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
|
||||||
|
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
import notesdb as ndb
|
||||||
from email.MIMEText import MIMEText
|
import sco_utils as scu
|
||||||
from email.Header import Header
|
|
||||||
from email import Encoders
|
|
||||||
|
|
||||||
from notesdb import *
|
|
||||||
from sco_utils import *
|
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from scolog import logdb
|
from scolog import logdb
|
||||||
import sco_bulletins
|
import sco_bulletins
|
||||||
@ -55,8 +58,8 @@ def abs_notify(context, etudid, date):
|
|||||||
if not sem:
|
if not sem:
|
||||||
return # non inscrit a la date, pas de notification
|
return # non inscrit a la date, pas de notification
|
||||||
|
|
||||||
debut_sem = DateDMYtoISO(sem["date_debut"])
|
debut_sem = ndb.DateDMYtoISO(sem["date_debut"])
|
||||||
fin_sem = DateDMYtoISO(sem["date_fin"])
|
fin_sem = ndb.DateDMYtoISO(sem["date_fin"])
|
||||||
nbabs = context.CountAbs(etudid, debut=debut_sem, fin=fin_sem)
|
nbabs = context.CountAbs(etudid, debut=debut_sem, fin=fin_sem)
|
||||||
nbabsjust = context.CountAbsJust(etudid, debut=debut_sem, fin=fin_sem)
|
nbabsjust = context.CountAbsJust(etudid, debut=debut_sem, fin=fin_sem)
|
||||||
|
|
||||||
@ -109,12 +112,12 @@ def abs_notify_send(
|
|||||||
"""Actually send the notification by email, and register it in database"""
|
"""Actually send the notification by email, and register it in database"""
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
log("abs_notify: sending notification to %s" % destinations)
|
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:
|
for email in destinations:
|
||||||
del msg["To"]
|
del msg["To"]
|
||||||
msg["To"] = email
|
msg["To"] = email
|
||||||
context.sendEmail(msg)
|
context.sendEmail(msg)
|
||||||
SimpleQuery(
|
ndb.SimpleQuery(
|
||||||
context,
|
context,
|
||||||
"""insert into absences_notifications (etudid, email, nbabs, nbabsjust, formsemestre_id) values (%(etudid)s, %(email)s, %(nbabs)s, %(nbabsjust)s, %(formsemestre_id)s)""",
|
"""insert into absences_notifications (etudid, email, nbabs, nbabsjust, formsemestre_id) values (%(etudid)s, %(email)s, %(nbabs)s, %(nbabsjust)s, %(formsemestre_id)s)""",
|
||||||
vars(),
|
vars(),
|
||||||
@ -201,7 +204,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
|
"""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)"""
|
ou sans semestre (ce dernier cas est nécessaire pour la transition au nouveau code)"""
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
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""",
|
"""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(),
|
vars(),
|
||||||
@ -216,17 +219,15 @@ def etud_nbabs_last_notified(context, etudid, formsemestre_id=None):
|
|||||||
def user_nbdays_since_last_notif(context, email_addr, etudid):
|
def user_nbdays_since_last_notif(context, email_addr, etudid):
|
||||||
"""nb days since last notification to this email, or None if no previous notification"""
|
"""nb days since last notification to this email, or None if no previous notification"""
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""select * from absences_notifications where email = %(email_addr)s and etudid=%(etudid)s order by notification_date desc""",
|
"""select * from absences_notifications where email = %(email_addr)s and etudid=%(etudid)s order by notification_date desc""",
|
||||||
{"email_addr": email_addr, "etudid": etudid},
|
{"email_addr": email_addr, "etudid": etudid},
|
||||||
)
|
)
|
||||||
res = cursor.dictfetchone()
|
res = cursor.dictfetchone()
|
||||||
if res:
|
if res:
|
||||||
mxd = res["notification_date"] # mx.DateTime instance
|
now = datetime.datetime.now(res["notification_date"].tzinfo)
|
||||||
lastdate = datetime.datetime(mxd.year, mxd.month, mxd.day)
|
return (now - res["notification_date"]).days
|
||||||
now = datetime.datetime.now()
|
|
||||||
return (now - lastdate).days
|
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -255,10 +256,10 @@ def abs_notification_message(context, sem, prefs, etudid, nbabs, nbabsjust):
|
|||||||
subject = """Trop d'absences pour %(nomprenom)s""" % etud
|
subject = """Trop d'absences pour %(nomprenom)s""" % etud
|
||||||
#
|
#
|
||||||
msg = MIMEMultipart()
|
msg = MIMEMultipart()
|
||||||
subj = Header("[ScoDoc] " + subject, SCO_ENCODING)
|
subj = Header("[ScoDoc] " + subject, scu.SCO_ENCODING)
|
||||||
msg["Subject"] = subj
|
msg["Subject"] = subj
|
||||||
msg["From"] = prefs["email_from_addr"]
|
msg["From"] = prefs["email_from_addr"]
|
||||||
txt = MIMEText(txt, "plain", SCO_ENCODING)
|
txt = MIMEText(txt, "plain", scu.SCO_ENCODING)
|
||||||
msg.attach(txt)
|
msg.attach(txt)
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
@ -271,7 +272,7 @@ def retreive_current_formsemestre(context, etudid, cur_date):
|
|||||||
WHERE sem.formsemestre_id = i.formsemestre_id AND i.etudid=%(etudid)s
|
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)"""
|
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:
|
if not r:
|
||||||
return None
|
return None
|
||||||
# s'il y a plusieurs semestres, prend le premier (rarissime et non significatif):
|
# s'il y a plusieurs semestres, prend le premier (rarissime et non significatif):
|
||||||
@ -284,5 +285,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
|
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
|
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"""
|
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
|
return r
|
||||||
|
119
sco_abs_views.py
119
sco_abs_views.py
@ -28,19 +28,24 @@
|
|||||||
"""Pages HTML gestion absences
|
"""Pages HTML gestion absences
|
||||||
(la plupart portées du DTML)
|
(la plupart portées du DTML)
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
|
|
||||||
from stripogram import html2text, html2safehtml
|
from stripogram import html2text, html2safehtml
|
||||||
|
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
|
|
||||||
from notesdb import *
|
from notesdb import DateISOtoDMY
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
|
from sco_permissions import ScoAbsChange
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_groups
|
import sco_groups
|
||||||
import sco_find_etud
|
import sco_find_etud
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
|
import sco_moduleimpl
|
||||||
import sco_photos
|
import sco_photos
|
||||||
|
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
|
|
||||||
|
|
||||||
def doSignaleAbsence(
|
def doSignaleAbsence(
|
||||||
@ -51,17 +56,29 @@ def doSignaleAbsence(
|
|||||||
demijournee=2,
|
demijournee=2,
|
||||||
estjust=False,
|
estjust=False,
|
||||||
description=None,
|
description=None,
|
||||||
|
etudid=False,
|
||||||
REQUEST=None,
|
REQUEST=None,
|
||||||
): # etudid implied
|
): # etudid implied
|
||||||
"""Signalement d'une absence"""
|
"""Signalement d'une absence.
|
||||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
|
||||||
|
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"]
|
etudid = etud["etudid"]
|
||||||
|
|
||||||
description_abs = description
|
description_abs = description
|
||||||
dates = context.DateRangeISO(datedebut, datefin)
|
dates = sco_abs.DateRangeISO(context, datedebut, datefin)
|
||||||
nbadded = 0
|
nbadded = 0
|
||||||
|
demijournee = int(demijournee)
|
||||||
for jour in dates:
|
for jour in dates:
|
||||||
if demijournee == "2":
|
if demijournee == 2:
|
||||||
context._AddAbsence(
|
context._AddAbsence(
|
||||||
etudid, jour, False, estjust, REQUEST, description_abs, moduleimpl_id
|
etudid, jour, False, estjust, REQUEST, description_abs, moduleimpl_id
|
||||||
)
|
)
|
||||||
@ -70,9 +87,8 @@ def doSignaleAbsence(
|
|||||||
)
|
)
|
||||||
nbadded += 2
|
nbadded += 2
|
||||||
else:
|
else:
|
||||||
matin = int(demijournee)
|
|
||||||
context._AddAbsence(
|
context._AddAbsence(
|
||||||
etudid, jour, matin, estjust, REQUEST, description_abs, moduleimpl_id
|
etudid, jour, demijournee, estjust, REQUEST, description_abs, moduleimpl_id
|
||||||
)
|
)
|
||||||
nbadded += 1
|
nbadded += 1
|
||||||
#
|
#
|
||||||
@ -82,7 +98,7 @@ def doSignaleAbsence(
|
|||||||
J = "NON "
|
J = "NON "
|
||||||
M = ""
|
M = ""
|
||||||
if moduleimpl_id and moduleimpl_id != "NULL":
|
if moduleimpl_id and moduleimpl_id != "NULL":
|
||||||
mod = context.Notes.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
mod = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
|
||||||
formsemestre_id = mod["formsemestre_id"]
|
formsemestre_id = mod["formsemestre_id"]
|
||||||
nt = context.Notes._getNotesCache().get_NotesTable(
|
nt = context.Notes._getNotesCache().get_NotesTable(
|
||||||
context.Notes, formsemestre_id
|
context.Notes, formsemestre_id
|
||||||
@ -242,16 +258,32 @@ Raison: <input type="text" name="description" size="42"/> (optionnel)
|
|||||||
|
|
||||||
|
|
||||||
def doJustifAbsence(
|
def doJustifAbsence(
|
||||||
context, datedebut, datefin, demijournee, description=None, REQUEST=None
|
context,
|
||||||
|
datedebut,
|
||||||
|
datefin,
|
||||||
|
demijournee,
|
||||||
|
description=None,
|
||||||
|
etudid=False,
|
||||||
|
REQUEST=None,
|
||||||
): # etudid implied
|
): # etudid implied
|
||||||
"""Justification d'une absence"""
|
"""Justification d'une absence
|
||||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
|
||||||
|
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"]
|
etudid = etud["etudid"]
|
||||||
description_abs = description
|
description_abs = description
|
||||||
dates = context.DateRangeISO(datedebut, datefin)
|
dates = sco_abs.DateRangeISO(context, datedebut, datefin)
|
||||||
nbadded = 0
|
nbadded = 0
|
||||||
|
demijournee = int(demijournee)
|
||||||
for jour in dates:
|
for jour in dates:
|
||||||
if demijournee == "2":
|
if demijournee == 2:
|
||||||
context._AddJustif(
|
context._AddJustif(
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
jour=jour,
|
jour=jour,
|
||||||
@ -268,11 +300,10 @@ def doJustifAbsence(
|
|||||||
)
|
)
|
||||||
nbadded += 2
|
nbadded += 2
|
||||||
else:
|
else:
|
||||||
matin = int(demijournee)
|
|
||||||
context._AddJustif(
|
context._AddJustif(
|
||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
jour=jour,
|
jour=jour,
|
||||||
matin=matin,
|
matin=demijournee,
|
||||||
REQUEST=REQUEST,
|
REQUEST=REQUEST,
|
||||||
description=description_abs,
|
description=description_abs,
|
||||||
)
|
)
|
||||||
@ -365,22 +396,22 @@ Raison: <input type="text" name="description" size="42"/> (optionnel)
|
|||||||
|
|
||||||
|
|
||||||
def doAnnuleAbsence(
|
def doAnnuleAbsence(
|
||||||
context, datedebut, datefin, demijournee, REQUEST=None
|
context, datedebut, datefin, demijournee, etudid=False, REQUEST=None
|
||||||
): # etudid implied
|
): # etudid implied
|
||||||
"""Annulation des absences pour une demi journée"""
|
"""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"]
|
etudid = etud["etudid"]
|
||||||
|
|
||||||
dates = context.DateRangeISO(datedebut, datefin)
|
dates = sco_abs.DateRangeISO(context, datedebut, datefin)
|
||||||
nbadded = 0
|
nbadded = 0
|
||||||
|
demijournee = int(demijournee)
|
||||||
for jour in dates:
|
for jour in dates:
|
||||||
if demijournee == "2":
|
if demijournee == 2:
|
||||||
context._AnnuleAbsence(etudid, jour, False, REQUEST=REQUEST)
|
context._AnnuleAbsence(etudid, jour, False, REQUEST=REQUEST)
|
||||||
context._AnnuleAbsence(etudid, jour, True, REQUEST=REQUEST)
|
context._AnnuleAbsence(etudid, jour, True, REQUEST=REQUEST)
|
||||||
nbadded += 2
|
nbadded += 2
|
||||||
else:
|
else:
|
||||||
matin = int(demijournee)
|
context._AnnuleAbsence(etudid, jour, demijournee, REQUEST=REQUEST)
|
||||||
context._AnnuleAbsence(etudid, jour, matin, REQUEST=REQUEST)
|
|
||||||
nbadded += 1
|
nbadded += 1
|
||||||
#
|
#
|
||||||
H = [
|
H = [
|
||||||
@ -506,17 +537,17 @@ def doAnnuleJustif(
|
|||||||
"""Annulation d'une justification"""
|
"""Annulation d'une justification"""
|
||||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
dates = context.DateRangeISO(datedebut0, datefin0)
|
dates = sco_abs.DateRangeISO(context, datedebut0, datefin0)
|
||||||
nbadded = 0
|
nbadded = 0
|
||||||
|
demijournee = int(demijournee)
|
||||||
for jour in dates:
|
for jour in dates:
|
||||||
# Attention: supprime matin et après-midi
|
# Attention: supprime matin et après-midi
|
||||||
if demijournee == "2":
|
if demijournee == 2:
|
||||||
context._AnnuleJustif(etudid, jour, False, REQUEST=REQUEST)
|
context._AnnuleJustif(etudid, jour, False, REQUEST=REQUEST)
|
||||||
context._AnnuleJustif(etudid, jour, True, REQUEST=REQUEST)
|
context._AnnuleJustif(etudid, jour, True, REQUEST=REQUEST)
|
||||||
nbadded += 2
|
nbadded += 2
|
||||||
else:
|
else:
|
||||||
matin = int(demijournee)
|
context._AnnuleJustif(etudid, jour, demijournee, REQUEST=REQUEST)
|
||||||
context._AnnuleJustif(etudid, jour, matin, REQUEST=REQUEST)
|
|
||||||
nbadded += 1
|
nbadded += 1
|
||||||
#
|
#
|
||||||
H = [
|
H = [
|
||||||
@ -571,7 +602,7 @@ def EtatAbsences(context, REQUEST=None):
|
|||||||
|
|
||||||
</td></tr></table>
|
</td></tr></table>
|
||||||
</form>"""
|
</form>"""
|
||||||
% (AnneeScolaire(REQUEST), datetime.datetime.now().strftime("%d/%m/%Y")),
|
% (scu.AnneeScolaire(REQUEST), datetime.datetime.now().strftime("%d/%m/%Y")),
|
||||||
context.sco_footer(REQUEST),
|
context.sco_footer(REQUEST),
|
||||||
]
|
]
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
@ -610,7 +641,7 @@ def CalAbs(context, REQUEST=None): # etud implied
|
|||||||
# crude portage from 1999 DTML
|
# crude portage from 1999 DTML
|
||||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
anneescolaire = int(AnneeScolaire(REQUEST))
|
anneescolaire = int(scu.AnneeScolaire(REQUEST))
|
||||||
datedebut = str(anneescolaire) + "-08-31"
|
datedebut = str(anneescolaire) + "-08-31"
|
||||||
datefin = str(anneescolaire + 1) + "-07-31"
|
datefin = str(anneescolaire + 1) + "-07-31"
|
||||||
nbabs = context.CountAbs(etudid=etudid, debut=datedebut, fin=datefin)
|
nbabs = context.CountAbs(etudid=etudid, debut=datedebut, fin=datefin)
|
||||||
@ -631,7 +662,7 @@ def CalAbs(context, REQUEST=None): # etud implied
|
|||||||
events.append(
|
events.append(
|
||||||
(str(a["jour"]), "X", "#8EA2C6", "", a["matin"], a["description"])
|
(str(a["jour"]), "X", "#8EA2C6", "", a["matin"], a["description"])
|
||||||
)
|
)
|
||||||
CalHTML = ZAbsences.YearTable(context, anneescolaire, events=events, halfday=1)
|
CalHTML = sco_abs.YearTable(context, anneescolaire, events=events, halfday=1)
|
||||||
|
|
||||||
#
|
#
|
||||||
H = [
|
H = [
|
||||||
@ -689,11 +720,11 @@ def ListeAbsEtud(
|
|||||||
):
|
):
|
||||||
"""Liste des absences d'un étudiant sur l'année en cours
|
"""Liste des absences d'un étudiant sur l'année en cours
|
||||||
En format 'html': page avec deux tableaux (non justifiées et justifiées).
|
En format 'html': page avec deux tableaux (non justifiées et justifiées).
|
||||||
En format xls ou pdf: l'un ou l'autre des table, suivant absjust_only.
|
En format json, xml, xls ou pdf: l'un ou l'autre des table, suivant absjust_only.
|
||||||
En format 'text': texte avec liste d'absences (pour mails).
|
En format 'text': texte avec liste d'absences (pour mails).
|
||||||
"""
|
"""
|
||||||
absjust_only = int(absjust_only) # si vrai, table absjust seule (export xls ou pdf)
|
absjust_only = int(absjust_only) # si vrai, table absjust seule (export xls ou pdf)
|
||||||
datedebut = "%s-08-31" % AnneeScolaire(REQUEST)
|
datedebut = "%s-08-31" % scu.AnneeScolaire(REQUEST)
|
||||||
|
|
||||||
etud = context.getEtudInfo(etudid=etudid, filled=True)[0]
|
etud = context.getEtudInfo(etudid=etudid, filled=True)[0]
|
||||||
|
|
||||||
@ -701,10 +732,9 @@ def ListeAbsEtud(
|
|||||||
titles, columns_ids, absnonjust, absjust = context.Absences._TablesAbsEtud(
|
titles, columns_ids, absnonjust, absjust = context.Absences._TablesAbsEtud(
|
||||||
etudid, datedebut, with_evals=with_evals, format=format
|
etudid, datedebut, with_evals=with_evals, format=format
|
||||||
)
|
)
|
||||||
|
|
||||||
if REQUEST:
|
if REQUEST:
|
||||||
base_url_nj = "%s?etudid=%s&absjust_only=0" % (REQUEST.URL0, etudid)
|
base_url_nj = "%s?etudid=%s&absjust_only=0" % (REQUEST.URL0, etudid)
|
||||||
base_url_j = "%s?etudid=%s&absjust_only=1" % (REQUEST.URL0, etudid)
|
base_url_j = "%s?etudid=%s&absjust_only=1" % (REQUEST.URL0, etudid)
|
||||||
else:
|
else:
|
||||||
base_url_nj = base_url_j = ""
|
base_url_nj = base_url_j = ""
|
||||||
tab_absnonjust = GenTable(
|
tab_absnonjust = GenTable(
|
||||||
@ -714,7 +744,7 @@ def ListeAbsEtud(
|
|||||||
html_class="table_leftalign",
|
html_class="table_leftalign",
|
||||||
table_id="tab_absnonjust",
|
table_id="tab_absnonjust",
|
||||||
base_url=base_url_nj,
|
base_url=base_url_nj,
|
||||||
filename="abs_" + make_filename(etud["nomprenom"]),
|
filename="abs_" + scu.make_filename(etud["nomprenom"]),
|
||||||
caption="Absences non justifiées de %(nomprenom)s" % etud,
|
caption="Absences non justifiées de %(nomprenom)s" % etud,
|
||||||
preferences=context.get_preferences(),
|
preferences=context.get_preferences(),
|
||||||
)
|
)
|
||||||
@ -725,7 +755,7 @@ def ListeAbsEtud(
|
|||||||
html_class="table_leftalign",
|
html_class="table_leftalign",
|
||||||
table_id="tab_absjust",
|
table_id="tab_absjust",
|
||||||
base_url=base_url_j,
|
base_url=base_url_j,
|
||||||
filename="absjust_" + make_filename(etud["nomprenom"]),
|
filename="absjust_" + scu.make_filename(etud["nomprenom"]),
|
||||||
caption="Absences justifiées de %(nomprenom)s" % etud,
|
caption="Absences justifiées de %(nomprenom)s" % etud,
|
||||||
preferences=context.get_preferences(),
|
preferences=context.get_preferences(),
|
||||||
)
|
)
|
||||||
@ -830,7 +860,7 @@ def absences_index_html(context, REQUEST=None):
|
|||||||
% REQUEST.URL0,
|
% REQUEST.URL0,
|
||||||
formChoixSemestreGroupe(context),
|
formChoixSemestreGroupe(context),
|
||||||
"</p>",
|
"</p>",
|
||||||
context.CalSelectWeek(REQUEST=REQUEST),
|
cal_select_week(context, REQUEST=REQUEST),
|
||||||
"""<p class="help">Sélectionner le groupe d'étudiants, puis cliquez sur une semaine pour
|
"""<p class="help">Sélectionner le groupe d'étudiants, puis cliquez sur une semaine pour
|
||||||
saisir les absences de toute cette semaine.</p>
|
saisir les absences de toute cette semaine.</p>
|
||||||
</form>""",
|
</form>""",
|
||||||
@ -843,3 +873,16 @@ saisir les absences de toute cette semaine.</p>
|
|||||||
|
|
||||||
H.append(context.sco_footer(REQUEST))
|
H.append(context.sco_footer(REQUEST))
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
|
def cal_select_week(context, year=None, REQUEST=None):
|
||||||
|
"display calendar allowing week selection"
|
||||||
|
if not year:
|
||||||
|
year = scu.AnneeScolaire(REQUEST)
|
||||||
|
sems = sco_formsemestre.do_formsemestre_list(context)
|
||||||
|
if not sems:
|
||||||
|
js = ""
|
||||||
|
else:
|
||||||
|
js = 'onmouseover="highlightweek(this);" onmouseout="deselectweeks();" onclick="wclick(this);"'
|
||||||
|
C = sco_abs.YearTable(context, int(year), dayattributes=js)
|
||||||
|
return C
|
||||||
|
@ -46,10 +46,11 @@ Pour chaque étudiant commun:
|
|||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_apogee_csv
|
import sco_apogee_csv
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
|
|
||||||
_help_txt = """
|
_help_txt = """
|
||||||
<div class="help">
|
<div class="help">
|
||||||
|
@ -27,9 +27,7 @@
|
|||||||
|
|
||||||
"""Exportation des résultats des étudiants vers Apogée.
|
"""Exportation des résultats des étudiants vers Apogée.
|
||||||
|
|
||||||
EXPERIMENTAL / PRECAUTIONS !
|
Ce code a été au départ inspiré par les travaux de Damien Mascré, scodoc2apogee (en Java).
|
||||||
|
|
||||||
Code inspiré par les travaux de Damien Mascré, scodoc2apogee (en Java).
|
|
||||||
|
|
||||||
A utiliser en fin de semestre, après les jury.
|
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
|
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 cStringIO import StringIO
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
import pprint
|
import pprint
|
||||||
@ -90,6 +95,10 @@ try:
|
|||||||
except:
|
except:
|
||||||
chardet_detect = None
|
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
|
import sco_formsemestre
|
||||||
from sco_formsemestre import ApoEtapeVDI
|
from sco_formsemestre import ApoEtapeVDI
|
||||||
import sco_formsemestre_status
|
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 code_semestre_validant
|
||||||
from sco_codes_parcours import ATT, ATB, ADM, ADC, ADJ, ATJ, ATB, AJ, CMP, NAR, RAT, DEF
|
from sco_codes_parcours import ATT, ATB, ADM, ADC, ADJ, ATJ, ATB, AJ, CMP, NAR, RAT, DEF
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
from notesdb import *
|
|
||||||
from sco_utils import *
|
|
||||||
|
|
||||||
APO_PORTAL_ENCODING = (
|
APO_PORTAL_ENCODING = (
|
||||||
"utf8" # encodage du fichier CSV Apogée (était 'ISO-8859-1' avant jul. 2016)
|
"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]:
|
for col_id in apo_data.col_ids[:4]:
|
||||||
self.new_cols[col_id] = self.cols[col_id]
|
self.new_cols[col_id] = self.cols[col_id]
|
||||||
|
|
||||||
def unassociated_codes(self, apo_data):
|
# def unassociated_codes(self, apo_data):
|
||||||
"list of apo elements for this student without a value in ScoDoc"
|
# "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])
|
# codes = set([apo_data.cols[col_id].code for col_id in apo_data.col_ids])
|
||||||
return codes - set(sco_elts)
|
# return codes - set(sco_elts)
|
||||||
|
|
||||||
def search_elt_in_sem(self, context, code, sem, cur_sem, autre_sem):
|
def search_elt_in_sem(self, context, code, sem, cur_sem, autre_sem):
|
||||||
"""
|
"""
|
||||||
@ -749,7 +756,7 @@ class ApoData:
|
|||||||
if not data:
|
if not data:
|
||||||
raise FormatError("Fichier Apogée vide !")
|
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
|
f = StringIOFileLineWrapper(data_utf8) # pour traiter comme un fichier
|
||||||
# check that we are at the begining of Apogee CSV
|
# check that we are at the begining of Apogee CSV
|
||||||
line = f.readline().strip()
|
line = f.readline().strip()
|
||||||
@ -1023,7 +1030,7 @@ def _apo_read_cols(f):
|
|||||||
line = f.readline().strip(" " + APO_NEWLINE)
|
line = f.readline().strip(" " + APO_NEWLINE)
|
||||||
fs = line.split(APO_SEP)
|
fs = line.split(APO_SEP)
|
||||||
if fs[0] != "apoL_a01_code":
|
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
|
col_keys = fs
|
||||||
|
|
||||||
while True: # skip premiere partie (apoL_a02_nom, ...)
|
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)
|
raise FormatError("duplicate column definition: %s" % col_id)
|
||||||
m = re.match(r"^apoL_c([0-9]{4})$", col_id)
|
m = re.match(r"^apoL_c([0-9]{4})$", col_id)
|
||||||
if not m:
|
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:
|
if int(m.group(1)) != i:
|
||||||
raise FormatError("invalid column id: %s for index %s" % (col_id, 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
|
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
|
# Write data to ZIP
|
||||||
dest_zip.writestr(csv_filename, csv_data)
|
dest_zip.writestr(csv_filename, csv_data)
|
||||||
|
@ -45,15 +45,16 @@
|
|||||||
qui est une description (humaine, format libre) de l'archive.
|
qui est une description (humaine, format libre) de l'archive.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
from mx.DateTime import DateTime as mxDateTime
|
import time
|
||||||
import mx.DateTime
|
import datetime
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import glob
|
import glob
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
|
from notes_log import log
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_pvjury
|
import sco_pvjury
|
||||||
import sco_excel
|
import sco_excel
|
||||||
@ -62,6 +63,10 @@ import sco_groups
|
|||||||
import sco_groups_view
|
import sco_groups_view
|
||||||
from sco_recapcomplet import make_formsemestre_recapcomplet
|
from sco_recapcomplet import make_formsemestre_recapcomplet
|
||||||
import sco_bulletins_pdf
|
import sco_bulletins_pdf
|
||||||
|
from TrivialFormulator import TrivialFormulator
|
||||||
|
from sco_exceptions import (
|
||||||
|
AccessDenied,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BaseArchiver:
|
class BaseArchiver:
|
||||||
@ -75,12 +80,12 @@ class BaseArchiver:
|
|||||||
for dir in dirs[1:]:
|
for dir in dirs[1:]:
|
||||||
path = os.path.join(path, dir)
|
path = os.path.join(path, dir)
|
||||||
try:
|
try:
|
||||||
GSL.acquire()
|
scu.GSL.acquire()
|
||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
log("creating directory %s" % path)
|
log("creating directory %s" % path)
|
||||||
os.mkdir(path)
|
os.mkdir(path)
|
||||||
finally:
|
finally:
|
||||||
GSL.release()
|
scu.GSL.release()
|
||||||
|
|
||||||
def get_obj_dir(self, context, oid):
|
def get_obj_dir(self, context, oid):
|
||||||
"""
|
"""
|
||||||
@ -89,7 +94,7 @@ class BaseArchiver:
|
|||||||
"""
|
"""
|
||||||
dept_dir = os.path.join(self.root, context.DeptId())
|
dept_dir = os.path.join(self.root, context.DeptId())
|
||||||
try:
|
try:
|
||||||
GSL.acquire()
|
scu.GSL.acquire()
|
||||||
if not os.path.isdir(dept_dir):
|
if not os.path.isdir(dept_dir):
|
||||||
log("creating directory %s" % dept_dir)
|
log("creating directory %s" % dept_dir)
|
||||||
os.mkdir(dept_dir)
|
os.mkdir(dept_dir)
|
||||||
@ -98,7 +103,7 @@ class BaseArchiver:
|
|||||||
log("creating directory %s" % obj_dir)
|
log("creating directory %s" % obj_dir)
|
||||||
os.mkdir(obj_dir)
|
os.mkdir(obj_dir)
|
||||||
finally:
|
finally:
|
||||||
GSL.release()
|
scu.GSL.release()
|
||||||
return obj_dir
|
return obj_dir
|
||||||
|
|
||||||
def list_oids(self, context):
|
def list_oids(self, context):
|
||||||
@ -126,23 +131,23 @@ class BaseArchiver:
|
|||||||
def delete_archive(self, archive_id):
|
def delete_archive(self, archive_id):
|
||||||
"""Delete (forever) this archive"""
|
"""Delete (forever) this archive"""
|
||||||
try:
|
try:
|
||||||
GSL.acquire()
|
scu.GSL.acquire()
|
||||||
shutil.rmtree(archive_id, ignore_errors=True)
|
shutil.rmtree(archive_id, ignore_errors=True)
|
||||||
finally:
|
finally:
|
||||||
GSL.release()
|
scu.GSL.release()
|
||||||
|
|
||||||
def get_archive_date(self, archive_id):
|
def get_archive_date(self, archive_id):
|
||||||
"""Returns date (as a DateTime object) of an archive"""
|
"""Returns date (as a DateTime object) of an archive"""
|
||||||
dt = [int(x) for x in os.path.split(archive_id)[1].split("-")]
|
dt = [int(x) for x in os.path.split(archive_id)[1].split("-")]
|
||||||
return mxDateTime(*dt)
|
return datetime.datetime(*dt)
|
||||||
|
|
||||||
def list_archive(self, archive_id):
|
def list_archive(self, archive_id):
|
||||||
"""Return list of filenames (without path) in archive"""
|
"""Return list of filenames (without path) in archive"""
|
||||||
try:
|
try:
|
||||||
GSL.acquire()
|
scu.GSL.acquire()
|
||||||
files = os.listdir(archive_id)
|
files = os.listdir(archive_id)
|
||||||
finally:
|
finally:
|
||||||
GSL.release()
|
scu.GSL.release()
|
||||||
files.sort()
|
files.sort()
|
||||||
return [f for f in files if f and f[0] != "_"]
|
return [f for f in files if f and f[0] != "_"]
|
||||||
|
|
||||||
@ -182,10 +187,10 @@ class BaseArchiver:
|
|||||||
)
|
)
|
||||||
log("creating archive: %s" % archive_id)
|
log("creating archive: %s" % archive_id)
|
||||||
try:
|
try:
|
||||||
GSL.acquire()
|
scu.GSL.acquire()
|
||||||
os.mkdir(archive_id) # if exists, raises an OSError
|
os.mkdir(archive_id) # if exists, raises an OSError
|
||||||
finally:
|
finally:
|
||||||
GSL.release()
|
scu.GSL.release()
|
||||||
self.store(archive_id, "_description.txt", description)
|
self.store(archive_id, "_description.txt", description)
|
||||||
return archive_id
|
return archive_id
|
||||||
|
|
||||||
@ -194,21 +199,21 @@ class BaseArchiver:
|
|||||||
Filename may be modified (sanitized): return used filename
|
Filename may be modified (sanitized): return used filename
|
||||||
The file is created or replaced.
|
The file is created or replaced.
|
||||||
"""
|
"""
|
||||||
filename = sanitize_filename(filename)
|
filename = scu.sanitize_filename(filename)
|
||||||
log("storing %s (%d bytes) in %s" % (filename, len(data), archive_id))
|
log("storing %s (%d bytes) in %s" % (filename, len(data), archive_id))
|
||||||
try:
|
try:
|
||||||
GSL.acquire()
|
scu.GSL.acquire()
|
||||||
fname = os.path.join(archive_id, filename)
|
fname = os.path.join(archive_id, filename)
|
||||||
f = open(fname, "w")
|
f = open(fname, "w")
|
||||||
f.write(data)
|
f.write(data)
|
||||||
f.close()
|
f.close()
|
||||||
finally:
|
finally:
|
||||||
GSL.release()
|
scu.GSL.release()
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
def get(self, archive_id, filename):
|
def get(self, archive_id, filename):
|
||||||
"""Retreive data"""
|
"""Retreive data"""
|
||||||
if not is_valid_filename(filename):
|
if not scu.is_valid_filename(filename):
|
||||||
log('Archiver.get: invalid filename "%s"' % filename)
|
log('Archiver.get: invalid filename "%s"' % filename)
|
||||||
raise ValueError("invalid filename")
|
raise ValueError("invalid filename")
|
||||||
fname = os.path.join(archive_id, filename)
|
fname = os.path.join(archive_id, filename)
|
||||||
@ -220,18 +225,18 @@ class BaseArchiver:
|
|||||||
# XXX très incomplet: devrait inférer et assigner un type MIME
|
# XXX très incomplet: devrait inférer et assigner un type MIME
|
||||||
archive_id = self.get_id_from_name(context, oid, archive_name)
|
archive_id = self.get_id_from_name(context, oid, archive_name)
|
||||||
data = self.get(archive_id, filename)
|
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":
|
if ext == ".html" or ext == ".htm":
|
||||||
return data
|
return data
|
||||||
elif ext == ".xml":
|
elif ext == ".xml":
|
||||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||||
return data
|
return data
|
||||||
elif ext == ".xls":
|
elif ext == ".xls":
|
||||||
return sco_excel.sendExcelFile(REQUEST, data, filename)
|
return sco_excel.sendExcelFile(REQUEST, data, filename)
|
||||||
elif ext == ".csv":
|
elif ext == ".csv":
|
||||||
return sendCSVFile(REQUEST, data, filename)
|
return scu.sendCSVFile(REQUEST, data, filename)
|
||||||
elif ext == ".pdf":
|
elif ext == ".pdf":
|
||||||
return sendPDFFile(REQUEST, data, filename)
|
return scu.sendPDFFile(REQUEST, data, filename)
|
||||||
|
|
||||||
return data # should set mimetype...
|
return data # should set mimetype...
|
||||||
|
|
||||||
@ -320,7 +325,7 @@ def do_formsemestre_archive(
|
|||||||
if data:
|
if data:
|
||||||
PVArchive.store(archive_id, "Decisions_Jury.xls", data)
|
PVArchive.store(archive_id, "Decisions_Jury.xls", data)
|
||||||
# Classeur bulletins (PDF)
|
# Classeur bulletins (PDF)
|
||||||
data, filename = sco_bulletins_pdf.get_formsemestre_bulletins_pdf(
|
data, _ = sco_bulletins_pdf.get_formsemestre_bulletins_pdf(
|
||||||
context, formsemestre_id, REQUEST, version=bulVersion
|
context, formsemestre_id, REQUEST, version=bulVersion
|
||||||
)
|
)
|
||||||
if data:
|
if data:
|
||||||
@ -479,7 +484,7 @@ enregistrés et non modifiables, on peut les retrouver ultérieurement.
|
|||||||
|
|
||||||
# submitted or cancelled:
|
# submitted or cancelled:
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"formsemestre_list_archives?formsemestre_id=%s&head_message=%s"
|
"formsemestre_list_archives?formsemestre_id=%s&head_message=%s"
|
||||||
% (formsemestre_id, msg)
|
% (formsemestre_id, msg)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -505,7 +510,7 @@ def formsemestre_list_archives(context, REQUEST, formsemestre_id):
|
|||||||
for a in L:
|
for a in L:
|
||||||
archive_name = PVArchive.get_archive_name(a["archive_id"])
|
archive_name = PVArchive.get_archive_name(a["archive_id"])
|
||||||
H.append(
|
H.append(
|
||||||
'<li>%s : <em>%s</em> (<a href="formsemestre_delete_archive?formsemestre_id=%s&archive_name=%s">supprimer</a>)<ul>'
|
'<li>%s : <em>%s</em> (<a href="formsemestre_delete_archive?formsemestre_id=%s&archive_name=%s">supprimer</a>)<ul>'
|
||||||
% (
|
% (
|
||||||
a["date"].strftime("%d/%m/%Y %H:%M"),
|
a["date"].strftime("%d/%m/%Y %H:%M"),
|
||||||
a["description"],
|
a["description"],
|
||||||
@ -515,7 +520,7 @@ def formsemestre_list_archives(context, REQUEST, formsemestre_id):
|
|||||||
)
|
)
|
||||||
for filename in a["content"]:
|
for filename in a["content"]:
|
||||||
H.append(
|
H.append(
|
||||||
'<li><a href="formsemestre_get_archived_file?formsemestre_id=%s&archive_name=%s&filename=%s">%s</a></li>'
|
'<li><a href="formsemestre_get_archived_file?formsemestre_id=%s&archive_name=%s&filename=%s">%s</a></li>'
|
||||||
% (formsemestre_id, archive_name, filename, filename)
|
% (formsemestre_id, archive_name, filename, filename)
|
||||||
)
|
)
|
||||||
if not a["content"]:
|
if not a["content"]:
|
||||||
@ -543,7 +548,7 @@ def formsemestre_delete_archive(
|
|||||||
raise AccessDenied(
|
raise AccessDenied(
|
||||||
"opération non autorisée pour %s" % str(REQUEST.AUTHENTICATED_USER)
|
"opération non autorisée pour %s" % str(REQUEST.AUTHENTICATED_USER)
|
||||||
)
|
)
|
||||||
sem = sco_formsemestre.get_formsemestre(
|
_ = sco_formsemestre.get_formsemestre(
|
||||||
context, formsemestre_id
|
context, formsemestre_id
|
||||||
) # check formsemestre_id
|
) # check formsemestre_id
|
||||||
archive_id = PVArchive.get_id_from_name(context, formsemestre_id, archive_name)
|
archive_id = PVArchive.get_id_from_name(context, formsemestre_id, archive_name)
|
||||||
@ -565,4 +570,4 @@ def formsemestre_delete_archive(
|
|||||||
)
|
)
|
||||||
|
|
||||||
PVArchive.delete_archive(archive_id)
|
PVArchive.delete_archive(archive_id)
|
||||||
return REQUEST.RESPONSE.redirect(dest_url + "&head_message=Archive%20supprimée")
|
return REQUEST.RESPONSE.redirect(dest_url + "&head_message=Archive%20supprimée")
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
les dossiers d'admission et autres pièces utiles.
|
les dossiers d'admission et autres pièces utiles.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import ImportScolars
|
import ImportScolars
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
@ -38,6 +38,9 @@ import sco_groups
|
|||||||
import sco_trombino
|
import sco_trombino
|
||||||
import sco_excel
|
import sco_excel
|
||||||
import sco_archives
|
import sco_archives
|
||||||
|
from sco_permissions import ScoEtudAddAnnotations
|
||||||
|
from sco_exceptions import AccessDenied
|
||||||
|
from TrivialFormulator import TrivialFormulator
|
||||||
|
|
||||||
|
|
||||||
class EtudsArchiver(sco_archives.BaseArchiver):
|
class EtudsArchiver(sco_archives.BaseArchiver):
|
||||||
@ -65,10 +68,10 @@ def etud_list_archives_html(context, REQUEST, etudid):
|
|||||||
"content": EtudsArchive.list_archive(archive_id),
|
"content": EtudsArchive.list_archive(archive_id),
|
||||||
}
|
}
|
||||||
L.append(a)
|
L.append(a)
|
||||||
delete_icon = icontag(
|
delete_icon = scu.icontag(
|
||||||
"delete_small_img", title="Supprimer fichier", alt="supprimer"
|
"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"
|
"delete_small_dis_img", title="Suppression non autorisée"
|
||||||
)
|
)
|
||||||
H = ['<div class="etudarchive"><ul>']
|
H = ['<div class="etudarchive"><ul>']
|
||||||
@ -80,14 +83,14 @@ def etud_list_archives_html(context, REQUEST, etudid):
|
|||||||
)
|
)
|
||||||
for filename in a["content"]:
|
for filename in a["content"]:
|
||||||
H.append(
|
H.append(
|
||||||
"""<a class="stdlink etudarchive_link" href="etud_get_archived_file?etudid=%s&archive_name=%s&filename=%s">%s</a>"""
|
"""<a class="stdlink etudarchive_link" href="etud_get_archived_file?etudid=%s&archive_name=%s&filename=%s">%s</a>"""
|
||||||
% (etudid, archive_name, filename, filename)
|
% (etudid, archive_name, filename, filename)
|
||||||
)
|
)
|
||||||
if not a["content"]:
|
if not a["content"]:
|
||||||
H.append("<em>aucun fichier !</em>")
|
H.append("<em>aucun fichier !</em>")
|
||||||
if can_edit:
|
if can_edit:
|
||||||
H.append(
|
H.append(
|
||||||
'<span class="deletudarchive"><a class="smallbutton" href="etud_delete_archive?etudid=%s&archive_name=%s">%s</a></span>'
|
'<span class="deletudarchive"><a class="smallbutton" href="etud_delete_archive?etudid=%s&archive_name=%s">%s</a></span>'
|
||||||
% (etudid, archive_name, delete_icon)
|
% (etudid, archive_name, delete_icon)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -137,7 +140,7 @@ def etud_upload_file_form(context, REQUEST, etudid):
|
|||||||
% etud,
|
% etud,
|
||||||
"""<p>Le fichier ne doit pas dépasser %sMo.</p>
|
"""<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(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
REQUEST.URL0,
|
||||||
@ -161,7 +164,9 @@ def etud_upload_file_form(context, REQUEST, etudid):
|
|||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1 + "/ficheEtud?etudid=" + etudid)
|
return REQUEST.RESPONSE.redirect(
|
||||||
|
context.NotesURL() + "/ficheEtud?etudid=" + etudid
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
data = tf[2]["datafile"].read()
|
data = tf[2]["datafile"].read()
|
||||||
descr = tf[2]["description"]
|
descr = tf[2]["description"]
|
||||||
@ -169,7 +174,9 @@ def etud_upload_file_form(context, REQUEST, etudid):
|
|||||||
_store_etud_file_to_new_archive(
|
_store_etud_file_to_new_archive(
|
||||||
context, REQUEST, etudid, data, filename, description=descr
|
context, REQUEST, etudid, data, filename, description=descr
|
||||||
)
|
)
|
||||||
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(
|
def _store_etud_file_to_new_archive(
|
||||||
@ -177,7 +184,7 @@ def _store_etud_file_to_new_archive(
|
|||||||
):
|
):
|
||||||
"""Store data to new archive."""
|
"""Store data to new archive."""
|
||||||
filesize = len(data)
|
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
|
return 0, "Fichier image de taille invalide ! (%d)" % filesize
|
||||||
archive_id = EtudsArchive.create_obj_archive(context, etudid, description)
|
archive_id = EtudsArchive.create_obj_archive(context, etudid, description)
|
||||||
EtudsArchive.store(archive_id, filename, data)
|
EtudsArchive.store(archive_id, filename, data)
|
||||||
@ -209,7 +216,7 @@ def etud_delete_archive(context, REQUEST, etudid, archive_name, dialog_confirmed
|
|||||||
)
|
)
|
||||||
|
|
||||||
EtudsArchive.delete_archive(archive_id)
|
EtudsArchive.delete_archive(archive_id)
|
||||||
return REQUEST.RESPONSE.redirect(dest_url + "&head_message=Archive%20supprimée")
|
return REQUEST.RESPONSE.redirect(dest_url + "&head_message=Archive%20supprimée")
|
||||||
|
|
||||||
|
|
||||||
def etud_get_archived_file(context, REQUEST, etudid, archive_name, filename):
|
def etud_get_archived_file(context, REQUEST, etudid, archive_name, filename):
|
||||||
|
158
sco_bulletins.py
158
sco_bulletins.py
@ -28,23 +28,34 @@
|
|||||||
"""Génération des bulletins de notes
|
"""Génération des bulletins de notes
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
from types import StringType
|
||||||
from email.MIMEText import MIMEText
|
import pprint
|
||||||
from email.MIMEBase import MIMEBase
|
import urllib
|
||||||
from email.Header import Header
|
from email.MIMEMultipart import ( # pylint: disable=no-name-in-module,import-error
|
||||||
from email import Encoders
|
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
|
||||||
|
|
||||||
import htmlutils, time
|
import time
|
||||||
|
import htmlutils
|
||||||
from reportlab.lib.colors import Color
|
from reportlab.lib.colors import Color
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_table import *
|
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_formsemestre
|
||||||
import sco_groups
|
import sco_groups
|
||||||
import sco_pvjury
|
import sco_pvjury
|
||||||
import sco_formsemestre_status
|
import sco_formsemestre_status
|
||||||
import sco_photos
|
import sco_photos
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
import sco_abs_views
|
import sco_abs_views
|
||||||
import sco_preferences
|
import sco_preferences
|
||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
@ -111,7 +122,7 @@ def formsemestre_bulletinetud_dict(
|
|||||||
context, formsemestre_id
|
context, formsemestre_id
|
||||||
) # > toutes notes
|
) # > toutes notes
|
||||||
|
|
||||||
I = DictDefault(defaultvalue="")
|
I = scu.DictDefault(defaultvalue="")
|
||||||
I["etudid"] = etudid
|
I["etudid"] = etudid
|
||||||
I["formsemestre_id"] = formsemestre_id
|
I["formsemestre_id"] = formsemestre_id
|
||||||
I["sem"] = nt.sem
|
I["sem"] = nt.sem
|
||||||
@ -150,7 +161,7 @@ def formsemestre_bulletinetud_dict(
|
|||||||
context, pid
|
context, pid
|
||||||
)
|
)
|
||||||
# --- Absences
|
# --- Absences
|
||||||
AbsSemEtud = ZAbsences.getAbsSemEtud(context, nt.sem, etudid)
|
AbsSemEtud = sco_abs.getAbsSemEtud(context, nt.sem, etudid)
|
||||||
I["nbabs"] = AbsSemEtud.CountAbs()
|
I["nbabs"] = AbsSemEtud.CountAbs()
|
||||||
I["nbabsjust"] = AbsSemEtud.CountAbsJust()
|
I["nbabsjust"] = AbsSemEtud.CountAbsJust()
|
||||||
|
|
||||||
@ -179,7 +190,7 @@ def formsemestre_bulletinetud_dict(
|
|||||||
if I["etud_etat"] == "D":
|
if I["etud_etat"] == "D":
|
||||||
I["demission"] = "(Démission)"
|
I["demission"] = "(Démission)"
|
||||||
I["filigranne"] = "Démission"
|
I["filigranne"] = "Démission"
|
||||||
elif I["etud_etat"] == DEF:
|
elif I["etud_etat"] == sco_codes_parcours.DEF:
|
||||||
I["demission"] = "(Défaillant)"
|
I["demission"] = "(Défaillant)"
|
||||||
I["filigranne"] = "Défaillant"
|
I["filigranne"] = "Défaillant"
|
||||||
elif (prefs["bul_show_temporary"] and not I["decision_sem"]) or prefs[
|
elif (prefs["bul_show_temporary"] and not I["decision_sem"]) or prefs[
|
||||||
@ -203,16 +214,16 @@ def formsemestre_bulletinetud_dict(
|
|||||||
modimpls = nt.get_modimpls()
|
modimpls = nt.get_modimpls()
|
||||||
moy_gen = nt.get_etud_moy_gen(etudid)
|
moy_gen = nt.get_etud_moy_gen(etudid)
|
||||||
I["nb_inscrits"] = len(nt.rangs)
|
I["nb_inscrits"] = len(nt.rangs)
|
||||||
I["moy_gen"] = fmt_note(moy_gen)
|
I["moy_gen"] = scu.fmt_note(moy_gen)
|
||||||
I["moy_min"] = fmt_note(nt.moy_min)
|
I["moy_min"] = scu.fmt_note(nt.moy_min)
|
||||||
I["moy_max"] = fmt_note(nt.moy_max)
|
I["moy_max"] = scu.fmt_note(nt.moy_max)
|
||||||
I["mention"] = ""
|
I["mention"] = ""
|
||||||
if dpv:
|
if dpv:
|
||||||
decision_sem = dpv["decisions"][0]["decision_sem"]
|
decision_sem = dpv["decisions"][0]["decision_sem"]
|
||||||
if decision_sem and sco_codes_parcours.code_semestre_validant(
|
if decision_sem and sco_codes_parcours.code_semestre_validant(
|
||||||
decision_sem["code"]
|
decision_sem["code"]
|
||||||
):
|
):
|
||||||
I["mention"] = get_mention(moy_gen)
|
I["mention"] = scu.get_mention(moy_gen)
|
||||||
|
|
||||||
if dpv and dpv["decisions"][0]:
|
if dpv and dpv["decisions"][0]:
|
||||||
I["sum_ects"] = dpv["decisions"][0]["sum_ects"]
|
I["sum_ects"] = dpv["decisions"][0]["sum_ects"]
|
||||||
@ -220,7 +231,7 @@ def formsemestre_bulletinetud_dict(
|
|||||||
else:
|
else:
|
||||||
I["sum_ects"] = 0
|
I["sum_ects"] = 0
|
||||||
I["sum_ects_capitalises"] = 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:
|
if type(moy_gen) != StringType and type(nt.moy_moy) != StringType:
|
||||||
I["moy_gen_bargraph_html"] = " " + htmlutils.horizontal_bargraph(
|
I["moy_gen_bargraph_html"] = " " + htmlutils.horizontal_bargraph(
|
||||||
moy_gen * 5, nt.moy_moy * 5
|
moy_gen * 5, nt.moy_moy * 5
|
||||||
@ -240,8 +251,8 @@ def formsemestre_bulletinetud_dict(
|
|||||||
if nt.get_moduleimpls_attente():
|
if nt.get_moduleimpls_attente():
|
||||||
# n'affiche pas le rang sur le bulletin s'il y a des
|
# n'affiche pas le rang sur le bulletin s'il y a des
|
||||||
# notes en attente dans ce semestre
|
# notes en attente dans ce semestre
|
||||||
rang = RANG_ATTENTE_STR
|
rang = scu.RANG_ATTENTE_STR
|
||||||
rang_gr = DictDefault(defaultvalue=RANG_ATTENTE_STR)
|
rang_gr = scu.DictDefault(defaultvalue=scu.RANG_ATTENTE_STR)
|
||||||
I["rang"] = rang
|
I["rang"] = rang
|
||||||
I["rang_gr"] = rang_gr
|
I["rang_gr"] = rang_gr
|
||||||
I["gr_name"] = gr_name
|
I["gr_name"] = gr_name
|
||||||
@ -267,17 +278,17 @@ def formsemestre_bulletinetud_dict(
|
|||||||
u = ue.copy()
|
u = ue.copy()
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
||||||
u["ue_status"] = ue_status # { 'moy', 'coef_ue', ...}
|
u["ue_status"] = ue_status # { 'moy', 'coef_ue', ...}
|
||||||
if ue["type"] != UE_SPORT:
|
if ue["type"] != sco_codes_parcours.UE_SPORT:
|
||||||
u["cur_moy_ue_txt"] = fmt_note(ue_status["cur_moy_ue"])
|
u["cur_moy_ue_txt"] = scu.fmt_note(ue_status["cur_moy_ue"])
|
||||||
else:
|
else:
|
||||||
x = fmt_note(nt.bonus[etudid], keep_numeric=True)
|
x = scu.fmt_note(nt.bonus[etudid], keep_numeric=True)
|
||||||
if type(x) == StringType:
|
if type(x) == StringType:
|
||||||
u["cur_moy_ue_txt"] = "pas de bonus"
|
u["cur_moy_ue_txt"] = "pas de bonus"
|
||||||
else:
|
else:
|
||||||
u["cur_moy_ue_txt"] = "bonus de %.3g points" % x
|
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:
|
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:
|
else:
|
||||||
# C'est un bug:
|
# C'est un bug:
|
||||||
log("u=" + pprint.pformat(u))
|
log("u=" + pprint.pformat(u))
|
||||||
@ -289,7 +300,7 @@ def formsemestre_bulletinetud_dict(
|
|||||||
and ue["ue_id"] in dpv["decisions"][0]["decisions_ue"]
|
and ue["ue_id"] in dpv["decisions"][0]["decisions_ue"]
|
||||||
):
|
):
|
||||||
u["ects"] = dpv["decisions"][0]["decisions_ue"][ue["ue_id"]]["ects"]
|
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"] = (
|
u["ects"] = (
|
||||||
"%g+" % u["ects"]
|
"%g+" % u["ects"]
|
||||||
) # ajoute un "+" pour indiquer ECTS d'une UE élective
|
) # ajoute un "+" pour indiquer ECTS d'une UE élective
|
||||||
@ -313,12 +324,12 @@ def formsemestre_bulletinetud_dict(
|
|||||||
sem_origin = sco_formsemestre.get_formsemestre(
|
sem_origin = sco_formsemestre.get_formsemestre(
|
||||||
context, ue_status["formsemestre_id"]
|
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"]
|
ue_status["event_date"]
|
||||||
)
|
)
|
||||||
u[
|
u[
|
||||||
"ue_descr_html"
|
"ue_descr_html"
|
||||||
] = '<a href="formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s" title="%s" class="bull_link">%s</a>' % (
|
] = '<a href="formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s" title="%s" class="bull_link">%s</a>' % (
|
||||||
sem_origin["formsemestre_id"],
|
sem_origin["formsemestre_id"],
|
||||||
etudid,
|
etudid,
|
||||||
sem_origin["titreannee"],
|
sem_origin["titreannee"],
|
||||||
@ -331,7 +342,7 @@ def formsemestre_bulletinetud_dict(
|
|||||||
context, ue_status["formsemestre_id"]
|
context, ue_status["formsemestre_id"]
|
||||||
) # > toutes notes
|
) # > toutes notes
|
||||||
|
|
||||||
u["modules_capitalized"], junk = _ue_mod_bulletin(
|
u["modules_capitalized"], _ = _ue_mod_bulletin(
|
||||||
context,
|
context,
|
||||||
etudid,
|
etudid,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
@ -344,10 +355,10 @@ def formsemestre_bulletinetud_dict(
|
|||||||
_sort_mod_by_matiere(u["modules_capitalized"], nt_cap, etudid)
|
_sort_mod_by_matiere(u["modules_capitalized"], nt_cap, etudid)
|
||||||
)
|
)
|
||||||
else:
|
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():
|
if ue_attente: # nt.get_moduleimpls_attente():
|
||||||
u["ue_descr_txt"] = "%s/%s" % (
|
u["ue_descr_txt"] = "%s/%s" % (
|
||||||
RANG_ATTENTE_STR,
|
scu.RANG_ATTENTE_STR,
|
||||||
nt.ue_rangs[ue["ue_id"]][1],
|
nt.ue_rangs[ue["ue_id"]][1],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -383,7 +394,7 @@ def _sort_mod_by_matiere(modlist, nt, etudid):
|
|||||||
"titre": mod["mat"]["titre"],
|
"titre": mod["mat"]["titre"],
|
||||||
"modules": mod,
|
"modules": mod,
|
||||||
"moy": moy,
|
"moy": moy,
|
||||||
"moy_txt": fmt_note(moy),
|
"moy_txt": scu.fmt_note(moy),
|
||||||
}
|
}
|
||||||
return matmod
|
return matmod
|
||||||
|
|
||||||
@ -399,8 +410,8 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||||||
)
|
)
|
||||||
if bul_show_abs_modules:
|
if bul_show_abs_modules:
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
debut_sem = DateDMYtoISO(sem["date_debut"])
|
debut_sem = ndb.DateDMYtoISO(sem["date_debut"])
|
||||||
fin_sem = DateDMYtoISO(sem["date_fin"])
|
fin_sem = ndb.DateDMYtoISO(sem["date_fin"])
|
||||||
|
|
||||||
ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue_id]
|
ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue_id]
|
||||||
mods = [] # result
|
mods = [] # result
|
||||||
@ -411,7 +422,7 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||||||
mod_moy = nt.get_etud_mod_moy(
|
mod_moy = nt.get_etud_mod_moy(
|
||||||
modimpl["moduleimpl_id"], etudid
|
modimpl["moduleimpl_id"], etudid
|
||||||
) # peut etre 'NI'
|
) # 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:
|
if bul_show_abs_modules:
|
||||||
mod_abs = [
|
mod_abs = [
|
||||||
context.Absences.CountAbs(
|
context.Absences.CountAbs(
|
||||||
@ -427,25 +438,25 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||||||
moduleimpl_id=modimpl["moduleimpl_id"],
|
moduleimpl_id=modimpl["moduleimpl_id"],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
mod["mod_abs_txt"] = fmt_abs(mod_abs)
|
mod["mod_abs_txt"] = scu.fmt_abs(mod_abs)
|
||||||
else:
|
else:
|
||||||
mod["mod_abs_txt"] = ""
|
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":
|
if mod["mod_moy_txt"][:2] == "NA":
|
||||||
mod["mod_moy_txt"] = "-"
|
mod["mod_moy_txt"] = "-"
|
||||||
if is_malus:
|
if is_malus:
|
||||||
if mod_moy > 0:
|
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"
|
mod["mod_coef_txt"] = "Malus"
|
||||||
elif mod_moy < 0:
|
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"
|
mod["mod_coef_txt"] = "Bonus"
|
||||||
else:
|
else:
|
||||||
mod["mod_moy_txt"] = "-"
|
mod["mod_moy_txt"] = "-"
|
||||||
mod["mod_coef_txt"] = "-"
|
mod["mod_coef_txt"] = "-"
|
||||||
else:
|
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'
|
if mod["mod_moy_txt"] != "NI": # ne montre pas les modules 'non inscrit'
|
||||||
mods.append(mod)
|
mods.append(mod)
|
||||||
if is_malus: # n'affiche pas les statistiques sur les modules malus
|
if is_malus: # n'affiche pas les statistiques sur les modules malus
|
||||||
@ -461,7 +472,7 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||||||
mod["stats"] = nt.get_mod_stats(modimpl["moduleimpl_id"])
|
mod["stats"] = nt.get_mod_stats(modimpl["moduleimpl_id"])
|
||||||
mod["mod_descr_txt"] = "Module %s, coef. %s (%s)" % (
|
mod["mod_descr_txt"] = "Module %s, coef. %s (%s)" % (
|
||||||
modimpl["module"]["titre"],
|
modimpl["module"]["titre"],
|
||||||
fmt_coef(modimpl["module"]["coefficient"]),
|
scu.fmt_coef(modimpl["module"]["coefficient"]),
|
||||||
context.Users.user_info(modimpl["responsable_id"])["nomcomplet"],
|
context.Users.user_info(modimpl["responsable_id"])["nomcomplet"],
|
||||||
)
|
)
|
||||||
link_mod = (
|
link_mod = (
|
||||||
@ -480,7 +491,7 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||||||
|
|
||||||
mod_descr = "Module %s, coef. %s (%s)" % (
|
mod_descr = "Module %s, coef. %s (%s)" % (
|
||||||
modimpl["module"]["titre"],
|
modimpl["module"]["titre"],
|
||||||
fmt_coef(modimpl["module"]["coefficient"]),
|
scu.fmt_coef(modimpl["module"]["coefficient"]),
|
||||||
context.Users.user_info(modimpl["responsable_id"])["nomcomplet"],
|
context.Users.user_info(modimpl["responsable_id"])["nomcomplet"],
|
||||||
)
|
)
|
||||||
link_mod = (
|
link_mod = (
|
||||||
@ -511,7 +522,7 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||||||
else:
|
else:
|
||||||
e["name"] = e["description"] or "le %s" % e["jour"]
|
e["name"] = e["description"] or "le %s" % e["jour"]
|
||||||
e["target_html"] = (
|
e["target_html"] = (
|
||||||
"evaluation_listenotes?evaluation_id=%s&format=html&tf-submitted=1"
|
"evaluation_listenotes?evaluation_id=%s&format=html&tf-submitted=1"
|
||||||
% e["evaluation_id"]
|
% e["evaluation_id"]
|
||||||
)
|
)
|
||||||
e["name_html"] = '<a class="bull_link" href="%s">%s</a>' % (
|
e["name_html"] = '<a class="bull_link" href="%s">%s</a>' % (
|
||||||
@ -524,19 +535,21 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||||||
if val == "NP":
|
if val == "NP":
|
||||||
e["note_txt"] = "nd"
|
e["note_txt"] = "nd"
|
||||||
e["note_html"] = '<span class="note_nd">nd</span>'
|
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:
|
else:
|
||||||
# (-0.15) s'affiche "bonus de 0.15"
|
# (-0.15) s'affiche "bonus de 0.15"
|
||||||
if is_malus:
|
if is_malus:
|
||||||
val = abs(val)
|
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"]
|
e["note_html"] = e["note_txt"]
|
||||||
if is_malus:
|
if is_malus:
|
||||||
e["coef_txt"] = ""
|
e["coef_txt"] = ""
|
||||||
else:
|
else:
|
||||||
e["coef_txt"] = fmt_coef(e["coefficient"])
|
e["coef_txt"] = scu.fmt_coef(e["coefficient"])
|
||||||
if e["evaluation_type"] == EVALUATION_RATTRAPAGE:
|
if e["evaluation_type"] == scu.EVALUATION_RATTRAPAGE:
|
||||||
e["coef_txt"] = "rat."
|
e["coef_txt"] = "rat."
|
||||||
|
elif e["evaluation_type"] == scu.EVALUATION_SESSION2:
|
||||||
|
e["coef_txt"] = "sess. 2"
|
||||||
if e["etat"]["evalattente"]:
|
if e["etat"]["evalattente"]:
|
||||||
mod_attente = True # une eval en attente dans ce module
|
mod_attente = True # une eval en attente dans ce module
|
||||||
if (not is_malus) or (val != "NP"):
|
if (not is_malus) or (val != "NP"):
|
||||||
@ -558,7 +571,7 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||||||
mod["evaluations_incompletes"].append(e)
|
mod["evaluations_incompletes"].append(e)
|
||||||
e["name"] = (e["description"] or "") + " (%s)" % e["jour"]
|
e["name"] = (e["description"] or "") + " (%s)" % e["jour"]
|
||||||
e["target_html"] = (
|
e["target_html"] = (
|
||||||
"evaluation_listenotes?evaluation_id=%s&format=html&tf-submitted=1"
|
"evaluation_listenotes?evaluation_id=%s&format=html&tf-submitted=1"
|
||||||
% e["evaluation_id"]
|
% e["evaluation_id"]
|
||||||
)
|
)
|
||||||
e["name_html"] = '<a class="bull_link" href="%s">%s</a>' % (
|
e["name_html"] = '<a class="bull_link" href="%s">%s</a>' % (
|
||||||
@ -566,12 +579,12 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||||||
e["name"],
|
e["name"],
|
||||||
)
|
)
|
||||||
e["note_txt"] = e["note_html"] = ""
|
e["note_txt"] = e["note_html"] = ""
|
||||||
e["coef_txt"] = fmt_coef(e["coefficient"])
|
e["coef_txt"] = scu.fmt_coef(e["coefficient"])
|
||||||
# Classement
|
# Classement
|
||||||
if bul_show_mod_rangs and mod["mod_moy_txt"] != "-" and not is_malus:
|
if bul_show_mod_rangs and mod["mod_moy_txt"] != "-" and not is_malus:
|
||||||
rg = nt.mod_rangs[modimpl["moduleimpl_id"]]
|
rg = nt.mod_rangs[modimpl["moduleimpl_id"]]
|
||||||
if mod_attente: # nt.get_moduleimpls_attente():
|
if mod_attente: # nt.get_moduleimpls_attente():
|
||||||
mod["mod_rang"] = RANG_ATTENTE_STR
|
mod["mod_rang"] = scu.RANG_ATTENTE_STR
|
||||||
else:
|
else:
|
||||||
mod["mod_rang"] = rg[0][etudid]
|
mod["mod_rang"] = rg[0][etudid]
|
||||||
mod["mod_eff"] = rg[1] # effectif dans ce module
|
mod["mod_eff"] = rg[1] # effectif dans ce module
|
||||||
@ -636,7 +649,7 @@ def etud_descr_situation_semestre(
|
|||||||
descr_mention : 'Mention Bien', ou vide si pas de mention ou si pas show_mention
|
descr_mention : 'Mention Bien', ou vide si pas de mention ou si pas show_mention
|
||||||
"""
|
"""
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
infos = DictDefault(defaultvalue="")
|
infos = scu.DictDefault(defaultvalue="")
|
||||||
|
|
||||||
# --- Situation et décisions jury
|
# --- Situation et décisions jury
|
||||||
|
|
||||||
@ -647,7 +660,6 @@ def etud_descr_situation_semestre(
|
|||||||
date_inscr = None
|
date_inscr = None
|
||||||
date_dem = None
|
date_dem = None
|
||||||
date_def = None
|
date_def = None
|
||||||
date_echec = None
|
|
||||||
for event in events:
|
for event in events:
|
||||||
event_type = event["event_type"]
|
event_type = event["event_type"]
|
||||||
if event_type == "INSCRIPTION":
|
if event_type == "INSCRIPTION":
|
||||||
@ -764,7 +776,7 @@ def formsemestre_bulletinetud(
|
|||||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
except:
|
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)
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
|
|
||||||
@ -804,7 +816,7 @@ def formsemestre_bulletinetud(
|
|||||||
if sem["modalite"] == "EXT":
|
if sem["modalite"] == "EXT":
|
||||||
R.append(
|
R.append(
|
||||||
"""<p><a
|
"""<p><a
|
||||||
href="formsemestre_ext_edit_ue_validations?formsemestre_id=%s&etudid=%s"
|
href="formsemestre_ext_edit_ue_validations?formsemestre_id=%s&etudid=%s"
|
||||||
class="stdlink">
|
class="stdlink">
|
||||||
Editer les validations d'UE dans ce semestre extérieur
|
Editer les validations d'UE dans ce semestre extérieur
|
||||||
</a></p>"""
|
</a></p>"""
|
||||||
@ -886,7 +898,7 @@ def do_formsemestre_bulletinetud(
|
|||||||
etud = I["etud"]
|
etud = I["etud"]
|
||||||
|
|
||||||
if format == "html":
|
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
|
context, I, version=version, format="html", REQUEST=REQUEST
|
||||||
)
|
)
|
||||||
return htm, I["filigranne"]
|
return htm, I["filigranne"]
|
||||||
@ -902,7 +914,7 @@ def do_formsemestre_bulletinetud(
|
|||||||
)
|
)
|
||||||
if format == "pdf":
|
if format == "pdf":
|
||||||
return (
|
return (
|
||||||
sendPDFFile(REQUEST, bul, filename),
|
scu.sendPDFFile(REQUEST, bul, filename),
|
||||||
I["filigranne"],
|
I["filigranne"],
|
||||||
) # unused ret. value
|
) # unused ret. value
|
||||||
else:
|
else:
|
||||||
@ -917,7 +929,7 @@ def do_formsemestre_bulletinetud(
|
|||||||
if nohtml:
|
if nohtml:
|
||||||
htm = "" # speed up if html version not needed
|
htm = "" # speed up if html version not needed
|
||||||
else:
|
else:
|
||||||
htm, junk = sco_bulletins_generator.make_formsemestre_bulletinetud(
|
htm, _ = sco_bulletins_generator.make_formsemestre_bulletinetud(
|
||||||
context, I, version=version, format="html", REQUEST=REQUEST
|
context, I, version=version, format="html", REQUEST=REQUEST
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -961,7 +973,7 @@ def mail_bulletin(context, formsemestre_id, I, pdfdata, filename, recipient_addr
|
|||||||
"""
|
"""
|
||||||
etud = I["etud"]
|
etud = I["etud"]
|
||||||
webmaster = context.get_preference("bul_mail_contact_addr", formsemestre_id)
|
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)
|
copy_addr = context.get_preference("email_copy_bulletins", formsemestre_id)
|
||||||
intro_mail = context.get_preference("bul_intro_mail", formsemestre_id)
|
intro_mail = context.get_preference("bul_intro_mail", formsemestre_id)
|
||||||
|
|
||||||
@ -980,7 +992,7 @@ def mail_bulletin(context, formsemestre_id, I, pdfdata, filename, recipient_addr
|
|||||||
)
|
)
|
||||||
|
|
||||||
msg = MIMEMultipart()
|
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]
|
recipients = [recipient_addr]
|
||||||
msg["Subject"] = subj
|
msg["Subject"] = subj
|
||||||
msg["From"] = context.get_preference("email_from_addr", formsemestre_id)
|
msg["From"] = context.get_preference("email_from_addr", formsemestre_id)
|
||||||
@ -990,7 +1002,7 @@ def mail_bulletin(context, formsemestre_id, I, pdfdata, filename, recipient_addr
|
|||||||
# Guarantees the message ends in a newline
|
# Guarantees the message ends in a newline
|
||||||
msg.epilogue = ""
|
msg.epilogue = ""
|
||||||
# Text
|
# Text
|
||||||
txt = MIMEText(hea, "plain", SCO_ENCODING)
|
txt = MIMEText(hea, "plain", scu.SCO_ENCODING)
|
||||||
# log('hea:\n' + hea)
|
# log('hea:\n' + hea)
|
||||||
msg.attach(txt)
|
msg.attach(txt)
|
||||||
# Attach pdf
|
# Attach pdf
|
||||||
@ -1064,7 +1076,7 @@ def _formsemestre_bulletinetud_header_html(
|
|||||||
menuBul = [
|
menuBul = [
|
||||||
{
|
{
|
||||||
"title": "Réglages bulletins",
|
"title": "Réglages bulletins",
|
||||||
"url": "formsemestre_edit_options?formsemestre_id=%s&target_url=%s"
|
"url": "formsemestre_edit_options?formsemestre_id=%s&target_url=%s"
|
||||||
% (formsemestre_id, qurl),
|
% (formsemestre_id, qurl),
|
||||||
"enabled": (uid in sem["responsables"])
|
"enabled": (uid in sem["responsables"])
|
||||||
or authuser.has_permission(ScoImplement, context),
|
or authuser.has_permission(ScoImplement, context),
|
||||||
@ -1075,13 +1087,13 @@ def _formsemestre_bulletinetud_header_html(
|
|||||||
context, formsemestre_id
|
context, formsemestre_id
|
||||||
),
|
),
|
||||||
"url": url
|
"url": url
|
||||||
+ "?formsemestre_id=%s&etudid=%s&format=pdf&version=%s"
|
+ "?formsemestre_id=%s&etudid=%s&format=pdf&version=%s"
|
||||||
% (formsemestre_id, etudid, version),
|
% (formsemestre_id, etudid, version),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Envoi par mail à %s" % etud["email"],
|
"title": "Envoi par mail à %s" % etud["email"],
|
||||||
"url": url
|
"url": url
|
||||||
+ "?formsemestre_id=%s&etudid=%s&format=pdfmail&version=%s"
|
+ "?formsemestre_id=%s&etudid=%s&format=pdfmail&version=%s"
|
||||||
% (formsemestre_id, etudid, version),
|
% (formsemestre_id, etudid, version),
|
||||||
"enabled": etud["email"]
|
"enabled": etud["email"]
|
||||||
and can_send_bulletin_by_mail(
|
and can_send_bulletin_by_mail(
|
||||||
@ -1091,7 +1103,7 @@ def _formsemestre_bulletinetud_header_html(
|
|||||||
{
|
{
|
||||||
"title": "Envoi par mail à %s (adr. personnelle)" % etud["emailperso"],
|
"title": "Envoi par mail à %s (adr. personnelle)" % etud["emailperso"],
|
||||||
"url": url
|
"url": url
|
||||||
+ "?formsemestre_id=%s&etudid=%s&format=pdfmail&version=%s&prefer_mail_perso=1"
|
+ "?formsemestre_id=%s&etudid=%s&format=pdfmail&version=%s&prefer_mail_perso=1"
|
||||||
% (formsemestre_id, etudid, version),
|
% (formsemestre_id, etudid, version),
|
||||||
"enabled": etud["emailperso"]
|
"enabled": etud["emailperso"]
|
||||||
and can_send_bulletin_by_mail(
|
and can_send_bulletin_by_mail(
|
||||||
@ -1101,12 +1113,12 @@ def _formsemestre_bulletinetud_header_html(
|
|||||||
{
|
{
|
||||||
"title": "Version XML",
|
"title": "Version XML",
|
||||||
"url": url
|
"url": url
|
||||||
+ "?formsemestre_id=%s&etudid=%s&format=xml&version=%s"
|
+ "?formsemestre_id=%s&etudid=%s&format=xml&version=%s"
|
||||||
% (formsemestre_id, etudid, version),
|
% (formsemestre_id, etudid, version),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Ajouter une appréciation",
|
"title": "Ajouter une appréciation",
|
||||||
"url": "appreciation_add_form?etudid=%s&formsemestre_id=%s"
|
"url": "appreciation_add_form?etudid=%s&formsemestre_id=%s"
|
||||||
% (etudid, formsemestre_id),
|
% (etudid, formsemestre_id),
|
||||||
"enabled": (
|
"enabled": (
|
||||||
(authuser in sem["responsables"])
|
(authuser in sem["responsables"])
|
||||||
@ -1115,46 +1127,46 @@ def _formsemestre_bulletinetud_header_html(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Enregistrer un semestre effectué ailleurs",
|
"title": "Enregistrer un semestre effectué ailleurs",
|
||||||
"url": "formsemestre_ext_create_form?etudid=%s&formsemestre_id=%s"
|
"url": "formsemestre_ext_create_form?etudid=%s&formsemestre_id=%s"
|
||||||
% (etudid, formsemestre_id),
|
% (etudid, formsemestre_id),
|
||||||
"enabled": authuser.has_permission(ScoImplement, context),
|
"enabled": authuser.has_permission(ScoImplement, context),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Enregistrer une validation d'UE antérieure",
|
"title": "Enregistrer une validation d'UE antérieure",
|
||||||
"url": "formsemestre_validate_previous_ue?etudid=%s&formsemestre_id=%s"
|
"url": "formsemestre_validate_previous_ue?etudid=%s&formsemestre_id=%s"
|
||||||
% (etudid, formsemestre_id),
|
% (etudid, formsemestre_id),
|
||||||
"enabled": context._can_validate_sem(REQUEST, formsemestre_id),
|
"enabled": context._can_validate_sem(REQUEST, formsemestre_id),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Enregistrer note d'une UE externe",
|
"title": "Enregistrer note d'une UE externe",
|
||||||
"url": "external_ue_create_form?etudid=%s&formsemestre_id=%s"
|
"url": "external_ue_create_form?etudid=%s&formsemestre_id=%s"
|
||||||
% (etudid, formsemestre_id),
|
% (etudid, formsemestre_id),
|
||||||
"enabled": context._can_validate_sem(REQUEST, formsemestre_id),
|
"enabled": context._can_validate_sem(REQUEST, formsemestre_id),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Entrer décisions jury",
|
"title": "Entrer décisions jury",
|
||||||
"url": "formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s"
|
"url": "formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s"
|
||||||
% (formsemestre_id, etudid),
|
% (formsemestre_id, etudid),
|
||||||
"enabled": context._can_validate_sem(REQUEST, formsemestre_id),
|
"enabled": context._can_validate_sem(REQUEST, formsemestre_id),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Editer PV jury",
|
"title": "Editer PV jury",
|
||||||
"url": "formsemestre_pvjury_pdf?formsemestre_id=%s&etudid=%s"
|
"url": "formsemestre_pvjury_pdf?formsemestre_id=%s&etudid=%s"
|
||||||
% (formsemestre_id, etudid),
|
% (formsemestre_id, etudid),
|
||||||
"enabled": True,
|
"enabled": True,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
H.append("""<td class="bulletin_menubar"><div class="bulletin_menubar">""")
|
H.append("""<td class="bulletin_menubar"><div class="bulletin_menubar">""")
|
||||||
H.append(sco_formsemestre_status.makeMenu("Autres opérations", menuBul, alone=True))
|
H.append(htmlutils.make_menu("Autres opérations", menuBul, alone=True))
|
||||||
H.append("""</div></td>""")
|
H.append("""</div></td>""")
|
||||||
H.append(
|
H.append(
|
||||||
'<td> <a href="%s">%s</a></td>'
|
'<td> <a href="%s">%s</a></td>'
|
||||||
% (
|
% (
|
||||||
url
|
url
|
||||||
+ "?formsemestre_id=%s&etudid=%s&format=pdf&version=%s"
|
+ "?formsemestre_id=%s&etudid=%s&format=pdf&version=%s"
|
||||||
% (formsemestre_id, etudid, version),
|
% (formsemestre_id, etudid, version),
|
||||||
ICON_PDF,
|
scu.ICON_PDF,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
H.append("""</tr></table>""")
|
H.append("""</tr></table>""")
|
||||||
|
@ -28,12 +28,14 @@
|
|||||||
"""Generation bulletins de notes: exemple minimal pour les programmeurs
|
"""Generation bulletins de notes: exemple minimal pour les programmeurs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Quelques modules ScoDoc utiles:
|
import VERSION
|
||||||
from sco_pdf import *
|
import sco_utils as scu
|
||||||
|
import sco_pdf
|
||||||
import sco_preferences
|
import sco_preferences
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_bulletins_generator
|
import sco_bulletins_generator
|
||||||
import sco_bulletins_standard
|
import sco_bulletins_standard
|
||||||
|
from reportlab.platypus import Paragraph
|
||||||
|
|
||||||
|
|
||||||
class BulletinGeneratorExample(sco_bulletins_standard.BulletinGeneratorStandard):
|
class BulletinGeneratorExample(sco_bulletins_standard.BulletinGeneratorStandard):
|
||||||
@ -59,7 +61,7 @@ class BulletinGeneratorExample(sco_bulletins_standard.BulletinGeneratorStandard)
|
|||||||
assert format == "pdf" # garde fou
|
assert format == "pdf" # garde fou
|
||||||
return [
|
return [
|
||||||
Paragraph(
|
Paragraph(
|
||||||
SU(
|
sco_pdf.SU(
|
||||||
"L'étudiant %(nomprenom)s a une moyenne générale de %(moy_gen)s"
|
"L'étudiant %(nomprenom)s a une moyenne générale de %(moy_gen)s"
|
||||||
% self.infos
|
% self.infos
|
||||||
),
|
),
|
||||||
|
@ -42,12 +42,22 @@ La préférence 'bul_pdf_class_name' est obsolete (inutilisée).
|
|||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
import time
|
||||||
|
import cStringIO
|
||||||
import collections
|
import collections
|
||||||
|
import traceback
|
||||||
|
import reportlab
|
||||||
|
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Frame, PageBreak
|
||||||
|
from reportlab.platypus import Table, TableStyle, Image, KeepInFrame
|
||||||
|
|
||||||
|
import sco_utils
|
||||||
|
import VERSION
|
||||||
|
from sco_exceptions import NoteProcessError
|
||||||
import sco_preferences
|
import sco_preferences
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
from sco_pdf import *
|
import sco_pdf
|
||||||
|
from sco_pdf import PDFLOCK
|
||||||
|
|
||||||
BULLETIN_CLASSES = (
|
BULLETIN_CLASSES = (
|
||||||
collections.OrderedDict()
|
collections.OrderedDict()
|
||||||
@ -145,7 +155,7 @@ class BulletinGenerator:
|
|||||||
dt,
|
dt,
|
||||||
self.infos["etud"]["nom"],
|
self.infos["etud"]["nom"],
|
||||||
)
|
)
|
||||||
filename = unescape_html(filename).replace(" ", "_").replace("&", "")
|
filename = sco_utils.unescape_html(filename).replace(" ", "_").replace("&", "")
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
def generate(self, format="", stand_alone=True):
|
def generate(self, format="", stand_alone=True):
|
||||||
@ -166,8 +176,10 @@ class BulletinGenerator:
|
|||||||
def generate_html(self):
|
def generate_html(self):
|
||||||
"""Return bulletin as an HTML string"""
|
"""Return bulletin as an HTML string"""
|
||||||
H = ['<div class="notes_bulletin">']
|
H = ['<div class="notes_bulletin">']
|
||||||
H.append(self.bul_table(format="html")) # table des notes
|
# table des notes:
|
||||||
H.append(self.bul_part_below(format="html")) # infos sous la table
|
H.append(self.bul_table(format="html")) # pylint: disable=no-member
|
||||||
|
# infos sous la table:
|
||||||
|
H.append(self.bul_part_below(format="html")) # pylint: disable=no-member
|
||||||
H.append("</div>")
|
H.append("</div>")
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
@ -179,10 +191,14 @@ class BulletinGenerator:
|
|||||||
"""
|
"""
|
||||||
formsemestre_id = self.infos["formsemestre_id"]
|
formsemestre_id = self.infos["formsemestre_id"]
|
||||||
|
|
||||||
objects = self.bul_title_pdf() # partie haute du bulletin
|
# partie haute du bulletin
|
||||||
objects += self.bul_table(format="pdf") # table des notes
|
objects = self.bul_title_pdf() # pylint: disable=no-member
|
||||||
objects += self.bul_part_below(format="pdf") # infos sous la table
|
# table des notes
|
||||||
objects += self.bul_signatures_pdf() # signatures
|
objects += self.bul_table(format="pdf") # pylint: disable=no-member
|
||||||
|
# infos sous la table
|
||||||
|
objects += self.bul_part_below(format="pdf") # pylint: disable=no-member
|
||||||
|
# signatures
|
||||||
|
objects += self.bul_signatures_pdf() # pylint: disable=no-member
|
||||||
|
|
||||||
# Réduit sur une page
|
# Réduit sur une page
|
||||||
objects = [KeepInFrame(0, 0, objects, mode="shrink")]
|
objects = [KeepInFrame(0, 0, objects, mode="shrink")]
|
||||||
@ -194,13 +210,13 @@ class BulletinGenerator:
|
|||||||
# Generation du document PDF
|
# Generation du document PDF
|
||||||
sem = sco_formsemestre.get_formsemestre(self.context, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(self.context, formsemestre_id)
|
||||||
report = cStringIO.StringIO() # in-memory document, no disk file
|
report = cStringIO.StringIO() # in-memory document, no disk file
|
||||||
document = BaseDocTemplate(report)
|
document = sco_pdf.BaseDocTemplate(report)
|
||||||
document.addPageTemplates(
|
document.addPageTemplates(
|
||||||
ScolarsPageTemplate(
|
sco_pdf.ScolarsPageTemplate(
|
||||||
document,
|
document,
|
||||||
self.context,
|
context=self.context,
|
||||||
author="%s %s (E. Viennet) [%s]"
|
author="%s %s (E. Viennet) [%s]"
|
||||||
% (SCONAME, SCOVERSION, self.description),
|
% (VERSION.SCONAME, VERSION.SCOVERSION, self.description),
|
||||||
title="Bulletin %s de %s"
|
title="Bulletin %s de %s"
|
||||||
% (sem["titremois"], self.infos["etud"]["nomprenom"]),
|
% (sem["titremois"], self.infos["etud"]["nomprenom"]),
|
||||||
subject="Bulletin de note",
|
subject="Bulletin de note",
|
||||||
@ -222,7 +238,9 @@ class BulletinGenerator:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# put each table cell in a Paragraph
|
# put each table cell in a Paragraph
|
||||||
Pt = [[Paragraph(SU(x), self.CellStyle) for x in line] for line in P]
|
Pt = [
|
||||||
|
[Paragraph(sco_pdf.SU(x), self.CellStyle) for x in line] for line in P
|
||||||
|
]
|
||||||
except:
|
except:
|
||||||
# enquête sur exception intermittente...
|
# enquête sur exception intermittente...
|
||||||
log("*** bug in PDF buildTableObject:")
|
log("*** bug in PDF buildTableObject:")
|
||||||
|
@ -28,13 +28,16 @@
|
|||||||
"""Génération du bulletin en format JSON (beta, non completement testé)
|
"""Génération du bulletin en format JSON (beta, non completement testé)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from notes_table import *
|
import sco_utils as scu
|
||||||
|
import notesdb as ndb
|
||||||
|
import scolars
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_groups
|
import sco_groups
|
||||||
import sco_photos
|
import sco_photos
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
import sco_bulletins
|
import sco_bulletins
|
||||||
|
|
||||||
# -------- Bulletin en JSON
|
# -------- Bulletin en JSON
|
||||||
@ -62,9 +65,9 @@ def make_json_formsemestre_bulletinetud(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if REQUEST:
|
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()
|
# (fonction séparée: n'utilise pas formsemestre_bulletinetud_dict()
|
||||||
@ -119,16 +122,16 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
code_nip=etudinfo["code_nip"],
|
code_nip=etudinfo["code_nip"],
|
||||||
code_ine=etudinfo["code_ine"],
|
code_ine=etudinfo["code_ine"],
|
||||||
nom=quote_xml_attr(etudinfo["nom"]),
|
nom=scu.quote_xml_attr(etudinfo["nom"]),
|
||||||
prenom=quote_xml_attr(etudinfo["prenom"]),
|
prenom=scu.quote_xml_attr(etudinfo["prenom"]),
|
||||||
sexe=quote_xml_attr(etudinfo["sexe"]),
|
civilite=scu.quote_xml_attr(etudinfo["civilite_str"]),
|
||||||
photo_url=quote_xml_attr(
|
photo_url=scu.quote_xml_attr(
|
||||||
sco_photos.etud_photo_url(context, etudinfo, fast=True)
|
sco_photos.etud_photo_url(context, etudinfo, fast=True)
|
||||||
),
|
),
|
||||||
email=quote_xml_attr(etudinfo["email"]),
|
email=scu.quote_xml_attr(etudinfo["email"]),
|
||||||
emailperso=quote_xml_attr(etudinfo["emailperso"]),
|
emailperso=scu.quote_xml_attr(etudinfo["emailperso"]),
|
||||||
)
|
)
|
||||||
|
d["etudiant"]["sexe"] = d["etudiant"]["civilite"] # backward compat for our clients
|
||||||
# Disponible pour publication ?
|
# Disponible pour publication ?
|
||||||
if not published:
|
if not published:
|
||||||
return d # stop !
|
return d # stop !
|
||||||
@ -150,7 +153,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
ues = nt.get_ues()
|
ues = nt.get_ues()
|
||||||
modimpls = nt.get_modimpls()
|
modimpls = nt.get_modimpls()
|
||||||
nbetuds = len(nt.rangs)
|
nbetuds = len(nt.rangs)
|
||||||
mg = fmt_note(nt.get_etud_moy_gen(etudid))
|
mg = scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
||||||
if (
|
if (
|
||||||
nt.get_moduleimpls_attente()
|
nt.get_moduleimpls_attente()
|
||||||
or context.get_preference("bul_show_rangs", formsemestre_id) == 0
|
or context.get_preference("bul_show_rangs", formsemestre_id) == 0
|
||||||
@ -168,9 +171,9 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
|
|
||||||
d["note"] = dict(
|
d["note"] = dict(
|
||||||
value=mg,
|
value=mg,
|
||||||
min=fmt_note(nt.moy_min),
|
min=scu.fmt_note(nt.moy_min),
|
||||||
max=fmt_note(nt.moy_max),
|
max=scu.fmt_note(nt.moy_max),
|
||||||
moy=fmt_note(nt.moy_moy),
|
moy=scu.fmt_note(nt.moy_moy),
|
||||||
)
|
)
|
||||||
d["rang"] = dict(value=rang, ninscrits=nbetuds)
|
d["rang"] = dict(value=rang, ninscrits=nbetuds)
|
||||||
d["rang_group"] = []
|
d["rang_group"] = []
|
||||||
@ -199,25 +202,28 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
ects_txt = ""
|
ects_txt = ""
|
||||||
u = dict(
|
u = dict(
|
||||||
id=ue["ue_id"],
|
id=ue["ue_id"],
|
||||||
numero=quote_xml_attr(ue["numero"]),
|
numero=scu.quote_xml_attr(ue["numero"]),
|
||||||
acronyme=quote_xml_attr(ue["acronyme"]),
|
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||||
titre=quote_xml_attr(ue["titre"]),
|
titre=scu.quote_xml_attr(ue["titre"]),
|
||||||
note=dict(
|
note=dict(
|
||||||
value=fmt_note(ue_status["cur_moy_ue"]),
|
value=scu.fmt_note(ue_status["cur_moy_ue"]),
|
||||||
min=fmt_note(ue["min"]),
|
min=scu.fmt_note(ue["min"]),
|
||||||
max=fmt_note(ue["max"]),
|
max=scu.fmt_note(ue["max"]),
|
||||||
|
moy=scu.fmt_note(ue["moy"]), # CM : ajout pour faire apparaitre la moyenne des UE
|
||||||
),
|
),
|
||||||
rang=str(nt.ue_rangs[ue["ue_id"]][0][etudid]),
|
rang=str(nt.ue_rangs[ue["ue_id"]][0][etudid]),
|
||||||
effectif=str(nt.ue_rangs[ue["ue_id"]][1]),
|
effectif=str(nt.ue_rangs[ue["ue_id"]][1]),
|
||||||
ects=ects_txt,
|
ects=ects_txt,
|
||||||
code_apogee=quote_xml_attr(ue["code_apogee"]),
|
code_apogee=scu.quote_xml_attr(ue["code_apogee"]),
|
||||||
)
|
)
|
||||||
d["ue"].append(u)
|
d["ue"].append(u)
|
||||||
u["module"] = []
|
u["module"] = []
|
||||||
# Liste les modules de l'UE
|
# Liste les modules de l'UE
|
||||||
ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]]
|
ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]]
|
||||||
for modimpl in ue_modimpls:
|
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
|
if mod_moy == "NI": # ne mentionne pas les modules ou n'est pas inscrit
|
||||||
continue
|
continue
|
||||||
mod = modimpl["module"]
|
mod = modimpl["module"]
|
||||||
@ -232,15 +238,15 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
code=mod["code"],
|
code=mod["code"],
|
||||||
coefficient=mod["coefficient"],
|
coefficient=mod["coefficient"],
|
||||||
numero=mod["numero"],
|
numero=mod["numero"],
|
||||||
titre=quote_xml_attr(mod["titre"]),
|
titre=scu.quote_xml_attr(mod["titre"]),
|
||||||
abbrev=quote_xml_attr(mod["abbrev"]),
|
abbrev=scu.quote_xml_attr(mod["abbrev"]),
|
||||||
# ects=ects, ects des modules maintenant inutilisés
|
# ects=ects, ects des modules maintenant inutilisés
|
||||||
note=dict(value=mod_moy),
|
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)
|
m["note"].update(modstat)
|
||||||
for k in ("min", "max", "moy"): # formatte toutes les notes
|
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)
|
u["module"].append(m)
|
||||||
if context.get_preference("bul_show_mod_rangs", formsemestre_id):
|
if context.get_preference("bul_show_mod_rangs", formsemestre_id):
|
||||||
@ -258,19 +264,20 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
val = e["notes"].get(etudid, {"value": "NP"})[
|
val = e["notes"].get(etudid, {"value": "NP"})[
|
||||||
"value"
|
"value"
|
||||||
] # NA si etud demissionnaire
|
] # 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(
|
m["evaluation"].append(
|
||||||
dict(
|
dict(
|
||||||
jour=DateDMYtoISO(e["jour"], null_is_empty=True),
|
jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||||
heure_debut=TimetoISO8601(
|
heure_debut=ndb.TimetoISO8601(
|
||||||
e["heure_debut"], null_is_empty=True
|
e["heure_debut"], null_is_empty=True
|
||||||
),
|
),
|
||||||
heure_fin=TimetoISO8601(
|
heure_fin=ndb.TimetoISO8601(
|
||||||
e["heure_fin"], null_is_empty=True
|
e["heure_fin"], null_is_empty=True
|
||||||
),
|
),
|
||||||
coefficient=e["coefficient"],
|
coefficient=e["coefficient"],
|
||||||
evaluation_type=e["evaluation_type"],
|
evaluation_type=e["evaluation_type"],
|
||||||
description=quote_xml_attr(e["description"]),
|
evaluation_id=e["evaluation_id"], # CM : ajout pour permettre de faire le lien sur les bulletins en ligne avec l'évaluation
|
||||||
|
description=scu.quote_xml_attr(e["description"]),
|
||||||
note=val,
|
note=val,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -285,15 +292,17 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
if e["evaluation_id"] not in complete_eval_ids:
|
if e["evaluation_id"] not in complete_eval_ids:
|
||||||
m["evaluation"].append(
|
m["evaluation"].append(
|
||||||
dict(
|
dict(
|
||||||
jour=DateDMYtoISO(e["jour"], null_is_empty=True),
|
jour=ndb.DateDMYtoISO(
|
||||||
heure_debut=TimetoISO8601(
|
e["jour"], null_is_empty=True
|
||||||
|
),
|
||||||
|
heure_debut=ndb.TimetoISO8601(
|
||||||
e["heure_debut"], null_is_empty=True
|
e["heure_debut"], null_is_empty=True
|
||||||
),
|
),
|
||||||
heure_fin=TimetoISO8601(
|
heure_fin=ndb.TimetoISO8601(
|
||||||
e["heure_fin"], null_is_empty=True
|
e["heure_fin"], null_is_empty=True
|
||||||
),
|
),
|
||||||
coefficient=e["coefficient"],
|
coefficient=e["coefficient"],
|
||||||
description=quote_xml_attr(e["description"]),
|
description=scu.quote_xml_attr(e["description"]),
|
||||||
incomplete="1",
|
incomplete="1",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -307,21 +316,19 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
d["ue_capitalisee"].append(
|
d["ue_capitalisee"].append(
|
||||||
dict(
|
dict(
|
||||||
id=ue["ue_id"],
|
id=ue["ue_id"],
|
||||||
numero=quote_xml_attr(ue["numero"]),
|
numero=scu.quote_xml_attr(ue["numero"]),
|
||||||
acronyme=quote_xml_attr(ue["acronyme"]),
|
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||||
titre=quote_xml_attr(ue["titre"]),
|
titre=scu.quote_xml_attr(ue["titre"]),
|
||||||
note=fmt_note(ue_status["moy"]),
|
note=scu.fmt_note(ue_status["moy"]),
|
||||||
coefficient_ue=fmt_note(ue_status["coef_ue"]),
|
coefficient_ue=scu.fmt_note(ue_status["coef_ue"]),
|
||||||
date_capitalisation=DateDMYtoISO(ue_status["event_date"]),
|
date_capitalisation=ndb.DateDMYtoISO(ue_status["event_date"]),
|
||||||
ects=ects_txt,
|
ects=ects_txt,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Absences
|
# --- Absences
|
||||||
if context.get_preference("bul_show_abs", formsemestre_id):
|
if context.get_preference("bul_show_abs", formsemestre_id):
|
||||||
debut_sem = DateDMYtoISO(sem["date_debut"])
|
AbsEtudSem = sco_abs.getAbsSemEtud(context, sem, etudid)
|
||||||
fin_sem = DateDMYtoISO(sem["date_fin"])
|
|
||||||
AbsEtudSem = ZAbsences.getAbsSemEtud(context, sem, etudid)
|
|
||||||
nbabs = AbsEtudSem.CountAbs()
|
nbabs = AbsEtudSem.CountAbs()
|
||||||
nbabsjust = AbsEtudSem.CountAbsJust()
|
nbabsjust = AbsEtudSem.CountAbsJust()
|
||||||
|
|
||||||
@ -339,7 +346,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
format="xml",
|
format="xml",
|
||||||
show_uevalid=context.get_preference("bul_show_uevalid", formsemestre_id),
|
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:
|
if dpv:
|
||||||
decision = dpv["decisions"][0]
|
decision = dpv["decisions"][0]
|
||||||
etat = decision["etat"]
|
etat = decision["etat"]
|
||||||
@ -366,11 +373,11 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
d["decision_ue"].append(
|
d["decision_ue"].append(
|
||||||
dict(
|
dict(
|
||||||
ue_id=ue["ue_id"],
|
ue_id=ue["ue_id"],
|
||||||
numero=quote_xml_attr(ue["numero"]),
|
numero=scu.quote_xml_attr(ue["numero"]),
|
||||||
acronyme=quote_xml_attr(ue["acronyme"]),
|
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||||
titre=quote_xml_attr(ue["titre"]),
|
titre=scu.quote_xml_attr(ue["titre"]),
|
||||||
code=decision["decisions_ue"][ue_id]["code"],
|
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"] = []
|
d["autorisation_inscription"] = []
|
||||||
@ -389,7 +396,10 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
d["appreciation"] = []
|
d["appreciation"] = []
|
||||||
for app in apprecs:
|
for app in apprecs:
|
||||||
d["appreciation"].append(
|
d["appreciation"].append(
|
||||||
dict(comment=quote_xml_attr(app["comment"]), date=DateDMYtoISO(app["date"]))
|
dict(
|
||||||
|
comment=scu.quote_xml_attr(app["comment"]),
|
||||||
|
date=ndb.DateDMYtoISO(app["date"]),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -37,8 +37,13 @@
|
|||||||
|
|
||||||
import traceback, re
|
import traceback, re
|
||||||
|
|
||||||
|
import sco_utils as scu
|
||||||
|
from sco_permissions import ScoEtudInscrit
|
||||||
import sco_formsemestre
|
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
|
import sco_preferences
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_bulletins_generator
|
import sco_bulletins_generator
|
||||||
@ -81,9 +86,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
|||||||
|
|
||||||
def bul_table_html(self):
|
def bul_table_html(self):
|
||||||
"""Génère la table centrale du bulletin de notes: chaine HTML"""
|
"""Génère la table centrale du bulletin de notes: chaine HTML"""
|
||||||
format = "html"
|
|
||||||
I = self.infos
|
I = self.infos
|
||||||
authuser = self.authuser
|
|
||||||
formsemestre_id = self.infos["formsemestre_id"]
|
formsemestre_id = self.infos["formsemestre_id"]
|
||||||
context = self.context
|
context = self.context
|
||||||
|
|
||||||
@ -98,8 +101,8 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
|||||||
bgcolor = "background-color: rgb(255,255,240)"
|
bgcolor = "background-color: rgb(255,255,240)"
|
||||||
|
|
||||||
linktmpl = '<span onclick="toggle_vis_ue(this);" class="toggle_ue">%s</span>'
|
linktmpl = '<span onclick="toggle_vis_ue(this);" class="toggle_ue">%s</span>'
|
||||||
minuslink = linktmpl % icontag("minus_img", border="0", alt="-")
|
minuslink = linktmpl % scu.icontag("minus_img", border="0", alt="-")
|
||||||
pluslink = linktmpl % icontag("plus_img", border="0", alt="+")
|
pluslink = linktmpl % scu.icontag("plus_img", border="0", alt="+")
|
||||||
|
|
||||||
H = ['<table class="notes_bulletin" style="background-color: %s;">' % bgcolor]
|
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):
|
if context.get_preference("bul_show_minmax_mod", formsemestre_id):
|
||||||
rang_minmax = '%s <span class="bul_minmax" title="[min, max] UE">[%s, %s]</span>' % (
|
rang_minmax = '%s <span class="bul_minmax" title="[min, max] UE">[%s, %s]</span>' % (
|
||||||
mod["mod_rang_txt"],
|
mod["mod_rang_txt"],
|
||||||
fmt_note(mod["stats"]["min"]),
|
scu.fmt_note(mod["stats"]["min"]),
|
||||||
fmt_note(mod["stats"]["max"]),
|
scu.fmt_note(mod["stats"]["max"]),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
rang_minmax = mod["mod_rang_txt"] # vide si pas option rang
|
rang_minmax = mod["mod_rang_txt"] # vide si pas option rang
|
||||||
@ -209,9 +212,9 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
|||||||
moy_txt = (
|
moy_txt = (
|
||||||
'%s <span class="bul_minmax" title="[min, max] UE">[%s, %s]</span>'
|
'%s <span class="bul_minmax" title="[min, max] UE">[%s, %s]</span>'
|
||||||
% (
|
% (
|
||||||
fmt_note(ue["cur_moy_ue_txt"]),
|
scu.fmt_note(ue["cur_moy_ue_txt"]),
|
||||||
fmt_note(ue["min"]),
|
scu.fmt_note(ue["min"]),
|
||||||
fmt_note(ue["max"]),
|
scu.fmt_note(ue["max"]),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -321,7 +324,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
|||||||
for app in I["appreciations_list"]:
|
for app in I["appreciations_list"]:
|
||||||
if can_edit_app:
|
if can_edit_app:
|
||||||
mlink = (
|
mlink = (
|
||||||
'<a class="stdlink" href="appreciation_add_form?id=%s">modifier</a> <a class="stdlink" href="appreciation_add_form?id=%s&suppress=1">supprimer</a>'
|
'<a class="stdlink" href="appreciation_add_form?id=%s">modifier</a> <a class="stdlink" href="appreciation_add_form?id=%s&suppress=1">supprimer</a>'
|
||||||
% (app["id"], app["id"])
|
% (app["id"], app["id"])
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -332,7 +335,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
|||||||
)
|
)
|
||||||
if can_edit_app:
|
if can_edit_app:
|
||||||
H.append(
|
H.append(
|
||||||
'<p><a class="stdlink" href="appreciation_add_form?etudid=%(etudid)s&formsemestre_id=%(formsemestre_id)s">Ajouter une appréciation</a></p>'
|
'<p><a class="stdlink" href="appreciation_add_form?etudid=%(etudid)s&formsemestre_id=%(formsemestre_id)s">Ajouter une appréciation</a></p>'
|
||||||
% self.infos
|
% self.infos
|
||||||
)
|
)
|
||||||
H.append("</div>")
|
H.append("</div>")
|
||||||
@ -441,7 +444,6 @@ def _bulletin_pdf_table_legacy(context, I, version="long"):
|
|||||||
S = BulTableStyle()
|
S = BulTableStyle()
|
||||||
P = [] # elems pour gen. pdf
|
P = [] # elems pour gen. pdf
|
||||||
formsemestre_id = I["formsemestre_id"]
|
formsemestre_id = I["formsemestre_id"]
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
|
||||||
bul_show_abs_modules = context.get_preference(
|
bul_show_abs_modules = context.get_preference(
|
||||||
"bul_show_abs_modules", formsemestre_id
|
"bul_show_abs_modules", formsemestre_id
|
||||||
)
|
)
|
||||||
@ -460,7 +462,7 @@ def _bulletin_pdf_table_legacy(context, I, version="long"):
|
|||||||
]
|
]
|
||||||
if bul_show_abs_modules:
|
if bul_show_abs_modules:
|
||||||
t.append("Abs (J. / N.J.)")
|
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):
|
def list_modules(ue_modules, ue_type=None):
|
||||||
"ajoute les lignes decrivant les modules d'une UE, avec eventuellement les évaluations de chacun"
|
"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):
|
if context.get_preference("bul_show_minmax_mod", formsemestre_id):
|
||||||
rang_minmax = '%s <font size="8">[%s, %s]</font>' % (
|
rang_minmax = '%s <font size="8">[%s, %s]</font>' % (
|
||||||
mod["mod_rang_txt"],
|
mod["mod_rang_txt"],
|
||||||
fmt_note(mod["stats"]["min"]),
|
scu.fmt_note(mod["stats"]["min"]),
|
||||||
fmt_note(mod["stats"]["max"]),
|
scu.fmt_note(mod["stats"]["max"]),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
rang_minmax = mod["mod_rang_txt"] # vide si pas option rang
|
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]
|
t = [ue["acronyme"], ue["moy_ue_txt"], ue_descr, "", coef_ue]
|
||||||
if bul_show_abs_modules:
|
if bul_show_abs_modules:
|
||||||
t.append("")
|
t.append("")
|
||||||
P.append(bold_paras(t))
|
P.append(sco_pdf.bold_paras(t))
|
||||||
coef_ue = ""
|
coef_ue = ""
|
||||||
ue_descr = "(en cours, non prise en compte)"
|
ue_descr = "(en cours, non prise en compte)"
|
||||||
S.ueline()
|
S.ueline()
|
||||||
@ -523,7 +525,7 @@ def _bulletin_pdf_table_legacy(context, I, version="long"):
|
|||||||
t = [ue["acronyme"], moy_txt, ue_descr, "", coef_ue]
|
t = [ue["acronyme"], moy_txt, ue_descr, "", coef_ue]
|
||||||
if bul_show_abs_modules:
|
if bul_show_abs_modules:
|
||||||
t.append("")
|
t.append("")
|
||||||
P.append(bold_paras(t))
|
P.append(sco_pdf.bold_paras(t))
|
||||||
S.ueline()
|
S.ueline()
|
||||||
list_modules(ue["modules"], ue_type=ue_type)
|
list_modules(ue["modules"], ue_type=ue_type)
|
||||||
|
|
||||||
|
@ -50,13 +50,21 @@ Pour définir un nouveau type de bulletin:
|
|||||||
Chaque semestre peut si nécessaire utiliser un type de bulletin différent.
|
Chaque semestre peut si nécessaire utiliser un type de bulletin différent.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import htmlutils, time
|
import htmlutils
|
||||||
import pprint, traceback
|
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
|
import sco_bulletins
|
||||||
|
|
||||||
from sco_pdf import *
|
import sco_pdf
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
@ -84,10 +92,10 @@ def pdfassemblebulletins(
|
|||||||
report = cStringIO.StringIO() # in-memory document, no disk file
|
report = cStringIO.StringIO() # in-memory document, no disk file
|
||||||
document = BaseDocTemplate(report)
|
document = BaseDocTemplate(report)
|
||||||
document.addPageTemplates(
|
document.addPageTemplates(
|
||||||
ScolarsPageTemplate(
|
sco_pdf.ScolarsPageTemplate(
|
||||||
document,
|
document,
|
||||||
context,
|
context=context,
|
||||||
author="%s %s (E. Viennet)" % (SCONAME, SCOVERSION),
|
author="%s %s (E. Viennet)" % (VERSION.SCONAME, VERSION.SCOVERSION),
|
||||||
title="Bulletin %s" % bul_title,
|
title="Bulletin %s" % bul_title,
|
||||||
subject="Bulletin de note",
|
subject="Bulletin de note",
|
||||||
server_name=server_name,
|
server_name=server_name,
|
||||||
@ -117,7 +125,7 @@ def process_field(
|
|||||||
If format = 'html', replaces <para> by <p>. HTML does not allow logos.
|
If format = 'html', replaces <para> by <p>. HTML does not allow logos.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
text = (field or "") % WrapDict(
|
text = (field or "") % scu.WrapDict(
|
||||||
cdict
|
cdict
|
||||||
) # note that None values are mapped to empty strings
|
) # note that None values are mapped to empty strings
|
||||||
except:
|
except:
|
||||||
@ -135,9 +143,9 @@ def process_field(
|
|||||||
return text
|
return text
|
||||||
# --- PDF format:
|
# --- PDF format:
|
||||||
# handle logos:
|
# 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):
|
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(
|
text = re.sub(
|
||||||
r"<(\s*)logo(.*?)src\s*=\s*(.*?)>", r"<\1logo\2\3>", text
|
r"<(\s*)logo(.*?)src\s*=\s*(.*?)>", r"<\1logo\2\3>", text
|
||||||
) # remove forbidden src attribute
|
) # remove forbidden src attribute
|
||||||
@ -150,7 +158,7 @@ def process_field(
|
|||||||
# tentatives d'acceder à d'autres fichiers !
|
# tentatives d'acceder à d'autres fichiers !
|
||||||
|
|
||||||
# log('field: %s' % (text))
|
# 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(
|
def get_formsemestre_bulletins_pdf(
|
||||||
@ -180,7 +188,7 @@ def get_formsemestre_bulletins_pdf(
|
|||||||
)
|
)
|
||||||
fragments += frag
|
fragments += frag
|
||||||
filigrannes[i] = filigranne
|
filigrannes[i] = filigranne
|
||||||
bookmarks[i] = suppress_accents(nt.get_sexnom(etudid))
|
bookmarks[i] = scu.suppress_accents(nt.get_sexnom(etudid))
|
||||||
i = i + 1
|
i = i + 1
|
||||||
#
|
#
|
||||||
infos = {"DeptName": context.get_preference("DeptName", formsemestre_id)}
|
infos = {"DeptName": context.get_preference("DeptName", formsemestre_id)}
|
||||||
@ -189,7 +197,7 @@ def get_formsemestre_bulletins_pdf(
|
|||||||
else:
|
else:
|
||||||
server_name = ""
|
server_name = ""
|
||||||
try:
|
try:
|
||||||
PDFLOCK.acquire()
|
sco_pdf.PDFLOCK.acquire()
|
||||||
pdfdoc = pdfassemblebulletins(
|
pdfdoc = pdfassemblebulletins(
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
fragments,
|
fragments,
|
||||||
@ -201,11 +209,11 @@ def get_formsemestre_bulletins_pdf(
|
|||||||
context=context,
|
context=context,
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
PDFLOCK.release()
|
sco_pdf.PDFLOCK.release()
|
||||||
#
|
#
|
||||||
dt = time.strftime("%Y-%m-%d")
|
dt = time.strftime("%Y-%m-%d")
|
||||||
filename = "bul-%s-%s.pdf" % (sem["titre_num"], dt)
|
filename = "bul-%s-%s.pdf" % (sem["titre_num"], dt)
|
||||||
filename = unescape_html(filename).replace(" ", "_").replace("&", "")
|
filename = scu.unescape_html(filename).replace(" ", "_").replace("&", "")
|
||||||
# fill cache
|
# fill cache
|
||||||
context._getNotesCache().store_bulletins_pdf(
|
context._getNotesCache().store_bulletins_pdf(
|
||||||
formsemestre_id, version, filename, pdfdoc
|
formsemestre_id, version, filename, pdfdoc
|
||||||
@ -239,7 +247,7 @@ def get_etud_bulletins_pdf(context, etudid, REQUEST, version="selectedevals"):
|
|||||||
else:
|
else:
|
||||||
server_name = ""
|
server_name = ""
|
||||||
try:
|
try:
|
||||||
PDFLOCK.acquire()
|
sco_pdf.PDFLOCK.acquire()
|
||||||
pdfdoc = pdfassemblebulletins(
|
pdfdoc = pdfassemblebulletins(
|
||||||
None,
|
None,
|
||||||
fragments,
|
fragments,
|
||||||
@ -251,11 +259,11 @@ def get_etud_bulletins_pdf(context, etudid, REQUEST, version="selectedevals"):
|
|||||||
context=context,
|
context=context,
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
PDFLOCK.release()
|
sco_pdf.PDFLOCK.release()
|
||||||
#
|
#
|
||||||
filename = "bul-%s" % (etud["nomprenom"])
|
filename = "bul-%s" % (etud["nomprenom"])
|
||||||
filename = (
|
filename = (
|
||||||
unescape_html(filename).replace(" ", "_").replace("&", "").replace(".", "")
|
scu.unescape_html(filename).replace(" ", "_").replace("&", "").replace(".", "")
|
||||||
+ ".pdf"
|
+ ".pdf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -53,53 +53,53 @@ Lien sur Scolarite/edit_preferences (sans formsemestre_id)
|
|||||||
et sur page "réglages bulletin" (avec 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):
|
# def form_change_bul_sig(context, side, formsemestre_id=None, REQUEST=None):
|
||||||
"""Change pdf signature"""
|
# """Change pdf signature"""
|
||||||
filename = _get_sig_existing_filename(
|
# filename = _get_sig_existing_filename(
|
||||||
context, side, formsemestre_id=formsemestre_id
|
# context, side, formsemestre_id=formsemestre_id
|
||||||
)
|
# )
|
||||||
if side == "left":
|
# if side == "left":
|
||||||
sidetxt = "gauche"
|
# sidetxt = "gauche"
|
||||||
elif side == "right":
|
# elif side == "right":
|
||||||
sidetxt = "droite"
|
# sidetxt = "droite"
|
||||||
else:
|
# else:
|
||||||
raise ValueError("invalid value for 'side' parameter")
|
# raise ValueError("invalid value for 'side' parameter")
|
||||||
signatureloc = get_bul_sig_img()
|
# signatureloc = get_bul_sig_img()
|
||||||
H = [
|
# H = [
|
||||||
self.sco_header(REQUEST, page_title="Changement de signature"),
|
# self.sco_header(REQUEST, page_title="Changement de signature"),
|
||||||
"""<h2>Changement de la signature bulletin de %(sidetxt)s</h2>
|
# """<h2>Changement de la signature bulletin de %(sidetxt)s</h2>
|
||||||
"""
|
# """
|
||||||
% (sidetxt,),
|
# % (sidetxt,),
|
||||||
]
|
# ]
|
||||||
"<p>Photo actuelle (%(signatureloc)s): "
|
# "<p>Photo actuelle (%(signatureloc)s): "
|
||||||
|
|
||||||
|
|
||||||
def get_bul_sig_img(context, side, formsemestre_id=None):
|
# def get_bul_sig_img(context, side, formsemestre_id=None):
|
||||||
"send back signature image data"
|
# "send back signature image data"
|
||||||
# slow, not cached, used for unfrequent access (do not bypass python)
|
# # slow, not cached, used for unfrequent access (do not bypass python)
|
||||||
|
|
||||||
|
|
||||||
def _sig_filename(context, side, formsemestre_id=None):
|
# def _sig_filename(context, side, formsemestre_id=None):
|
||||||
if not side in ("left", "right"):
|
# if not side in ("left", "right"):
|
||||||
raise ValueError("side must be left or right")
|
# raise ValueError("side must be left or right")
|
||||||
dirs = [SCODOC_LOGOS_DIR, context.DeptId()]
|
# dirs = [SCODOC_LOGOS_DIR, context.DeptId()]
|
||||||
if formsemestre_id:
|
# if formsemestre_id:
|
||||||
dirs.append(formsemestre_id)
|
# dirs.append(formsemestre_id)
|
||||||
dirs.append("bul_sig_{}".format(side))
|
# dirs.append("bul_sig_{}".format(side))
|
||||||
return os.path.join(*dirs)
|
# return os.path.join(*dirs)
|
||||||
|
|
||||||
|
|
||||||
def _get_sig_existing_filename(context, side, formsemestre_id=None):
|
# def _get_sig_existing_filename(context, side, formsemestre_id=None):
|
||||||
"full path to signature to use, or None if no signature available"
|
# "full path to signature to use, or None if no signature available"
|
||||||
if formsemestre_id:
|
# if formsemestre_id:
|
||||||
filename = _sig_filename(context, side, formsemestre_id=formsemestre_id)
|
# filename = _sig_filename(context, side, formsemestre_id=formsemestre_id)
|
||||||
if os.path.exists(filename):
|
# if os.path.exists(filename):
|
||||||
return filename
|
# return filename
|
||||||
filename = _sig_filename(context, side)
|
# filename = _sig_filename(context, side)
|
||||||
if os.path.exists(filename):
|
# if os.path.exists(filename):
|
||||||
return filename
|
# return filename
|
||||||
else:
|
# else:
|
||||||
return None
|
# return None
|
||||||
|
@ -46,7 +46,10 @@ de la forme %(XXX)s sont remplacées par la valeur de XXX, pour XXX dans:
|
|||||||
Balises img: actuellement interdites.
|
Balises img: actuellement interdites.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import traceback, re
|
import datetime
|
||||||
|
import traceback
|
||||||
|
import re
|
||||||
|
import jaxml
|
||||||
|
|
||||||
import sco_utils as scu
|
import sco_utils as scu
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
@ -156,7 +159,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
for app in self.infos["appreciations_list"]:
|
for app in self.infos["appreciations_list"]:
|
||||||
if can_edit_app:
|
if can_edit_app:
|
||||||
mlink = (
|
mlink = (
|
||||||
'<a class="stdlink" href="appreciation_add_form?id=%s">modifier</a> <a class="stdlink" href="appreciation_add_form?id=%s&suppress=1">supprimer</a>'
|
'<a class="stdlink" href="appreciation_add_form?id=%s">modifier</a> <a class="stdlink" href="appreciation_add_form?id=%s&suppress=1">supprimer</a>'
|
||||||
% (app["id"], app["id"])
|
% (app["id"], app["id"])
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -167,7 +170,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
)
|
)
|
||||||
if can_edit_app:
|
if can_edit_app:
|
||||||
H.append(
|
H.append(
|
||||||
'<p><a class="stdlink" href="appreciation_add_form?etudid=%(etudid)s&formsemestre_id=%(formsemestre_id)s">Ajouter une appréciation</a></p>'
|
'<p><a class="stdlink" href="appreciation_add_form?etudid=%(etudid)s&formsemestre_id=%(formsemestre_id)s">Ajouter une appréciation</a></p>'
|
||||||
% self.infos
|
% self.infos
|
||||||
)
|
)
|
||||||
H.append("</div>")
|
H.append("</div>")
|
||||||
@ -375,7 +378,8 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
P[-1]["_pdf_style"].append(
|
P[-1]["_pdf_style"].append(
|
||||||
("LINEBELOW", (0, 0), (-1, 0), self.PDF_LINEWIDTH, self.PDF_LINECOLOR)
|
("LINEBELOW", (0, 0), (-1, 0), self.PDF_LINEWIDTH, self.PDF_LINECOLOR)
|
||||||
)
|
)
|
||||||
|
# Espacement sous la ligne moyenne générale:
|
||||||
|
P[-1]["_pdf_style"].append(("BOTTOMPADDING", (0, 1), (-1, 1), 8))
|
||||||
# Moyenne générale:
|
# Moyenne générale:
|
||||||
nbabs = I["nbabs"]
|
nbabs = I["nbabs"]
|
||||||
nbabsjust = I["nbabsjust"]
|
nbabsjust = I["nbabsjust"]
|
||||||
@ -389,8 +393,10 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
"abs": "%s / %s" % (nbabs, nbabsjust),
|
"abs": "%s / %s" % (nbabs, nbabsjust),
|
||||||
"_css_row_class": "notes_bulletin_row_gen",
|
"_css_row_class": "notes_bulletin_row_gen",
|
||||||
"_titre_colspan": 2,
|
"_titre_colspan": 2,
|
||||||
"_pdf_row_markup": ['font size="12"', "b"], # bold, size 12
|
"_pdf_row_markup": ["b"], # bold. On peut ajouter 'font size="12"'
|
||||||
"_pdf_style": [("LINEABOVE", (0, 1), (-1, 1), 1, self.PDF_LINECOLOR)],
|
"_pdf_style": [
|
||||||
|
("LINEABOVE", (0, 1), (-1, 1), 1, self.PDF_LINECOLOR),
|
||||||
|
],
|
||||||
}
|
}
|
||||||
P.append(t)
|
P.append(t)
|
||||||
|
|
||||||
|
@ -34,8 +34,12 @@ E. Viennet, juillet 2011
|
|||||||
"""
|
"""
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
import sco_utils as scu
|
||||||
import sco_formsemestre
|
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
|
import sco_preferences
|
||||||
|
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
@ -72,7 +76,6 @@ class BulletinGeneratorUCAC(sco_bulletins_standard.BulletinGeneratorStandard):
|
|||||||
I = self.infos
|
I = self.infos
|
||||||
context = self.context
|
context = self.context
|
||||||
formsemestre_id = I["formsemestre_id"]
|
formsemestre_id = I["formsemestre_id"]
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
|
||||||
prefs = context.get_preferences(formsemestre_id)
|
prefs = context.get_preferences(formsemestre_id)
|
||||||
|
|
||||||
P = [] # elems pour générer table avec gen_table (liste de dicts)
|
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 = (
|
total_pt_ue_v = (
|
||||||
ue["ue_status"]["cur_moy_ue"] * ue["ue_status"]["coef_ue"]
|
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)
|
# log('total_pt_ue = %s' % total_pt_ue)
|
||||||
except:
|
except:
|
||||||
# log("ue['ue_status']['cur_moy_ue'] = %s" % ue['ue_status']['cur_moy_ue'] )
|
# 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_descr = "(en cours, non prise en compte)"
|
||||||
ue_type = "cur"
|
ue_type = "cur"
|
||||||
rowstyle = " bul_ucac_row_ue_cur"
|
|
||||||
|
|
||||||
# --- UE ordinaire
|
# --- UE ordinaire
|
||||||
pt = list_ue(ue, ue_descr)
|
pt = list_ue(ue, ue_descr)
|
||||||
@ -228,8 +230,8 @@ class BulletinGeneratorUCAC(sco_bulletins_standard.BulletinGeneratorStandard):
|
|||||||
{
|
{
|
||||||
"code_ue": "Total",
|
"code_ue": "Total",
|
||||||
"moyenne_ue": I["moy_gen"],
|
"moyenne_ue": I["moy_gen"],
|
||||||
"coef": fmt_note(sum_coef_ues),
|
"coef": scu.fmt_note(sum_coef_ues),
|
||||||
"total": fmt_note(sum_pt_sem),
|
"total": scu.fmt_note(sum_pt_sem),
|
||||||
"_code_ue_colspan": 4,
|
"_code_ue_colspan": 4,
|
||||||
"_css_row_class": "bul_ucac_row_total",
|
"_css_row_class": "bul_ucac_row_total",
|
||||||
"_pdf_row_markup": ["b"],
|
"_pdf_row_markup": ["b"],
|
||||||
|
@ -37,11 +37,18 @@ 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é.
|
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_formsemestre
|
||||||
import sco_groups
|
import sco_groups
|
||||||
import sco_photos
|
import sco_photos
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
import sco_bulletins
|
import sco_bulletins
|
||||||
|
|
||||||
# -------- Bulletin en XML
|
# -------- Bulletin en XML
|
||||||
@ -62,9 +69,9 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
"bulletin au format XML"
|
"bulletin au format XML"
|
||||||
log("xml_bulletin( formsemestre_id=%s, etudid=%s )" % (formsemestre_id, etudid))
|
log("xml_bulletin( formsemestre_id=%s, etudid=%s )" % (formsemestre_id, etudid))
|
||||||
if REQUEST:
|
if REQUEST:
|
||||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||||
if not doc:
|
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)
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
if sem["bul_hide_xml"] == "0" or force_publishing:
|
if sem["bul_hide_xml"] == "0" or force_publishing:
|
||||||
@ -98,12 +105,13 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
etudid=etudid,
|
etudid=etudid,
|
||||||
code_nip=etudinfo["code_nip"],
|
code_nip=etudinfo["code_nip"],
|
||||||
code_ine=etudinfo["code_ine"],
|
code_ine=etudinfo["code_ine"],
|
||||||
nom=quote_xml_attr(etudinfo["nom"]),
|
nom=scu.quote_xml_attr(etudinfo["nom"]),
|
||||||
prenom=quote_xml_attr(etudinfo["prenom"]),
|
prenom=scu.quote_xml_attr(etudinfo["prenom"]),
|
||||||
sexe=quote_xml_attr(etudinfo["sexe"]),
|
civilite=scu.quote_xml_attr(etudinfo["civilite_str"]),
|
||||||
photo_url=quote_xml_attr(sco_photos.etud_photo_url(context, etudinfo)),
|
sexe=scu.quote_xml_attr(etudinfo["civilite_str"]), # compat
|
||||||
email=quote_xml_attr(etudinfo["email"]),
|
photo_url=scu.quote_xml_attr(sco_photos.etud_photo_url(context, etudinfo)),
|
||||||
emailperso=quote_xml_attr(etudinfo["emailperso"]),
|
email=scu.quote_xml_attr(etudinfo["email"]),
|
||||||
|
emailperso=scu.quote_xml_attr(etudinfo["emailperso"]),
|
||||||
)
|
)
|
||||||
doc._pop()
|
doc._pop()
|
||||||
|
|
||||||
@ -128,7 +136,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
ues = nt.get_ues()
|
ues = nt.get_ues()
|
||||||
modimpls = nt.get_modimpls()
|
modimpls = nt.get_modimpls()
|
||||||
nbetuds = len(nt.rangs)
|
nbetuds = len(nt.rangs)
|
||||||
mg = fmt_note(nt.get_etud_moy_gen(etudid))
|
mg = scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
||||||
if (
|
if (
|
||||||
nt.get_moduleimpls_attente()
|
nt.get_moduleimpls_attente()
|
||||||
or context.get_preference("bul_show_rangs", formsemestre_id) == 0
|
or context.get_preference("bul_show_rangs", formsemestre_id) == 0
|
||||||
@ -147,9 +155,9 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
doc._push()
|
doc._push()
|
||||||
doc.note(
|
doc.note(
|
||||||
value=mg,
|
value=mg,
|
||||||
min=fmt_note(nt.moy_min),
|
min=scu.fmt_note(nt.moy_min),
|
||||||
max=fmt_note(nt.moy_max),
|
max=scu.fmt_note(nt.moy_max),
|
||||||
moy=fmt_note(nt.moy_moy),
|
moy=scu.fmt_note(nt.moy_moy),
|
||||||
)
|
)
|
||||||
doc._pop()
|
doc._pop()
|
||||||
doc._push()
|
doc._push()
|
||||||
@ -177,17 +185,21 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
doc._push()
|
doc._push()
|
||||||
doc.ue(
|
doc.ue(
|
||||||
id=ue["ue_id"],
|
id=ue["ue_id"],
|
||||||
numero=quote_xml_attr(ue["numero"]),
|
numero=scu.quote_xml_attr(ue["numero"]),
|
||||||
acronyme=quote_xml_attr(ue["acronyme"]),
|
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||||
titre=quote_xml_attr(ue["titre"]),
|
titre=scu.quote_xml_attr(ue["titre"]),
|
||||||
code_apogee=quote_xml_attr(ue["code_apogee"]),
|
code_apogee=scu.quote_xml_attr(ue["code_apogee"]),
|
||||||
)
|
)
|
||||||
doc._push()
|
doc._push()
|
||||||
if ue["type"] != UE_SPORT:
|
if ue["type"] != sco_codes_parcours.UE_SPORT:
|
||||||
v = ue_status["cur_moy_ue"]
|
v = ue_status["cur_moy_ue"]
|
||||||
else:
|
else:
|
||||||
v = nt.bonus[etudid]
|
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()
|
doc._pop()
|
||||||
try:
|
try:
|
||||||
ects_txt = str(int(ue["ects"]))
|
ects_txt = str(int(ue["ects"]))
|
||||||
@ -205,7 +217,9 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
# Liste les modules de l'UE
|
# Liste les modules de l'UE
|
||||||
ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]]
|
ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]]
|
||||||
for modimpl in ue_modimpls:
|
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
|
if mod_moy == "NI": # ne mentionne pas les modules ou n'est pas inscrit
|
||||||
continue
|
continue
|
||||||
mod = modimpl["module"]
|
mod = modimpl["module"]
|
||||||
@ -219,17 +233,18 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
code=mod["code"],
|
code=mod["code"],
|
||||||
coefficient=mod["coefficient"],
|
coefficient=mod["coefficient"],
|
||||||
numero=mod["numero"],
|
numero=mod["numero"],
|
||||||
titre=quote_xml_attr(mod["titre"]),
|
titre=scu.quote_xml_attr(mod["titre"]),
|
||||||
abbrev=quote_xml_attr(mod["abbrev"]),
|
abbrev=scu.quote_xml_attr(mod["abbrev"]),
|
||||||
code_apogee=quote_xml_attr(mod["code_apogee"])
|
code_apogee=scu.quote_xml_attr(mod["code_apogee"])
|
||||||
# ects=ects ects des modules maintenant inutilisés
|
# ects=ects ects des modules maintenant inutilisés
|
||||||
)
|
)
|
||||||
doc._push()
|
doc._push()
|
||||||
modstat = nt.get_mod_stats(modimpl["moduleimpl_id"])
|
modstat = nt.get_mod_stats(modimpl["moduleimpl_id"])
|
||||||
doc.note(
|
doc.note(
|
||||||
value=mod_moy,
|
value=mod_moy,
|
||||||
min=fmt_note(modstat["min"]),
|
min=scu.fmt_note(modstat["min"]),
|
||||||
max=fmt_note(modstat["max"]),
|
max=scu.fmt_note(modstat["max"]),
|
||||||
|
moy=scu.fmt_note(modstat["moy"]),
|
||||||
)
|
)
|
||||||
doc._pop()
|
doc._pop()
|
||||||
if context.get_preference("bul_show_mod_rangs", formsemestre_id):
|
if context.get_preference("bul_show_mod_rangs", formsemestre_id):
|
||||||
@ -246,14 +261,16 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
if int(e["visibulletin"]) == 1 or version == "long":
|
if int(e["visibulletin"]) == 1 or version == "long":
|
||||||
doc._push()
|
doc._push()
|
||||||
doc.evaluation(
|
doc.evaluation(
|
||||||
jour=DateDMYtoISO(e["jour"], null_is_empty=True),
|
jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||||
heure_debut=TimetoISO8601(
|
heure_debut=ndb.TimetoISO8601(
|
||||||
e["heure_debut"], null_is_empty=True
|
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"],
|
coefficient=e["coefficient"],
|
||||||
evaluation_type=e["evaluation_type"],
|
evaluation_type=e["evaluation_type"],
|
||||||
description=quote_xml_attr(e["description"]),
|
description=scu.quote_xml_attr(e["description"]),
|
||||||
note_max_origin=e[
|
note_max_origin=e[
|
||||||
"note_max"
|
"note_max"
|
||||||
], # notes envoyées sur 20, ceci juste pour garder trace
|
], # notes envoyées sur 20, ceci juste pour garder trace
|
||||||
@ -261,7 +278,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
val = e["notes"].get(etudid, {"value": "NP"})[
|
val = e["notes"].get(etudid, {"value": "NP"})[
|
||||||
"value"
|
"value"
|
||||||
] # NA si etud demissionnaire
|
] # 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.note(value=val)
|
||||||
doc._pop()
|
doc._pop()
|
||||||
# Evaluations incomplètes ou futures:
|
# Evaluations incomplètes ou futures:
|
||||||
@ -275,15 +292,15 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
if e["evaluation_id"] not in complete_eval_ids:
|
if e["evaluation_id"] not in complete_eval_ids:
|
||||||
doc._push()
|
doc._push()
|
||||||
doc.evaluation(
|
doc.evaluation(
|
||||||
jour=DateDMYtoISO(e["jour"], null_is_empty=True),
|
jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||||
heure_debut=TimetoISO8601(
|
heure_debut=ndb.TimetoISO8601(
|
||||||
e["heure_debut"], null_is_empty=True
|
e["heure_debut"], null_is_empty=True
|
||||||
),
|
),
|
||||||
heure_fin=TimetoISO8601(
|
heure_fin=ndb.TimetoISO8601(
|
||||||
e["heure_fin"], null_is_empty=True
|
e["heure_fin"], null_is_empty=True
|
||||||
),
|
),
|
||||||
coefficient=e["coefficient"],
|
coefficient=e["coefficient"],
|
||||||
description=quote_xml_attr(e["description"]),
|
description=scu.quote_xml_attr(e["description"]),
|
||||||
incomplete="1",
|
incomplete="1",
|
||||||
note_max_origin=e[
|
note_max_origin=e[
|
||||||
"note_max"
|
"note_max"
|
||||||
@ -301,28 +318,26 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
doc._push()
|
doc._push()
|
||||||
doc.ue_capitalisee(
|
doc.ue_capitalisee(
|
||||||
id=ue["ue_id"],
|
id=ue["ue_id"],
|
||||||
numero=quote_xml_attr(ue["numero"]),
|
numero=scu.quote_xml_attr(ue["numero"]),
|
||||||
acronyme=quote_xml_attr(ue["acronyme"]),
|
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||||
titre=quote_xml_attr(ue["titre"]),
|
titre=scu.quote_xml_attr(ue["titre"]),
|
||||||
)
|
)
|
||||||
doc._push()
|
doc._push()
|
||||||
doc.note(value=fmt_note(ue_status["moy"]))
|
doc.note(value=scu.fmt_note(ue_status["moy"]))
|
||||||
doc._pop()
|
doc._pop()
|
||||||
doc._push()
|
doc._push()
|
||||||
doc.ects(value=ects_txt)
|
doc.ects(value=ects_txt)
|
||||||
doc._pop()
|
doc._pop()
|
||||||
doc._push()
|
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._pop()
|
||||||
doc._push()
|
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()
|
||||||
doc._pop()
|
doc._pop()
|
||||||
# --- Absences
|
# --- Absences
|
||||||
if context.get_preference("bul_show_abs", formsemestre_id):
|
if context.get_preference("bul_show_abs", formsemestre_id):
|
||||||
debut_sem = DateDMYtoISO(sem["date_debut"])
|
AbsEtudSem = sco_abs.getAbsSemEtud(context, sem, etudid)
|
||||||
fin_sem = DateDMYtoISO(sem["date_fin"])
|
|
||||||
AbsEtudSem = ZAbsences.getAbsSemEtud(context, sem, etudid)
|
|
||||||
nbabs = AbsEtudSem.CountAbs()
|
nbabs = AbsEtudSem.CountAbs()
|
||||||
nbabsjust = AbsEtudSem.CountAbsJust()
|
nbabsjust = AbsEtudSem.CountAbsJust()
|
||||||
doc._push()
|
doc._push()
|
||||||
@ -340,7 +355,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
format="xml",
|
format="xml",
|
||||||
show_uevalid=context.get_preference("bul_show_uevalid", formsemestre_id),
|
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:
|
if dpv:
|
||||||
decision = dpv["decisions"][0]
|
decision = dpv["decisions"][0]
|
||||||
etat = decision["etat"]
|
etat = decision["etat"]
|
||||||
@ -374,9 +389,9 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
doc._push()
|
doc._push()
|
||||||
doc.decision_ue(
|
doc.decision_ue(
|
||||||
ue_id=ue["ue_id"],
|
ue_id=ue["ue_id"],
|
||||||
numero=quote_xml_attr(ue["numero"]),
|
numero=scu.quote_xml_attr(ue["numero"]),
|
||||||
acronyme=quote_xml_attr(ue["acronyme"]),
|
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||||
titre=quote_xml_attr(ue["titre"]),
|
titre=scu.quote_xml_attr(ue["titre"]),
|
||||||
code=decision["decisions_ue"][ue_id]["code"],
|
code=decision["decisions_ue"][ue_id]["code"],
|
||||||
)
|
)
|
||||||
doc._pop()
|
doc._pop()
|
||||||
@ -395,5 +410,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
cnx, args={"etudid": etudid, "formsemestre_id": formsemestre_id}
|
cnx, args={"etudid": etudid, "formsemestre_id": formsemestre_id}
|
||||||
)
|
)
|
||||||
for app in apprecs:
|
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
|
return doc
|
||||||
|
@ -29,15 +29,26 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
|
import pprint
|
||||||
|
from types import FloatType
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notesdb import *
|
from sco_utils import (
|
||||||
|
NOTES_ATTENTE,
|
||||||
|
NOTES_NEUTRALISE,
|
||||||
|
EVALUATION_NORMALE,
|
||||||
|
EVALUATION_RATTRAPAGE,
|
||||||
|
EVALUATION_SESSION2,
|
||||||
|
)
|
||||||
|
from sco_exceptions import ScoException
|
||||||
|
from notesdb import EditableTable, quote_html
|
||||||
from notes_log import log, sendAlarm
|
from notes_log import log, sendAlarm
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
|
import sco_moduleimpl
|
||||||
import sco_groups
|
import sco_groups
|
||||||
import sco_evaluations
|
import sco_evaluations
|
||||||
from sco_formulas import *
|
import sco_formulas
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
|
|
||||||
|
|
||||||
def moduleimpl_has_expression(context, mod):
|
def moduleimpl_has_expression(context, mod):
|
||||||
@ -67,7 +78,9 @@ def formsemestre_expressions_use_abscounts(context, formsemestre_id):
|
|||||||
if expr and expr[0] != "#" and ab in expr:
|
if expr and expr[0] != "#" and ab in expr:
|
||||||
return True
|
return True
|
||||||
# 2- moyennes de modules
|
# 2- moyennes de modules
|
||||||
for mod in context.Notes.do_moduleimpl_list(formsemestre_id=formsemestre_id):
|
for mod in sco_moduleimpl.do_moduleimpl_list(
|
||||||
|
context, formsemestre_id=formsemestre_id
|
||||||
|
):
|
||||||
if moduleimpl_has_expression(context, mod) and ab in mod["computation_expr"]:
|
if moduleimpl_has_expression(context, mod) and ab in mod["computation_expr"]:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -124,7 +137,7 @@ def compute_user_formula(
|
|||||||
Retourne moy, et en cas d'erreur met à jour diag_info (msg)
|
Retourne moy, et en cas d'erreur met à jour diag_info (msg)
|
||||||
"""
|
"""
|
||||||
if use_abs:
|
if use_abs:
|
||||||
AbsSemEtud = ZAbsences.getAbsSemEtud(context, sem, etudid)
|
AbsSemEtud = sco_abs.getAbsSemEtud(context, sem, etudid)
|
||||||
nbabs = AbsSemEtud.CountAbs()
|
nbabs = AbsSemEtud.CountAbs()
|
||||||
nbabs_just = AbsSemEtud.CountAbsJust()
|
nbabs_just = AbsSemEtud.CountAbsJust()
|
||||||
else:
|
else:
|
||||||
@ -148,7 +161,7 @@ def compute_user_formula(
|
|||||||
try:
|
try:
|
||||||
formula = formula.replace("\n", "").replace("\r", "")
|
formula = formula.replace("\n", "").replace("\r", "")
|
||||||
# log('expression : %s\nvariables=%s\n' % (formula, variables)) # XXX debug
|
# log('expression : %s\nvariables=%s\n' % (formula, variables)) # XXX debug
|
||||||
user_moy = eval_user_expression(context, formula, variables)
|
user_moy = sco_formulas.eval_user_expression(context, formula, variables)
|
||||||
# log('user_moy=%s' % user_moy)
|
# log('user_moy=%s' % user_moy)
|
||||||
if user_moy != "NA0" and user_moy != "NA":
|
if user_moy != "NA0" and user_moy != "NA":
|
||||||
user_moy = float(user_moy)
|
user_moy = float(user_moy)
|
||||||
@ -188,10 +201,10 @@ def do_moduleimpl_moyennes(context, nt, mod):
|
|||||||
"""
|
"""
|
||||||
diag_info = {} # message d'erreur formule
|
diag_info = {} # message d'erreur formule
|
||||||
moduleimpl_id = mod["moduleimpl_id"]
|
moduleimpl_id = mod["moduleimpl_id"]
|
||||||
is_malus = mod["module"]["module_type"] == MODULE_MALUS
|
is_malus = mod["module"]["module_type"] == scu.MODULE_MALUS
|
||||||
sem = sco_formsemestre.get_formsemestre(context, mod["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(context, mod["formsemestre_id"])
|
||||||
etudids = context.do_moduleimpl_listeetuds(
|
etudids = sco_moduleimpl.do_moduleimpl_listeetuds(
|
||||||
moduleimpl_id
|
context, moduleimpl_id
|
||||||
) # tous, y compris demissions
|
) # tous, y compris demissions
|
||||||
# Inscrits au semestre (pour traiter les demissions):
|
# Inscrits au semestre (pour traiter les demissions):
|
||||||
inssem_set = set(
|
inssem_set = set(
|
||||||
@ -230,7 +243,10 @@ def do_moduleimpl_moyennes(context, nt, mod):
|
|||||||
|
|
||||||
if e["etat"]["evalattente"]:
|
if e["etat"]["evalattente"]:
|
||||||
attente = True
|
attente = True
|
||||||
if e["evaluation_type"] == EVALUATION_RATTRAPAGE:
|
if (
|
||||||
|
e["evaluation_type"] == EVALUATION_RATTRAPAGE
|
||||||
|
or e["evaluation_type"] == EVALUATION_SESSION2
|
||||||
|
):
|
||||||
if eval_rattr:
|
if eval_rattr:
|
||||||
# !!! plusieurs rattrapages !
|
# !!! plusieurs rattrapages !
|
||||||
diag_info.update(
|
diag_info.update(
|
||||||
@ -256,7 +272,7 @@ def do_moduleimpl_moyennes(context, nt, mod):
|
|||||||
]
|
]
|
||||||
#
|
#
|
||||||
R = {}
|
R = {}
|
||||||
formula = unescape_html(mod["computation_expr"])
|
formula = scu.unescape_html(mod["computation_expr"])
|
||||||
formula_use_abs = "abs" in formula
|
formula_use_abs = "abs" in formula
|
||||||
|
|
||||||
for etudid in insmod_set: # inscrits au semestre et au module
|
for etudid in insmod_set: # inscrits au semestre et au module
|
||||||
@ -332,7 +348,7 @@ def do_moduleimpl_moyennes(context, nt, mod):
|
|||||||
if diag_info:
|
if diag_info:
|
||||||
diag_info["moduleimpl_id"] = moduleimpl_id
|
diag_info["moduleimpl_id"] = moduleimpl_id
|
||||||
R[etudid] = user_moy
|
R[etudid] = user_moy
|
||||||
# Note de rattrapage ?
|
# Note de rattrapage ou deuxième session ?
|
||||||
if eval_rattr:
|
if eval_rattr:
|
||||||
if eval_rattr["notes"].has_key(etudid):
|
if eval_rattr["notes"].has_key(etudid):
|
||||||
note = eval_rattr["notes"][etudid]["value"]
|
note = eval_rattr["notes"][etudid]["value"]
|
||||||
@ -341,8 +357,14 @@ def do_moduleimpl_moyennes(context, nt, mod):
|
|||||||
R[etudid] = note
|
R[etudid] = note
|
||||||
else:
|
else:
|
||||||
note_sur_20 = note * 20.0 / eval_rattr["note_max"]
|
note_sur_20 = note * 20.0 / eval_rattr["note_max"]
|
||||||
if note_sur_20 > R[etudid]:
|
if eval_rattr["evaluation_type"] == EVALUATION_RATTRAPAGE:
|
||||||
# log('note_sur_20=%s' % note_sur_20)
|
# rattrapage classique: prend la meilleure note entre moyenne
|
||||||
|
# module et note eval rattrapage
|
||||||
|
if note_sur_20 > R[etudid]:
|
||||||
|
# log('note_sur_20=%s' % note_sur_20)
|
||||||
|
R[etudid] = note_sur_20
|
||||||
|
elif eval_rattr["evaluation_type"] == EVALUATION_SESSION2:
|
||||||
|
# rattrapage type "deuxième session": remplace la note moyenne
|
||||||
R[etudid] = note_sur_20
|
R[etudid] = note_sur_20
|
||||||
|
|
||||||
return R, valid_evals, attente, diag_info
|
return R, valid_evals, attente, diag_info
|
||||||
@ -353,12 +375,14 @@ def do_formsemestre_moyennes(context, nt, formsemestre_id):
|
|||||||
la liste des moduleimpls, la liste des evaluations valides,
|
la liste des moduleimpls, la liste des evaluations valides,
|
||||||
liste des moduleimpls avec notes en attente.
|
liste des moduleimpls avec notes en attente.
|
||||||
"""
|
"""
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
# sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
inscr = context.do_formsemestre_inscription_list(
|
# inscr = context.do_formsemestre_inscription_list(
|
||||||
args={"formsemestre_id": formsemestre_id}
|
# args={"formsemestre_id": formsemestre_id}
|
||||||
|
# )
|
||||||
|
# etudids = [x["etudid"] for x in inscr]
|
||||||
|
modimpls = sco_moduleimpl.do_moduleimpl_list(
|
||||||
|
context, formsemestre_id=formsemestre_id
|
||||||
)
|
)
|
||||||
etudids = [x["etudid"] for x in inscr]
|
|
||||||
modimpls = context.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
|
||||||
# recupere les moyennes des etudiants de tous les modules
|
# recupere les moyennes des etudiants de tous les modules
|
||||||
D = {}
|
D = {}
|
||||||
valid_evals = []
|
valid_evals = []
|
||||||
|
@ -30,14 +30,16 @@
|
|||||||
|
|
||||||
(coût théorique en heures équivalent TD)
|
(coût théorique en heures équivalent TD)
|
||||||
"""
|
"""
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
import sco_excel, sco_pdf
|
import sco_excel, sco_pdf
|
||||||
from sco_pdf import SU
|
from sco_pdf import SU
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
|
import sco_moduleimpl
|
||||||
import sco_formsemestre_status
|
import sco_formsemestre_status
|
||||||
|
import VERSION
|
||||||
|
|
||||||
|
|
||||||
def formsemestre_table_estim_cost(
|
def formsemestre_table_estim_cost(
|
||||||
@ -60,7 +62,9 @@ def formsemestre_table_estim_cost(
|
|||||||
"""
|
"""
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
sco_formsemestre_status.fill_formsemestre(context, sem, REQUEST=REQUEST)
|
sco_formsemestre_status.fill_formsemestre(context, sem, REQUEST=REQUEST)
|
||||||
Mlist = context.do_moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||||
|
context, formsemestre_id=formsemestre_id
|
||||||
|
)
|
||||||
T = []
|
T = []
|
||||||
for M in Mlist:
|
for M in Mlist:
|
||||||
Mod = M["module"]
|
Mod = M["module"]
|
||||||
@ -141,7 +145,7 @@ def formsemestre_table_estim_cost(
|
|||||||
(dans ce cas, retoucher le tableau excel exporté).
|
(dans ce cas, retoucher le tableau excel exporté).
|
||||||
</div>
|
</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"],
|
filename="EstimCout-S%s" % sem["semestre_id"],
|
||||||
)
|
)
|
||||||
return tab
|
return tab
|
||||||
@ -190,7 +194,7 @@ def formsemestre_estim_cost(
|
|||||||
)
|
)
|
||||||
tab.html_before_table = h
|
tab.html_before_table = h
|
||||||
tab.base_url = (
|
tab.base_url = (
|
||||||
"%s?formsemestre_id=%s&n_group_td=%s&n_group_tp=%s&coef_tp=%s"
|
"%s?formsemestre_id=%s&n_group_td=%s&n_group_tp=%s&coef_tp=%s"
|
||||||
% (REQUEST.URL0, formsemestre_id, n_group_td, n_group_tp, coef_tp)
|
% (REQUEST.URL0, formsemestre_id, n_group_td, n_group_tp, coef_tp)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ def table_debouche_etudids(context, etudids, keep_numeric=True):
|
|||||||
)
|
)
|
||||||
row = {
|
row = {
|
||||||
"etudid": etudid,
|
"etudid": etudid,
|
||||||
"sexe": etud["sexe"],
|
"civilite": etud["civilite"],
|
||||||
"nom": etud["nom"],
|
"nom": etud["nom"],
|
||||||
"prenom": etud["prenom"],
|
"prenom": etud["prenom"],
|
||||||
"_nom_target": "ficheEtud?etudid=" + etud["etudid"],
|
"_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"])
|
L.sort(key=lambda x: x["sem_ident"])
|
||||||
|
|
||||||
titles = {
|
titles = {
|
||||||
"sexe": "",
|
"civilite": "",
|
||||||
"nom": "Nom",
|
"nom": "Nom",
|
||||||
"prenom": "Prénom",
|
"prenom": "Prénom",
|
||||||
"semestre": "Dernier semestre",
|
"semestre": "Dernier semestre",
|
||||||
@ -170,7 +170,7 @@ def table_debouche_etudids(context, etudids, keep_numeric=True):
|
|||||||
"semestre",
|
"semestre",
|
||||||
"semestre_id",
|
"semestre_id",
|
||||||
"periode",
|
"periode",
|
||||||
"sexe",
|
"civilite",
|
||||||
"nom",
|
"nom",
|
||||||
"prenom",
|
"prenom",
|
||||||
"moy",
|
"moy",
|
||||||
|
36
sco_dept.py
36
sco_dept.py
@ -27,14 +27,15 @@
|
|||||||
|
|
||||||
"""Page accueil département (liste des semestres, etc)
|
"""Page accueil département (liste des semestres, etc)
|
||||||
"""
|
"""
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_modalites
|
import sco_modalites
|
||||||
import sco_news
|
import sco_news
|
||||||
import sco_up_to_date
|
import sco_up_to_date
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
|
from sco_permissions import ScoEtudInscrit, ScoEditApo
|
||||||
|
|
||||||
|
|
||||||
def index_html(context, REQUEST=None, showcodes=0, showsemtable=0):
|
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:
|
# News:
|
||||||
# 2020-12-30: abandonne l'icon rss
|
# 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))
|
H.append(sco_news.scolar_news_summary_html(context)) # , rssicon=rssicon))
|
||||||
|
|
||||||
# Avertissement de mise à jour:
|
# Avertissement de mise à jour:
|
||||||
@ -55,9 +56,11 @@ def index_html(context, REQUEST=None, showcodes=0, showsemtable=0):
|
|||||||
cursems = [] # semestres "courants"
|
cursems = [] # semestres "courants"
|
||||||
othersems = [] # autres (verrouillés)
|
othersems = [] # autres (verrouillés)
|
||||||
# icon image:
|
# icon image:
|
||||||
groupicon = icontag("groupicon_img", title="Inscrits", border="0")
|
groupicon = scu.icontag("groupicon_img", title="Inscrits", border="0")
|
||||||
emptygroupicon = icontag("emptygroupicon_img", title="Pas d'inscrits", border="0")
|
emptygroupicon = scu.icontag(
|
||||||
lockicon = icontag("lock32_img", title="verrouillé", border="0")
|
"emptygroupicon_img", title="Pas d'inscrits", border="0"
|
||||||
|
)
|
||||||
|
lockicon = scu.icontag("lock32_img", title="verrouillé", border="0")
|
||||||
# Sélection sur l'etat du semestre
|
# Sélection sur l'etat du semestre
|
||||||
for sem in sems:
|
for sem in sems:
|
||||||
if sem["etat"] == "1" and sem["modalite"] != "EXT":
|
if sem["etat"] == "1" and sem["modalite"] != "EXT":
|
||||||
@ -126,11 +129,12 @@ def index_html(context, REQUEST=None, showcodes=0, showsemtable=0):
|
|||||||
)
|
)
|
||||||
|
|
||||||
H.append(
|
H.append(
|
||||||
"""<p><form action="Notes/view_formsemestre_by_etape">
|
"""<p><form action="%s/view_formsemestre_by_etape">
|
||||||
Chercher étape courante: <input name="etape_apo" type="text" size="8"></input>
|
Chercher étape courante: <input name="etape_apo" type="text" size="8" spellcheck="false"></input>
|
||||||
</form
|
</form
|
||||||
</p>
|
</p>
|
||||||
"""
|
"""
|
||||||
|
% context.NotesURL()
|
||||||
)
|
)
|
||||||
#
|
#
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = REQUEST.AUTHENTICATED_USER
|
||||||
@ -139,7 +143,7 @@ Chercher étape courante: <input name="etape_apo" type="text" size="8"></input>
|
|||||||
"""<hr>
|
"""<hr>
|
||||||
<h3>Gestion des étudiants</h3>
|
<h3>Gestion des étudiants</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a class="stdlink" href="etudident_create_form">créer <em>un</em> nouvel étudiant</a></li>
|
<li><a class="stdlink" id="link_create_etudident" href="etudident_create_form">créer <em>un</em> nouvel étudiant</a></li>
|
||||||
<li><a class="stdlink" href="form_students_import_excel">importer de nouveaux étudiants</a> (ne pas utiliser sauf cas particulier, utilisez plutôt le lien dans
|
<li><a class="stdlink" href="form_students_import_excel">importer de nouveaux étudiants</a> (ne pas utiliser sauf cas particulier, utilisez plutôt le lien dans
|
||||||
le tableau de bord semestre si vous souhaitez inscrire les
|
le tableau de bord semestre si vous souhaitez inscrire les
|
||||||
étudiants importés à un semestre)</li>
|
étudiants importés à un semestre)</li>
|
||||||
@ -152,9 +156,10 @@ Chercher étape courante: <input name="etape_apo" type="text" size="8"></input>
|
|||||||
"""<hr>
|
"""<hr>
|
||||||
<h3>Exports Apogée</h3>
|
<h3>Exports Apogée</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a class="stdlink" href="Notes/semset_page">Années scolaires / exports Apogée</a></li>
|
<li><a class="stdlink" href="%s/semset_page">Années scolaires / exports Apogée</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
"""
|
"""
|
||||||
|
% context.NotesURL()
|
||||||
)
|
)
|
||||||
#
|
#
|
||||||
H.append(
|
H.append(
|
||||||
@ -172,9 +177,9 @@ Chercher étape courante: <input name="etape_apo" type="text" size="8"></input>
|
|||||||
def _sem_table(context, sems):
|
def _sem_table(context, sems):
|
||||||
"""Affiche liste des semestres, utilisée pour semestres en cours"""
|
"""Affiche liste des semestres, utilisée pour semestres en cours"""
|
||||||
tmpl = """<tr class="%(trclass)s">%(tmpcode)s
|
tmpl = """<tr class="%(trclass)s">%(tmpcode)s
|
||||||
<td class="semicon">%(lockimg)s <a href="Notes/formsemestre_status?formsemestre_id=%(formsemestre_id)s#groupes">%(groupicon)s</a></td>
|
<td class="semicon">%(lockimg)s <a href="%(notes_url)s/formsemestre_status?formsemestre_id=%(formsemestre_id)s#groupes">%(groupicon)s</a></td>
|
||||||
<td class="datesem">%(mois_debut)s</td><td class="datesem"><a title="%(session_id)s">-</a> %(mois_fin)s</td>
|
<td class="datesem">%(mois_debut)s</td><td class="datesem"><a title="%(session_id)s">-</a> %(mois_fin)s</td>
|
||||||
<td><a class="stdlink" href="Notes/formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titre_num)s</a>
|
<td><a class="stdlink" href="%(notes_url)s/formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titre_num)s</a>
|
||||||
<span class="respsem">(%(responsable_name)s)</span>
|
<span class="respsem">(%(responsable_name)s)</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -196,6 +201,7 @@ def _sem_table(context, sems):
|
|||||||
cur_idx = sem["semestre_id"]
|
cur_idx = sem["semestre_id"]
|
||||||
else:
|
else:
|
||||||
sem["trclass"] = ""
|
sem["trclass"] = ""
|
||||||
|
sem["notes_url"] = context.NotesURL()
|
||||||
H.append(tmpl % sem)
|
H.append(tmpl % sem)
|
||||||
H.append("</table>")
|
H.append("</table>")
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
@ -242,14 +248,16 @@ def _sem_table_gt(context, sems, showcodes=False):
|
|||||||
def _style_sems(context, sems):
|
def _style_sems(context, sems):
|
||||||
"""ajoute quelques attributs de présentation pour la table"""
|
"""ajoute quelques attributs de présentation pour la table"""
|
||||||
for sem in sems:
|
for sem in sems:
|
||||||
|
sem["notes_url"] = context.NotesURL()
|
||||||
sem["_groupicon_target"] = (
|
sem["_groupicon_target"] = (
|
||||||
"Notes/formsemestre_status?formsemestre_id=%(formsemestre_id)s" % sem
|
"%(notes_url)s/formsemestre_status?formsemestre_id=%(formsemestre_id)s"
|
||||||
|
% sem
|
||||||
)
|
)
|
||||||
sem["_formsemestre_id_class"] = "blacktt"
|
sem["_formsemestre_id_class"] = "blacktt"
|
||||||
sem["dash_mois_fin"] = '<a title="%(session_id)s"></a> %(anneescolaire)s' % sem
|
sem["dash_mois_fin"] = '<a title="%(session_id)s"></a> %(anneescolaire)s' % sem
|
||||||
sem["_dash_mois_fin_class"] = "datesem"
|
sem["_dash_mois_fin_class"] = "datesem"
|
||||||
sem["titre_resp"] = (
|
sem["titre_resp"] = (
|
||||||
"""<a class="stdlink" href="Notes/formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titre_num)s</a>
|
"""<a class="stdlink" href="%(notes_url)s/formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titre_num)s</a>
|
||||||
<span class="respsem">(%(responsable_name)s)</span>"""
|
<span class="respsem">(%(responsable_name)s)</span>"""
|
||||||
% sem
|
% sem
|
||||||
)
|
)
|
||||||
|
@ -46,19 +46,24 @@ pg_dump SCORT | psql ANORT
|
|||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
import fcntl
|
import fcntl
|
||||||
import subprocess
|
import subprocess
|
||||||
import requests
|
import requests
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
|
||||||
from email.MIMEText import MIMEText
|
|
||||||
from email.MIMEBase import MIMEBase
|
|
||||||
from email.Header import Header
|
|
||||||
from email import Encoders
|
|
||||||
|
|
||||||
from notesdb import *
|
from email.MIMEMultipart import ( # pylint: disable=no-name-in-module,import-error
|
||||||
from sco_utils import *
|
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
|
||||||
|
|
||||||
|
|
||||||
|
import notesdb as ndb
|
||||||
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
|
|
||||||
SCO_DUMP_LOCK = "/tmp/scodump.lock"
|
SCO_DUMP_LOCK = "/tmp/scodump.lock"
|
||||||
|
|
||||||
@ -67,14 +72,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"""
|
"""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")]
|
H = [context.sco_header(REQUEST, page_title="Assistance technique")]
|
||||||
# get currect (dept) DB name:
|
# get currect (dept) DB name:
|
||||||
cursor = SimpleQuery(context, "SELECT current_database()", {})
|
cursor = ndb.SimpleQuery(context, "SELECT current_database()", {})
|
||||||
db_name = cursor.fetchone()[0]
|
db_name = cursor.fetchone()[0]
|
||||||
ano_db_name = "ANO" + db_name
|
ano_db_name = "ANO" + db_name
|
||||||
# Lock
|
# Lock
|
||||||
try:
|
try:
|
||||||
x = open(SCO_DUMP_LOCK, "w+")
|
x = open(SCO_DUMP_LOCK, "w+")
|
||||||
fcntl.flock(x, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
fcntl.flock(x, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||||
except fcntl.BlockingIOError:
|
except (IOError, OSError): # exception changed from Python 2 to 3
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"Un envoi de la base "
|
"Un envoi de la base "
|
||||||
+ db_name
|
+ db_name
|
||||||
@ -93,22 +98,25 @@ def sco_dump_and_send_db(context, REQUEST=None):
|
|||||||
|
|
||||||
# Send
|
# Send
|
||||||
r = _send_db(context, REQUEST, ano_db_name)
|
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(
|
H.append(
|
||||||
"""<p class="warning">
|
"""<p class="warning">
|
||||||
Erreur: espace serveur trop plein.
|
Erreur: espace serveur trop plein.
|
||||||
Merci de contacter <a href="mailto:{0}">{0}</a></p>""".format(
|
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>""")
|
H.append("""<p>Opération effectuée.</p>""")
|
||||||
else:
|
else:
|
||||||
H.append(
|
H.append(
|
||||||
"""<p class="warning">
|
"""<p class="warning">
|
||||||
Erreur: code <tt>{0} {1}</tt>
|
Erreur: code <tt>{0} {1}</tt>
|
||||||
Merci de contacter <a href="mailto:{2}">{2}</a></p>""".format(
|
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
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -128,7 +136,7 @@ def _duplicate_db(db_name, ano_db_name):
|
|||||||
cmd = ["createdb", "-E", "UTF-8", ano_db_name]
|
cmd = ["createdb", "-E", "UTF-8", ano_db_name]
|
||||||
log("sco_dump_and_send_db/_duplicate_db: {}".format(cmd))
|
log("sco_dump_and_send_db/_duplicate_db: {}".format(cmd))
|
||||||
try:
|
try:
|
||||||
out = subprocess.check_output(cmd)
|
_ = subprocess.check_output(cmd)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
log("sco_dump_and_send_db: exception createdb {}".format(e))
|
log("sco_dump_and_send_db: exception createdb {}".format(e))
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
@ -138,7 +146,7 @@ def _duplicate_db(db_name, ano_db_name):
|
|||||||
cmd = "pg_dump {} | psql {}".format(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))
|
log("sco_dump_and_send_db/_duplicate_db: {}".format(cmd))
|
||||||
try:
|
try:
|
||||||
out = subprocess.check_output(cmd, shell=1)
|
_ = subprocess.check_output(cmd, shell=1)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
log("sco_dump_and_send_db: exception {}".format(e))
|
log("sco_dump_and_send_db: exception {}".format(e))
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
@ -150,10 +158,10 @@ def _duplicate_db(db_name, ano_db_name):
|
|||||||
|
|
||||||
def _anonymize_db(ano_db_name):
|
def _anonymize_db(ano_db_name):
|
||||||
"""Anonymize a departement database"""
|
"""Anonymize a departement database"""
|
||||||
cmd = os.path.join(SCO_CONFIG_DIR, "anonymize_db.py")
|
cmd = os.path.join(scu.SCO_CONFIG_DIR, "anonymize_db.py")
|
||||||
log("_anonymize_db: {}".format(cmd))
|
log("_anonymize_db: {}".format(cmd))
|
||||||
try:
|
try:
|
||||||
out = subprocess.check_output([cmd, ano_db_name])
|
_ = subprocess.check_output([cmd, ano_db_name])
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
log("sco_dump_and_send_db: exception in anonymisation: {}".format(e))
|
log("sco_dump_and_send_db: exception in anonymisation: {}".format(e))
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
@ -163,7 +171,7 @@ def _anonymize_db(ano_db_name):
|
|||||||
|
|
||||||
def _get_scodoc_serial(context):
|
def _get_scodoc_serial(context):
|
||||||
try:
|
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:
|
except:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@ -182,7 +190,7 @@ def _send_db(context, REQUEST, ano_db_name):
|
|||||||
log("uploading anonymized dump...")
|
log("uploading anonymized dump...")
|
||||||
files = {"file": (ano_db_name + ".gz", data)}
|
files = {"file": (ano_db_name + ".gz", data)}
|
||||||
r = requests.post(
|
r = requests.post(
|
||||||
SCO_DUMP_UP_URL,
|
scu.SCO_DUMP_UP_URL,
|
||||||
files=files,
|
files=files,
|
||||||
data={
|
data={
|
||||||
"dept_name": context.get_preference("DeptName"),
|
"dept_name": context.get_preference("DeptName"),
|
||||||
@ -191,8 +199,8 @@ def _send_db(context, REQUEST, ano_db_name):
|
|||||||
"sent_by": context.Users.user_info(str(REQUEST.AUTHENTICATED_USER))[
|
"sent_by": context.Users.user_info(str(REQUEST.AUTHENTICATED_USER))[
|
||||||
"nomcomplet"
|
"nomcomplet"
|
||||||
],
|
],
|
||||||
"sco_version": SCOVERSION,
|
"sco_version": scu.SCOVERSION,
|
||||||
"sco_subversion": get_svn_version(SCO_CONFIG_DIR),
|
"sco_subversion": scu.get_svn_version(scu.SCO_CONFIG_DIR),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return r
|
return r
|
||||||
@ -210,7 +218,7 @@ def _drop_ano_db(ano_db_name):
|
|||||||
cmd = ["dropdb", ano_db_name]
|
cmd = ["dropdb", ano_db_name]
|
||||||
log("sco_dump_and_send_db: {}".format(cmd))
|
log("sco_dump_and_send_db: {}".format(cmd))
|
||||||
try:
|
try:
|
||||||
out = subprocess.check_output(cmd)
|
_ = subprocess.check_output(cmd)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
log("sco_dump_and_send_db: exception dropdb {}".format(e))
|
log("sco_dump_and_send_db: exception dropdb {}".format(e))
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
|
@ -28,12 +28,13 @@
|
|||||||
"""Ajout/Modification/Supression formations
|
"""Ajout/Modification/Supression formations
|
||||||
(portage from DTML)
|
(portage from DTML)
|
||||||
"""
|
"""
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from TrivialFormulator import TrivialFormulator, TF
|
from TrivialFormulator import TrivialFormulator, TF, tf_error_message
|
||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
|
|
||||||
|
|
||||||
def formation_delete(context, formation_id=None, dialog_confirmed=False, REQUEST=None):
|
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>'
|
'<li><a href="formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titremois)s</a></li>'
|
||||||
% sem
|
% 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:
|
else:
|
||||||
if not dialog_confirmed:
|
if not dialog_confirmed:
|
||||||
return context.confirmDialog(
|
return context.confirmDialog(
|
||||||
@ -72,7 +73,7 @@ def formation_delete(context, formation_id=None, dialog_confirmed=False, REQUEST
|
|||||||
% F,
|
% F,
|
||||||
REQUEST=REQUEST,
|
REQUEST=REQUEST,
|
||||||
OK="Supprimer cette formation",
|
OK="Supprimer cette formation",
|
||||||
cancel_url=REQUEST.URL1,
|
cancel_url=context.NotesURL(),
|
||||||
parameters={"formation_id": formation_id},
|
parameters={"formation_id": formation_id},
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -80,7 +81,7 @@ def formation_delete(context, formation_id=None, dialog_confirmed=False, REQUEST
|
|||||||
H.append(
|
H.append(
|
||||||
"""<p>OK, formation supprimée.</p>
|
"""<p>OK, formation supprimée.</p>
|
||||||
<p><a class="stdlink" href="%s">continuer</a></p>"""
|
<p><a class="stdlink" href="%s">continuer</a></p>"""
|
||||||
% REQUEST.URL1
|
% context.NotesURL()
|
||||||
)
|
)
|
||||||
|
|
||||||
H.append(context.sco_footer(REQUEST))
|
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:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
return REQUEST.RESPONSE.redirect(context.NotesURL())
|
||||||
else:
|
else:
|
||||||
# check unicity : constraint UNIQUE(acronyme,titre,version)
|
# check unicity : constraint UNIQUE(acronyme,titre,version)
|
||||||
if create:
|
if create:
|
||||||
@ -202,7 +203,7 @@ def formation_edit(context, formation_id=None, create=False, REQUEST=None):
|
|||||||
"titre": tf[2]["titre"],
|
"titre": tf[2]["titre"],
|
||||||
"version": version,
|
"version": version,
|
||||||
}
|
}
|
||||||
quote_dict(args)
|
ndb.quote_dict(args)
|
||||||
others = context.formation_list(args=args)
|
others = context.formation_list(args=args)
|
||||||
if others and ((len(others) > 1) or others[0]["formation_id"] != formation_id):
|
if others and ((len(others) > 1) or others[0]["formation_id"] != formation_id):
|
||||||
return (
|
return (
|
||||||
|
@ -28,11 +28,12 @@
|
|||||||
"""Ajout/Modification/Supression matieres
|
"""Ajout/Modification/Supression matieres
|
||||||
(portage from DTML)
|
(portage from DTML)
|
||||||
"""
|
"""
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from TrivialFormulator import TrivialFormulator, TF
|
from TrivialFormulator import TrivialFormulator, TF, tf_error_message
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
|
|
||||||
|
|
||||||
def matiere_create(context, ue_id=None, REQUEST=None):
|
def matiere_create(context, ue_id=None, REQUEST=None):
|
||||||
@ -74,7 +75,7 @@ associé.
|
|||||||
submitlabel="Créer cette matière",
|
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:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
||||||
@ -90,7 +91,7 @@ associé.
|
|||||||
+ tf[1]
|
+ tf[1]
|
||||||
+ context.sco_footer(REQUEST)
|
+ 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)
|
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,
|
"<h2>Suppression de la matière %(titre)s" % M,
|
||||||
" dans l'UE (%(acronyme)s))</h2>" % UE,
|
" dans l'UE (%(acronyme)s))</h2>" % UE,
|
||||||
]
|
]
|
||||||
|
dest_url = context.NotesURL() + "/ue_list?formation_id=" + str(UE["formation_id"])
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
REQUEST.URL0,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
@ -115,12 +116,10 @@ def matiere_delete(context, matiere_id=None, REQUEST=None):
|
|||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
return REQUEST.RESPONSE.redirect(dest_url)
|
||||||
else:
|
else:
|
||||||
context.do_matiere_delete(matiere_id, REQUEST)
|
context.do_matiere_delete(matiere_id, REQUEST)
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(dest_url)
|
||||||
REQUEST.URL1 + "/ue_list?formation_id=" + str(UE["formation_id"])
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def matiere_edit(context, matiere_id=None, REQUEST=None):
|
def matiere_edit(context, matiere_id=None, REQUEST=None):
|
||||||
@ -180,7 +179,7 @@ associé.
|
|||||||
submitlabel="Modifier les valeurs",
|
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:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + help + context.sco_footer(REQUEST)
|
return "\n".join(H) + tf[1] + help + context.sco_footer(REQUEST)
|
||||||
@ -202,7 +201,7 @@ associé.
|
|||||||
# changement d'UE ?
|
# changement d'UE ?
|
||||||
if tf[2]["ue_id"] != F["ue_id"]:
|
if tf[2]["ue_id"] != F["ue_id"]:
|
||||||
log("attaching mat %s to new UE %s" % (matiere_id, tf[2]["ue_id"]))
|
log("attaching mat %s to new UE %s" % (matiere_id, tf[2]["ue_id"]))
|
||||||
SimpleQuery(
|
ndb.SimpleQuery(
|
||||||
context,
|
context,
|
||||||
"UPDATE notes_modules SET ue_id = %(ue_id)s WHERE matiere_id=%(matiere_id)s",
|
"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},
|
{"ue_id": tf[2]["ue_id"], "matiere_id": matiere_id},
|
||||||
|
@ -28,14 +28,16 @@
|
|||||||
"""Ajout/Modification/Supression UE
|
"""Ajout/Modification/Supression UE
|
||||||
(portage from DTML)
|
(portage from DTML)
|
||||||
"""
|
"""
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
from TrivialFormulator import TrivialFormulator, TF
|
from TrivialFormulator import TrivialFormulator, TF
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_edit_ue
|
import sco_edit_ue
|
||||||
import sco_tag_module
|
import sco_tag_module
|
||||||
|
from sco_permissions import ScoChangeFormation
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
|
|
||||||
_MODULE_HELP = """<p class="help">
|
_MODULE_HELP = """<p class="help">
|
||||||
Les modules sont décrits dans le programme pédagogique. Un module est pour ce
|
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",
|
"title": "Type",
|
||||||
"explanation": "",
|
"explanation": "",
|
||||||
"labels": ("Standard", "Malus"),
|
"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",
|
"input_type": "menu",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"title": strcapitalize(parcours.SESSION_NAME),
|
"title": scu.strcapitalize(parcours.SESSION_NAME),
|
||||||
"explanation": "%s de début du module dans la formation standard"
|
"explanation": "%s de début du module dans la formation standard"
|
||||||
% parcours.SESSION_NAME,
|
% parcours.SESSION_NAME,
|
||||||
"labels": [str(x) for x in semestres_indices],
|
"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:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
return "\n".join(H) + tf[1] + context.sco_footer(REQUEST)
|
||||||
else:
|
else:
|
||||||
moduleid = context.do_module_create(tf[2], REQUEST)
|
context.do_module_create(tf[2], REQUEST)
|
||||||
return REQUEST.RESPONSE.redirect(
|
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,
|
"""<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(
|
tf = TrivialFormulator(
|
||||||
REQUEST.URL0,
|
REQUEST.URL0,
|
||||||
REQUEST.form,
|
REQUEST.form,
|
||||||
@ -227,7 +229,7 @@ def module_edit(context, module_id=None, REQUEST=None):
|
|||||||
unlocked = not context.module_is_locked(module_id)
|
unlocked = not context.module_is_locked(module_id)
|
||||||
Fo = context.formation_list(args={"formation_id": Mod["formation_id"]})[0]
|
Fo = context.formation_list(args={"formation_id": Mod["formation_id"]})[0]
|
||||||
parcours = sco_codes_parcours.get_parcours_from_code(Fo["type_parcours"])
|
parcours = sco_codes_parcours.get_parcours_from_code(Fo["type_parcours"])
|
||||||
M = SimpleDictFetch(
|
M = ndb.SimpleDictFetch(
|
||||||
context,
|
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",
|
"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"]},
|
{"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)
|
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 = [
|
H = [
|
||||||
context.sco_header(
|
context.sco_header(
|
||||||
@ -286,7 +288,7 @@ def module_edit(context, module_id=None, REQUEST=None):
|
|||||||
"title": "Type",
|
"title": "Type",
|
||||||
"explanation": "",
|
"explanation": "",
|
||||||
"labels": ("Standard", "Malus"),
|
"labels": ("Standard", "Malus"),
|
||||||
"allowed_values": (str(MODULE_STANDARD), str(MODULE_MALUS)),
|
"allowed_values": (str(scu.MODULE_STANDARD), str(scu.MODULE_MALUS)),
|
||||||
"enabled": unlocked,
|
"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})
|
modules = context.do_module_list(args={"module_id": module_id})
|
||||||
if not modules:
|
if not modules:
|
||||||
return "module invalide" # shoud not occur
|
return "module invalide" # shoud not occur
|
||||||
module = modules[0]
|
|
||||||
|
|
||||||
context.do_module_edit({"module_id": module_id, "code_apogee": value})
|
context.do_module_edit({"module_id": module_id, "code_apogee": value})
|
||||||
if not value:
|
if not value:
|
||||||
value = APO_MISSING_CODE_STR
|
value = scu.APO_MISSING_CODE_STR
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
@ -444,14 +445,14 @@ def formation_add_malus_modules(context, formation_id, titre=None, REQUEST=None)
|
|||||||
[
|
[
|
||||||
mod
|
mod
|
||||||
for mod in context.do_module_list(args={"ue_id": ue["ue_id"]})
|
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:
|
if nb_mod_malus == 0:
|
||||||
ue_add_malus_module(context, ue["ue_id"], titre=titre, REQUEST=REQUEST)
|
ue_add_malus_module(context, ue["ue_id"], titre=titre, REQUEST=REQUEST)
|
||||||
|
|
||||||
if 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):
|
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,
|
"matiere_id": matiere_id,
|
||||||
"formation_id": ue["formation_id"],
|
"formation_id": ue["formation_id"],
|
||||||
"semestre_id": semestre_id,
|
"semestre_id": semestre_id,
|
||||||
"module_type": MODULE_MALUS,
|
"module_type": scu.MODULE_MALUS,
|
||||||
},
|
},
|
||||||
REQUEST,
|
REQUEST,
|
||||||
)
|
)
|
||||||
|
@ -28,8 +28,8 @@
|
|||||||
"""Ajout/Modification/Supression UE
|
"""Ajout/Modification/Supression UE
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from TrivialFormulator import TrivialFormulator, TF
|
from TrivialFormulator import TrivialFormulator, TF
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
@ -38,6 +38,8 @@ import sco_formsemestre
|
|||||||
import sco_formsemestre_validation
|
import sco_formsemestre_validation
|
||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
import sco_tag_module
|
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):
|
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 = parcours.ALLOWED_UE_TYPES
|
||||||
ue_types.sort()
|
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]
|
ue_types = [str(x) for x in ue_types]
|
||||||
|
|
||||||
fw = [
|
fw = [
|
||||||
@ -158,7 +160,7 @@ def ue_edit(context, ue_id=None, create=False, formation_id=None, REQUEST=None):
|
|||||||
{
|
{
|
||||||
"input_type": "menu",
|
"input_type": "menu",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"title": strcapitalize(parcours.SESSION_NAME),
|
"title": scu.strcapitalize(parcours.SESSION_NAME),
|
||||||
"explanation": "%s de début du module dans la formation"
|
"explanation": "%s de début du module dans la formation"
|
||||||
% parcours.SESSION_NAME,
|
% parcours.SESSION_NAME,
|
||||||
"labels": [str(x) for x in semestres_indices],
|
"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:
|
if parcours.UE_IS_MODULE:
|
||||||
# dans ce mode, crée un (unique) module dans l'UE:
|
# 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"],
|
"titre": tf[2]["titre"],
|
||||||
"code": tf[2]["acronyme"],
|
"code": tf[2]["acronyme"],
|
||||||
@ -217,9 +219,9 @@ def ue_edit(context, ue_id=None, create=False, formation_id=None, REQUEST=None):
|
|||||||
REQUEST,
|
REQUEST,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
ue_id = do_ue_edit(context, tf[2])
|
do_ue_edit(context, tf[2])
|
||||||
return REQUEST.RESPONSE.redirect(
|
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
|
editable = perm_change
|
||||||
tag_editable = authuser.has_permission(ScoEditFormationTags, context) or perm_change
|
tag_editable = authuser.has_permission(ScoEditFormationTags, context) or perm_change
|
||||||
if locked:
|
if locked:
|
||||||
lockicon = icontag("lock32_img", title="verrouillé")
|
lockicon = scu.icontag("lock32_img", title="verrouillé")
|
||||||
else:
|
else:
|
||||||
lockicon = ""
|
lockicon = ""
|
||||||
|
|
||||||
arrow_up, arrow_down, arrow_none = sco_groups.getArrowIconsTags(context, REQUEST)
|
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_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é)"
|
"delete_small_dis_img", title="Suppression impossible (module utilisé)"
|
||||||
)
|
)
|
||||||
H = [
|
H = [
|
||||||
@ -415,7 +417,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
|||||||
klass = ""
|
klass = ""
|
||||||
UE["code_apogee_str"] = (
|
UE["code_apogee_str"] = (
|
||||||
""", Apo: <span class="%s" data-url="edit_ue_set_code_apogee" id="%s" data-placeholder="%s">"""
|
""", 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 "")
|
+ (UE["code_apogee"] or "")
|
||||||
+ "</span>"
|
+ "</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"]
|
cur_ue_semestre_id = UE["semestre_id"]
|
||||||
if iue > 0:
|
if iue > 0:
|
||||||
H.append("</ul>")
|
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:"
|
lab = "Pas d'indication de semestre:"
|
||||||
else:
|
else:
|
||||||
lab = "Semestre %s:" % UE["semestre_id"]
|
lab = "Semestre %s:" % UE["semestre_id"]
|
||||||
@ -433,14 +435,14 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
|||||||
H.append('<li class="notes_ue_list">')
|
H.append('<li class="notes_ue_list">')
|
||||||
if iue != 0 and editable:
|
if iue != 0 and editable:
|
||||||
H.append(
|
H.append(
|
||||||
'<a href="ue_move?ue_id=%s&after=0" class="aud">%s</a>'
|
'<a href="ue_move?ue_id=%s&after=0" class="aud">%s</a>'
|
||||||
% (UE["ue_id"], arrow_up)
|
% (UE["ue_id"], arrow_up)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
H.append(arrow_none)
|
H.append(arrow_none)
|
||||||
if iue < len(ue_list) - 1 and editable:
|
if iue < len(ue_list) - 1 and editable:
|
||||||
H.append(
|
H.append(
|
||||||
'<a href="ue_move?ue_id=%s&after=1" class="aud">%s</a>'
|
'<a href="ue_move?ue_id=%s&after=1" class="aud">%s</a>'
|
||||||
% (UE["ue_id"], arrow_down)
|
% (UE["ue_id"], arrow_down)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -456,8 +458,11 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
|||||||
% UE
|
% UE
|
||||||
)
|
)
|
||||||
|
|
||||||
if UE["type"] != UE_STANDARD:
|
if UE["type"] != sco_codes_parcours.UE_STANDARD:
|
||||||
H.append('<span class="ue_type">%s</span>' % UE_TYPE_NAME[UE["type"]])
|
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"])
|
ue_editable = editable and not context.ue_is_locked(UE["ue_id"])
|
||||||
if ue_editable:
|
if ue_editable:
|
||||||
H.append(
|
H.append(
|
||||||
@ -488,21 +493,21 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
|||||||
Mod["module_id"]
|
Mod["module_id"]
|
||||||
)
|
)
|
||||||
klass = "notes_module_list"
|
klass = "notes_module_list"
|
||||||
if Mod["module_type"] == MODULE_MALUS:
|
if Mod["module_type"] == scu.MODULE_MALUS:
|
||||||
klass += " module_malus"
|
klass += " module_malus"
|
||||||
H.append('<li class="%s">' % klass)
|
H.append('<li class="%s">' % klass)
|
||||||
|
|
||||||
H.append('<span class="notes_module_list_buts">')
|
H.append('<span class="notes_module_list_buts">')
|
||||||
if im != 0 and editable:
|
if im != 0 and editable:
|
||||||
H.append(
|
H.append(
|
||||||
'<a href="module_move?module_id=%s&after=0" class="aud">%s</a>'
|
'<a href="module_move?module_id=%s&after=0" class="aud">%s</a>'
|
||||||
% (Mod["module_id"], arrow_up)
|
% (Mod["module_id"], arrow_up)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
H.append(arrow_none)
|
H.append(arrow_none)
|
||||||
if im < len(Modlist) - 1 and editable:
|
if im < len(Modlist) - 1 and editable:
|
||||||
H.append(
|
H.append(
|
||||||
'<a href="module_move?module_id=%s&after=1" class="aud">%s</a>'
|
'<a href="module_move?module_id=%s&after=1" class="aud">%s</a>'
|
||||||
% (Mod["module_id"], arrow_down)
|
% (Mod["module_id"], arrow_down)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -527,7 +532,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
|||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
'<span class="formation_module_tit">%s</span>'
|
'<span class="formation_module_tit">%s</span>'
|
||||||
% join_words(Mod["code"], Mod["titre"])
|
% scu.join_words(Mod["code"], Mod["titre"])
|
||||||
)
|
)
|
||||||
if mod_editable:
|
if mod_editable:
|
||||||
H.append("</a>")
|
H.append("</a>")
|
||||||
@ -541,7 +546,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
|||||||
klass = ""
|
klass = ""
|
||||||
heurescoef += (
|
heurescoef += (
|
||||||
', Apo: <span class="%s" data-url="edit_module_set_code_apogee" id="%s" data-placeholder="%s">'
|
', 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 "")
|
+ (Mod["code_apogee"] or "")
|
||||||
+ "</span>"
|
+ "</span>"
|
||||||
)
|
)
|
||||||
@ -615,9 +620,9 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
|||||||
"""
|
"""
|
||||||
<li><a class="stdlink" href="formation_table_recap?formation_id=%(formation_id)s">Table récapitulative de la formation</a></li>
|
<li><a class="stdlink" href="formation_table_recap?formation_id=%(formation_id)s">Table récapitulative de la formation</a></li>
|
||||||
|
|
||||||
<li><a class="stdlink" href="formation_export?formation_id=%(formation_id)s&format=xml">Export XML de la formation</a> (permet de la sauvegarder pour l'échanger avec un autre site)</li>
|
<li><a class="stdlink" href="formation_export?formation_id=%(formation_id)s&format=xml">Export XML de la formation</a> (permet de la sauvegarder pour l'échanger avec un autre site)</li>
|
||||||
|
|
||||||
<li><a class="stdlink" href="formation_export?formation_id=%(formation_id)s&format=json">Export JSON de la formation</a></li>
|
<li><a class="stdlink" href="formation_export?formation_id=%(formation_id)s&format=json">Export JSON de la formation</a></li>
|
||||||
|
|
||||||
<li><a class="stdlink" href="module_list?formation_id=%(formation_id)s">Liste détaillée des modules de la formation</a> (debug) </li>
|
<li><a class="stdlink" href="module_list?formation_id=%(formation_id)s">Liste détaillée des modules de la formation</a> (debug) </li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -641,7 +646,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
|||||||
H.append(" [verrouillé]")
|
H.append(" [verrouillé]")
|
||||||
else:
|
else:
|
||||||
H.append(
|
H.append(
|
||||||
' <a class="stdlink" href="formsemestre_editwithmodules?formation_id=%(formation_id)s&formsemestre_id=%(formsemestre_id)s">Modifier</a>'
|
' <a class="stdlink" href="formsemestre_editwithmodules?formation_id=%(formation_id)s&formsemestre_id=%(formsemestre_id)s">Modifier</a>'
|
||||||
% sem
|
% sem
|
||||||
)
|
)
|
||||||
H.append("</li>")
|
H.append("</li>")
|
||||||
@ -650,7 +655,7 @@ Si vous souhaitez modifier cette formation (par exemple pour y ajouter un module
|
|||||||
if authuser.has_permission(ScoImplement, context):
|
if authuser.has_permission(ScoImplement, context):
|
||||||
H.append(
|
H.append(
|
||||||
"""<ul>
|
"""<ul>
|
||||||
<li><a class="stdlink" href="formsemestre_createwithmodules?formation_id=%(formation_id)s&semestre_id=1">Mettre en place un nouveau semestre de formation %(acronyme)s</a>
|
<li><a class="stdlink" href="formsemestre_createwithmodules?formation_id=%(formation_id)s&semestre_id=1">Mettre en place un nouveau semestre de formation %(acronyme)s</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>"""
|
</ul>"""
|
||||||
@ -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>
|
# <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(
|
warn, _ = sco_formsemestre_validation.check_formation_ues(context, formation_id)
|
||||||
context, formation_id
|
|
||||||
)
|
|
||||||
H.append(warn)
|
H.append(warn)
|
||||||
|
|
||||||
H.append(context.sco_footer(REQUEST))
|
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})
|
ues = context.do_ue_list(args={"ue_id": ue_id})
|
||||||
if not ues:
|
if not ues:
|
||||||
return "ue invalide"
|
return "ue invalide"
|
||||||
ue = ues[0]
|
|
||||||
|
|
||||||
do_ue_edit(
|
do_ue_edit(
|
||||||
context,
|
context,
|
||||||
@ -773,13 +775,13 @@ def edit_ue_set_code_apogee(context, id=None, value=None, REQUEST=None):
|
|||||||
dont_invalidate_cache=False,
|
dont_invalidate_cache=False,
|
||||||
)
|
)
|
||||||
if not value:
|
if not value:
|
||||||
value = APO_MISSING_CODE_STR
|
value = scu.APO_MISSING_CODE_STR
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
# ---- Table recap formation
|
# ---- Table recap formation
|
||||||
def formation_table_recap(context, formation_id, format="html", REQUEST=None):
|
def formation_table_recap(context, formation_id, format="html", REQUEST=None):
|
||||||
""""""
|
"""Table recapitulant formation."""
|
||||||
F = context.formation_list(args={"formation_id": formation_id})
|
F = context.formation_list(args={"formation_id": formation_id})
|
||||||
if not F:
|
if not F:
|
||||||
raise ScoValueError("invalid formation_id")
|
raise ScoValueError("invalid formation_id")
|
||||||
@ -845,7 +847,9 @@ def formation_table_recap(context, formation_id, format="html", REQUEST=None):
|
|||||||
columns_ids=columns_ids,
|
columns_ids=columns_ids,
|
||||||
rows=T,
|
rows=T,
|
||||||
titles=titles,
|
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,
|
caption=title,
|
||||||
html_caption=title,
|
html_caption=title,
|
||||||
html_class="table_leftalign",
|
html_class="table_leftalign",
|
||||||
|
@ -36,8 +36,10 @@ XXX incompatible avec les ics HyperPlanning Paris 13 (était pour GPU).
|
|||||||
import urllib2
|
import urllib2
|
||||||
import traceback
|
import traceback
|
||||||
import icalendar
|
import icalendar
|
||||||
|
import pprint
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
|
from notes_log import log
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_groups
|
import sco_groups
|
||||||
import sco_groups_view
|
import sco_groups_view
|
||||||
@ -84,10 +86,10 @@ def formsemestre_load_ics(context, sem):
|
|||||||
return cal
|
return cal
|
||||||
|
|
||||||
|
|
||||||
def formsemestre_edt_groups_used(context, sem):
|
# def formsemestre_edt_groups_used(context, sem):
|
||||||
"""L'ensemble des groupes EDT utilisés dans l'emplois du temps publié"""
|
# """L'ensemble des groupes EDT utilisés dans l'emploi du temps publié"""
|
||||||
cal = formsemestre_load_ics(context, sem)
|
# cal = formsemestre_load_ics(context, sem)
|
||||||
return {e["X-GROUP-ID"].decode("utf8") for e in events}
|
# return {e["X-GROUP-ID"].decode("utf8") for e in events}
|
||||||
|
|
||||||
|
|
||||||
def get_edt_transcodage_groups(context, formsemestre_id):
|
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)
|
J.append(d)
|
||||||
|
|
||||||
return sendJSON(REQUEST, J)
|
return scu.sendJSON(REQUEST, J)
|
||||||
|
|
||||||
|
|
||||||
"""XXX
|
"""XXX
|
||||||
|
326
sco_entreprises.py
Normal file
326
sco_entreprises.py
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gestion scolarite IUT
|
||||||
|
#
|
||||||
|
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Emmanuel Viennet emmanuel.viennet@viennet.net
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""Fonctions sur les entreprises
|
||||||
|
"""
|
||||||
|
# codes anciens déplacés de ZEntreprise
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
import sco_utils as scu
|
||||||
|
from notesdb import ScoDocCursor, EditableTable, DateISOtoDMY, DateDMYtoISO
|
||||||
|
|
||||||
|
|
||||||
|
def _format_nom(nom):
|
||||||
|
"formatte nom (filtre en entree db) d'une entreprise"
|
||||||
|
if not nom:
|
||||||
|
return nom
|
||||||
|
nom = nom.decode(scu.SCO_ENCODING)
|
||||||
|
return (nom[0].upper() + nom[1:]).encode(scu.SCO_ENCODING)
|
||||||
|
|
||||||
|
|
||||||
|
class EntreprisesEditor(EditableTable):
|
||||||
|
def delete(self, cnx, oid):
|
||||||
|
"delete correspondants and contacts, then self"
|
||||||
|
# first, delete all correspondants and contacts
|
||||||
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
|
cursor.execute(
|
||||||
|
"delete from entreprise_contact where entreprise_id=%(entreprise_id)s",
|
||||||
|
{"entreprise_id": oid},
|
||||||
|
)
|
||||||
|
cursor.execute(
|
||||||
|
"delete from entreprise_correspondant where entreprise_id=%(entreprise_id)s",
|
||||||
|
{"entreprise_id": oid},
|
||||||
|
)
|
||||||
|
cnx.commit()
|
||||||
|
EditableTable.delete(self, cnx, oid)
|
||||||
|
|
||||||
|
def list(
|
||||||
|
self,
|
||||||
|
cnx,
|
||||||
|
args={},
|
||||||
|
operator="and",
|
||||||
|
test="=",
|
||||||
|
sortkey=None,
|
||||||
|
sort_on_contact=False,
|
||||||
|
context=None,
|
||||||
|
limit="",
|
||||||
|
offset="",
|
||||||
|
):
|
||||||
|
# list, then sort on date of last contact
|
||||||
|
R = EditableTable.list(
|
||||||
|
self,
|
||||||
|
cnx,
|
||||||
|
args=args,
|
||||||
|
operator=operator,
|
||||||
|
test=test,
|
||||||
|
sortkey=sortkey,
|
||||||
|
limit=limit,
|
||||||
|
offset=offset,
|
||||||
|
)
|
||||||
|
if sort_on_contact:
|
||||||
|
for r in R:
|
||||||
|
c = do_entreprise_contact_list(
|
||||||
|
context,
|
||||||
|
args={"entreprise_id": r["entreprise_id"]},
|
||||||
|
disable_formatting=True,
|
||||||
|
)
|
||||||
|
if c:
|
||||||
|
r["date"] = max([x["date"] or datetime.date.min for x in c])
|
||||||
|
else:
|
||||||
|
r["date"] = datetime.date.min
|
||||||
|
# sort
|
||||||
|
R.sort(lambda r1, r2: cmp(r2["date"], r1["date"]))
|
||||||
|
for r in R:
|
||||||
|
r["date"] = DateISOtoDMY(r["date"])
|
||||||
|
return R
|
||||||
|
|
||||||
|
def list_by_etud(
|
||||||
|
self, cnx, args={}, sort_on_contact=False, disable_formatting=False
|
||||||
|
):
|
||||||
|
"cherche rentreprise ayant eu contact avec etudiant"
|
||||||
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
|
cursor.execute(
|
||||||
|
"select E.*, I.nom as etud_nom, I.prenom as etud_prenom, C.date from entreprises E, entreprise_contact C, identite I where C.entreprise_id = E.entreprise_id and C.etudid = I.etudid and I.nom ~* %(etud_nom)s ORDER BY E.nom",
|
||||||
|
args,
|
||||||
|
)
|
||||||
|
_, res = [x[0] for x in cursor.description], cursor.dictfetchall()
|
||||||
|
R = []
|
||||||
|
for r in res:
|
||||||
|
r["etud_prenom"] = r["etud_prenom"] or ""
|
||||||
|
d = {}
|
||||||
|
for key in r:
|
||||||
|
v = r[key]
|
||||||
|
# format value
|
||||||
|
if not disable_formatting and self.output_formators.has_key(key):
|
||||||
|
v = self.output_formators[key](v)
|
||||||
|
d[key] = v
|
||||||
|
R.append(d)
|
||||||
|
# sort
|
||||||
|
if sort_on_contact:
|
||||||
|
R.sort(
|
||||||
|
lambda r1, r2: cmp(
|
||||||
|
r2["date"] or datetime.date.min, r1["date"] or datetime.date.min
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for r in R:
|
||||||
|
r["date"] = DateISOtoDMY(r["date"] or datetime.date.min)
|
||||||
|
return R
|
||||||
|
|
||||||
|
|
||||||
|
_entreprisesEditor = EntreprisesEditor(
|
||||||
|
"entreprises",
|
||||||
|
"entreprise_id",
|
||||||
|
(
|
||||||
|
"entreprise_id",
|
||||||
|
"nom",
|
||||||
|
"adresse",
|
||||||
|
"ville",
|
||||||
|
"codepostal",
|
||||||
|
"pays",
|
||||||
|
"contact_origine",
|
||||||
|
"secteur",
|
||||||
|
"privee",
|
||||||
|
"localisation",
|
||||||
|
"qualite_relation",
|
||||||
|
"plus10salaries",
|
||||||
|
"note",
|
||||||
|
"date_creation",
|
||||||
|
),
|
||||||
|
sortkey="nom",
|
||||||
|
input_formators={"nom": _format_nom},
|
||||||
|
)
|
||||||
|
|
||||||
|
# ----------- Correspondants
|
||||||
|
_entreprise_correspEditor = EditableTable(
|
||||||
|
"entreprise_correspondant",
|
||||||
|
"entreprise_corresp_id",
|
||||||
|
(
|
||||||
|
"entreprise_corresp_id",
|
||||||
|
"entreprise_id",
|
||||||
|
"civilite",
|
||||||
|
"nom",
|
||||||
|
"prenom",
|
||||||
|
"fonction",
|
||||||
|
"phone1",
|
||||||
|
"phone2",
|
||||||
|
"mobile",
|
||||||
|
"fax",
|
||||||
|
"mail1",
|
||||||
|
"mail2",
|
||||||
|
"note",
|
||||||
|
),
|
||||||
|
sortkey="nom",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ----------- Contacts
|
||||||
|
_entreprise_contactEditor = EditableTable(
|
||||||
|
"entreprise_contact",
|
||||||
|
"entreprise_contact_id",
|
||||||
|
(
|
||||||
|
"entreprise_contact_id",
|
||||||
|
"date",
|
||||||
|
"type_contact",
|
||||||
|
"entreprise_id",
|
||||||
|
"entreprise_corresp_id",
|
||||||
|
"etudid",
|
||||||
|
"description",
|
||||||
|
"enseignant",
|
||||||
|
),
|
||||||
|
sortkey="date",
|
||||||
|
output_formators={"date": DateISOtoDMY},
|
||||||
|
input_formators={"date": DateDMYtoISO},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_create(context, args):
|
||||||
|
"entreprise_create"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
r = _entreprisesEditor.create(cnx, args)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_delete(context, oid):
|
||||||
|
"entreprise_delete"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
_entreprisesEditor.delete(cnx, oid)
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_list(context, **kw):
|
||||||
|
"entreprise_list"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
kw["context"] = context
|
||||||
|
return _entreprisesEditor.list(cnx, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_list_by_etud(context, **kw):
|
||||||
|
"entreprise_list_by_etud"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
return _entreprisesEditor.list_by_etud(cnx, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_edit(context, *args, **kw):
|
||||||
|
"entreprise_edit"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
_entreprisesEditor.edit(cnx, *args, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_correspondant_create(context, args):
|
||||||
|
"entreprise_correspondant_create"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
r = _entreprise_correspEditor.create(cnx, args)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_correspondant_delete(context, oid):
|
||||||
|
"entreprise_correspondant_delete"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
_entreprise_correspEditor.delete(cnx, oid)
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_correspondant_list(context, **kw):
|
||||||
|
"entreprise_correspondant_list"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
return _entreprise_correspEditor.list(cnx, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_correspondant_edit(context, *args, **kw):
|
||||||
|
"entreprise_correspondant_edit"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
_entreprise_correspEditor.edit(cnx, *args, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_correspondant_listnames(context, args={}):
|
||||||
|
"-> liste des noms des correspondants (pour affichage menu)"
|
||||||
|
C = do_entreprise_correspondant_list(context, args=args)
|
||||||
|
return [(x["prenom"] + " " + x["nom"], str(x["entreprise_corresp_id"])) for x in C]
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_contact_delete(context, oid):
|
||||||
|
"entreprise_contact_delete"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
_entreprise_contactEditor.delete(cnx, oid)
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_contact_list(context, **kw):
|
||||||
|
"entreprise_contact_list"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
return _entreprise_contactEditor.list(cnx, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_contact_edit(context, *args, **kw):
|
||||||
|
"entreprise_contact_edit"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
_entreprise_contactEditor.edit(cnx, *args, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_contact_create(context, args):
|
||||||
|
"entreprise_contact_create"
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
r = _entreprise_contactEditor.create(cnx, args)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def do_entreprise_check_etudiant(context, etudiant):
|
||||||
|
"""Si etudiant est vide, ou un ETUDID valide, ou un nom unique,
|
||||||
|
retourne (1, ETUDID).
|
||||||
|
Sinon, retourne (0, 'message explicatif')
|
||||||
|
"""
|
||||||
|
etudiant = etudiant.strip().translate(
|
||||||
|
None, "'()"
|
||||||
|
) # suppress parens and quote from name
|
||||||
|
if not etudiant:
|
||||||
|
return 1, None
|
||||||
|
cnx = context.GetDBConnexion()
|
||||||
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
|
cursor.execute(
|
||||||
|
"select etudid, nom, prenom from identite where upper(nom) ~ upper(%(etudiant)s) or etudid=%(etudiant)s",
|
||||||
|
{"etudiant": etudiant},
|
||||||
|
)
|
||||||
|
r = cursor.fetchall()
|
||||||
|
if len(r) < 1:
|
||||||
|
return 0, 'Aucun etudiant ne correspond à "%s"' % etudiant
|
||||||
|
elif len(r) > 10:
|
||||||
|
return (
|
||||||
|
0,
|
||||||
|
"<b>%d etudiants</b> correspondent à ce nom (utilisez le code)" % len(r),
|
||||||
|
)
|
||||||
|
elif len(r) > 1:
|
||||||
|
e = ['<ul class="entreprise_etud_list">']
|
||||||
|
for x in r:
|
||||||
|
e.append(
|
||||||
|
"<li>%s %s (code %s)</li>"
|
||||||
|
% (scu.strupper(x[1]), x[2] or "", x[0].strip())
|
||||||
|
)
|
||||||
|
e.append("</ul>")
|
||||||
|
return (
|
||||||
|
0,
|
||||||
|
"Les étudiants suivants correspondent: préciser le nom complet ou le code\n"
|
||||||
|
+ "\n".join(e),
|
||||||
|
)
|
||||||
|
else: # une seule reponse !
|
||||||
|
return 1, r[0][0].strip()
|
@ -75,7 +75,9 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from sco_utils import *
|
import re
|
||||||
|
|
||||||
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import notes_table
|
import notes_table
|
||||||
@ -83,6 +85,7 @@ import sco_groups
|
|||||||
import sco_groups_view
|
import sco_groups_view
|
||||||
import sco_archives
|
import sco_archives
|
||||||
import sco_apogee_csv
|
import sco_apogee_csv
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
|
|
||||||
|
|
||||||
class ApoCSVArchiver(sco_archives.BaseArchiver):
|
class ApoCSVArchiver(sco_archives.BaseArchiver):
|
||||||
@ -110,7 +113,7 @@ def apo_csv_store(context, csv_data, annee_scolaire, sem_id):
|
|||||||
"""
|
"""
|
||||||
# sanity check
|
# sanity check
|
||||||
filesize = len(csv_data)
|
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)
|
raise ScoValueError("Fichier csv de taille invalide ! (%d)" % filesize)
|
||||||
|
|
||||||
if not annee_scolaire:
|
if not annee_scolaire:
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_formsemestre_status
|
import sco_formsemestre_status
|
||||||
@ -43,6 +43,7 @@ import sco_apogee_csv
|
|||||||
import sco_portal_apogee
|
import sco_portal_apogee
|
||||||
from sco_apogee_csv import APO_PORTAL_ENCODING, APO_INPUT_ENCODING
|
from sco_apogee_csv import APO_PORTAL_ENCODING, APO_INPUT_ENCODING
|
||||||
import sco_archives
|
import sco_archives
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
|
|
||||||
|
|
||||||
def apo_semset_maq_status(
|
def apo_semset_maq_status(
|
||||||
@ -176,8 +177,8 @@ def apo_semset_maq_status(
|
|||||||
H.append("""<li>Il y a plusieurs années scolaires !</li>""")
|
H.append("""<li>Il y a plusieurs années scolaires !</li>""")
|
||||||
if nips_no_sco: # seulement un warning
|
if nips_no_sco: # seulement un warning
|
||||||
url_list = (
|
url_list = (
|
||||||
"view_apo_etuds?semset_id=%s&title=Etudiants%%20presents%%20dans%%20maquettes%%20Apogee%%20mais%%20pas%%20dans%%20les%%20semestres%%20ScoDoc:&nips=%s"
|
"view_apo_etuds?semset_id=%s&title=Etudiants%%20presents%%20dans%%20maquettes%%20Apogee%%20mais%%20pas%%20dans%%20les%%20semestres%%20ScoDoc:&nips=%s"
|
||||||
% (semset_id, "&nips=".join(nips_no_sco))
|
% (semset_id, "&nips=".join(nips_no_sco))
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
'<li class="apo_csv_warning">Attention: il y a <a href="%s">%d étudiant(s)</a> dans les maquettes Apogée chargées non inscrit(s) dans ce semestre ScoDoc;</li>'
|
'<li class="apo_csv_warning">Attention: il y a <a href="%s">%d étudiant(s)</a> dans les maquettes Apogée chargées non inscrit(s) dans ce semestre ScoDoc;</li>'
|
||||||
@ -195,8 +196,8 @@ def apo_semset_maq_status(
|
|||||||
|
|
||||||
if nips_no_apo:
|
if nips_no_apo:
|
||||||
url_list = (
|
url_list = (
|
||||||
"view_scodoc_etuds?semset_id=%s&title=Etudiants%%20ScoDoc%%20non%%20listés%%20dans%%20les%%20maquettes%%20Apogée%%20chargées&nips=%s"
|
"view_scodoc_etuds?semset_id=%s&title=Etudiants%%20ScoDoc%%20non%%20listés%%20dans%%20les%%20maquettes%%20Apogée%%20chargées&nips=%s"
|
||||||
% (semset_id, "&nips=".join(nips_no_apo))
|
% (semset_id, "&nips=".join(nips_no_apo))
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
'<li><a href="%s">%d étudiants</a> dans ce semestre non présents dans les maquettes Apogée chargées</li>'
|
'<li><a href="%s">%d étudiants</a> dans ce semestre non présents dans les maquettes Apogée chargées</li>'
|
||||||
@ -205,8 +206,8 @@ def apo_semset_maq_status(
|
|||||||
|
|
||||||
if nips_no_sco: # seulement un warning
|
if nips_no_sco: # seulement un warning
|
||||||
url_list = (
|
url_list = (
|
||||||
"view_apo_etuds?semset_id=%s&title=Etudiants%%20presents%%20dans%%20maquettes%%20Apogee%%20mais%%20pas%%20dans%%20les%%20semestres%%20ScoDoc:&nips=%s"
|
"view_apo_etuds?semset_id=%s&title=Etudiants%%20presents%%20dans%%20maquettes%%20Apogee%%20mais%%20pas%%20dans%%20les%%20semestres%%20ScoDoc:&nips=%s"
|
||||||
% (semset_id, "&nips=".join(nips_no_sco))
|
% (semset_id, "&nips=".join(nips_no_sco))
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
'<li class="apo_csv_warning">Attention: il reste <a href="%s">%d étudiants</a> dans les maquettes Apogée chargées mais pas inscrits dans ce semestre ScoDoc</li>'
|
'<li class="apo_csv_warning">Attention: il reste <a href="%s">%d étudiants</a> dans les maquettes Apogée chargées mais pas inscrits dans ce semestre ScoDoc</li>'
|
||||||
@ -215,8 +216,8 @@ def apo_semset_maq_status(
|
|||||||
|
|
||||||
if apo_dups:
|
if apo_dups:
|
||||||
url_list = (
|
url_list = (
|
||||||
"view_apo_etuds?semset_id=%s&title=Doublons%%20Apogee&nips=%s"
|
"view_apo_etuds?semset_id=%s&title=Doublons%%20Apogee&nips=%s"
|
||||||
% (semset_id, "&nips=".join(apo_dups))
|
% (semset_id, "&nips=".join(apo_dups))
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
'<li><a href="%s">%d étudiants</a> présents dans les <em>plusieurs</em> maquettes Apogée chargées</li>'
|
'<li><a href="%s">%d étudiants</a> présents dans les <em>plusieurs</em> maquettes Apogée chargées</li>'
|
||||||
@ -447,7 +448,7 @@ def table_apo_csv_list(context, semset, REQUEST=None):
|
|||||||
)
|
)
|
||||||
t["_filename_target"] = view_link
|
t["_filename_target"] = view_link
|
||||||
t["_etape_apo_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"
|
"delete_small_img", border="0", alt="supprimer", title="Supprimer"
|
||||||
)
|
)
|
||||||
t["_suppress_target"] = "view_apo_csv_delete?etape_apo=%s&semset_id=%s" % (
|
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:
|
if not semset_id:
|
||||||
raise ValueError("invalid null semset_id")
|
raise ValueError("invalid null semset_id")
|
||||||
semset = sco_semset.SemSet(context, semset_id=semset_id)
|
semset = sco_semset.SemSet(context, semset_id=semset_id)
|
||||||
annee_scolaire = semset["annee_scolaire"]
|
# annee_scolaire = semset["annee_scolaire"]
|
||||||
sem_id = semset["sem_id"]
|
# sem_id = semset["sem_id"]
|
||||||
|
|
||||||
if nips and type(nips) != type([]):
|
if nips and type(nips) != type([]):
|
||||||
nips = [nips]
|
nips = [nips]
|
||||||
@ -672,7 +673,7 @@ def view_apo_csv_delete(
|
|||||||
context, etape_apo, semset["annee_scolaire"], semset["sem_id"]
|
context, etape_apo, semset["annee_scolaire"], semset["sem_id"]
|
||||||
)
|
)
|
||||||
sco_etape_apogee.apo_csv_delete(context, info["archive_id"])
|
sco_etape_apogee.apo_csv_delete(context, info["archive_id"])
|
||||||
return REQUEST.RESPONSE.redirect(dest_url + "&head_message=Archive%20supprimée")
|
return REQUEST.RESPONSE.redirect(dest_url + "&head_message=Archive%20supprimée")
|
||||||
|
|
||||||
|
|
||||||
def view_apo_csv(context, etape_apo="", semset_id="", format="html", REQUEST=None):
|
def view_apo_csv(context, etape_apo="", semset_id="", format="html", REQUEST=None):
|
||||||
@ -686,7 +687,7 @@ def view_apo_csv(context, etape_apo="", semset_id="", format="html", REQUEST=Non
|
|||||||
sem_id = semset["sem_id"]
|
sem_id = semset["sem_id"]
|
||||||
csv_data = sco_etape_apogee.apo_csv_get(context, etape_apo, annee_scolaire, sem_id)
|
csv_data = sco_etape_apogee.apo_csv_get(context, etape_apo, annee_scolaire, sem_id)
|
||||||
if format == "raw":
|
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"])
|
apo_data = sco_apogee_csv.ApoData(csv_data, periode=semset["sem_id"])
|
||||||
|
|
||||||
(
|
(
|
||||||
@ -838,7 +839,7 @@ def apo_csv_export_results(
|
|||||||
+ "-%s-" % periode
|
+ "-%s-" % periode
|
||||||
+ "-".join(etapes_apo)
|
+ "-".join(etapes_apo)
|
||||||
)
|
)
|
||||||
basename = sco_archives.sanitize_filename(unescape_html(basename))
|
basename = scu.sanitize_filename(scu.unescape_html(basename))
|
||||||
|
|
||||||
dest_zip.close()
|
dest_zip.close()
|
||||||
size = data.tell()
|
size = data.tell()
|
||||||
|
@ -90,6 +90,7 @@ l'inscrition de semestres décalés (S1 en septembre, ...).
|
|||||||
Le filtrage s'effctue sur la date et non plus sur la parité du semestre (1-3/2-4).
|
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 sco_portal_apogee import get_inscrits_etape
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
@ -540,7 +541,7 @@ class EtapeBilan:
|
|||||||
ind_col,
|
ind_col,
|
||||||
comptage,
|
comptage,
|
||||||
"",
|
"",
|
||||||
self.titres[ind_col].replace("<br/>", " / "),
|
json.dumps(self.titres[ind_col].replace("<br/>", " / "))[1:-1],
|
||||||
)
|
)
|
||||||
elif ind_col == COL_CUMUL:
|
elif ind_col == COL_CUMUL:
|
||||||
javascript = "doFiltrage(%s, %s, '.%s', '*', '%s', '%s', '%s');" % (
|
javascript = "doFiltrage(%s, %s, '.%s', '*', '%s', '%s', '%s');" % (
|
||||||
@ -548,7 +549,7 @@ class EtapeBilan:
|
|||||||
self.all_cols_str,
|
self.all_cols_str,
|
||||||
ind_row,
|
ind_row,
|
||||||
" (%d étudiants)" % count,
|
" (%d étudiants)" % count,
|
||||||
self.titres[ind_row],
|
json.dumps(self.titres[ind_row])[1:-1],
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -558,10 +559,10 @@ class EtapeBilan:
|
|||||||
ind_row,
|
ind_row,
|
||||||
ind_col,
|
ind_col,
|
||||||
comptage,
|
comptage,
|
||||||
self.titres[ind_row],
|
json.dumps(self.titres[ind_row])[1:-1],
|
||||||
self.titres[ind_col].replace("<br/>", " / "),
|
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):
|
def _diagtable(self):
|
||||||
H = []
|
H = []
|
||||||
|
@ -41,9 +41,11 @@ from gen_tables import GenTable
|
|||||||
from TrivialFormulator import TrivialFormulator
|
from TrivialFormulator import TrivialFormulator
|
||||||
import sco_news
|
import sco_news
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
|
import sco_moduleimpl
|
||||||
import sco_groups
|
import sco_groups
|
||||||
import ZAbsences
|
import sco_abs
|
||||||
import sco_evaluations
|
import sco_evaluations
|
||||||
|
import sco_saisie_notes
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@ -101,12 +103,14 @@ def do_evaluation_delete(context, REQUEST, evaluation_id):
|
|||||||
|
|
||||||
context._evaluationEditor.delete(cnx, evaluation_id)
|
context._evaluationEditor.delete(cnx, evaluation_id)
|
||||||
# inval cache pour ce semestre
|
# inval cache pour ce semestre
|
||||||
M = context.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
|
||||||
context._inval_cache(formsemestre_id=M["formsemestre_id"]) # > eval delete
|
context._inval_cache(formsemestre_id=M["formsemestre_id"]) # > eval delete
|
||||||
# news
|
# news
|
||||||
mod = context.do_module_list(args={"module_id": M["module_id"]})[0]
|
mod = context.do_module_list(args={"module_id": M["module_id"]})[0]
|
||||||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||||
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
mod["url"] = (
|
||||||
|
context.NotesURL() + "/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||||
|
)
|
||||||
sco_news.add(
|
sco_news.add(
|
||||||
context,
|
context,
|
||||||
REQUEST,
|
REQUEST,
|
||||||
@ -131,11 +135,6 @@ def do_evaluation_etat(
|
|||||||
à ce module ont des notes)
|
à ce module ont des notes)
|
||||||
evalattente est vrai s'il ne manque que des notes en attente
|
evalattente est vrai s'il ne manque que des notes en attente
|
||||||
"""
|
"""
|
||||||
# global _DEE_TOT
|
|
||||||
# t0=time.time()
|
|
||||||
# if evaluation_id == 'GEAEVAL82883':
|
|
||||||
# log('do_evaluation_etat: evaluation_id=%s partition_id=%s sfp=%s' % (evaluation_id, partition_id, select_first_partition))
|
|
||||||
|
|
||||||
nb_inscrits = len(
|
nb_inscrits = len(
|
||||||
sco_groups.do_evaluation_listeetuds_groups(
|
sco_groups.do_evaluation_listeetuds_groups(
|
||||||
context, evaluation_id, getallstudents=True
|
context, evaluation_id, getallstudents=True
|
||||||
@ -165,7 +164,7 @@ def do_evaluation_etat(
|
|||||||
last_modif = None
|
last_modif = None
|
||||||
# ---- Liste des groupes complets et incomplets
|
# ---- Liste des groupes complets et incomplets
|
||||||
E = context.do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
E = context.do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
||||||
M = context.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
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]
|
Mod = context.do_module_list(args={"module_id": M["module_id"]})[0]
|
||||||
is_malus = Mod["module_type"] == scu.MODULE_MALUS # True si module de malus
|
is_malus = Mod["module_type"] == scu.MODULE_MALUS # True si module de malus
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
@ -182,7 +181,9 @@ def do_evaluation_etat(
|
|||||||
# (pour avoir l'etat et le groupe) et aussi les inscriptions
|
# (pour avoir l'etat et le groupe) et aussi les inscriptions
|
||||||
# au module (pour gerer les modules optionnels correctement)
|
# au module (pour gerer les modules optionnels correctement)
|
||||||
insem = context.do_formsemestre_inscription_listinscrits(formsemestre_id)
|
insem = context.do_formsemestre_inscription_listinscrits(formsemestre_id)
|
||||||
insmod = context.do_moduleimpl_inscription_list(moduleimpl_id=E["moduleimpl_id"])
|
insmod = sco_moduleimpl.do_moduleimpl_inscription_list(
|
||||||
|
context, moduleimpl_id=E["moduleimpl_id"]
|
||||||
|
)
|
||||||
insmodset = set([x["etudid"] for x in insmod])
|
insmodset = set([x["etudid"] for x in insmod])
|
||||||
# retire de insem ceux qui ne sont pas inscrits au module
|
# retire de insem ceux qui ne sont pas inscrits au module
|
||||||
ins = [i for i in insem if i["etudid"] in insmodset]
|
ins = [i for i in insem if i["etudid"] in insmodset]
|
||||||
@ -228,6 +229,7 @@ def do_evaluation_etat(
|
|||||||
if (
|
if (
|
||||||
(TotalNbMissing > 0)
|
(TotalNbMissing > 0)
|
||||||
and (E["evaluation_type"] != scu.EVALUATION_RATTRAPAGE)
|
and (E["evaluation_type"] != scu.EVALUATION_RATTRAPAGE)
|
||||||
|
and (E["evaluation_type"] != scu.EVALUATION_SESSION2)
|
||||||
and not is_malus
|
and not is_malus
|
||||||
):
|
):
|
||||||
complete = False
|
complete = False
|
||||||
@ -241,6 +243,9 @@ def do_evaluation_etat(
|
|||||||
evalattente = True
|
evalattente = True
|
||||||
else:
|
else:
|
||||||
evalattente = False
|
evalattente = False
|
||||||
|
# mais ne met pas en attente les evals immediates sans aucune notes:
|
||||||
|
if E["publish_incomplete"] != "0" and nb_notes == 0:
|
||||||
|
evalattente = False
|
||||||
|
|
||||||
# Calcul moyenne dans chaque groupe de TD
|
# Calcul moyenne dans chaque groupe de TD
|
||||||
gr_moyennes = [] # group : {moy,median, nb_notes}
|
gr_moyennes = [] # group : {moy,median, nb_notes}
|
||||||
@ -264,11 +269,6 @@ def do_evaluation_etat(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
gr_moyennes.sort(key=operator.itemgetter("group_name"))
|
gr_moyennes.sort(key=operator.itemgetter("group_name"))
|
||||||
# log('gr_moyennes=%s' % gr_moyennes)
|
|
||||||
# _DEE_TOT += (time.time() - t0)
|
|
||||||
# log('%s\t_DEE_TOT=%f' % (evaluation_id, _DEE_TOT))
|
|
||||||
# if evaluation_id == 'GEAEVAL82883':
|
|
||||||
# logCallStack()
|
|
||||||
|
|
||||||
# retourne mapping
|
# retourne mapping
|
||||||
return {
|
return {
|
||||||
@ -451,7 +451,9 @@ def formsemestre_evaluations_cal(context, formsemestre_id, REQUEST=None):
|
|||||||
if not e["jour"]:
|
if not e["jour"]:
|
||||||
continue
|
continue
|
||||||
day = e["jour"].strftime("%Y-%m-%d")
|
day = e["jour"].strftime("%Y-%m-%d")
|
||||||
mod = context.do_moduleimpl_withmodule_list(moduleimpl_id=e["moduleimpl_id"])[0]
|
mod = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||||
|
context, moduleimpl_id=e["moduleimpl_id"]
|
||||||
|
)[0]
|
||||||
txt = mod["module"]["code"] or mod["module"]["abbrev"] or "eval"
|
txt = mod["module"]["code"] or mod["module"]["abbrev"] or "eval"
|
||||||
if e["heure_debut"]:
|
if e["heure_debut"]:
|
||||||
debut = e["heure_debut"].strftime("%Hh%M")
|
debut = e["heure_debut"].strftime("%Hh%M")
|
||||||
@ -487,7 +489,7 @@ def formsemestre_evaluations_cal(context, formsemestre_id, REQUEST=None):
|
|||||||
if day > today:
|
if day > today:
|
||||||
e[2] = color_futur
|
e[2] = color_futur
|
||||||
|
|
||||||
CalHTML = ZAbsences.YearTable(
|
CalHTML = sco_abs.YearTable(
|
||||||
context.Absences, year, events=events.values(), halfday=False, pad_width=None
|
context.Absences, year, events=events.values(), halfday=False, pad_width=None
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -524,10 +526,10 @@ def evaluation_date_first_completion(context, evaluation_id):
|
|||||||
# (pour avoir l'etat et le groupe) et aussi les inscriptions
|
# (pour avoir l'etat et le groupe) et aussi les inscriptions
|
||||||
# au module (pour gerer les modules optionnels correctement)
|
# au module (pour gerer les modules optionnels correctement)
|
||||||
# E = context.do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
# E = context.do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
||||||
# M = context.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
# M = sco_moduleimpl.do_moduleimpl_list(context,moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
# formsemestre_id = M["formsemestre_id"]
|
# formsemestre_id = M["formsemestre_id"]
|
||||||
# insem = context.do_formsemestre_inscription_listinscrits(formsemestre_id)
|
# insem = context.do_formsemestre_inscription_listinscrits(formsemestre_id)
|
||||||
# insmod = context.do_moduleimpl_inscription_list(moduleimpl_id=E["moduleimpl_id"])
|
# insmod = sco_moduleimpl.do_moduleimpl_inscription_list(context,moduleimpl_id=E["moduleimpl_id"])
|
||||||
# insmodset = set([x["etudid"] for x in insmod])
|
# insmodset = set([x["etudid"] for x in insmod])
|
||||||
# retire de insem ceux qui ne sont pas inscrits au module
|
# retire de insem ceux qui ne sont pas inscrits au module
|
||||||
# ins = [i for i in insem if i["etudid"] in insmodset]
|
# ins = [i for i in insem if i["etudid"] in insmodset]
|
||||||
@ -566,7 +568,9 @@ def formsemestre_evaluations_delai_correction(
|
|||||||
evals = nt.get_sem_evaluation_etat_list()
|
evals = nt.get_sem_evaluation_etat_list()
|
||||||
T = []
|
T = []
|
||||||
for e in evals:
|
for e in evals:
|
||||||
M = context.do_moduleimpl_list(moduleimpl_id=e["moduleimpl_id"])[0]
|
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]
|
Mod = context.do_module_list(args={"module_id": M["module_id"]})[0]
|
||||||
if (e["evaluation_type"] != scu.EVALUATION_NORMALE) or (
|
if (e["evaluation_type"] != scu.EVALUATION_NORMALE) or (
|
||||||
Mod["module_type"] == scu.MODULE_MALUS
|
Mod["module_type"] == scu.MODULE_MALUS
|
||||||
@ -732,14 +736,14 @@ def evaluation_describe(context, evaluation_id="", edit_in_place=True, REQUEST=N
|
|||||||
"""
|
"""
|
||||||
E = context.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = context.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
moduleimpl_id = E["moduleimpl_id"]
|
moduleimpl_id = E["moduleimpl_id"]
|
||||||
M = context.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)[0]
|
||||||
Mod = context.do_module_list(args={"module_id": M["module_id"]})[0]
|
Mod = context.do_module_list(args={"module_id": M["module_id"]})[0]
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
u = context.Users.user_info(M["responsable_id"])
|
u = context.Users.user_info(M["responsable_id"])
|
||||||
resp = u["prenomnom"]
|
resp = u["prenomnom"]
|
||||||
nomcomplet = u["nomcomplet"]
|
nomcomplet = u["nomcomplet"]
|
||||||
can_edit = context.can_edit_notes(
|
can_edit = sco_saisie_notes.can_edit_notes(
|
||||||
REQUEST.AUTHENTICATED_USER, moduleimpl_id, allow_ens=False
|
context, REQUEST.AUTHENTICATED_USER, moduleimpl_id, allow_ens=False
|
||||||
)
|
)
|
||||||
|
|
||||||
link = (
|
link = (
|
||||||
@ -810,7 +814,9 @@ def evaluation_create_form(
|
|||||||
the_eval = context.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
the_eval = context.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
moduleimpl_id = the_eval["moduleimpl_id"]
|
moduleimpl_id = the_eval["moduleimpl_id"]
|
||||||
#
|
#
|
||||||
M = context.do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||||
|
context, moduleimpl_id=moduleimpl_id
|
||||||
|
)[0]
|
||||||
is_malus = M["module"]["module_type"] == scu.MODULE_MALUS # True si module de malus
|
is_malus = M["module"]["module_type"] == scu.MODULE_MALUS # True si module de malus
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible
|
min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible
|
||||||
@ -886,12 +892,20 @@ def evaluation_create_form(
|
|||||||
notes, en sus des moyennes de modules. Attention, cette option n'empêche pas la publication sur
|
notes, en sus des moyennes de modules. Attention, cette option n'empêche pas la publication sur
|
||||||
les bulletins en version "longue" (la note est donc visible par les étudiants sur le portail).
|
les bulletins en version "longue" (la note est donc visible par les étudiants sur le portail).
|
||||||
</p><p class="help">
|
</p><p class="help">
|
||||||
La modalité "rattrapage" permet de définir une évaluation dont les notes remplaceront les moyennes du modules
|
Les modalités "rattrapage" et "deuxième session" définissent des évaluations prises en compte de
|
||||||
si elles sont meilleures que celles calculées. Dans ce cas, le coefficient est ignoré, et toutes les notes n'ont
|
façon spéciale: </p>
|
||||||
|
<ul>
|
||||||
|
<li>les notes d'une évaluation de "rattrapage" remplaceront les moyennes du module
|
||||||
|
<em>si elles sont meilleures que celles calculées</em>.</li>
|
||||||
|
<li>les notes de "deuxième session" remplacent, lorsqu'elles sont saisies, la moyenne de l'étudiant
|
||||||
|
à ce module, même si la note de deuxième session est plus faible.</li>
|
||||||
|
</ul>
|
||||||
|
<p class="help">
|
||||||
|
Dans ces deux cas, le coefficient est ignoré, et toutes les notes n'ont
|
||||||
pas besoin d'être rentrées.
|
pas besoin d'être rentrées.
|
||||||
</p>
|
</p>
|
||||||
<p class="help">
|
<p class="help">
|
||||||
Les évaluations des modules de type "malus" sont spéciales: le coefficient n'est pas utilisé.
|
Par ailleurs, les évaluations des modules de type "malus" sont toujours spéciales: le coefficient n'est pas utilisé.
|
||||||
Les notes de malus sont toujours comprises entre -20 et 20. Les points sont soustraits à la moyenne
|
Les notes de malus sont toujours comprises entre -20 et 20. Les points sont soustraits à la moyenne
|
||||||
de l'UE à laquelle appartient le module malus (si la note est négative, la moyenne est donc augmentée).
|
de l'UE à laquelle appartient le module malus (si la note est négative, la moyenne est donc augmentée).
|
||||||
</p>
|
</p>
|
||||||
@ -1014,9 +1028,17 @@ def evaluation_create_form(
|
|||||||
{
|
{
|
||||||
"input_type": "menu",
|
"input_type": "menu",
|
||||||
"title": "Modalité",
|
"title": "Modalité",
|
||||||
"allowed_values": (scu.EVALUATION_NORMALE, scu.EVALUATION_RATTRAPAGE),
|
"allowed_values": (
|
||||||
|
scu.EVALUATION_NORMALE,
|
||||||
|
scu.EVALUATION_RATTRAPAGE,
|
||||||
|
scu.EVALUATION_SESSION2,
|
||||||
|
),
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"labels": ("Normale", "Rattrapage"),
|
"labels": (
|
||||||
|
"Normale",
|
||||||
|
"Rattrapage (remplace si meilleure note)",
|
||||||
|
"Deuxième session (remplace toujours)",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
81
sco_excel.py
81
sco_excel.py
@ -33,8 +33,9 @@ from pyExcelerator import *
|
|||||||
|
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from scolog import logdb
|
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 notesdb
|
||||||
|
|
||||||
import time, datetime
|
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)
|
(on ne doit rien avoir émis avant, car ici sont générés les entetes)
|
||||||
"""
|
"""
|
||||||
filename = (
|
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(
|
REQUEST.RESPONSE.setHeader(
|
||||||
"content-disposition", 'attachment; filename="%s"' % filename
|
"content-disposition", 'attachment; filename="%s"' % filename
|
||||||
)
|
)
|
||||||
@ -216,7 +219,7 @@ class ScoExcelSheet:
|
|||||||
sauvegarde = True
|
sauvegarde = True
|
||||||
else:
|
else:
|
||||||
sauvegarde = False
|
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
|
li = 0
|
||||||
for l in self.cells:
|
for l in self.cells:
|
||||||
co = 0
|
co = 0
|
||||||
@ -225,7 +228,7 @@ class ScoExcelSheet:
|
|||||||
if type(c) == LongType:
|
if type(c) == LongType:
|
||||||
c = int(c) # assume all ScoDoc longs fits in int !
|
c = int(c) # assume all ScoDoc longs fits in int !
|
||||||
elif type(c) not in (IntType, FloatType):
|
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))
|
ws0.write(li, co, c, self.get_cell_style(li, co))
|
||||||
co += 1
|
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"""
|
"""Export simple type 'CSV': 1ere ligne en gras, le reste tel quel"""
|
||||||
# XXX devrait maintenant utiliser ScoExcelSheet
|
# XXX devrait maintenant utiliser ScoExcelSheet
|
||||||
wb = Workbook()
|
wb = Workbook()
|
||||||
ws0 = wb.add_sheet(SheetName.decode(SCO_ENCODING))
|
ws0 = wb.add_sheet(SheetName.decode(scu.SCO_ENCODING))
|
||||||
if not titlesStyles:
|
if not titlesStyles:
|
||||||
style = Excel_MakeStyle(bold=True)
|
style = Excel_MakeStyle(bold=True)
|
||||||
titlesStyles = [style] * len(titles)
|
titlesStyles = [style] * len(titles)
|
||||||
# ligne de titres
|
# ligne de titres
|
||||||
col = 0
|
col = 0
|
||||||
for it in titles:
|
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
|
col += 1
|
||||||
# suite
|
# suite
|
||||||
default_style = Excel_MakeStyle()
|
default_style = Excel_MakeStyle()
|
||||||
@ -262,7 +265,7 @@ def Excel_SimpleTable(titles=[], lines=[[]], SheetName="feuille", titlesStyles=[
|
|||||||
if type(it) == LongType:
|
if type(it) == LongType:
|
||||||
it = int(it) # assume all ScoDoc longs fits in int !
|
it = int(it) # assume all ScoDoc longs fits in int !
|
||||||
elif type(it) not in (IntType, FloatType):
|
elif type(it) not in (IntType, FloatType):
|
||||||
it = str(it).decode(SCO_ENCODING)
|
it = str(it).decode(scu.SCO_ENCODING)
|
||||||
cell_style = text_style
|
cell_style = text_style
|
||||||
ws0.write(li, col, it, cell_style)
|
ws0.write(li, col, it, cell_style)
|
||||||
col += 1
|
col += 1
|
||||||
@ -279,7 +282,7 @@ def Excel_feuille_saisie(E, titreannee, description, lines):
|
|||||||
"""
|
"""
|
||||||
SheetName = "Saisie notes"
|
SheetName = "Saisie notes"
|
||||||
wb = Workbook()
|
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)
|
# ajuste largeurs colonnes (unite inconnue, empirique)
|
||||||
ws0.col(0).width = 400 # codes
|
ws0.col(0).width = 400 # codes
|
||||||
ws0.col(1).width = 6000 # noms
|
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)
|
ws0.write(li, 0, u"Ne pas modifier les cases en mauve !", style_expl)
|
||||||
li += 1
|
li += 1
|
||||||
# Nom du semestre
|
# 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
|
li += 1
|
||||||
# description evaluation
|
# 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
|
li += 1
|
||||||
ws0.write(
|
ws0.write(
|
||||||
li, 0, u"Evaluation du %s (coef. %g)" % (E["jour"], E["coefficient"]), style
|
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:
|
for line in lines:
|
||||||
li += 1
|
li += 1
|
||||||
st = style_nom
|
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":
|
if line[3] != "I":
|
||||||
st = style_dem
|
st = style_dem
|
||||||
if line[3] == "D": # demissionnaire
|
if line[3] == "D": # demissionnaire
|
||||||
@ -396,15 +403,15 @@ def Excel_feuille_saisie(E, titreannee, description, lines):
|
|||||||
s = line[3] # etat autre
|
s = line[3] # etat autre
|
||||||
else:
|
else:
|
||||||
s = line[4] # groupes TD/TP/...
|
s = line[4] # groupes TD/TP/...
|
||||||
ws0.write(li, 1, line[1].decode(SCO_ENCODING), st)
|
ws0.write(li, 1, line[1].decode(scu.SCO_ENCODING), st)
|
||||||
ws0.write(li, 2, line[2].decode(SCO_ENCODING), st)
|
ws0.write(li, 2, line[2].decode(scu.SCO_ENCODING), st)
|
||||||
ws0.write(li, 3, s.decode(SCO_ENCODING), st)
|
ws0.write(li, 3, s.decode(scu.SCO_ENCODING), st)
|
||||||
try:
|
try:
|
||||||
val = float(line[5])
|
val = float(line[5])
|
||||||
except:
|
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, 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
|
# explication en bas
|
||||||
li += 2
|
li += 2
|
||||||
ws0.write(li, 1, u"Code notes", style_titres)
|
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)
|
convert_to_string is a conversion function applied to all non-string values (ie numbers)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
P = parse_xls("", SCO_ENCODING, doc=data)
|
P = parse_xls("", scu.SCO_ENCODING, doc=data)
|
||||||
except:
|
except:
|
||||||
log("Excel_to_list: failure to import document")
|
log("Excel_to_list: failure to import document")
|
||||||
open("/tmp/last_scodoc_import_failure.xls", "w").write(data)
|
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 !")
|
diag.append("Attention: n'utilise que la première feuille du classeur !")
|
||||||
# fill matrix
|
# fill matrix
|
||||||
sheet_name, values = P[0]
|
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:
|
if not values:
|
||||||
diag.append("Aucune valeur trouvée dans le classeur !")
|
diag.append("Aucune valeur trouvée dans le classeur !")
|
||||||
return diag, None
|
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
|
nbcols = max(cols) + 1
|
||||||
nbrows = max(rows) + 1
|
nbrows = max(rows) + 1
|
||||||
M = []
|
M = []
|
||||||
for i in range(nbrows):
|
for _ in range(nbrows):
|
||||||
M.append([""] * nbcols)
|
M.append([""] * nbcols)
|
||||||
|
|
||||||
for row_idx, col_idx in indexes:
|
for row_idx, col_idx in indexes:
|
||||||
v = values[(row_idx, col_idx)]
|
v = values[(row_idx, col_idx)]
|
||||||
if isinstance(v, unicode):
|
if isinstance(v, unicode):
|
||||||
v = v.encode(SCO_ENCODING, "backslashreplace")
|
v = v.encode(scu.SCO_ENCODING, "backslashreplace")
|
||||||
elif convert_to_string:
|
elif convert_to_string:
|
||||||
v = convert_to_string(v)
|
v = convert_to_string(v)
|
||||||
M[row_idx][col_idx] = v
|
M[row_idx][col_idx] = v
|
||||||
@ -485,7 +492,7 @@ def Excel_feuille_listeappel(
|
|||||||
formsemestre_id = sem["formsemestre_id"]
|
formsemestre_id = sem["formsemestre_id"]
|
||||||
SheetName = "Liste " + groupname
|
SheetName = "Liste " + groupname
|
||||||
wb = Workbook()
|
wb = Workbook()
|
||||||
ws0 = wb.add_sheet(SheetName.decode(SCO_ENCODING))
|
ws0 = wb.add_sheet(SheetName.decode(scu.SCO_ENCODING))
|
||||||
|
|
||||||
font1 = Font()
|
font1 = Font()
|
||||||
font1.name = "Arial"
|
font1.name = "Arial"
|
||||||
@ -569,7 +576,7 @@ def Excel_feuille_listeappel(
|
|||||||
sem["date_debut"],
|
sem["date_debut"],
|
||||||
sem["date_fin"],
|
sem["date_fin"],
|
||||||
)
|
)
|
||||||
).decode(SCO_ENCODING),
|
).decode(scu.SCO_ENCODING),
|
||||||
style2,
|
style2,
|
||||||
)
|
)
|
||||||
# ligne 2
|
# ligne 2
|
||||||
@ -578,7 +585,7 @@ def Excel_feuille_listeappel(
|
|||||||
# ligne 3
|
# ligne 3
|
||||||
li += 1
|
li += 1
|
||||||
ws0.write(li, 1, u"Enseignant :", style2)
|
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
|
# Avertissement pour ne pas confondre avec listes notes
|
||||||
ws0.write(
|
ws0.write(
|
||||||
li + 1, 2, u"Ne pas utiliser cette feuille pour saisir les notes !", style1i
|
li + 1, 2, u"Ne pas utiliser cette feuille pour saisir les notes !", style1i
|
||||||
@ -590,7 +597,9 @@ def Excel_feuille_listeappel(
|
|||||||
co = 2
|
co = 2
|
||||||
for partition in partitions:
|
for partition in partitions:
|
||||||
if partition["partition_name"]:
|
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
|
co += 1
|
||||||
if with_codes:
|
if with_codes:
|
||||||
coc = co
|
coc = co
|
||||||
@ -607,7 +616,11 @@ def Excel_feuille_listeappel(
|
|||||||
li += 1
|
li += 1
|
||||||
ws0.write(li, 0, n, style1b)
|
ws0.write(li, 0, n, style1b)
|
||||||
nomprenom = (
|
nomprenom = (
|
||||||
t["sexe"] + " " + t["nom"] + " " + strcapitalize(strlower(t["prenom"]))
|
t["civilite_str"]
|
||||||
|
+ " "
|
||||||
|
+ t["nom"]
|
||||||
|
+ " "
|
||||||
|
+ scu.strcapitalize(scu.strlower(t["prenom"]))
|
||||||
)
|
)
|
||||||
style_nom = style2t3
|
style_nom = style2t3
|
||||||
if with_paiement:
|
if with_paiement:
|
||||||
@ -618,31 +631,31 @@ def Excel_feuille_listeappel(
|
|||||||
elif not paie:
|
elif not paie:
|
||||||
nomprenom += " (non paiement)"
|
nomprenom += " (non paiement)"
|
||||||
style_nom = style2t3bold
|
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
|
co = 2
|
||||||
for partition in partitions:
|
for partition in partitions:
|
||||||
if partition["partition_name"]:
|
if partition["partition_name"]:
|
||||||
ws0.write(
|
ws0.write(
|
||||||
li,
|
li,
|
||||||
co,
|
co,
|
||||||
t.get(partition["partition_id"], "").decode(SCO_ENCODING),
|
t.get(partition["partition_id"], "").decode(scu.SCO_ENCODING),
|
||||||
style2t3,
|
style2t3,
|
||||||
)
|
)
|
||||||
co += 1
|
co += 1
|
||||||
if with_codes:
|
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"]:
|
if t["code_nip"]:
|
||||||
code_nip = t["code_nip"].decode(SCO_ENCODING)
|
code_nip = t["code_nip"].decode(scu.SCO_ENCODING)
|
||||||
else:
|
else:
|
||||||
code_nip = u""
|
code_nip = u""
|
||||||
ws0.write(li, coc + 1, code_nip, style2t3)
|
ws0.write(li, coc + 1, code_nip, style2t3)
|
||||||
if t["code_ine"]:
|
if t["code_ine"]:
|
||||||
code_ine = t["code_ine"].decode(SCO_ENCODING)
|
code_ine = t["code_ine"].decode(scu.SCO_ENCODING)
|
||||||
else:
|
else:
|
||||||
code_ine = u""
|
code_ine = u""
|
||||||
ws0.write(li, coc + 2, code_ine, style2t3)
|
ws0.write(li, coc + 2, code_ine, style2t3)
|
||||||
if t["etath"]:
|
if t["etath"]:
|
||||||
etath = t["etath"].decode(SCO_ENCODING)
|
etath = t["etath"].decode(scu.SCO_ENCODING)
|
||||||
else:
|
else:
|
||||||
etath = u""
|
etath = u""
|
||||||
ws0.write(li, co, etath, style2b) # etat
|
ws0.write(li, co, etath, style2b) # etat
|
||||||
@ -654,7 +667,7 @@ def Excel_feuille_listeappel(
|
|||||||
dt = time.strftime("%d/%m/%Y à %Hh%M")
|
dt = time.strftime("%d/%m/%Y à %Hh%M")
|
||||||
if server_name:
|
if server_name:
|
||||||
dt += " sur " + 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(0).width = 850
|
||||||
ws0.col(1).width = 9000
|
ws0.col(1).width = 9000
|
||||||
|
@ -27,7 +27,11 @@
|
|||||||
|
|
||||||
"""Export d'une table avec les résultats de tous les étudiants
|
"""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 scolars
|
||||||
import sco_bac
|
import sco_bac
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
@ -35,11 +39,10 @@ import sco_parcours_dut
|
|||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
from sco_codes_parcours import NO_SEMESTRE_ID
|
from sco_codes_parcours import NO_SEMESTRE_ID
|
||||||
import sco_excel
|
import sco_excel
|
||||||
from notesdb import *
|
|
||||||
from sco_utils import *
|
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
import sco_pvjury
|
import sco_pvjury
|
||||||
import html_sco_header
|
import html_sco_header
|
||||||
|
import VERSION
|
||||||
|
|
||||||
|
|
||||||
def _build_results_table(context, start_date=None, end_date=None, types_parcours=[]):
|
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,
|
rows=rows,
|
||||||
titles=titles,
|
titles=titles,
|
||||||
columns_ids=columns_ids,
|
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),
|
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_class="table_leftalign",
|
||||||
html_sortable=True,
|
html_sortable=True,
|
||||||
preferences=context.get_preferences(),
|
preferences=context.get_preferences(),
|
||||||
@ -119,7 +122,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
|
|||||||
"code_nip": "NIP",
|
"code_nip": "NIP",
|
||||||
"nom": "Nom",
|
"nom": "Nom",
|
||||||
"prenom": "Prénom",
|
"prenom": "Prénom",
|
||||||
"sexe": "Civ.",
|
"civilite_str": "Civ.",
|
||||||
"nom_usuel": "Nom usuel",
|
"nom_usuel": "Nom usuel",
|
||||||
"bac": "Bac",
|
"bac": "Bac",
|
||||||
"parcours": "Parcours",
|
"parcours": "Parcours",
|
||||||
@ -130,7 +133,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
|
|||||||
"periode",
|
"periode",
|
||||||
"sid",
|
"sid",
|
||||||
"code_nip",
|
"code_nip",
|
||||||
"sexe",
|
"civilite_str",
|
||||||
"nom",
|
"nom",
|
||||||
# 'nom_usuel', # inutile ?
|
# 'nom_usuel', # inutile ?
|
||||||
"prenom",
|
"prenom",
|
||||||
@ -168,7 +171,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
|
|||||||
"nom": etud["nom"],
|
"nom": etud["nom"],
|
||||||
"nom_usuel": etud["nom_usuel"],
|
"nom_usuel": etud["nom_usuel"],
|
||||||
"prenom": etud["prenom"],
|
"prenom": etud["prenom"],
|
||||||
"sexe": etud["sexe"],
|
"civilite_str": etud["civilite_str"],
|
||||||
"_nom_target": "%s/ficheEtud?etudid=%s" % (context.ScoURL(), etudid),
|
"_nom_target": "%s/ficheEtud?etudid=%s" % (context.ScoURL(), etudid),
|
||||||
"_nom_td_attrs": 'id="%s" class="etudinfo"' % etudid,
|
"_nom_td_attrs": 'id="%s" class="etudinfo"' % etudid,
|
||||||
"bac": bac.abbrev(),
|
"bac": bac.abbrev(),
|
||||||
@ -189,7 +192,7 @@ def _build_results_list(context, dpv_by_sem, etuds_infos):
|
|||||||
code = "-"
|
code = "-"
|
||||||
r[sem["semestre_id"]] = code
|
r[sem["semestre_id"]] = code
|
||||||
r["periode"] = sem["periode"]
|
r["periode"] = sem["periode"]
|
||||||
r["anneescolaire"] = annee_scolaire_debut(
|
r["anneescolaire"] = scu.annee_scolaire_debut(
|
||||||
int(sem["annee_debut"]), sem["mois_debut_ord"]
|
int(sem["annee_debut"]), sem["mois_debut_ord"]
|
||||||
)
|
)
|
||||||
r["sid"] = "{} {} {}".format(
|
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):
|
def get_set_formsemestre_id_dates(context, start_date, end_date):
|
||||||
"""Ensemble des formsemestre_id entre ces dates"""
|
"""Ensemble des formsemestre_id entre ces dates"""
|
||||||
s = SimpleDictFetch(
|
s = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT formsemestre_id FROM notes_formsemestre WHERE date_debut >= %(start_date)s AND date_fin <= %(end_date)s",
|
"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},
|
{"start_date": start_date, "end_date": end_date},
|
||||||
@ -224,20 +227,20 @@ def scodoc_table_results(
|
|||||||
if not isinstance(types_parcours, ListType):
|
if not isinstance(types_parcours, ListType):
|
||||||
types_parcours = [types_parcours]
|
types_parcours = [types_parcours]
|
||||||
if start_date:
|
if start_date:
|
||||||
start_date_iso = DateDMYtoISO(start_date)
|
start_date_iso = ndb.DateDMYtoISO(start_date)
|
||||||
if end_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]
|
types_parcours = [int(x) for x in types_parcours if x]
|
||||||
|
|
||||||
if start_date and end_date:
|
if start_date and end_date:
|
||||||
tab, semlist = _build_results_table(
|
tab, semlist = _build_results_table(
|
||||||
context, start_date_iso, end_date_iso, types_parcours
|
context, start_date_iso, end_date_iso, types_parcours
|
||||||
)
|
)
|
||||||
tab.base_url = "%s?start_date=%s&end_date=%s&types_parcours=%s" % (
|
tab.base_url = "%s?start_date=%s&end_date=%s&types_parcours=%s" % (
|
||||||
REQUEST.URL0,
|
REQUEST.URL0,
|
||||||
start_date,
|
start_date,
|
||||||
end_date,
|
end_date,
|
||||||
"&types_parcours=".join([str(x) for s in types_parcours]),
|
"&types_parcours=".join([str(x) for x in types_parcours]),
|
||||||
)
|
)
|
||||||
if format != "html":
|
if format != "html":
|
||||||
return tab.make_page(
|
return tab.make_page(
|
||||||
|
160
sco_find_etud.py
160
sco_find_etud.py
@ -27,17 +27,19 @@
|
|||||||
|
|
||||||
"""Recherche d'étudiants
|
"""Recherche d'étudiants
|
||||||
"""
|
"""
|
||||||
|
from types import ListType
|
||||||
from sco_utils import *
|
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
|
|
||||||
from notesdb import *
|
import sco_utils as scu
|
||||||
|
|
||||||
|
import notesdb as ndb
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
|
|
||||||
import scolars
|
import scolars
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_groups
|
import sco_groups
|
||||||
|
from sco_permissions import ScoView
|
||||||
|
|
||||||
|
|
||||||
def form_search_etud(
|
def form_search_etud(
|
||||||
@ -56,7 +58,7 @@ def form_search_etud(
|
|||||||
H.append(
|
H.append(
|
||||||
"""<form action="search_etud_in_dept" method="POST">
|
"""<form action="search_etud_in_dept" method="POST">
|
||||||
<b>%s</b>
|
<b>%s</b>
|
||||||
<input type="text" name="expnom" width=12 value="">
|
<input type="text" name="expnom" id="searchEtud" width="12" spellcheck="false" value="">
|
||||||
<input type="submit" value="Chercher">
|
<input type="submit" value="Chercher">
|
||||||
<br/>(entrer une partie du nom)
|
<br/>(entrer une partie du nom)
|
||||||
"""
|
"""
|
||||||
@ -94,71 +96,52 @@ def form_search_etud(
|
|||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
# was chercheEtud()
|
def search_etud_in_dept(context, expnom="", REQUEST=None):
|
||||||
def search_etud_in_dept(
|
"""Page recherche d'un etudiant.
|
||||||
context,
|
|
||||||
expnom=None,
|
Affiche la fiche de l'étudiant, ou, si la recherche donne plusieurs résultats, la liste des étudianst
|
||||||
dest_url="ficheEtud",
|
correspondants.
|
||||||
parameters={},
|
Appelée par boite de recherche barre latérale gauche.
|
||||||
parameters_keys="",
|
|
||||||
add_headers=True, # complete page
|
Args:
|
||||||
title=None,
|
expnom: string, regexp sur le nom ou un code_nip ou un etudid
|
||||||
REQUEST=None,
|
|
||||||
):
|
|
||||||
"""Page recherche d'un etudiant
|
|
||||||
expnom est un regexp sur le nom ou un code_nip
|
|
||||||
dest_url est la page sur laquelle on sera redirigé après choix
|
|
||||||
parameters spécifie des arguments additionnels à passer à l'URL (en plus de etudid)
|
|
||||||
"""
|
"""
|
||||||
if type(expnom) == ListType:
|
dest_url = "ficheEtud"
|
||||||
expnom = expnom[0]
|
if len(expnom) > 1:
|
||||||
q = []
|
etuds = context.getEtudInfo(filled=1, etudid=expnom, REQUEST=REQUEST)
|
||||||
if parameters:
|
if len(etuds) != 1:
|
||||||
for param in parameters.keys():
|
if scu.is_valid_code_nip(expnom):
|
||||||
q.append("%s=%s" % (param, parameters[param]))
|
etuds = search_etuds_infos(context, code_nip=expnom, REQUEST=REQUEST)
|
||||||
elif parameters_keys:
|
else:
|
||||||
for key in parameters_keys.split(","):
|
etuds = search_etuds_infos(context, expnom=expnom, REQUEST=REQUEST)
|
||||||
v = REQUEST.form.get(key, False)
|
|
||||||
if v:
|
|
||||||
q.append("%s=%s" % (key, v))
|
|
||||||
query_string = "&".join(q)
|
|
||||||
|
|
||||||
no_side_bar = True
|
|
||||||
H = []
|
|
||||||
if title:
|
|
||||||
H.append("<h2>%s</h2>" % title)
|
|
||||||
|
|
||||||
if 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)
|
|
||||||
else:
|
else:
|
||||||
etuds = []
|
etuds = [] # si expnom est trop court, n'affiche rien
|
||||||
|
|
||||||
if len(etuds) == 1:
|
if len(etuds) == 1:
|
||||||
# va directement a la destination
|
# va directement a la destination
|
||||||
return REQUEST.RESPONSE.redirect(
|
return context.ficheEtud(etudid=etuds[0]["etudid"], REQUEST=REQUEST)
|
||||||
dest_url + "?etudid=%s&" % etuds[0]["etudid"] + query_string
|
|
||||||
)
|
|
||||||
|
|
||||||
|
H = [
|
||||||
|
context.sco_header(
|
||||||
|
page_title="Recherche d'un étudiant",
|
||||||
|
no_side_bar=True,
|
||||||
|
init_qtip=True,
|
||||||
|
javascripts=["js/etud_info.js"],
|
||||||
|
REQUEST=REQUEST,
|
||||||
|
),
|
||||||
|
"""<h2>%d résultats pour "%s": choisissez un étudiant:</h2>"""
|
||||||
|
% (len(etuds), expnom),
|
||||||
|
form_search_etud(
|
||||||
|
context,
|
||||||
|
dest_url=dest_url,
|
||||||
|
REQUEST=REQUEST,
|
||||||
|
title="Autre recherche",
|
||||||
|
),
|
||||||
|
]
|
||||||
if len(etuds) > 0:
|
if len(etuds) > 0:
|
||||||
# Choix dans la liste des résultats:
|
# Choix dans la liste des résultats:
|
||||||
H.append(
|
|
||||||
"""<h2>%d résultats pour "%s": choisissez un étudiant:</h2>"""
|
|
||||||
% (len(etuds), expnom)
|
|
||||||
)
|
|
||||||
H.append(
|
|
||||||
form_search_etud(
|
|
||||||
context,
|
|
||||||
dest_url=dest_url,
|
|
||||||
parameters=parameters,
|
|
||||||
parameters_keys=parameters_keys,
|
|
||||||
REQUEST=REQUEST,
|
|
||||||
title="Autre recherche",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for e in etuds:
|
for e in etuds:
|
||||||
target = dest_url + "?etudid=%s&" % e["etudid"] + query_string
|
target = dest_url + "?etudid=%s&" % e["etudid"]
|
||||||
e["_nomprenom_target"] = target
|
e["_nomprenom_target"] = target
|
||||||
e["inscription_target"] = target
|
e["inscription_target"] = target
|
||||||
e["_nomprenom_td_attrs"] = 'id="%s" class="etudinfo"' % (e["etudid"])
|
e["_nomprenom_td_attrs"] = 'id="%s" class="etudinfo"' % (e["etudid"])
|
||||||
@ -183,34 +166,16 @@ def search_etud_in_dept(
|
|||||||
form_search_etud(
|
form_search_etud(
|
||||||
context,
|
context,
|
||||||
dest_url=dest_url,
|
dest_url=dest_url,
|
||||||
parameters=parameters,
|
|
||||||
parameters_keys=parameters_keys,
|
|
||||||
REQUEST=REQUEST,
|
REQUEST=REQUEST,
|
||||||
title="Autre recherche",
|
title="Autre recherche",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
H.append('<h2 style="color: red;">Aucun résultat pour "%s".</h2>' % expnom)
|
H.append('<h2 style="color: red;">Aucun résultat pour "%s".</h2>' % expnom)
|
||||||
add_headers = True
|
|
||||||
no_side_bar = False
|
|
||||||
H.append(
|
H.append(
|
||||||
"""<p class="help">La recherche porte sur tout ou partie du NOM ou du NIP de l'étudiant</p>"""
|
"""<p class="help">La recherche porte sur tout ou partie du NOM ou du NIP de l'étudiant</p>"""
|
||||||
)
|
)
|
||||||
if add_headers:
|
return "\n".join(H) + context.sco_footer(REQUEST)
|
||||||
return (
|
|
||||||
context.sco_header(
|
|
||||||
REQUEST,
|
|
||||||
page_title="Choix d'un étudiant",
|
|
||||||
init_qtip=True,
|
|
||||||
javascripts=["js/etud_info.js"],
|
|
||||||
no_side_bar=no_side_bar,
|
|
||||||
)
|
|
||||||
+ "\n".join(H)
|
|
||||||
+ context.sco_footer(REQUEST)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return "\n".join(H)
|
|
||||||
|
|
||||||
|
|
||||||
# Was chercheEtudsInfo()
|
# Was chercheEtudsInfo()
|
||||||
@ -218,10 +183,10 @@ def search_etuds_infos(context, expnom=None, code_nip=None, REQUEST=None):
|
|||||||
"""recherche les étudiants correspondants à expnom ou au code_nip
|
"""recherche les étudiants correspondants à expnom ou au code_nip
|
||||||
et ramene liste de mappings utilisables en DTML.
|
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()
|
cnx = context.GetDBConnexion()
|
||||||
if expnom and not may_be_nip:
|
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="~")
|
etuds = scolars.etudident_list(cnx, args={"nom": expnom}, test="~")
|
||||||
else:
|
else:
|
||||||
code_nip = code_nip or expnom
|
code_nip = code_nip or expnom
|
||||||
@ -238,20 +203,19 @@ def search_etud_by_name(context, term, REQUEST=None):
|
|||||||
Accepte aussi un début de code NIP (au moins 6 caractères)
|
Accepte aussi un début de code NIP (au moins 6 caractères)
|
||||||
Renvoie une liste de nom en JSON
|
Renvoie une liste de nom en JSON
|
||||||
"""
|
"""
|
||||||
cnx = context.GetDBConnexion()
|
may_be_nip = scu.is_valid_code_nip(term)
|
||||||
may_be_nip = is_valid_code_nip(term)
|
# term = scu.strupper(term) # conserve les accents
|
||||||
# term = strupper(term) # conserve les accents
|
|
||||||
term = term.upper()
|
term = term.upper()
|
||||||
if (
|
if (
|
||||||
not ALPHANUM_EXP.match(
|
not scu.ALPHANUM_EXP.match(
|
||||||
term.decode(SCO_ENCODING)
|
term.decode(scu.SCO_ENCODING)
|
||||||
) # n'autorise pas les caractères spéciaux
|
) # n'autorise pas les caractères spéciaux
|
||||||
and not may_be_nip
|
and not may_be_nip
|
||||||
):
|
):
|
||||||
data = []
|
data = []
|
||||||
else:
|
else:
|
||||||
if may_be_nip:
|
if may_be_nip:
|
||||||
r = SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT nom, prenom, code_nip FROM identite WHERE code_nip LIKE %(beginning)s ORDER BY nom",
|
"SELECT nom, prenom, code_nip FROM identite WHERE code_nip LIKE %(beginning)s ORDER BY nom",
|
||||||
{"beginning": term + "%"},
|
{"beginning": term + "%"},
|
||||||
@ -265,21 +229,21 @@ def search_etud_by_name(context, term, REQUEST=None):
|
|||||||
for x in r
|
for x in r
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
r = SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT nom, prenom FROM identite WHERE nom LIKE %(beginning)s ORDER BY nom",
|
"SELECT etudid, nom, prenom FROM identite WHERE nom LIKE %(beginning)s ORDER BY nom",
|
||||||
{"beginning": term + "%"},
|
{"beginning": term + "%"},
|
||||||
)
|
)
|
||||||
|
|
||||||
data = [
|
data = [
|
||||||
{
|
{
|
||||||
"label": "%s %s" % (x["nom"], scolars.format_prenom(x["prenom"])),
|
"label": "%s %s" % (x["nom"], scolars.format_prenom(x["prenom"])),
|
||||||
"value": x["nom"],
|
"value": x["etudid"],
|
||||||
}
|
}
|
||||||
for x in r
|
for x in r
|
||||||
]
|
]
|
||||||
# log(data)
|
# log(data)
|
||||||
return sendJSON(REQUEST, data)
|
return scu.sendJSON(REQUEST, data)
|
||||||
|
|
||||||
|
|
||||||
# ---------- Recherche sur plusieurs département
|
# ---------- Recherche sur plusieurs département
|
||||||
@ -293,7 +257,7 @@ def form_search_etud_in_accessible_depts(context, REQUEST):
|
|||||||
return ""
|
return ""
|
||||||
return """<form action="table_etud_in_accessible_depts" method="POST">
|
return """<form action="table_etud_in_accessible_depts" method="POST">
|
||||||
<b>Chercher étudiant:</b>
|
<b>Chercher étudiant:</b>
|
||||||
<input type="text" name="expnom" width=12 value="">
|
<input type="text" name="expnom" width="12" spellcheck="false" value="">
|
||||||
<input type="submit" value="Chercher">
|
<input type="submit" value="Chercher">
|
||||||
<br/>(entrer une partie du nom ou le code NIP, cherche dans tous les départements autorisés)
|
<br/>(entrer une partie du nom ou le code NIP, cherche dans tous les départements autorisés)
|
||||||
"""
|
"""
|
||||||
@ -312,7 +276,7 @@ def search_etud_in_accessible_depts(context, expnom=None, code_nip=None, REQUEST
|
|||||||
"""
|
"""
|
||||||
result = []
|
result = []
|
||||||
accessible_depts = []
|
accessible_depts = []
|
||||||
deptList = context.list_depts() # definis dans Zope
|
deptList = context._list_depts() # definis dans Zope
|
||||||
for dept in deptList:
|
for dept in deptList:
|
||||||
# log('%s searching %s' % (str(REQUEST.AUTHENTICATED_USER),dept))
|
# log('%s searching %s' % (str(REQUEST.AUTHENTICATED_USER),dept))
|
||||||
if can_view_dept(dept, REQUEST):
|
if can_view_dept(dept, REQUEST):
|
||||||
@ -383,9 +347,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.
|
Seuls les départements accessibles par l'utilisateur sont cherchés.
|
||||||
|
|
||||||
Renvoie une liste des inscriptions de l'étudiants dans tout ScoDoc:
|
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
|
context, code_nip=code_nip, REQUEST=REQUEST
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -400,7 +364,7 @@ def search_inscr_etud_by_nip(context, code_nip, REQUEST=None, format="json"):
|
|||||||
"dept": DeptId,
|
"dept": DeptId,
|
||||||
"etudid": e["etudid"],
|
"etudid": e["etudid"],
|
||||||
"code_nip": e["code_nip"],
|
"code_nip": e["code_nip"],
|
||||||
"sexe": e["sexe"],
|
"civilite_str": e["civilite_str"],
|
||||||
"nom": e["nom"],
|
"nom": e["nom"],
|
||||||
"prenom": e["prenom"],
|
"prenom": e["prenom"],
|
||||||
"formsemestre_id": sem["formsemestre_id"],
|
"formsemestre_id": sem["formsemestre_id"],
|
||||||
@ -413,7 +377,7 @@ def search_inscr_etud_by_nip(context, code_nip, REQUEST=None, format="json"):
|
|||||||
"dept",
|
"dept",
|
||||||
"etudid",
|
"etudid",
|
||||||
"code_nip",
|
"code_nip",
|
||||||
"sexe",
|
"civilite_str",
|
||||||
"nom",
|
"nom",
|
||||||
"prenom",
|
"prenom",
|
||||||
"formsemestre_id",
|
"formsemestre_id",
|
||||||
|
@ -28,16 +28,19 @@
|
|||||||
"""Import / Export de formations
|
"""Import / Export de formations
|
||||||
"""
|
"""
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from sco_utils import *
|
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
|
|
||||||
from notesdb import *
|
import sco_utils as scu
|
||||||
|
|
||||||
|
import notesdb as ndb
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_tag_module
|
import sco_tag_module
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
|
from sco_permissions import ScoChangeFormation
|
||||||
|
import VERSION
|
||||||
|
|
||||||
|
|
||||||
def formation_export(
|
def formation_export(
|
||||||
@ -81,7 +84,7 @@ def formation_export(
|
|||||||
if mod["ects"] is None:
|
if mod["ects"] is None:
|
||||||
del mod["ects"]
|
del mod["ects"]
|
||||||
|
|
||||||
return sendResult(
|
return scu.sendResult(
|
||||||
REQUEST, F, name="formation", format=format, force_outer_xml_tag=False
|
REQUEST, F, name="formation", format=format, force_outer_xml_tag=False
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -113,7 +116,7 @@ def XMLToDicts(element, encoding):
|
|||||||
|
|
||||||
|
|
||||||
def formation_import_xml(
|
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
|
"""Create a formation from XML representation
|
||||||
(format dumped by formation_export( format='xml' ))
|
(format dumped by formation_export( format='xml' ))
|
||||||
@ -131,11 +134,11 @@ def formation_import_xml(
|
|||||||
F = D[1]
|
F = D[1]
|
||||||
F_quoted = F.copy()
|
F_quoted = F.copy()
|
||||||
log("F=%s" % F)
|
log("F=%s" % F)
|
||||||
quote_dict(F_quoted)
|
ndb.quote_dict(F_quoted)
|
||||||
log("F_quoted=%s" % F_quoted)
|
log("F_quoted=%s" % F_quoted)
|
||||||
# find new version number
|
# find new version number
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
log(
|
log(
|
||||||
"select max(version) from notes_formations where acronyme=%(acronyme)s and titre=%(titre)s"
|
"select max(version) from notes_formations where acronyme=%(acronyme)s and titre=%(titre)s"
|
||||||
% F_quoted
|
% 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)
|
formations = context.formation_list(formation_id=formation_id, args=args)
|
||||||
title = "Programmes pédagogiques"
|
title = "Programmes pédagogiques"
|
||||||
lockicon = icontag(
|
lockicon = scu.icontag(
|
||||||
"lock32_img", title="Comporte des semestres verrouillés", border="0"
|
"lock32_img", title="Comporte des semestres verrouillés", border="0"
|
||||||
)
|
)
|
||||||
suppricon = icontag(
|
suppricon = scu.icontag(
|
||||||
"delete_small_img", border="0", alt="supprimer", title="Supprimer"
|
"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"
|
"edit_img", border="0", alt="modifier", title="Modifier titres et code"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -226,6 +229,7 @@ def formation_list_table(context, formation_id=None, args={}, REQUEST=None):
|
|||||||
f["parcours_name"] = ""
|
f["parcours_name"] = ""
|
||||||
f["_titre_target"] = "ue_list?formation_id=%(formation_id)s" % f
|
f["_titre_target"] = "ue_list?formation_id=%(formation_id)s" % f
|
||||||
f["_titre_link_class"] = "stdlink"
|
f["_titre_link_class"] = "stdlink"
|
||||||
|
f["_titre_id"] = "titre_%s" % f["acronyme"]
|
||||||
# Ajoute les semestres associés à chaque formation:
|
# Ajoute les semestres associés à chaque formation:
|
||||||
f["sems"] = sco_formsemestre.do_formsemestre_list(
|
f["sems"] = sco_formsemestre.do_formsemestre_list(
|
||||||
context, args={"formation_id": f["formation_id"]}
|
context, args={"formation_id": f["formation_id"]}
|
||||||
@ -238,8 +242,8 @@ def formation_list_table(context, formation_id=None, args={}, REQUEST=None):
|
|||||||
for s in f["sems"]
|
for s in f["sems"]
|
||||||
]
|
]
|
||||||
+ [
|
+ [
|
||||||
'<a class="stdlink" href="formsemestre_createwithmodules?formation_id=%(formation_id)s&semestre_id=1">ajouter</a>'
|
'<a class="stdlink" id="addSemestre_%s" href="formsemestre_createwithmodules?formation_id=%s&semestre_id=1">ajouter</a>'
|
||||||
% f
|
% (f["acronyme"],f["formation_id"])
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
if f["sems"]:
|
if f["sems"]:
|
||||||
@ -256,15 +260,15 @@ def formation_list_table(context, formation_id=None, args={}, REQUEST=None):
|
|||||||
but_locked = '<span class="but_placeholder"></span>'
|
but_locked = '<span class="but_placeholder"></span>'
|
||||||
if editable and not locked:
|
if editable and not locked:
|
||||||
but_suppr = (
|
but_suppr = (
|
||||||
'<a class="stdlink" href="formation_delete?formation_id=%s">%s</a>'
|
'<a class="stdlink" id="delete_Formation_%s" href="formation_delete?formation_id=%s">%s</a>'
|
||||||
% (f["formation_id"], suppricon)
|
% (f["acronyme"],f["formation_id"], suppricon)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
but_suppr = '<span class="but_placeholder"></span>'
|
but_suppr = '<span class="but_placeholder"></span>'
|
||||||
if editable:
|
if editable:
|
||||||
but_edit = (
|
but_edit = (
|
||||||
'<a class="stdlink" href="formation_edit?formation_id=%s">%s</a>'
|
'<a class="stdlink" id="edit_Formation_%s" href="formation_edit?formation_id=%s">%s</a>'
|
||||||
% (f["formation_id"], editicon)
|
% (f["acronyme"],f["formation_id"], editicon)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
but_edit = '<span class="but_placeholder"></span>'
|
but_edit = '<span class="but_placeholder"></span>'
|
||||||
@ -302,7 +306,7 @@ def formation_list_table(context, formation_id=None, args={}, REQUEST=None):
|
|||||||
columns_ids=columns_ids,
|
columns_ids=columns_ids,
|
||||||
rows=formations,
|
rows=formations,
|
||||||
titles=titles,
|
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,
|
caption=title,
|
||||||
html_caption=title,
|
html_caption=title,
|
||||||
table_id="formation_list_table",
|
table_id="formation_list_table",
|
||||||
|
@ -27,16 +27,18 @@
|
|||||||
|
|
||||||
"""Operations de base sur les formsemestres
|
"""Operations de base sur les formsemestres
|
||||||
"""
|
"""
|
||||||
|
import time
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
|
|
||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
from sco_codes_parcours import NO_SEMESTRE_ID
|
from sco_codes_parcours import NO_SEMESTRE_ID
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
|
|
||||||
_formsemestreEditor = EditableTable(
|
_formsemestreEditor = ndb.EditableTable(
|
||||||
"notes_formsemestre",
|
"notes_formsemestre",
|
||||||
"formsemestre_id",
|
"formsemestre_id",
|
||||||
(
|
(
|
||||||
@ -60,16 +62,16 @@ _formsemestreEditor = EditableTable(
|
|||||||
),
|
),
|
||||||
sortkey="date_debut",
|
sortkey="date_debut",
|
||||||
output_formators={
|
output_formators={
|
||||||
"date_debut": DateISOtoDMY,
|
"date_debut": ndb.DateISOtoDMY,
|
||||||
"date_fin": DateISOtoDMY,
|
"date_fin": ndb.DateISOtoDMY,
|
||||||
"gestion_compensation": str,
|
"gestion_compensation": str,
|
||||||
"gestion_semestrielle": str,
|
"gestion_semestrielle": str,
|
||||||
"etat": str,
|
"etat": str,
|
||||||
"bul_hide_xml": str,
|
"bul_hide_xml": str,
|
||||||
},
|
},
|
||||||
input_formators={
|
input_formators={
|
||||||
"date_debut": DateDMYtoISO,
|
"date_debut": ndb.DateDMYtoISO,
|
||||||
"date_fin": DateDMYtoISO,
|
"date_fin": ndb.DateDMYtoISO,
|
||||||
"gestion_compensation": int,
|
"gestion_compensation": int,
|
||||||
"gestion_semestrielle": int,
|
"gestion_semestrielle": int,
|
||||||
"etat": int,
|
"etat": int,
|
||||||
@ -144,9 +146,9 @@ def formsemestre_enrich(context, sem):
|
|||||||
sem["semestre_id"],
|
sem["semestre_id"],
|
||||||
) # eg "DUT Informatique semestre 2"
|
) # eg "DUT Informatique semestre 2"
|
||||||
|
|
||||||
sem["dateord"] = DateDMYtoISO(sem["date_debut"])
|
sem["dateord"] = ndb.DateDMYtoISO(sem["date_debut"])
|
||||||
sem["date_debut_iso"] = DateDMYtoISO(sem["date_debut"])
|
sem["date_debut_iso"] = ndb.DateDMYtoISO(sem["date_debut"])
|
||||||
sem["date_fin_iso"] = DateDMYtoISO(sem["date_fin"])
|
sem["date_fin_iso"] = ndb.DateDMYtoISO(sem["date_fin"])
|
||||||
try:
|
try:
|
||||||
mois_debut, annee_debut = sem["date_debut"].split("/")[1:]
|
mois_debut, annee_debut = sem["date_debut"].split("/")[1:]
|
||||||
except:
|
except:
|
||||||
@ -162,7 +164,9 @@ def formsemestre_enrich(context, sem):
|
|||||||
|
|
||||||
sem["annee"] = annee_debut
|
sem["annee"] = annee_debut
|
||||||
# 2007 ou 2007-2008:
|
# 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
|
# La période: considère comme "S1" (ou S3) les débuts en aout-sept-octobre
|
||||||
# devrait sans doute pouvoir etre changé...
|
# devrait sans doute pouvoir etre changé...
|
||||||
if sem["mois_debut_ord"] >= 8 and sem["mois_debut_ord"] <= 10:
|
if sem["mois_debut_ord"] >= 8 and sem["mois_debut_ord"] <= 10:
|
||||||
@ -213,6 +217,8 @@ def etapes_apo_str(etapes):
|
|||||||
|
|
||||||
|
|
||||||
def do_formsemestre_edit(context, sem, cnx=None, **kw):
|
def do_formsemestre_edit(context, sem, cnx=None, **kw):
|
||||||
|
"""Apply modifications to formsemestre.
|
||||||
|
Update etapes and resps. Invalidate cache."""
|
||||||
if not cnx:
|
if not cnx:
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
|
|
||||||
@ -227,7 +233,7 @@ def read_formsemestre_responsables(context, formsemestre_id):
|
|||||||
"""recupere liste des responsables de ce semestre
|
"""recupere liste des responsables de ce semestre
|
||||||
:returns: liste de chaines
|
:returns: liste de chaines
|
||||||
"""
|
"""
|
||||||
r = SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT responsable_id FROM notes_formsemestre_responsables WHERE formsemestre_id = %(formsemestre_id)s",
|
"SELECT responsable_id FROM notes_formsemestre_responsables WHERE formsemestre_id = %(formsemestre_id)s",
|
||||||
{"formsemestre_id": formsemestre_id},
|
{"formsemestre_id": formsemestre_id},
|
||||||
@ -239,11 +245,58 @@ def write_formsemestre_responsables(context, sem):
|
|||||||
return _write_formsemestre_aux(context, sem, "responsables", "responsable_id")
|
return _write_formsemestre_aux(context, sem, "responsables", "responsable_id")
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------- Coefs des UE
|
||||||
|
|
||||||
|
_formsemestre_uecoef_editor = ndb.EditableTable(
|
||||||
|
"notes_formsemestre_uecoef",
|
||||||
|
"formsemestre_uecoef_id",
|
||||||
|
("formsemestre_uecoef_id", "formsemestre_id", "ue_id", "coefficient"),
|
||||||
|
)
|
||||||
|
|
||||||
|
formsemestre_uecoef_create = _formsemestre_uecoef_editor.create
|
||||||
|
formsemestre_uecoef_edit = _formsemestre_uecoef_editor.edit
|
||||||
|
formsemestre_uecoef_list = _formsemestre_uecoef_editor.list
|
||||||
|
formsemestre_uecoef_delete = _formsemestre_uecoef_editor.delete
|
||||||
|
|
||||||
|
|
||||||
|
def do_formsemestre_uecoef_edit_or_create(context, cnx, formsemestre_id, ue_id, coef):
|
||||||
|
"modify or create the coef"
|
||||||
|
coefs = formsemestre_uecoef_list(
|
||||||
|
cnx, args={"formsemestre_id": formsemestre_id, "ue_id": ue_id}
|
||||||
|
)
|
||||||
|
if coefs:
|
||||||
|
formsemestre_uecoef_edit(
|
||||||
|
cnx,
|
||||||
|
args={
|
||||||
|
"formsemestre_uecoef_id": coefs[0]["formsemestre_uecoef_id"],
|
||||||
|
"coefficient": coef,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
formsemestre_uecoef_create(
|
||||||
|
cnx,
|
||||||
|
args={
|
||||||
|
"formsemestre_id": formsemestre_id,
|
||||||
|
"ue_id": ue_id,
|
||||||
|
"coefficient": coef,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def do_formsemestre_uecoef_delete(context, cnx, formsemestre_id, ue_id):
|
||||||
|
"delete coef for this (ue,sem)"
|
||||||
|
coefs = formsemestre_uecoef_list(
|
||||||
|
cnx, args={"formsemestre_id": formsemestre_id, "ue_id": ue_id}
|
||||||
|
)
|
||||||
|
if coefs:
|
||||||
|
formsemestre_uecoef_delete(cnx, coefs[0]["formsemestre_uecoef_id"])
|
||||||
|
|
||||||
|
|
||||||
def read_formsemestre_etapes(context, formsemestre_id):
|
def read_formsemestre_etapes(context, formsemestre_id):
|
||||||
"""recupere liste des codes etapes associés à ce semestre
|
"""recupere liste des codes etapes associés à ce semestre
|
||||||
:returns: liste d'instance de ApoEtapeVDI
|
:returns: liste d'instance de ApoEtapeVDI
|
||||||
"""
|
"""
|
||||||
r = SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT etape_apo FROM notes_formsemestre_etapes WHERE formsemestre_id = %(formsemestre_id)s",
|
"SELECT etape_apo FROM notes_formsemestre_etapes WHERE formsemestre_id = %(formsemestre_id)s",
|
||||||
{"formsemestre_id": formsemestre_id},
|
{"formsemestre_id": formsemestre_id},
|
||||||
@ -259,17 +312,20 @@ def _write_formsemestre_aux(context, sem, fieldname, valuename):
|
|||||||
"""fieldname: 'etapes' ou 'responsables'
|
"""fieldname: 'etapes' ou 'responsables'
|
||||||
valuename: 'etape_apo' ou 'responsable_id'
|
valuename: 'etape_apo' ou 'responsable_id'
|
||||||
"""
|
"""
|
||||||
if not "etapes" in sem:
|
if not fieldname in sem:
|
||||||
return
|
return
|
||||||
|
# uniquify
|
||||||
|
values = set([str(x) for x in sem[fieldname]])
|
||||||
|
|
||||||
cnx = context.GetDBConnexion(autocommit=False)
|
cnx = context.GetDBConnexion(autocommit=False)
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
tablename = "notes_formsemestre_" + fieldname
|
tablename = "notes_formsemestre_" + fieldname
|
||||||
try:
|
try:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"DELETE from " + tablename + " where formsemestre_id = %(formsemestre_id)s",
|
"DELETE from " + tablename + " where formsemestre_id = %(formsemestre_id)s",
|
||||||
{"formsemestre_id": sem["formsemestre_id"]},
|
{"formsemestre_id": sem["formsemestre_id"]},
|
||||||
)
|
)
|
||||||
for item in sem[fieldname]:
|
for item in values:
|
||||||
if item:
|
if item:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"INSERT INTO "
|
"INSERT INTO "
|
||||||
@ -279,7 +335,7 @@ def _write_formsemestre_aux(context, sem, fieldname, valuename):
|
|||||||
+ ") VALUES (%(formsemestre_id)s, %("
|
+ ") VALUES (%(formsemestre_id)s, %("
|
||||||
+ valuename
|
+ valuename
|
||||||
+ ")s)",
|
+ ")s)",
|
||||||
{"formsemestre_id": sem["formsemestre_id"], valuename: str(item)},
|
{"formsemestre_id": sem["formsemestre_id"], valuename: item},
|
||||||
)
|
)
|
||||||
except:
|
except:
|
||||||
log("Warning: exception in write_formsemestre_aux !")
|
log("Warning: exception in write_formsemestre_aux !")
|
||||||
@ -374,12 +430,12 @@ def sem_in_semestre_scolaire(context, sem, year=False, saison=0, REQUEST=None):
|
|||||||
si saison non spécifiée: année complète
|
si saison non spécifiée: année complète
|
||||||
pivot de saison au 1er décembre
|
pivot de saison au 1er décembre
|
||||||
XXX TODO: la période (ici appelée "saison" devrait être éditable
|
XXX TODO: la période (ici appelée "saison" devrait être éditable
|
||||||
manuellement dans le formsemestre_edit afin de couvrir els cas particulier
|
manuellement dans le formsemestre_edit afin de couvrir les cas particulier
|
||||||
comme un semestre S2 qui commecerait en décembre... voire novembre.
|
comme un semestre S2 qui commencerait en décembre... voire novembre.
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
if not year:
|
if not year:
|
||||||
year = AnneeScolaire(REQUEST)
|
year = scu.AnneeScolaire(REQUEST)
|
||||||
# est-on dans la même année universitaire ?
|
# est-on dans la même année universitaire ?
|
||||||
if sem["mois_debut_ord"] > 7:
|
if sem["mois_debut_ord"] > 7:
|
||||||
if sem["annee_debut"] != str(year):
|
if sem["annee_debut"] != str(year):
|
||||||
@ -403,7 +459,7 @@ def sem_in_annee_scolaire(context, sem, year=False, REQUEST=None):
|
|||||||
Si annee non specifiée, année scolaire courante
|
Si annee non specifiée, année scolaire courante
|
||||||
"""
|
"""
|
||||||
if not year:
|
if not year:
|
||||||
year = AnneeScolaire(REQUEST)
|
year = scu.AnneeScolaire(REQUEST)
|
||||||
return ((sem["annee_debut"] == str(year)) and (sem["mois_debut_ord"] > 7)) or (
|
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)
|
(sem["annee_debut"] == str(year + 1)) and (sem["mois_debut_ord"] <= 7)
|
||||||
)
|
)
|
||||||
@ -429,9 +485,17 @@ def sem_une_annee(context, sem):
|
|||||||
return debut == fin
|
return debut == fin
|
||||||
|
|
||||||
|
|
||||||
|
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 = ndb.DateDMYtoISO(sem["date_debut"])
|
||||||
|
fin = ndb.DateDMYtoISO(sem["date_fin"])
|
||||||
|
return (debut <= now) and (now <= fin)
|
||||||
|
|
||||||
|
|
||||||
def scodoc_get_all_unlocked_sems(context):
|
def scodoc_get_all_unlocked_sems(context):
|
||||||
"""Liste de tous les semestres non verrouillés de tous les départements"""
|
"""Liste de tous les semestres non verrouillés de tous les départements"""
|
||||||
depts = context.list_depts()
|
depts = context._list_depts()
|
||||||
semdepts = []
|
semdepts = []
|
||||||
for dept in depts:
|
for dept in depts:
|
||||||
semdepts += [
|
semdepts += [
|
||||||
@ -537,7 +601,7 @@ def view_formsemestre_by_etape(context, etape_apo=None, format="html", REQUEST=N
|
|||||||
tab = table_formsemestres(
|
tab = table_formsemestres(
|
||||||
context,
|
context,
|
||||||
list_formsemestre_by_etape(
|
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_title=html_title,
|
||||||
html_next_section="""<form action="view_formsemestre_by_etape">
|
html_next_section="""<form action="view_formsemestre_by_etape">
|
||||||
|
@ -29,15 +29,15 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from TrivialFormulator import TrivialFormulator, TF
|
from TrivialFormulator import TrivialFormulator, TF
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_formsemestre_status
|
import sco_formsemestre_status
|
||||||
import sco_edt_cal
|
import sco_edt_cal
|
||||||
|
|
||||||
_custommenuEditor = EditableTable(
|
_custommenuEditor = ndb.EditableTable(
|
||||||
"notes_formsemestre_custommenu",
|
"notes_formsemestre_custommenu",
|
||||||
"custommenu_id",
|
"custommenu_id",
|
||||||
("custommenu_id", "formsemestre_id", "title", "url", "idx"),
|
("custommenu_id", "formsemestre_id", "title", "url", "idx"),
|
||||||
@ -74,12 +74,15 @@ def formsemestre_custommenu_html(context, formsemestre_id, base_url=""):
|
|||||||
+ formsemestre_id,
|
+ formsemestre_id,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return sco_formsemestre_status.makeMenu("Liens", menu)
|
return sco_formsemestre_status.htmlutils.make_menu("Liens", menu)
|
||||||
|
|
||||||
|
|
||||||
def formsemestre_custommenu_edit(context, formsemestre_id, REQUEST=None):
|
def formsemestre_custommenu_edit(context, formsemestre_id, REQUEST=None):
|
||||||
"""Dialog to edit the custom menu"""
|
"""Dialog to edit the custom menu"""
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
|
dest_url = (
|
||||||
|
context.NotesURL() + "/formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||||
|
)
|
||||||
H = [
|
H = [
|
||||||
context.html_sem_header(REQUEST, "Modification du menu du semestre ", sem),
|
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>
|
"""<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:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + "\n" + tf[1] + context.sco_footer(REQUEST)
|
return "\n".join(H) + "\n" + tf[1] + context.sco_footer(REQUEST)
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
return REQUEST.RESPONSE.redirect(dest_url)
|
||||||
else:
|
else:
|
||||||
# form submission
|
# form submission
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
@ -153,6 +156,4 @@ def formsemestre_custommenu_edit(context, formsemestre_id, REQUEST=None):
|
|||||||
"url": tf[2]["url_" + custommenu_id],
|
"url": tf[2]["url_" + custommenu_id],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(dest_url)
|
||||||
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
|
||||||
)
|
|
||||||
|
@ -28,8 +28,8 @@
|
|||||||
"""Form choix modules / responsables et creation formsemestre
|
"""Form choix modules / responsables et creation formsemestre
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
import sco_groups
|
import sco_groups
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from TrivialFormulator import TrivialFormulator, TF
|
from TrivialFormulator import TrivialFormulator, TF
|
||||||
@ -41,7 +41,10 @@ import sco_codes_parcours
|
|||||||
import sco_compute_moy
|
import sco_compute_moy
|
||||||
import sco_modalites
|
import sco_modalites
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
|
import sco_moduleimpl
|
||||||
from sco_formsemestre import ApoEtapeVDI
|
from sco_formsemestre import ApoEtapeVDI
|
||||||
|
from sco_permissions import ScoImplement
|
||||||
|
from sco_exceptions import AccessDenied, ScoValueError
|
||||||
|
|
||||||
|
|
||||||
def _default_sem_title(F):
|
def _default_sem_title(F):
|
||||||
@ -69,9 +72,7 @@ def formsemestre_createwithmodules(context, REQUEST=None):
|
|||||||
def formsemestre_editwithmodules(context, REQUEST, formsemestre_id):
|
def formsemestre_editwithmodules(context, REQUEST, formsemestre_id):
|
||||||
"""Page modification semestre"""
|
"""Page modification semestre"""
|
||||||
# portage from dtml
|
# portage from dtml
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
F = context.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
|
||||||
H = [
|
H = [
|
||||||
context.html_sem_header(
|
context.html_sem_header(
|
||||||
REQUEST,
|
REQUEST,
|
||||||
@ -85,7 +86,7 @@ def formsemestre_editwithmodules(context, REQUEST, formsemestre_id):
|
|||||||
if sem["etat"] != "1":
|
if sem["etat"] != "1":
|
||||||
H.append(
|
H.append(
|
||||||
"""<p>%s<b>Ce semestre est verrouillé.</b></p>"""
|
"""<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:
|
else:
|
||||||
H.append(do_formsemestre_createwithmodules(context, REQUEST=REQUEST, edit=1))
|
H.append(do_formsemestre_createwithmodules(context, REQUEST=REQUEST, edit=1))
|
||||||
@ -155,7 +156,9 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||||||
# if REQUEST.form.get('tf-submitted',False) and not REQUEST.form.has_key('inscrire_etudslist'):
|
# if REQUEST.form.get('tf-submitted',False) and not REQUEST.form.has_key('inscrire_etudslist'):
|
||||||
# REQUEST.form['inscrire_etudslist'] = []
|
# REQUEST.form['inscrire_etudslist'] = []
|
||||||
# add associated modules to tf-checked
|
# add associated modules to tf-checked
|
||||||
ams = context.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
ams = sco_moduleimpl.do_moduleimpl_list(
|
||||||
|
context, formsemestre_id=formsemestre_id
|
||||||
|
)
|
||||||
sem_module_ids = set([x["module_id"] for x in ams])
|
sem_module_ids = set([x["module_id"] for x in ams])
|
||||||
initvalues["tf-checked"] = [x["module_id"] for x in ams]
|
initvalues["tf-checked"] = [x["module_id"] for x in ams]
|
||||||
for x in ams:
|
for x in ams:
|
||||||
@ -173,7 +176,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||||||
|
|
||||||
# Liste des ID de semestres
|
# Liste des ID de semestres
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute("select semestre_id from notes_semestres")
|
cursor.execute("select semestre_id from notes_semestres")
|
||||||
semestre_id_list = [str(x[0]) for x in cursor.fetchall()]
|
semestre_id_list = [str(x[0]) for x in cursor.fetchall()]
|
||||||
semestre_id_labels = []
|
semestre_id_labels = []
|
||||||
@ -341,7 +344,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||||||
# fallback: code etape libre
|
# fallback: code etape libre
|
||||||
mf = mf_manual
|
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
|
mf["title"] = "Etape Apogée (%d)" % n
|
||||||
modform.append(("etape_apo" + str(n), mf.copy()))
|
modform.append(("etape_apo" + str(n), mf.copy()))
|
||||||
modform.append(
|
modform.append(
|
||||||
@ -636,10 +639,10 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||||||
msg = ""
|
msg = ""
|
||||||
if tf[0] == 1:
|
if tf[0] == 1:
|
||||||
# check dates
|
# 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>'
|
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(
|
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>'
|
msg = '<ul class="tf-msg"><li class="tf-msg">Code étape Apogée manquant</li></ul>'
|
||||||
|
|
||||||
@ -690,7 +693,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||||||
start_i = 0
|
start_i = 0
|
||||||
else:
|
else:
|
||||||
start_i = 1
|
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(
|
tf[2]["etapes"].append(
|
||||||
ApoEtapeVDI(
|
ApoEtapeVDI(
|
||||||
etape=tf[2]["etape_apo" + str(n)], vdi=tf[2]["vdi_apo" + str(n)]
|
etape=tf[2]["etape_apo" + str(n)], vdi=tf[2]["vdi_apo" + str(n)]
|
||||||
@ -706,9 +709,9 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||||||
"formsemestre_id": formsemestre_id,
|
"formsemestre_id": formsemestre_id,
|
||||||
"responsable_id": tf[2][module_id],
|
"responsable_id": tf[2][module_id],
|
||||||
}
|
}
|
||||||
mid = context.do_moduleimpl_create(modargs)
|
_ = sco_moduleimpl.do_moduleimpl_create(context, modargs)
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"formsemestre_status?formsemestre_id=%s&head_message=Nouveau%%20semestre%%20créé"
|
"formsemestre_status?formsemestre_id=%s&head_message=Nouveau%%20semestre%%20créé"
|
||||||
% formsemestre_id
|
% formsemestre_id
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -720,7 +723,9 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||||||
# nouveaux modules
|
# nouveaux modules
|
||||||
checkedmods = tf[2]["tf-checked"]
|
checkedmods = tf[2]["tf-checked"]
|
||||||
sco_formsemestre.do_formsemestre_edit(context, tf[2])
|
sco_formsemestre.do_formsemestre_edit(context, tf[2])
|
||||||
ams = context.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
ams = sco_moduleimpl.do_moduleimpl_list(
|
||||||
|
context, formsemestre_id=formsemestre_id
|
||||||
|
)
|
||||||
existingmods = [x["module_id"] for x in ams]
|
existingmods = [x["module_id"] for x in ams]
|
||||||
mods_tocreate = [x for x in checkedmods if not x in existingmods]
|
mods_tocreate = [x for x in checkedmods if not x in existingmods]
|
||||||
# modules a existants a modifier
|
# modules a existants a modifier
|
||||||
@ -735,7 +740,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||||||
"formsemestre_id": formsemestre_id,
|
"formsemestre_id": formsemestre_id,
|
||||||
"responsable_id": tf[2][module_id],
|
"responsable_id": tf[2][module_id],
|
||||||
}
|
}
|
||||||
moduleimpl_id = context.do_moduleimpl_create(modargs)
|
moduleimpl_id = sco_moduleimpl.do_moduleimpl_create(context, modargs)
|
||||||
mod = context.do_module_list({"module_id": module_id})[0]
|
mod = context.do_module_list({"module_id": module_id})[0]
|
||||||
msg += ["création de %s (%s)" % (mod["code"], mod["titre"])]
|
msg += ["création de %s (%s)" % (mod["code"], mod["titre"])]
|
||||||
# INSCRIPTIONS DES ETUDIANTS
|
# INSCRIPTIONS DES ETUDIANTS
|
||||||
@ -753,8 +758,12 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||||||
"inscription module:module_id=%s,moduleimpl_id=%s: %s"
|
"inscription module:module_id=%s,moduleimpl_id=%s: %s"
|
||||||
% (module_id, moduleimpl_id, etudids)
|
% (module_id, moduleimpl_id, etudids)
|
||||||
)
|
)
|
||||||
context.do_moduleimpl_inscrit_etuds(
|
sco_moduleimpl.do_moduleimpl_inscrit_etuds(
|
||||||
moduleimpl_id, formsemestre_id, etudids, REQUEST=REQUEST
|
context,
|
||||||
|
moduleimpl_id,
|
||||||
|
formsemestre_id,
|
||||||
|
etudids,
|
||||||
|
REQUEST=REQUEST,
|
||||||
)
|
)
|
||||||
msg += [
|
msg += [
|
||||||
"inscription de %d étudiants au module %s"
|
"inscription de %d étudiants au module %s"
|
||||||
@ -771,8 +780,8 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||||||
)
|
)
|
||||||
msg += diag
|
msg += diag
|
||||||
for module_id in mods_toedit:
|
for module_id in mods_toedit:
|
||||||
moduleimpl_id = context.do_moduleimpl_list(
|
moduleimpl_id = sco_moduleimpl.do_moduleimpl_list(
|
||||||
formsemestre_id=formsemestre_id, module_id=module_id
|
context, formsemestre_id=formsemestre_id, module_id=module_id
|
||||||
)[0]["moduleimpl_id"]
|
)[0]["moduleimpl_id"]
|
||||||
modargs = {
|
modargs = {
|
||||||
"moduleimpl_id": moduleimpl_id,
|
"moduleimpl_id": moduleimpl_id,
|
||||||
@ -780,7 +789,9 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||||||
"formsemestre_id": formsemestre_id,
|
"formsemestre_id": formsemestre_id,
|
||||||
"responsable_id": tf[2][module_id],
|
"responsable_id": tf[2][module_id],
|
||||||
}
|
}
|
||||||
context.do_moduleimpl_edit(modargs, formsemestre_id=formsemestre_id)
|
sco_moduleimpl.do_moduleimpl_edit(
|
||||||
|
context, modargs, formsemestre_id=formsemestre_id
|
||||||
|
)
|
||||||
mod = context.do_module_list({"module_id": module_id})[0]
|
mod = context.do_module_list({"module_id": module_id})[0]
|
||||||
|
|
||||||
if msg:
|
if msg:
|
||||||
@ -800,7 +811,7 @@ def do_formsemestre_createwithmodules(context, REQUEST=None, edit=False):
|
|||||||
return msg_html
|
return msg_html
|
||||||
else:
|
else:
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"formsemestre_status?formsemestre_id=%s&head_message=Semestre modifié"
|
"formsemestre_status?formsemestre_id=%s&head_message=Semestre modifié"
|
||||||
% formsemestre_id
|
% formsemestre_id
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -814,8 +825,8 @@ def formsemestre_delete_moduleimpls(context, formsemestre_id, module_ids_to_del)
|
|||||||
msg = []
|
msg = []
|
||||||
for module_id in module_ids_to_del:
|
for module_id in module_ids_to_del:
|
||||||
# get id
|
# get id
|
||||||
moduleimpl_id = context.do_moduleimpl_list(
|
moduleimpl_id = sco_moduleimpl.do_moduleimpl_list(
|
||||||
formsemestre_id=formsemestre_id, module_id=module_id
|
context, formsemestre_id=formsemestre_id, module_id=module_id
|
||||||
)[0]["moduleimpl_id"]
|
)[0]["moduleimpl_id"]
|
||||||
mod = context.do_module_list({"module_id": module_id})[0]
|
mod = context.do_module_list({"module_id": module_id})[0]
|
||||||
# Evaluations dans ce module ?
|
# Evaluations dans ce module ?
|
||||||
@ -828,7 +839,9 @@ def formsemestre_delete_moduleimpls(context, formsemestre_id, module_ids_to_del)
|
|||||||
ok = False
|
ok = False
|
||||||
else:
|
else:
|
||||||
msg += ["suppression de %s (%s)" % (mod["code"], mod["titre"])]
|
msg += ["suppression de %s (%s)" % (mod["code"], mod["titre"])]
|
||||||
context.do_moduleimpl_delete(moduleimpl_id, formsemestre_id=formsemestre_id)
|
sco_moduleimpl.do_moduleimpl_delete(
|
||||||
|
context, moduleimpl_id, formsemestre_id=formsemestre_id
|
||||||
|
)
|
||||||
|
|
||||||
return ok, msg
|
return ok, msg
|
||||||
|
|
||||||
@ -837,7 +850,6 @@ def formsemestre_clone(context, formsemestre_id, REQUEST=None):
|
|||||||
"""
|
"""
|
||||||
Formulaire clonage d'un semestre
|
Formulaire clonage d'un semestre
|
||||||
"""
|
"""
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
# Liste des enseignants avec forme pour affichage / saisie avec suggestion
|
# Liste des enseignants avec forme pour affichage / saisie avec suggestion
|
||||||
userlist = context.Users.get_userlist()
|
userlist = context.Users.get_userlist()
|
||||||
@ -933,7 +945,7 @@ def formsemestre_clone(context, formsemestre_id, REQUEST=None):
|
|||||||
msg = ""
|
msg = ""
|
||||||
if tf[0] == 1:
|
if tf[0] == 1:
|
||||||
# check dates
|
# 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>'
|
msg = '<ul class="tf-msg"><li class="tf-msg">Dates de début et fin incompatibles !</li></ul>'
|
||||||
if tf[0] == 0 or msg:
|
if tf[0] == 0 or msg:
|
||||||
return "".join(H) + msg + tf[1] + context.sco_footer(REQUEST)
|
return "".join(H) + msg + tf[1] + context.sco_footer(REQUEST)
|
||||||
@ -953,7 +965,7 @@ def formsemestre_clone(context, formsemestre_id, REQUEST=None):
|
|||||||
REQUEST=REQUEST,
|
REQUEST=REQUEST,
|
||||||
)
|
)
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"formsemestre_status?formsemestre_id=%s&head_message=Nouveau%%20semestre%%20créé"
|
"formsemestre_status?formsemestre_id=%s&head_message=Nouveau%%20semestre%%20créé"
|
||||||
% new_formsemestre_id
|
% new_formsemestre_id
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -984,17 +996,21 @@ def do_formsemestre_clone(
|
|||||||
formsemestre_id = context.do_formsemestre_create(args, REQUEST)
|
formsemestre_id = context.do_formsemestre_create(args, REQUEST)
|
||||||
log("created formsemestre %s" % formsemestre_id)
|
log("created formsemestre %s" % formsemestre_id)
|
||||||
# 2- create moduleimpls
|
# 2- create moduleimpls
|
||||||
mods_orig = context.do_moduleimpl_list(formsemestre_id=orig_formsemestre_id)
|
mods_orig = sco_moduleimpl.do_moduleimpl_list(
|
||||||
|
context, formsemestre_id=orig_formsemestre_id
|
||||||
|
)
|
||||||
for mod_orig in mods_orig:
|
for mod_orig in mods_orig:
|
||||||
args = mod_orig.copy()
|
args = mod_orig.copy()
|
||||||
args["formsemestre_id"] = formsemestre_id
|
args["formsemestre_id"] = formsemestre_id
|
||||||
mid = context.do_moduleimpl_create(args)
|
mid = sco_moduleimpl.do_moduleimpl_create(context, args)
|
||||||
# copy notes_modules_enseignants
|
# copy notes_modules_enseignants
|
||||||
ens = context.do_ens_list(args={"moduleimpl_id": mod_orig["moduleimpl_id"]})
|
ens = sco_moduleimpl.do_ens_list(
|
||||||
|
context, args={"moduleimpl_id": mod_orig["moduleimpl_id"]}
|
||||||
|
)
|
||||||
for e in ens:
|
for e in ens:
|
||||||
args = e.copy()
|
args = e.copy()
|
||||||
args["moduleimpl_id"] = mid
|
args["moduleimpl_id"] = mid
|
||||||
context.do_ens_create(args)
|
sco_moduleimpl.do_ens_create(context, args)
|
||||||
# optionally, copy evaluations
|
# optionally, copy evaluations
|
||||||
if clone_evaluations:
|
if clone_evaluations:
|
||||||
evals = context.do_evaluation_list(
|
evals = context.do_evaluation_list(
|
||||||
@ -1004,14 +1020,16 @@ def do_formsemestre_clone(
|
|||||||
args = e.copy()
|
args = e.copy()
|
||||||
del args["jour"] # erase date
|
del args["jour"] # erase date
|
||||||
args["moduleimpl_id"] = mid
|
args["moduleimpl_id"] = mid
|
||||||
evaluation_id = context.do_evaluation_create(REQUEST=REQUEST, **args)
|
_ = context.do_evaluation_create(REQUEST=REQUEST, **args)
|
||||||
|
|
||||||
# 3- copy uecoefs
|
# 3- copy uecoefs
|
||||||
objs = formsemestre_uecoef_list(cnx, args={"formsemestre_id": orig_formsemestre_id})
|
objs = sco_formsemestre.formsemestre_uecoef_list(
|
||||||
|
cnx, args={"formsemestre_id": orig_formsemestre_id}
|
||||||
|
)
|
||||||
for obj in objs:
|
for obj in objs:
|
||||||
args = obj.copy()
|
args = obj.copy()
|
||||||
args["formsemestre_id"] = formsemestre_id
|
args["formsemestre_id"] = formsemestre_id
|
||||||
c = formsemestre_uecoef_create(cnx, args)
|
_ = sco_formsemestre.formsemestre_uecoef_create(cnx, args)
|
||||||
|
|
||||||
# NB: don't copy notes_formsemestre_custommenu (usually specific)
|
# NB: don't copy notes_formsemestre_custommenu (usually specific)
|
||||||
|
|
||||||
@ -1034,7 +1052,7 @@ def do_formsemestre_clone(
|
|||||||
for obj in objs:
|
for obj in objs:
|
||||||
args = obj.copy()
|
args = obj.copy()
|
||||||
args["formsemestre_id"] = formsemestre_id
|
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
|
# 5- Copy partitions
|
||||||
if clone_partitions:
|
if clone_partitions:
|
||||||
@ -1044,7 +1062,6 @@ def do_formsemestre_clone(
|
|||||||
for part in sco_groups.get_partitions_list(context, orig_formsemestre_id):
|
for part in sco_groups.get_partitions_list(context, orig_formsemestre_id):
|
||||||
if part["partition_name"] != None:
|
if part["partition_name"] != None:
|
||||||
partname = part["partition_name"]
|
partname = part["partition_name"]
|
||||||
orig_partition_id = part["partition_id"]
|
|
||||||
new_partition_id = sco_groups.partition_create(
|
new_partition_id = sco_groups.partition_create(
|
||||||
context,
|
context,
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
@ -1064,7 +1081,7 @@ def do_formsemestre_clone(
|
|||||||
if newpart["partition_id"] == g[0]:
|
if newpart["partition_id"] == g[0]:
|
||||||
part_id = g[0]
|
part_id = g[0]
|
||||||
for group_name in g[1]:
|
for group_name in g[1]:
|
||||||
group_id = sco_groups.createGroup(
|
_ = sco_groups.createGroup(
|
||||||
context, part_id, group_name=group_name, REQUEST=REQUEST
|
context, part_id, group_name=group_name, REQUEST=REQUEST
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1131,7 +1148,7 @@ def formsemestre_associate_new_version(
|
|||||||
context, [formsemestre_id] + other_formsemestre_ids, REQUEST=REQUEST
|
context, [formsemestre_id] + other_formsemestre_ids, REQUEST=REQUEST
|
||||||
)
|
)
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"formsemestre_status?formsemestre_id=%s&head_message=Formation%%20dupliquée"
|
"formsemestre_status?formsemestre_id=%s&head_message=Formation%%20dupliquée"
|
||||||
% formsemestre_id
|
% formsemestre_id
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1177,10 +1194,12 @@ def _reassociate_moduleimpls(
|
|||||||
et met à jour les décisions de jury (validations d'UE).
|
et met à jour les décisions de jury (validations d'UE).
|
||||||
"""
|
"""
|
||||||
# re-associate moduleimpls to new modules:
|
# re-associate moduleimpls to new modules:
|
||||||
modimpls = context.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
modimpls = sco_moduleimpl.do_moduleimpl_list(
|
||||||
|
context, formsemestre_id=formsemestre_id
|
||||||
|
)
|
||||||
for mod in modimpls:
|
for mod in modimpls:
|
||||||
mod["module_id"] = modules_old2new[mod["module_id"]]
|
mod["module_id"] = modules_old2new[mod["module_id"]]
|
||||||
context.do_moduleimpl_edit(mod, formsemestre_id=formsemestre_id, cnx=cnx)
|
sco_moduleimpl.do_moduleimpl_edit(context, mod, formsemestre_id=formsemestre_id)
|
||||||
# update decisions:
|
# update decisions:
|
||||||
events = scolars.scolar_events_list(cnx, args={"formsemestre_id": formsemestre_id})
|
events = scolars.scolar_events_list(cnx, args={"formsemestre_id": formsemestre_id})
|
||||||
for e in events:
|
for e in events:
|
||||||
@ -1244,7 +1263,11 @@ def formsemestre_delete(context, formsemestre_id, REQUEST=None):
|
|||||||
H.append(tf[1])
|
H.append(tf[1])
|
||||||
return "\n".join(H) + context.sco_footer(REQUEST)
|
return "\n".join(H) + context.sco_footer(REQUEST)
|
||||||
elif tf[0] == -1: # cancel
|
elif tf[0] == -1: # cancel
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
return REQUEST.RESPONSE.redirect(
|
||||||
|
context.NotesURL()
|
||||||
|
+ "/formsemestre_status?formsemestre_id="
|
||||||
|
+ formsemestre_id
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"formsemestre_delete2?formsemestre_id=" + formsemestre_id
|
"formsemestre_delete2?formsemestre_id=" + formsemestre_id
|
||||||
@ -1255,9 +1278,6 @@ def formsemestre_delete2(
|
|||||||
context, formsemestre_id, dialog_confirmed=False, REQUEST=None
|
context, formsemestre_id, dialog_confirmed=False, REQUEST=None
|
||||||
):
|
):
|
||||||
"""Delete a formsemestre (confirmation)"""
|
"""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
|
# Confirmation dialog
|
||||||
if not dialog_confirmed:
|
if not dialog_confirmed:
|
||||||
return context.confirmDialog(
|
return context.confirmDialog(
|
||||||
@ -1269,14 +1289,16 @@ def formsemestre_delete2(
|
|||||||
)
|
)
|
||||||
# Bon, s'il le faut...
|
# Bon, s'il le faut...
|
||||||
do_formsemestre_delete(context, formsemestre_id, REQUEST)
|
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):
|
def formsemestre_has_decisions_or_compensations(context, formsemestre_id):
|
||||||
"""True if decision de jury dans ce semestre
|
"""True if decision de jury dans ce semestre
|
||||||
ou bien compensation de ce semestre par d'autre ssemestres.
|
ou bien compensation de ce semestre par d'autre ssemestres.
|
||||||
"""
|
"""
|
||||||
r = SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT v.* FROM scolar_formsemestre_validation v WHERE v.formsemestre_id = %(formsemestre_id)s OR v.compense_formsemestre_id = %(formsemestre_id)s",
|
"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},
|
{"formsemestre_id": formsemestre_id},
|
||||||
@ -1297,28 +1319,28 @@ def do_formsemestre_delete(context, formsemestre_id, REQUEST):
|
|||||||
# evaluations
|
# evaluations
|
||||||
evals = context.do_evaluation_list(args={"moduleimpl_id": mod["moduleimpl_id"]})
|
evals = context.do_evaluation_list(args={"moduleimpl_id": mod["moduleimpl_id"]})
|
||||||
for e in evals:
|
for e in evals:
|
||||||
SimpleQuery(
|
ndb.SimpleQuery(
|
||||||
context,
|
context,
|
||||||
"DELETE FROM notes_notes WHERE evaluation_id=%(evaluation_id)s",
|
"DELETE FROM notes_notes WHERE evaluation_id=%(evaluation_id)s",
|
||||||
e,
|
e,
|
||||||
)
|
)
|
||||||
SimpleQuery(
|
ndb.SimpleQuery(
|
||||||
context,
|
context,
|
||||||
"DELETE FROM notes_notes_log WHERE evaluation_id=%(evaluation_id)s",
|
"DELETE FROM notes_notes_log WHERE evaluation_id=%(evaluation_id)s",
|
||||||
e,
|
e,
|
||||||
)
|
)
|
||||||
SimpleQuery(
|
ndb.SimpleQuery(
|
||||||
context,
|
context,
|
||||||
"DELETE FROM notes_evaluation WHERE evaluation_id=%(evaluation_id)s",
|
"DELETE FROM notes_evaluation WHERE evaluation_id=%(evaluation_id)s",
|
||||||
e,
|
e,
|
||||||
)
|
)
|
||||||
context.get_evaluations_cache().inval_cache(key=e["evaluation_id"])
|
context.get_evaluations_cache().inval_cache(key=e["evaluation_id"])
|
||||||
|
|
||||||
context.do_moduleimpl_delete(
|
sco_moduleimpl.do_moduleimpl_delete(
|
||||||
mod["moduleimpl_id"], formsemestre_id=formsemestre_id
|
context, mod["moduleimpl_id"], formsemestre_id=formsemestre_id
|
||||||
)
|
)
|
||||||
# --- Desinscription des etudiants
|
# --- 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"
|
req = "DELETE FROM notes_formsemestre_inscription WHERE formsemestre_id=%(formsemestre_id)s"
|
||||||
cursor.execute(req, {"formsemestre_id": formsemestre_id})
|
cursor.execute(req, {"formsemestre_id": formsemestre_id})
|
||||||
# --- Suppression des evenements
|
# --- Suppression des evenements
|
||||||
@ -1420,7 +1442,7 @@ def formsemestre_change_lock(
|
|||||||
args = {"formsemestre_id": formsemestre_id, "etat": etat}
|
args = {"formsemestre_id": formsemestre_id, "etat": etat}
|
||||||
context.do_formsemestre_edit(args)
|
context.do_formsemestre_edit(args)
|
||||||
if REQUEST:
|
if REQUEST:
|
||||||
REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1460,23 +1482,10 @@ def formsemestre_change_publication_bul(
|
|||||||
args = {"formsemestre_id": formsemestre_id, "bul_hide_xml": etat}
|
args = {"formsemestre_id": formsemestre_id, "bul_hide_xml": etat}
|
||||||
context.do_formsemestre_edit(args)
|
context.do_formsemestre_edit(args)
|
||||||
if REQUEST:
|
if REQUEST:
|
||||||
REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
|
||||||
)
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
# ---------------------- Coefs des UE
|
|
||||||
|
|
||||||
_formsemestre_uecoef_editor = EditableTable(
|
|
||||||
"notes_formsemestre_uecoef",
|
|
||||||
"formsemestre_uecoef_id",
|
|
||||||
("formsemestre_uecoef_id", "formsemestre_id", "ue_id", "coefficient"),
|
|
||||||
)
|
|
||||||
|
|
||||||
formsemestre_uecoef_create = _formsemestre_uecoef_editor.create
|
|
||||||
formsemestre_uecoef_edit = _formsemestre_uecoef_editor.edit
|
|
||||||
formsemestre_uecoef_list = _formsemestre_uecoef_editor.list
|
|
||||||
formsemestre_uecoef_delete = _formsemestre_uecoef_editor.delete
|
|
||||||
|
|
||||||
|
|
||||||
def formsemestre_edit_uecoefs(context, formsemestre_id, err_ue_id=None, REQUEST=None):
|
def formsemestre_edit_uecoefs(context, formsemestre_id, err_ue_id=None, REQUEST=None):
|
||||||
@ -1486,7 +1495,6 @@ def formsemestre_edit_uecoefs(context, formsemestre_id, err_ue_id=None, REQUEST=
|
|||||||
if not ok:
|
if not ok:
|
||||||
return err
|
return err
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
F = context.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
|
||||||
|
|
||||||
footer = context.sco_footer(REQUEST)
|
footer = context.sco_footer(REQUEST)
|
||||||
help = """<p class="help">
|
help = """<p class="help">
|
||||||
@ -1527,7 +1535,7 @@ def formsemestre_edit_uecoefs(context, formsemestre_id, err_ue_id=None, REQUEST=
|
|||||||
initvalues = {"formsemestre_id": formsemestre_id}
|
initvalues = {"formsemestre_id": formsemestre_id}
|
||||||
form = [("formsemestre_id", {"input_type": "hidden"})]
|
form = [("formsemestre_id", {"input_type": "hidden"})]
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
coefs = formsemestre_uecoef_list(
|
coefs = sco_formsemestre.formsemestre_uecoef_list(
|
||||||
cnx, args={"formsemestre_id": formsemestre_id, "ue_id": ue["ue_id"]}
|
cnx, args={"formsemestre_id": formsemestre_id, "ue_id": ue["ue_id"]}
|
||||||
)
|
)
|
||||||
if coefs:
|
if coefs:
|
||||||
@ -1564,7 +1572,7 @@ def formsemestre_edit_uecoefs(context, formsemestre_id, err_ue_id=None, REQUEST=
|
|||||||
msg = []
|
msg = []
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
val = tf[2]["ue_" + ue["ue_id"]]
|
val = tf[2]["ue_" + ue["ue_id"]]
|
||||||
coefs = formsemestre_uecoef_list(
|
coefs = sco_formsemestre.formsemestre_uecoef_list(
|
||||||
cnx, args={"formsemestre_id": formsemestre_id, "ue_id": ue["ue_id"]}
|
cnx, args={"formsemestre_id": formsemestre_id, "ue_id": ue["ue_id"]}
|
||||||
)
|
)
|
||||||
if val == "" or val == "auto":
|
if val == "" or val == "auto":
|
||||||
@ -1594,11 +1602,13 @@ def formsemestre_edit_uecoefs(context, formsemestre_id, err_ue_id=None, REQUEST=
|
|||||||
|
|
||||||
# apply modifications
|
# apply modifications
|
||||||
for ue in ue_modified:
|
for ue in ue_modified:
|
||||||
do_formsemestre_uecoef_edit_or_create(
|
sco_formsemestre.do_formsemestre_uecoef_edit_or_create(
|
||||||
context, cnx, formsemestre_id, ue["ue_id"], ue["coef"]
|
context, cnx, formsemestre_id, ue["ue_id"], ue["coef"]
|
||||||
)
|
)
|
||||||
for ue in ue_deleted:
|
for ue in ue_deleted:
|
||||||
do_formsemestre_uecoef_delete(context, cnx, formsemestre_id, ue["ue_id"])
|
sco_formsemestre.do_formsemestre_uecoef_delete(
|
||||||
|
context, cnx, formsemestre_id, ue["ue_id"]
|
||||||
|
)
|
||||||
|
|
||||||
if ue_modified or ue_deleted:
|
if ue_modified or ue_deleted:
|
||||||
z = ["""<h3>Modification effectuées</h3>"""]
|
z = ["""<h3>Modification effectuées</h3>"""]
|
||||||
@ -1630,39 +1640,6 @@ def formsemestre_edit_uecoefs(context, formsemestre_id, err_ue_id=None, REQUEST=
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def do_formsemestre_uecoef_edit_or_create(context, cnx, formsemestre_id, ue_id, coef):
|
|
||||||
"modify or create the coef"
|
|
||||||
coefs = formsemestre_uecoef_list(
|
|
||||||
cnx, args={"formsemestre_id": formsemestre_id, "ue_id": ue_id}
|
|
||||||
)
|
|
||||||
if coefs:
|
|
||||||
formsemestre_uecoef_edit(
|
|
||||||
cnx,
|
|
||||||
args={
|
|
||||||
"formsemestre_uecoef_id": coefs[0]["formsemestre_uecoef_id"],
|
|
||||||
"coefficient": coef,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
formsemestre_uecoef_create(
|
|
||||||
cnx,
|
|
||||||
args={
|
|
||||||
"formsemestre_id": formsemestre_id,
|
|
||||||
"ue_id": ue_id,
|
|
||||||
"coefficient": coef,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def do_formsemestre_uecoef_delete(context, cnx, formsemestre_id, ue_id):
|
|
||||||
"delete coef for this (ue,sem)"
|
|
||||||
coefs = formsemestre_uecoef_list(
|
|
||||||
cnx, args={"formsemestre_id": formsemestre_id, "ue_id": ue_id}
|
|
||||||
)
|
|
||||||
if coefs:
|
|
||||||
formsemestre_uecoef_delete(cnx, coefs[0]["formsemestre_uecoef_id"])
|
|
||||||
|
|
||||||
|
|
||||||
# ----- identification externe des sessions (pour SOJA et autres logiciels)
|
# ----- identification externe des sessions (pour SOJA et autres logiciels)
|
||||||
def get_formsemestre_session_id(context, sem, F, parcours):
|
def get_formsemestre_session_id(context, sem, F, parcours):
|
||||||
"""Identifiant de session pour ce semestre
|
"""Identifiant de session pour ce semestre
|
||||||
@ -1692,12 +1669,12 @@ def get_formsemestre_session_id(context, sem, F, parcours):
|
|||||||
(modalite or "").replace("FAP", "FA").replace("APP", "FA")
|
(modalite or "").replace("FAP", "FA").replace("APP", "FA")
|
||||||
) # exception pour code Apprentissage
|
) # exception pour code Apprentissage
|
||||||
if sem["semestre_id"] > 0:
|
if sem["semestre_id"] > 0:
|
||||||
decale = sem_decale_str(sem)
|
decale = scu.sem_decale_str(sem)
|
||||||
semestre_id = "S%d" % sem["semestre_id"] + decale
|
semestre_id = "S%d" % sem["semestre_id"] + decale
|
||||||
else:
|
else:
|
||||||
semestre_id = F["code_specialite"]
|
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))
|
"-".join((ImputationDept, parcours_type, modalite, semestre_id, annee_sco))
|
||||||
)
|
)
|
||||||
|
@ -86,7 +86,7 @@ def formsemestre_ext_create_form(context, etudid, formsemestre_id, REQUEST=None)
|
|||||||
<p class="help">
|
<p class="help">
|
||||||
Notez que si un semestre extérieur similaire a déjà été créé pour un autre étudiant,
|
Notez que si un semestre extérieur similaire a déjà été créé pour un autre étudiant,
|
||||||
il est préférable d'utiliser la fonction
|
il est préférable d'utiliser la fonction
|
||||||
"<a href="formsemestre_inscription_with_modules_form?etudid=%s&only_ext=1">
|
"<a href="formsemestre_inscription_with_modules_form?etudid=%s&only_ext=1">
|
||||||
inscrire à un autre semestre</a>"
|
inscrire à un autre semestre</a>"
|
||||||
</p>
|
</p>
|
||||||
"""
|
"""
|
||||||
@ -191,7 +191,7 @@ def formsemestre_ext_create_form(context, etudid, formsemestre_id, REQUEST=None)
|
|||||||
return "\n".join(H) + "\n" + tf[1] + F
|
return "\n".join(H) + "\n" + tf[1] + F
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
"%s/formsemestre_bulletinetud?formsemestre_id==%s&etudid=%s"
|
"%s/formsemestre_bulletinetud?formsemestre_id==%s&etudid=%s"
|
||||||
% (context.ScoURL(), formsemestre_id, etudid)
|
% (context.ScoURL(), formsemestre_id, etudid)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -436,7 +436,7 @@ def _list_ue_with_coef_and_validations(context, sem, etudid):
|
|||||||
ue_list = context.do_ue_list({"formation_id": sem["formation_id"]})
|
ue_list = context.do_ue_list({"formation_id": sem["formation_id"]})
|
||||||
for ue in ue_list:
|
for ue in ue_list:
|
||||||
# add coefficient
|
# add coefficient
|
||||||
uecoef = sco_formsemestre_edit.formsemestre_uecoef_list(
|
uecoef = sco_formsemestre.formsemestre_uecoef_list(
|
||||||
cnx, args={"formsemestre_id": formsemestre_id, "ue_id": ue["ue_id"]}
|
cnx, args={"formsemestre_id": formsemestre_id, "ue_id": ue["ue_id"]}
|
||||||
)
|
)
|
||||||
if uecoef:
|
if uecoef:
|
||||||
|
@ -28,8 +28,11 @@
|
|||||||
"""Opérations d'inscriptions aux semestres et modules
|
"""Opérations d'inscriptions aux semestres et modules
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from sco_utils import ScoEtudInscrit, log, ScoValueError, DictDefault
|
import sco_utils as scu
|
||||||
from sco_utils import UE_STANDARD, UE_SPORT, UE_TYPE_NAME
|
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 notesdb import ScoDocCursor, DateISOtoDMY, DateDMYtoISO
|
||||||
|
|
||||||
from TrivialFormulator import TrivialFormulator, TF
|
from TrivialFormulator import TrivialFormulator, TF
|
||||||
@ -37,6 +40,7 @@ from TrivialFormulator import TrivialFormulator, TF
|
|||||||
# from notes_table import *
|
# from notes_table import *
|
||||||
import sco_find_etud
|
import sco_find_etud
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
|
import sco_moduleimpl
|
||||||
import sco_groups
|
import sco_groups
|
||||||
|
|
||||||
|
|
||||||
@ -75,10 +79,13 @@ def do_formsemestre_inscription_with_modules(
|
|||||||
gdone[group_id] = 1
|
gdone[group_id] = 1
|
||||||
|
|
||||||
# inscription a tous les modules de ce semestre
|
# inscription a tous les modules de ce semestre
|
||||||
modimpls = context.do_moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
modimpls = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||||
|
context, formsemestre_id=formsemestre_id
|
||||||
|
)
|
||||||
for mod in modimpls:
|
for mod in modimpls:
|
||||||
if mod["ue"]["type"] != UE_SPORT:
|
if mod["ue"]["type"] != UE_SPORT:
|
||||||
context.do_moduleimpl_inscription_create(
|
sco_moduleimpl.do_moduleimpl_inscription_create(
|
||||||
|
context,
|
||||||
{"moduleimpl_id": mod["moduleimpl_id"], "etudid": etudid},
|
{"moduleimpl_id": mod["moduleimpl_id"], "etudid": etudid},
|
||||||
REQUEST=REQUEST,
|
REQUEST=REQUEST,
|
||||||
formsemestre_id=formsemestre_id,
|
formsemestre_id=formsemestre_id,
|
||||||
@ -140,9 +147,9 @@ def formsemestre_inscription_with_modules_form(
|
|||||||
if (not only_ext) or (sem["modalite"] == "EXT"):
|
if (not only_ext) or (sem["modalite"] == "EXT"):
|
||||||
H.append(
|
H.append(
|
||||||
"""
|
"""
|
||||||
<li><a class="stdlink" href="formsemestre_inscription_with_modules?etudid=%s&formsemestre_id=%s">%s</a>
|
<li><a class="stdlink" id="inscription_Semestre_%s" href="formsemestre_inscription_with_modules?etudid=%s&formsemestre_id=%s">%s</a>
|
||||||
"""
|
"""
|
||||||
% (etudid, sem["formsemestre_id"], sem["titremois"])
|
% (sem["formsemestre_id"],etudid, sem["formsemestre_id"], sem["titremois"])
|
||||||
)
|
)
|
||||||
H.append("</ul>")
|
H.append("</ul>")
|
||||||
else:
|
else:
|
||||||
@ -210,12 +217,12 @@ def formsemestre_inscription_with_modules(
|
|||||||
H.append("<ul>")
|
H.append("<ul>")
|
||||||
for s in others:
|
for s in others:
|
||||||
H.append(
|
H.append(
|
||||||
'<li><a href="formsemestre_desinscription?formsemestre_id=%s&etudid=%s">déinscrire de %s</li>'
|
'<li><a href="formsemestre_desinscription?formsemestre_id=%s&etudid=%s">déinscrire de %s</li>'
|
||||||
% (s["formsemestre_id"], etudid, s["titreannee"])
|
% (s["formsemestre_id"], etudid, s["titreannee"])
|
||||||
)
|
)
|
||||||
H.append("</ul>")
|
H.append("</ul>")
|
||||||
H.append(
|
H.append(
|
||||||
"""<p><a href="formsemestre_inscription_with_modules?etudid=%s&formsemestre_id=%s&multiple_ok=1&%s">Continuer quand même l'inscription</a></p>"""
|
"""<p><a href="formsemestre_inscription_with_modules?etudid=%s&formsemestre_id=%s&multiple_ok=1&%s">Continuer quand même l'inscription</a></p>"""
|
||||||
% (etudid, formsemestre_id, sco_groups.make_query_groups(group_ids))
|
% (etudid, formsemestre_id, sco_groups.make_query_groups(group_ids))
|
||||||
)
|
)
|
||||||
return "\n".join(H) + F
|
return "\n".join(H) + F
|
||||||
@ -278,11 +285,15 @@ def formsemestre_inscription_option(context, etudid, formsemestre_id, REQUEST=No
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Cherche les moduleimpls et les inscriptions
|
# Cherche les moduleimpls et les inscriptions
|
||||||
mods = context.do_moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
mods = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||||
inscr = context.do_moduleimpl_inscription_list(etudid=etudid)
|
context, formsemestre_id=formsemestre_id
|
||||||
|
)
|
||||||
|
inscr = sco_moduleimpl.do_moduleimpl_inscription_list(context, etudid=etudid)
|
||||||
# Formulaire
|
# Formulaire
|
||||||
modimpls_by_ue_ids = DictDefault(defaultvalue=[]) # ue_id : [ moduleimpl_id ]
|
modimpls_by_ue_ids = scu.DictDefault(defaultvalue=[]) # ue_id : [ moduleimpl_id ]
|
||||||
modimpls_by_ue_names = DictDefault(defaultvalue=[]) # ue_id : [ moduleimpl_name ]
|
modimpls_by_ue_names = scu.DictDefault(
|
||||||
|
defaultvalue=[]
|
||||||
|
) # ue_id : [ moduleimpl_name ]
|
||||||
ues = []
|
ues = []
|
||||||
ue_ids = set()
|
ue_ids = set()
|
||||||
initvalues = {}
|
initvalues = {}
|
||||||
@ -321,7 +332,7 @@ def formsemestre_inscription_option(context, etudid, formsemestre_id, REQUEST=No
|
|||||||
sem_origin = sco_formsemestre.get_formsemestre(
|
sem_origin = sco_formsemestre.get_formsemestre(
|
||||||
context, ue_status["formsemestre_id"]
|
context, ue_status["formsemestre_id"]
|
||||||
)
|
)
|
||||||
ue_descr += ' <a class="discretelink" href="formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s" title="%s">(capitalisée le %s)' % (
|
ue_descr += ' <a class="discretelink" href="formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s" title="%s">(capitalisée le %s)' % (
|
||||||
sem_origin["formsemestre_id"],
|
sem_origin["formsemestre_id"],
|
||||||
etudid,
|
etudid,
|
||||||
sem_origin["titreannee"],
|
sem_origin["titreannee"],
|
||||||
@ -502,13 +513,14 @@ def do_moduleimpl_incription_options(
|
|||||||
# inscriptions
|
# inscriptions
|
||||||
for moduleimpl_id in a_inscrire:
|
for moduleimpl_id in a_inscrire:
|
||||||
# verifie que ce module existe bien
|
# verifie que ce module existe bien
|
||||||
mods = context.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
mods = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)
|
||||||
if len(mods) != 1:
|
if len(mods) != 1:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"inscription: invalid moduleimpl_id: %s" % moduleimpl_id
|
"inscription: invalid moduleimpl_id: %s" % moduleimpl_id
|
||||||
)
|
)
|
||||||
mod = mods[0]
|
mod = mods[0]
|
||||||
context.do_moduleimpl_inscription_create(
|
sco_moduleimpl.do_moduleimpl_inscription_create(
|
||||||
|
context,
|
||||||
{"moduleimpl_id": moduleimpl_id, "etudid": etudid},
|
{"moduleimpl_id": moduleimpl_id, "etudid": etudid},
|
||||||
REQUEST=REQUEST,
|
REQUEST=REQUEST,
|
||||||
formsemestre_id=mod["formsemestre_id"],
|
formsemestre_id=mod["formsemestre_id"],
|
||||||
@ -516,14 +528,14 @@ def do_moduleimpl_incription_options(
|
|||||||
# desinscriptions
|
# desinscriptions
|
||||||
for moduleimpl_id in a_desinscrire:
|
for moduleimpl_id in a_desinscrire:
|
||||||
# verifie que ce module existe bien
|
# verifie que ce module existe bien
|
||||||
mods = context.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
mods = sco_moduleimpl.do_moduleimpl_list(context, moduleimpl_id=moduleimpl_id)
|
||||||
if len(mods) != 1:
|
if len(mods) != 1:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"desinscription: invalid moduleimpl_id: %s" % moduleimpl_id
|
"desinscription: invalid moduleimpl_id: %s" % moduleimpl_id
|
||||||
)
|
)
|
||||||
mod = mods[0]
|
mod = mods[0]
|
||||||
inscr = context.do_moduleimpl_inscription_list(
|
inscr = sco_moduleimpl.do_moduleimpl_inscription_list(
|
||||||
moduleimpl_id=moduleimpl_id, etudid=etudid
|
context, moduleimpl_id=moduleimpl_id, etudid=etudid
|
||||||
)
|
)
|
||||||
if not inscr:
|
if not inscr:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
@ -531,8 +543,8 @@ def do_moduleimpl_incription_options(
|
|||||||
% (etudid, moduleimpl_id)
|
% (etudid, moduleimpl_id)
|
||||||
)
|
)
|
||||||
oid = inscr[0]["moduleimpl_inscription_id"]
|
oid = inscr[0]["moduleimpl_inscription_id"]
|
||||||
context.do_moduleimpl_inscription_delete(
|
sco_moduleimpl.do_moduleimpl_inscription_delete(
|
||||||
oid, formsemestre_id=mod["formsemestre_id"]
|
context, oid, formsemestre_id=mod["formsemestre_id"]
|
||||||
)
|
)
|
||||||
|
|
||||||
if REQUEST:
|
if REQUEST:
|
||||||
|
@ -29,11 +29,19 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Rewritten from ancient DTML code
|
# Rewritten from ancient DTML code
|
||||||
from mx.DateTime import DateTime as mxDateTime
|
|
||||||
|
|
||||||
from notesdb import *
|
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
|
from sco_permissions import (
|
||||||
|
ScoImplement,
|
||||||
|
ScoChangeFormation,
|
||||||
|
ScoEtudInscrit,
|
||||||
|
ScoView,
|
||||||
|
ScoEtudChangeAdr,
|
||||||
|
)
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
|
import VERSION
|
||||||
|
import htmlutils
|
||||||
from sco_formsemestre_custommenu import formsemestre_custommenu_html
|
from sco_formsemestre_custommenu import formsemestre_custommenu_html
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
import sco_archives
|
import sco_archives
|
||||||
@ -41,64 +49,12 @@ import sco_groups
|
|||||||
import sco_evaluations
|
import sco_evaluations
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_formsemestre_edit
|
import sco_formsemestre_edit
|
||||||
|
import sco_moduleimpl
|
||||||
import sco_compute_moy
|
import sco_compute_moy
|
||||||
import sco_codes_parcours
|
import sco_codes_parcours
|
||||||
import sco_bulletins
|
import sco_bulletins
|
||||||
|
|
||||||
|
|
||||||
def makeMenu(title, items, css_class="", base_url="", alone=False):
|
|
||||||
"""HTML snippet to render a simple drop down menu.
|
|
||||||
items is a list of dicts:
|
|
||||||
{ 'title' :
|
|
||||||
'url' :
|
|
||||||
'id' :
|
|
||||||
'attr' : "" # optionnal html <a> attributes
|
|
||||||
'enabled' : # True by default
|
|
||||||
'helpmsg' :
|
|
||||||
'submenu' : [ list of sub-items ]
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
def gen_menu_items(items):
|
|
||||||
H.append("<ul>")
|
|
||||||
for item in items:
|
|
||||||
if not item.get("enabled", True):
|
|
||||||
cls = ' class="ui-state-disabled"'
|
|
||||||
else:
|
|
||||||
cls = ""
|
|
||||||
the_id = item.get("id", "")
|
|
||||||
if the_id:
|
|
||||||
li_id = 'id="%s" ' % the_id
|
|
||||||
else:
|
|
||||||
li_id = ""
|
|
||||||
if base_url and "url" in item:
|
|
||||||
item["urlq"] = base_url + item["url"]
|
|
||||||
else:
|
|
||||||
item["urlq"] = item.get("url", "#")
|
|
||||||
item["attr"] = item.get("attr", "")
|
|
||||||
submenu = item.get("submenu", None)
|
|
||||||
H.append(
|
|
||||||
"<li "
|
|
||||||
+ li_id
|
|
||||||
+ cls
|
|
||||||
+ '><a href="%(urlq)s" %(attr)s>%(title)s</a>' % item
|
|
||||||
)
|
|
||||||
if submenu:
|
|
||||||
gen_menu_items(submenu)
|
|
||||||
H.append("</li>")
|
|
||||||
H.append("</ul>")
|
|
||||||
|
|
||||||
H = []
|
|
||||||
if alone:
|
|
||||||
H.append('<ul class="sco_dropdown_menu %s">' % css_class)
|
|
||||||
H.append("""<li><a href="#">%s</a>""" % title)
|
|
||||||
gen_menu_items(items)
|
|
||||||
H.append("</li>")
|
|
||||||
if alone:
|
|
||||||
H.append("</ul>")
|
|
||||||
return "".join(H)
|
|
||||||
|
|
||||||
|
|
||||||
# H = [ """<span class="barrenav"><ul class="nav">
|
# H = [ """<span class="barrenav"><ul class="nav">
|
||||||
# <li onmouseover="MenuDisplay(this)" onmouseout="MenuHide(this)"><a href="#" class="menu %s">%s</a><ul>""" % (cssclass, title)
|
# <li onmouseover="MenuDisplay(this)" onmouseout="MenuHide(this)"><a href="#" class="menu %s">%s</a><ul>""" % (cssclass, title)
|
||||||
# ]
|
# ]
|
||||||
@ -130,7 +86,7 @@ def defMenuStats(context, formsemestre_id):
|
|||||||
{
|
{
|
||||||
"title": "Graphe des parcours",
|
"title": "Graphe des parcours",
|
||||||
"url": "formsemestre_graph_parcours?formsemestre_id=" + formsemestre_id,
|
"url": "formsemestre_graph_parcours?formsemestre_id=" + formsemestre_id,
|
||||||
"enabled": WITH_PYDOT,
|
"enabled": scu.WITH_PYDOT,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Codes des parcours",
|
"title": "Codes des parcours",
|
||||||
@ -198,7 +154,7 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Modifier le semestre",
|
"title": "Modifier le semestre",
|
||||||
"url": "formsemestre_editwithmodules?formation_id=%(formation_id)s&formsemestre_id=%(formsemestre_id)s"
|
"url": "formsemestre_editwithmodules?formation_id=%(formation_id)s&formsemestre_id=%(formsemestre_id)s"
|
||||||
% sem,
|
% sem,
|
||||||
"enabled": (
|
"enabled": (
|
||||||
authuser.has_permission(ScoImplement, context)
|
authuser.has_permission(ScoImplement, context)
|
||||||
@ -336,7 +292,7 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Exporter table des étudiants",
|
"title": "Exporter table des étudiants",
|
||||||
"url": "groups_view?format=allxls&group_ids="
|
"url": "groups_view?format=allxls&group_ids="
|
||||||
+ sco_groups.get_default_group(
|
+ sco_groups.get_default_group(
|
||||||
context, formsemestre_id, fix_if_missing=True, REQUEST=REQUEST
|
context, formsemestre_id, fix_if_missing=True, REQUEST=REQUEST
|
||||||
),
|
),
|
||||||
@ -364,7 +320,7 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||||||
{
|
{
|
||||||
"title": "Créer/modifier les partitions...",
|
"title": "Créer/modifier les partitions...",
|
||||||
"url": "editPartitionForm?formsemestre_id=" + formsemestre_id,
|
"url": "editPartitionForm?formsemestre_id=" + formsemestre_id,
|
||||||
"enabled": context.can_change_groups(REQUEST, formsemestre_id),
|
"enabled": sco_groups.can_change_groups(context, REQUEST, formsemestre_id),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
# 1 item / partition:
|
# 1 item / partition:
|
||||||
@ -372,7 +328,9 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||||||
context, formsemestre_id, with_default=False
|
context, formsemestre_id, with_default=False
|
||||||
)
|
)
|
||||||
submenu = []
|
submenu = []
|
||||||
enabled = context.can_change_groups(REQUEST, formsemestre_id) and partitions
|
enabled = (
|
||||||
|
sco_groups.can_change_groups(context, REQUEST, formsemestre_id) and partitions
|
||||||
|
)
|
||||||
for partition in partitions:
|
for partition in partitions:
|
||||||
submenu.append(
|
submenu.append(
|
||||||
{
|
{
|
||||||
@ -430,7 +388,7 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Saisie des décisions du jury",
|
"title": "Saisie des décisions du jury",
|
||||||
"url": "formsemestre_recapcomplet?modejury=1&hidemodules=1&hidebac=1&pref_override=0&formsemestre_id="
|
"url": "formsemestre_recapcomplet?modejury=1&hidemodules=1&hidebac=1&pref_override=0&formsemestre_id="
|
||||||
+ formsemestre_id,
|
+ formsemestre_id,
|
||||||
"enabled": context._can_validate_sem(REQUEST, formsemestre_id),
|
"enabled": context._can_validate_sem(REQUEST, formsemestre_id),
|
||||||
},
|
},
|
||||||
@ -453,12 +411,12 @@ def formsemestre_status_menubar(context, sem, REQUEST):
|
|||||||
H = [
|
H = [
|
||||||
# <table><tr><td>',
|
# <table><tr><td>',
|
||||||
'<ul id="sco_menu">',
|
'<ul id="sco_menu">',
|
||||||
makeMenu("Semestre", menuSemestre, base_url=base_url),
|
htmlutils.make_menu("Semestre", menuSemestre, base_url=base_url),
|
||||||
makeMenu("Inscriptions", menuInscriptions, base_url=base_url),
|
htmlutils.make_menu("Inscriptions", menuInscriptions, base_url=base_url),
|
||||||
makeMenu("Groupes", menuGroupes, base_url=base_url),
|
htmlutils.make_menu("Groupes", menuGroupes, base_url=base_url),
|
||||||
makeMenu("Notes", menuNotes, base_url=base_url),
|
htmlutils.make_menu("Notes", menuNotes, base_url=base_url),
|
||||||
makeMenu("Jury", menuJury, base_url=base_url),
|
htmlutils.make_menu("Jury", menuJury, base_url=base_url),
|
||||||
makeMenu("Statistiques", menuStats, base_url=base_url),
|
htmlutils.make_menu("Statistiques", menuStats, base_url=base_url),
|
||||||
formsemestre_custommenu_html(context, formsemestre_id, base_url=base_url),
|
formsemestre_custommenu_html(context, formsemestre_id, base_url=base_url),
|
||||||
"</ul>",
|
"</ul>",
|
||||||
#'</td></tr></table>'
|
#'</td></tr></table>'
|
||||||
@ -476,8 +434,8 @@ def retreive_formsemestre_from_request(context, REQUEST):
|
|||||||
if REQUEST.form.has_key("formsemestre_id"):
|
if REQUEST.form.has_key("formsemestre_id"):
|
||||||
formsemestre_id = REQUEST.form["formsemestre_id"]
|
formsemestre_id = REQUEST.form["formsemestre_id"]
|
||||||
elif REQUEST.form.has_key("moduleimpl_id"):
|
elif REQUEST.form.has_key("moduleimpl_id"):
|
||||||
modimpl = context.do_moduleimpl_list(
|
modimpl = sco_moduleimpl.do_moduleimpl_list(
|
||||||
moduleimpl_id=REQUEST.form["moduleimpl_id"]
|
context, moduleimpl_id=REQUEST.form["moduleimpl_id"]
|
||||||
)
|
)
|
||||||
if not modimpl:
|
if not modimpl:
|
||||||
return None # suppressed ?
|
return None # suppressed ?
|
||||||
@ -488,7 +446,9 @@ def retreive_formsemestre_from_request(context, REQUEST):
|
|||||||
if not E:
|
if not E:
|
||||||
return None # evaluation suppressed ?
|
return None # evaluation suppressed ?
|
||||||
E = E[0]
|
E = E[0]
|
||||||
modimpl = context.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
modimpl = sco_moduleimpl.do_moduleimpl_list(
|
||||||
|
context, moduleimpl_id=E["moduleimpl_id"]
|
||||||
|
)[0]
|
||||||
formsemestre_id = modimpl["formsemestre_id"]
|
formsemestre_id = modimpl["formsemestre_id"]
|
||||||
elif REQUEST.form.has_key("group_id"):
|
elif REQUEST.form.has_key("group_id"):
|
||||||
group = sco_groups.get_group(context, REQUEST.form["group_id"])
|
group = sco_groups.get_group(context, REQUEST.form["group_id"])
|
||||||
@ -545,10 +505,7 @@ def formsemestre_page_title(context, REQUEST):
|
|||||||
|
|
||||||
def fill_formsemestre(context, sem, REQUEST=None):
|
def fill_formsemestre(context, sem, REQUEST=None):
|
||||||
"""Add some useful fields to help display formsemestres"""
|
"""Add some useful fields to help display formsemestres"""
|
||||||
# Notes URL
|
notes_url = context.NotesURL()
|
||||||
notes_url = context.absolute_url()
|
|
||||||
if "/Notes" not in notes_url:
|
|
||||||
notes_url += "/Notes"
|
|
||||||
sem["notes_url"] = notes_url
|
sem["notes_url"] = notes_url
|
||||||
formsemestre_id = sem["formsemestre_id"]
|
formsemestre_id = sem["formsemestre_id"]
|
||||||
if sem["etat"] != "1":
|
if sem["etat"] != "1":
|
||||||
@ -557,15 +514,15 @@ def fill_formsemestre(context, sem, REQUEST=None):
|
|||||||
] = """<a href="%s/formsemestre_change_lock?formsemestre_id=%s">%s</a>""" % (
|
] = """<a href="%s/formsemestre_change_lock?formsemestre_id=%s">%s</a>""" % (
|
||||||
notes_url,
|
notes_url,
|
||||||
sem["formsemestre_id"],
|
sem["formsemestre_id"],
|
||||||
icontag("lock_img", border="0", title="Semestre verrouillé"),
|
scu.icontag("lock_img", border="0", title="Semestre verrouillé"),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
sem["locklink"] = ""
|
sem["locklink"] = ""
|
||||||
if context.get_preference("bul_display_publication", formsemestre_id):
|
if context.get_preference("bul_display_publication", formsemestre_id):
|
||||||
if sem["bul_hide_xml"] != "0":
|
if sem["bul_hide_xml"] != "0":
|
||||||
eyeicon = icontag("hide_img", border="0", title="Bulletins NON publiés")
|
eyeicon = scu.icontag("hide_img", border="0", title="Bulletins NON publiés")
|
||||||
else:
|
else:
|
||||||
eyeicon = icontag("eye_img", border="0", title="Bulletins publiés")
|
eyeicon = scu.icontag("eye_img", border="0", title="Bulletins publiés")
|
||||||
sem["eyelink"] = (
|
sem["eyelink"] = (
|
||||||
"""<a href="%s/formsemestre_change_publication_bul?formsemestre_id=%s">%s</a>"""
|
"""<a href="%s/formsemestre_change_publication_bul?formsemestre_id=%s">%s</a>"""
|
||||||
% (notes_url, sem["formsemestre_id"], eyeicon)
|
% (notes_url, sem["formsemestre_id"], eyeicon)
|
||||||
@ -614,7 +571,9 @@ def formsemestre_description_table(
|
|||||||
use_ue_coefs = context.get_preference("use_ue_coefs", formsemestre_id)
|
use_ue_coefs = context.get_preference("use_ue_coefs", formsemestre_id)
|
||||||
F = context.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
F = context.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
||||||
parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"])
|
parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"])
|
||||||
Mlist = context.do_moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||||
|
context, formsemestre_id=formsemestre_id
|
||||||
|
)
|
||||||
|
|
||||||
R = []
|
R = []
|
||||||
sum_coef = 0
|
sum_coef = 0
|
||||||
@ -641,8 +600,8 @@ def formsemestre_description_table(
|
|||||||
ue_info["Coef._class"] = "ue_coef"
|
ue_info["Coef._class"] = "ue_coef"
|
||||||
R.append(ue_info)
|
R.append(ue_info)
|
||||||
|
|
||||||
ModInscrits = context.do_moduleimpl_inscription_list(
|
ModInscrits = sco_moduleimpl.do_moduleimpl_inscription_list(
|
||||||
moduleimpl_id=M["moduleimpl_id"]
|
context, moduleimpl_id=M["moduleimpl_id"]
|
||||||
)
|
)
|
||||||
enseignants = ", ".join(
|
enseignants = ", ".join(
|
||||||
[
|
[
|
||||||
@ -715,17 +674,17 @@ def formsemestre_description_table(
|
|||||||
titles["coefficient"] = "Coef. éval."
|
titles["coefficient"] = "Coef. éval."
|
||||||
titles["evalcomplete_str"] = "Complète"
|
titles["evalcomplete_str"] = "Complète"
|
||||||
titles["publish_incomplete_str"] = "Toujours Utilisée"
|
titles["publish_incomplete_str"] = "Toujours Utilisée"
|
||||||
title = "%s %s" % (strcapitalize(parcours.SESSION_NAME), sem["titremois"])
|
title = "%s %s" % (scu.strcapitalize(parcours.SESSION_NAME), sem["titremois"])
|
||||||
|
|
||||||
return GenTable(
|
return GenTable(
|
||||||
columns_ids=columns_ids,
|
columns_ids=columns_ids,
|
||||||
rows=R,
|
rows=R,
|
||||||
titles=titles,
|
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,
|
caption=title,
|
||||||
html_caption=title,
|
html_caption=title,
|
||||||
html_class="table_leftalign formsemestre_description",
|
html_class="table_leftalign formsemestre_description",
|
||||||
base_url="%s?formsemestre_id=%s&with_evals=%s"
|
base_url="%s?formsemestre_id=%s&with_evals=%s"
|
||||||
% (REQUEST.URL0, formsemestre_id, with_evals),
|
% (REQUEST.URL0, formsemestre_id, with_evals),
|
||||||
page_title=title,
|
page_title=title,
|
||||||
html_title=context.html_sem_header(
|
html_title=context.html_sem_header(
|
||||||
@ -779,8 +738,8 @@ def html_expr_diagnostic(context, diagnostics):
|
|||||||
last_id, last_msg = None, None
|
last_id, last_msg = None, None
|
||||||
for diag in diagnostics:
|
for diag in diagnostics:
|
||||||
if "moduleimpl_id" in diag:
|
if "moduleimpl_id" in diag:
|
||||||
mod = context.do_moduleimpl_withmodule_list(
|
mod = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||||
moduleimpl_id=diag["moduleimpl_id"]
|
context, moduleimpl_id=diag["moduleimpl_id"]
|
||||||
)[0]
|
)[0]
|
||||||
H.append(
|
H.append(
|
||||||
'<li>module <a href="moduleimpl_status?moduleimpl_id=%s">%s</a>: %s</li>'
|
'<li>module <a href="moduleimpl_status?moduleimpl_id=%s">%s</a>: %s</li>'
|
||||||
@ -875,10 +834,12 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||||||
# porté du DTML
|
# porté du DTML
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
Mlist = context.do_moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
||||||
inscrits = context.do_formsemestre_inscription_list(
|
context, formsemestre_id=formsemestre_id
|
||||||
args={"formsemestre_id": formsemestre_id}
|
|
||||||
)
|
)
|
||||||
|
# inscrits = context.do_formsemestre_inscription_list(
|
||||||
|
# args={"formsemestre_id": formsemestre_id}
|
||||||
|
# )
|
||||||
prev_ue_id = None
|
prev_ue_id = None
|
||||||
|
|
||||||
can_edit = sco_formsemestre_edit.can_edit_sem(
|
can_edit = sco_formsemestre_edit.can_edit_sem(
|
||||||
@ -926,8 +887,8 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||||||
ModEns += " (resp.), " + ", ".join(
|
ModEns += " (resp.), " + ", ".join(
|
||||||
[context.Users.user_info(e["ens_id"])["nomcomplet"] for e in M["ens"]]
|
[context.Users.user_info(e["ens_id"])["nomcomplet"] for e in M["ens"]]
|
||||||
)
|
)
|
||||||
ModInscrits = context.do_moduleimpl_inscription_list(
|
ModInscrits = sco_moduleimpl.do_moduleimpl_inscription_list(
|
||||||
moduleimpl_id=M["moduleimpl_id"]
|
context, moduleimpl_id=M["moduleimpl_id"]
|
||||||
)
|
)
|
||||||
mails_enseignants.add(
|
mails_enseignants.add(
|
||||||
context.Users.user_info(M["responsable_id"], REQUEST)["email"]
|
context.Users.user_info(M["responsable_id"], REQUEST)["email"]
|
||||||
@ -956,11 +917,11 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||||||
|
|
||||||
if can_edit:
|
if can_edit:
|
||||||
H.append(
|
H.append(
|
||||||
' <a href="edit_ue_expr?formsemestre_id=%s&ue_id=%s">'
|
' <a href="edit_ue_expr?formsemestre_id=%s&ue_id=%s">'
|
||||||
% (formsemestre_id, ue["ue_id"])
|
% (formsemestre_id, ue["ue_id"])
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
icontag(
|
scu.icontag(
|
||||||
"formula",
|
"formula",
|
||||||
title="Mode calcul moyenne d'UE",
|
title="Mode calcul moyenne d'UE",
|
||||||
style="vertical-align:middle",
|
style="vertical-align:middle",
|
||||||
@ -976,7 +937,7 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||||||
|
|
||||||
H.append("</td></tr>")
|
H.append("</td></tr>")
|
||||||
|
|
||||||
if M["ue"]["type"] != UE_STANDARD:
|
if M["ue"]["type"] != sco_codes_parcours.UE_STANDARD:
|
||||||
fontorange = " fontorange" # style css additionnel
|
fontorange = " fontorange" # style css additionnel
|
||||||
else:
|
else:
|
||||||
fontorange = ""
|
fontorange = ""
|
||||||
@ -1011,7 +972,7 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if Mod["module_type"] == MODULE_STANDARD:
|
if Mod["module_type"] == scu.MODULE_STANDARD:
|
||||||
H.append('<td class="evals">')
|
H.append('<td class="evals">')
|
||||||
nb_evals = (
|
nb_evals = (
|
||||||
etat["nb_evals_completes"]
|
etat["nb_evals_completes"]
|
||||||
@ -1033,7 +994,7 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||||||
' <span><a class="redlink" href="moduleimpl_status?moduleimpl_id=%s" title="Il y a des notes en attente">[en attente]</a></span>'
|
' <span><a class="redlink" href="moduleimpl_status?moduleimpl_id=%s" title="Il y a des notes en attente">[en attente]</a></span>'
|
||||||
% M["moduleimpl_id"]
|
% M["moduleimpl_id"]
|
||||||
)
|
)
|
||||||
elif Mod["module_type"] == MODULE_MALUS:
|
elif Mod["module_type"] == scu.MODULE_MALUS:
|
||||||
nb_malus_notes = sum(
|
nb_malus_notes = sum(
|
||||||
[
|
[
|
||||||
e["etat"]["nb_notes"]
|
e["etat"]["nb_notes"]
|
||||||
|
@ -29,14 +29,14 @@
|
|||||||
"""
|
"""
|
||||||
import urllib, time, datetime
|
import urllib, time, datetime
|
||||||
|
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from scolog import logdb
|
from scolog import logdb
|
||||||
from notes_table import *
|
|
||||||
import notes_table
|
import notes_table
|
||||||
from ZAbsences import getAbsSemEtud
|
from TrivialFormulator import TrivialFormulator, tf_error_message
|
||||||
|
from sco_exceptions import ScoValueError
|
||||||
|
from sco_abs import getAbsSemEtud
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_formsemestre_edit
|
import sco_formsemestre_edit
|
||||||
import sco_formsemestre_status
|
import sco_formsemestre_status
|
||||||
@ -109,13 +109,13 @@ def formsemestre_validation_etud_form(
|
|||||||
if etud_index_prev != None:
|
if etud_index_prev != None:
|
||||||
etud_p = context.getEtudInfo(etudid=T[etud_index_prev][-1], filled=True)[0]
|
etud_p = context.getEtudInfo(etudid=T[etud_index_prev][-1], filled=True)[0]
|
||||||
Footer.append(
|
Footer.append(
|
||||||
'<span><a href="formsemestre_validation_etud_form?formsemestre_id=%s&etud_index=%s">Etud. précédent (%s)</a></span>'
|
'<span><a href="formsemestre_validation_etud_form?formsemestre_id=%s&etud_index=%s">Etud. précédent (%s)</a></span>'
|
||||||
% (formsemestre_id, etud_index_prev, etud_p["nomprenom"])
|
% (formsemestre_id, etud_index_prev, etud_p["nomprenom"])
|
||||||
)
|
)
|
||||||
if etud_index_next != None:
|
if etud_index_next != None:
|
||||||
etud_n = context.getEtudInfo(etudid=T[etud_index_next][-1], filled=True)[0]
|
etud_n = context.getEtudInfo(etudid=T[etud_index_next][-1], filled=True)[0]
|
||||||
Footer.append(
|
Footer.append(
|
||||||
'<span style="padding-left: 50px;"><a href="formsemestre_validation_etud_form?formsemestre_id=%s&etud_index=%s">Etud. suivant (%s)</a></span>'
|
'<span style="padding-left: 50px;"><a href="formsemestre_validation_etud_form?formsemestre_id=%s&etud_index=%s">Etud. suivant (%s)</a></span>'
|
||||||
% (formsemestre_id, etud_index_next, etud_n["nomprenom"])
|
% (formsemestre_id, etud_index_next, etud_n["nomprenom"])
|
||||||
)
|
)
|
||||||
Footer.append("</p>")
|
Footer.append("</p>")
|
||||||
@ -171,12 +171,12 @@ def formsemestre_validation_etud_form(
|
|||||||
if check:
|
if check:
|
||||||
if not desturl:
|
if not desturl:
|
||||||
desturl = (
|
desturl = (
|
||||||
"formsemestre_recapcomplet?modejury=1&hidemodules=1&hidebac=1&pref_override=0&formsemestre_id="
|
"formsemestre_recapcomplet?modejury=1&hidemodules=1&hidebac=1&pref_override=0&formsemestre_id="
|
||||||
+ formsemestre_id
|
+ formsemestre_id
|
||||||
)
|
)
|
||||||
if sortcol:
|
if sortcol:
|
||||||
desturl += (
|
desturl += (
|
||||||
"&sortcol=" + sortcol
|
"&sortcol=" + sortcol
|
||||||
) # pour refaire tri sorttable du tableau de notes
|
) # pour refaire tri sorttable du tableau de notes
|
||||||
desturl += "#etudid%s" % etudid # va a la bonne ligne
|
desturl += "#etudid%s" % etudid # va a la bonne ligne
|
||||||
H.append('<ul><li><a href="%s">Continuer</a></li></ul>' % desturl)
|
H.append('<ul><li><a href="%s">Continuer</a></li></ul>' % desturl)
|
||||||
@ -205,13 +205,13 @@ def formsemestre_validation_etud_form(
|
|||||||
if not Se.prev_decision:
|
if not Se.prev_decision:
|
||||||
H.append(
|
H.append(
|
||||||
tf_error_message(
|
tf_error_message(
|
||||||
"""Le jury n\'a pas statué sur le semestre précédent ! (<a href="formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s">le faire maintenant</a>)"""
|
"""Le jury n\'a pas statué sur le semestre précédent ! (<a href="formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s">le faire maintenant</a>)"""
|
||||||
% (Se.prev["formsemestre_id"], etudid)
|
% (Se.prev["formsemestre_id"], etudid)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if decision_jury:
|
if decision_jury:
|
||||||
H.append(
|
H.append(
|
||||||
'<a href="formsemestre_validation_suppress_etud?etudid=%s&formsemestre_id=%s" class="stdlink">Supprimer décision existante</a>'
|
'<a href="formsemestre_validation_suppress_etud?etudid=%s&formsemestre_id=%s" class="stdlink">Supprimer décision existante</a>'
|
||||||
% (etudid, formsemestre_id)
|
% (etudid, formsemestre_id)
|
||||||
)
|
)
|
||||||
H.append(context.sco_footer(REQUEST))
|
H.append(context.sco_footer(REQUEST))
|
||||||
@ -249,7 +249,7 @@ def formsemestre_validation_etud_form(
|
|||||||
<input type="submit" value="Statuer sur le semestre précédent"/>
|
<input type="submit" value="Statuer sur le semestre précédent"/>
|
||||||
<input type="hidden" name="formsemestre_id" value="%s"/>
|
<input type="hidden" name="formsemestre_id" value="%s"/>
|
||||||
<input type="hidden" name="etudid" value="%s"/>
|
<input type="hidden" name="etudid" value="%s"/>
|
||||||
<input type="hidden" name="desturl" value="formsemestre_validation_etud_form?etudid=%s&formsemestre_id=%s"/>
|
<input type="hidden" name="desturl" value="formsemestre_validation_etud_form?etudid=%s&formsemestre_id=%s"/>
|
||||||
"""
|
"""
|
||||||
% (Se.prev["formsemestre_id"], etudid, etudid, formsemestre_id)
|
% (Se.prev["formsemestre_id"], etudid, etudid, formsemestre_id)
|
||||||
)
|
)
|
||||||
@ -309,7 +309,7 @@ def formsemestre_validation_etud_form(
|
|||||||
H.append(form_decision_manuelle(context, Se, formsemestre_id, etudid))
|
H.append(form_decision_manuelle(context, Se, formsemestre_id, etudid))
|
||||||
|
|
||||||
H.append(
|
H.append(
|
||||||
"""<div class="link_defaillance">Ou <a class="stdlink" href="formDef?etudid=%s&formsemestre_id=%s">déclarer l'étudiant comme défaillant dans ce semestre</a></div>"""
|
"""<div class="link_defaillance">Ou <a class="stdlink" href="formDef?etudid=%s&formsemestre_id=%s">déclarer l'étudiant comme défaillant dans ce semestre</a></div>"""
|
||||||
% (etudid, formsemestre_id)
|
% (etudid, formsemestre_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -346,7 +346,7 @@ def formsemestre_validation_etud(
|
|||||||
raise ValueError("code choix invalide ! (%s)" % codechoice)
|
raise ValueError("code choix invalide ! (%s)" % codechoice)
|
||||||
#
|
#
|
||||||
Se.valide_decision(choice, REQUEST) # enregistre
|
Se.valide_decision(choice, REQUEST) # enregistre
|
||||||
_redirect_valid_choice(
|
return _redirect_valid_choice(
|
||||||
formsemestre_id, etudid, Se, choice, desturl, sortcol, REQUEST
|
formsemestre_id, etudid, Se, choice, desturl, sortcol, REQUEST
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -393,7 +393,7 @@ def formsemestre_validation_etud_manu(
|
|||||||
#
|
#
|
||||||
Se.valide_decision(choice, REQUEST) # enregistre
|
Se.valide_decision(choice, REQUEST) # enregistre
|
||||||
if redirect:
|
if redirect:
|
||||||
_redirect_valid_choice(
|
return _redirect_valid_choice(
|
||||||
formsemestre_id, etudid, Se, choice, desturl, sortcol, REQUEST
|
formsemestre_id, etudid, Se, choice, desturl, sortcol, REQUEST
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -402,23 +402,23 @@ def _redirect_valid_choice(
|
|||||||
formsemestre_id, etudid, Se, choice, desturl, sortcol, REQUEST
|
formsemestre_id, etudid, Se, choice, desturl, sortcol, REQUEST
|
||||||
):
|
):
|
||||||
adr = (
|
adr = (
|
||||||
"formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1"
|
"formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1"
|
||||||
% (formsemestre_id, etudid)
|
% (formsemestre_id, etudid)
|
||||||
)
|
)
|
||||||
if sortcol:
|
if sortcol:
|
||||||
adr += "&sortcol=" + sortcol
|
adr += "&sortcol=" + sortcol
|
||||||
if desturl:
|
# if desturl:
|
||||||
desturl += "&desturl=" + desturl
|
# desturl += "&desturl=" + desturl
|
||||||
REQUEST.RESPONSE.redirect(adr)
|
return REQUEST.RESPONSE.redirect(adr)
|
||||||
# Si le precedent a été modifié, demande relecture du parcours.
|
# Si le precedent a été modifié, demande relecture du parcours.
|
||||||
# sinon renvoie au listing general,
|
# sinon renvoie au listing general,
|
||||||
|
|
||||||
|
|
||||||
# if choice.new_code_prev:
|
# if choice.new_code_prev:
|
||||||
# REQUEST.RESPONSE.redirect( 'formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1&desturl=%s' % (formsemestre_id, etudid, desturl) )
|
# REQUEST.RESPONSE.redirect( 'formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1&desturl=%s' % (formsemestre_id, etudid, desturl) )
|
||||||
# else:
|
# else:
|
||||||
# if not desturl:
|
# if not desturl:
|
||||||
# desturl = 'formsemestre_recapcomplet?modejury=1&hidemodules=1&formsemestre_id=' + formsemestre_id
|
# desturl = 'formsemestre_recapcomplet?modejury=1&hidemodules=1&formsemestre_id=' + formsemestre_id
|
||||||
# REQUEST.RESPONSE.redirect(desturl)
|
# REQUEST.RESPONSE.redirect(desturl)
|
||||||
|
|
||||||
|
|
||||||
@ -454,8 +454,8 @@ def decisions_possible_rows(Se, assiduite, subtitle="", trclass=""):
|
|||||||
H.append("<th>Code %s</th><th>Devenir</th></tr>" % TitleCur)
|
H.append("<th>Code %s</th><th>Devenir</th></tr>" % TitleCur)
|
||||||
for ch in choices:
|
for ch in choices:
|
||||||
H.append(
|
H.append(
|
||||||
"""<tr class="%s"><td title="règle %s"><input type="radio" name="codechoice" value="%s" onClick="document.getElementById('subut').disabled=false;">"""
|
"""<tr class="%s"><td title="règle %s"><input type="radio" name="codechoice" value="%s" id="choice_input_%s" onClick="document.getElementById('subut').disabled=false;">"""
|
||||||
% (trclass, ch.rule_id, ch.codechoice)
|
% (trclass, ch.rule_id, ch.codechoice,ch.rule_id)
|
||||||
)
|
)
|
||||||
H.append("%s </input></td>" % ch.explication)
|
H.append("%s </input></td>" % ch.explication)
|
||||||
if Se.prev:
|
if Se.prev:
|
||||||
@ -486,8 +486,8 @@ def formsemestre_recap_parcours_table(
|
|||||||
"""
|
"""
|
||||||
H = []
|
H = []
|
||||||
linktmpl = '<span onclick="toggle_vis(this);" class="toggle_sem sem_%%s">%s</span>'
|
linktmpl = '<span onclick="toggle_vis(this);" class="toggle_sem sem_%%s">%s</span>'
|
||||||
minuslink = linktmpl % icontag("minus_img", border="0", alt="-")
|
minuslink = linktmpl % scu.icontag("minus_img", border="0", alt="-")
|
||||||
pluslink = linktmpl % icontag("plus_img", border="0", alt="+")
|
pluslink = linktmpl % scu.icontag("plus_img", border="0", alt="+")
|
||||||
if show_details:
|
if show_details:
|
||||||
sd = " recap_show_details"
|
sd = " recap_show_details"
|
||||||
plusminus = minuslink
|
plusminus = minuslink
|
||||||
@ -497,7 +497,7 @@ def formsemestre_recap_parcours_table(
|
|||||||
H.append('<table class="recap_parcours%s"><tr>' % sd)
|
H.append('<table class="recap_parcours%s"><tr>' % sd)
|
||||||
H.append(
|
H.append(
|
||||||
'<th><span onclick="toggle_all_sems(this);" title="Ouvrir/fermer tous les semestres">%s</span></th><th></th><th>Semestre</th>'
|
'<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>")
|
H.append("<th>Etat</th><th>Abs</th>")
|
||||||
# titres des UE
|
# titres des UE
|
||||||
@ -555,7 +555,7 @@ def formsemestre_recap_parcours_table(
|
|||||||
)
|
)
|
||||||
H.append('<td class="datedebut">%(mois_debut)s</td>' % sem)
|
H.append('<td class="datedebut">%(mois_debut)s</td>' % sem)
|
||||||
H.append(
|
H.append(
|
||||||
'<td class="rcp_titre_sem"><a class="formsemestre_status_link" href="%sformsemestre_bulletinetud?formsemestre_id=%s&etudid=%s" title="Bulletin de notes">%s</a></td>'
|
'<td class="rcp_titre_sem"><a class="formsemestre_status_link" href="%sformsemestre_bulletinetud?formsemestre_id=%s&etudid=%s" title="Bulletin de notes">%s</a></td>'
|
||||||
% (a_url, sem["formsemestre_id"], etudid, sem["titreannee"])
|
% (a_url, sem["formsemestre_id"], etudid, sem["titreannee"])
|
||||||
)
|
)
|
||||||
if decision_sem:
|
if decision_sem:
|
||||||
@ -591,7 +591,7 @@ def formsemestre_recap_parcours_table(
|
|||||||
else:
|
else:
|
||||||
default_sem_info = ""
|
default_sem_info = ""
|
||||||
if sem["etat"] != "1": # locked
|
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
|
default_sem_info += lockicon
|
||||||
if sem["formation_code"] != Se.formation["formation_code"]:
|
if sem["formation_code"] != Se.formation["formation_code"]:
|
||||||
default_sem_info += "Autre formation: %s" % sem["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)
|
# Moy Gen (sous le code decision)
|
||||||
H.append(
|
H.append(
|
||||||
'<td class="rcp_moy">%s</td>'
|
'<td class="rcp_moy">%s</td>' % scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
||||||
% notes_table.fmt_note(nt.get_etud_moy_gen(etudid))
|
|
||||||
)
|
)
|
||||||
# Absences (nb d'abs non just. dans ce semestre)
|
# Absences (nb d'abs non just. dans ce semestre)
|
||||||
AbsEtudSem = getAbsSemEtud(context, sem, etudid)
|
AbsEtudSem = getAbsSemEtud(context, sem, etudid)
|
||||||
@ -641,8 +640,8 @@ def formsemestre_recap_parcours_table(
|
|||||||
# log('')
|
# log('')
|
||||||
|
|
||||||
H.append(
|
H.append(
|
||||||
'<td class="%s" title="%s">%s</td>'
|
'<td class="%s" id="ue_%s" title="%s">%s</td>'
|
||||||
% (class_ue, " ".join(explanation_ue), notes_table.fmt_note(moy_ue))
|
% (class_ue,ue["acronyme"], " ".join(explanation_ue), scu.fmt_note(moy_ue))
|
||||||
)
|
)
|
||||||
if len(ues) < Se.nb_max_ue:
|
if len(ues) < Se.nb_max_ue:
|
||||||
H.append('<td colspan="%d"></td>' % (Se.nb_max_ue - len(ues)))
|
H.append('<td colspan="%d"></td>' % (Se.nb_max_ue - len(ues)))
|
||||||
@ -650,7 +649,7 @@ def formsemestre_recap_parcours_table(
|
|||||||
H.append("<td></td>")
|
H.append("<td></td>")
|
||||||
if with_links:
|
if with_links:
|
||||||
H.append(
|
H.append(
|
||||||
'<td><a href="%sformsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s">modifier</a></td>'
|
'<td><a href="%sformsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s">modifier</a></td>'
|
||||||
% (a_url, sem["formsemestre_id"], etudid)
|
% (a_url, sem["formsemestre_id"], etudid)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -678,7 +677,7 @@ def formsemestre_recap_parcours_table(
|
|||||||
for ue in ues:
|
for ue in ues:
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
||||||
H.append(
|
H.append(
|
||||||
'<td class="ue">%g <span class="ects_fond">%g</span></td>'
|
'<td class="ue">%g<span class="ects_fond">%g</span></td>'
|
||||||
% (ue_status["ects_pot"], ue_status["ects_pot_fond"])
|
% (ue_status["ects_pot"], ue_status["ects_pot_fond"])
|
||||||
)
|
)
|
||||||
H.append("<td></td></tr>")
|
H.append("<td></td></tr>")
|
||||||
@ -810,7 +809,7 @@ def form_decision_manuelle(
|
|||||||
H.append(
|
H.append(
|
||||||
"""</table>
|
"""</table>
|
||||||
<input type="submit" name="formvalidmanu_submit" value="Valider décision manuelle"/>
|
<input type="submit" name="formvalidmanu_submit" value="Valider décision manuelle"/>
|
||||||
<span style="padding-left: 5em;"><a href="formsemestre_validation_suppress_etud?etudid=%s&formsemestre_id=%s" class="stdlink">Supprimer décision existante</a></span>
|
<span style="padding-left: 5em;"><a href="formsemestre_validation_suppress_etud?etudid=%s&formsemestre_id=%s" class="stdlink">Supprimer décision existante</a></span>
|
||||||
</form>
|
</form>
|
||||||
"""
|
"""
|
||||||
% (etudid, formsemestre_id)
|
% (etudid, formsemestre_id)
|
||||||
@ -929,12 +928,12 @@ def do_formsemestre_validation_auto(context, formsemestre_id, REQUEST):
|
|||||||
)
|
)
|
||||||
for etud in conflicts:
|
for etud in conflicts:
|
||||||
H.append(
|
H.append(
|
||||||
'<li><a href="formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1">%s</li>'
|
'<li><a href="formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1">%s</li>'
|
||||||
% (formsemestre_id, etud["etudid"], etud["nomprenom"])
|
% (formsemestre_id, etud["etudid"], etud["nomprenom"])
|
||||||
)
|
)
|
||||||
H.append("</ul>")
|
H.append("</ul>")
|
||||||
H.append(
|
H.append(
|
||||||
'<a href="formsemestre_recapcomplet?formsemestre_id=%s&modejury=1&hidemodules=1&hidebac=1&pref_override=0">continuer</a>'
|
'<a href="formsemestre_recapcomplet?formsemestre_id=%s&modejury=1&hidemodules=1&hidebac=1&pref_override=0">continuer</a>'
|
||||||
% formsemestre_id
|
% formsemestre_id
|
||||||
)
|
)
|
||||||
H.append(context.sco_footer(REQUEST))
|
H.append(context.sco_footer(REQUEST))
|
||||||
@ -1035,7 +1034,7 @@ def formsemestre_validation_suppress_etud(context, formsemestre_id, etudid):
|
|||||||
"""Suppression des decisions de jury pour un etudiant."""
|
"""Suppression des decisions de jury pour un etudiant."""
|
||||||
log("formsemestre_validation_suppress_etud( %s, %s)" % (formsemestre_id, etudid))
|
log("formsemestre_validation_suppress_etud( %s, %s)" % (formsemestre_id, etudid))
|
||||||
cnx = context.GetDBConnexion(autocommit=False)
|
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}
|
args = {"formsemestre_id": formsemestre_id, "etudid": etudid}
|
||||||
try:
|
try:
|
||||||
# -- Validation du semestre et des UEs
|
# -- Validation du semestre et des UEs
|
||||||
@ -1164,8 +1163,8 @@ def formsemestre_validate_previous_ue(context, formsemestre_id, etudid, REQUEST=
|
|||||||
return "\n".join(H) + tf[1] + X + warn + context.sco_footer(REQUEST)
|
return "\n".join(H) + tf[1] + X + warn + context.sco_footer(REQUEST)
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
context.ScoURL()
|
context.NotesURL()
|
||||||
+ "/Notes/formsemestre_status?formsemestre_id="
|
+ "/formsemestre_status?formsemestre_id="
|
||||||
+ formsemestre_id
|
+ formsemestre_id
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -1185,7 +1184,7 @@ def formsemestre_validate_previous_ue(context, formsemestre_id, etudid, REQUEST=
|
|||||||
)
|
)
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
context.ScoURL()
|
context.ScoURL()
|
||||||
+ "/Notes/formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s&head_message=Validation%%20d'UE%%20enregistree"
|
+ "/Notes/formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s&head_message=Validation%%20d'UE%%20enregistree"
|
||||||
% (formsemestre_id, etudid)
|
% (formsemestre_id, etudid)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1212,11 +1211,11 @@ def do_formsemestre_validate_previous_ue(
|
|||||||
context, formsemestre_id
|
context, formsemestre_id
|
||||||
) # > get_etud_ue_status
|
) # > get_etud_ue_status
|
||||||
if ue_coefficient != None:
|
if ue_coefficient != None:
|
||||||
sco_formsemestre_edit.do_formsemestre_uecoef_edit_or_create(
|
sco_formsemestre.do_formsemestre_uecoef_edit_or_create(
|
||||||
context, cnx, formsemestre_id, ue_id, ue_coefficient
|
context, cnx, formsemestre_id, ue_id, ue_coefficient
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
sco_formsemestre_edit.do_formsemestre_uecoef_delete(
|
sco_formsemestre.do_formsemestre_uecoef_delete(
|
||||||
context, cnx, formsemestre_id, ue_id
|
context, cnx, formsemestre_id, ue_id
|
||||||
)
|
)
|
||||||
sco_parcours_dut.do_formsemestre_validate_ue(
|
sco_parcours_dut.do_formsemestre_validate_ue(
|
||||||
@ -1246,7 +1245,7 @@ def do_formsemestre_validate_previous_ue(
|
|||||||
|
|
||||||
def _invalidate_etud_formation_caches(context, etudid, formation_id):
|
def _invalidate_etud_formation_caches(context, etudid, formation_id):
|
||||||
"Invalide tous les semestres de cette formation où l'etudiant est inscrit..."
|
"Invalide tous les semestres de cette formation où l'etudiant est inscrit..."
|
||||||
r = SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"""SELECT sem.*
|
"""SELECT sem.*
|
||||||
FROM notes_formsemestre sem, notes_formsemestre_inscription i
|
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):
|
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"""
|
"""Ramene bout de HTML pour pouvoir supprimer une validation de cette UE"""
|
||||||
valids = SimpleDictFetch(
|
valids = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"""SELECT SFV.* FROM scolar_formsemestre_validation SFV
|
"""SELECT SFV.* FROM scolar_formsemestre_validation SFV
|
||||||
WHERE ue_id=%(ue_id)s AND etudid=%(etudid)s""",
|
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>'
|
'<div class="existing_valids"><span>Validations existantes pour cette UE:</span><ul>'
|
||||||
]
|
]
|
||||||
for valid in valids:
|
for valid in valids:
|
||||||
valid["event_date"] = DateISOtoDMY(valid["event_date"])
|
valid["event_date"] = ndb.DateISOtoDMY(valid["event_date"])
|
||||||
if valid["moy_ue"] != None:
|
if valid["moy_ue"] != None:
|
||||||
valid["m"] = ", moyenne %(moy_ue)g/20" % valid
|
valid["m"] = ", moyenne %(moy_ue)g/20" % valid
|
||||||
else:
|
else:
|
||||||
@ -1290,7 +1289,7 @@ def get_etud_ue_cap_html(context, etudid, formsemestre_id, ue_id, REQUEST=None):
|
|||||||
valid["s"] += " (<b>S%d</b>)" % valid["semestre_id"]
|
valid["s"] += " (<b>S%d</b>)" % valid["semestre_id"]
|
||||||
valid["ds"] = formsemestre_id
|
valid["ds"] = formsemestre_id
|
||||||
H.append(
|
H.append(
|
||||||
'<li>%(code)s%(m)s%(s)s, le %(event_date)s <a class="stdlink" href="etud_ue_suppress_validation?etudid=%(etudid)s&ue_id=%(ue_id)s&formsemestre_id=%(ds)s" title="supprime cette validation">effacer</a></li>'
|
'<li>%(code)s%(m)s%(s)s, le %(event_date)s <a class="stdlink" href="etud_ue_suppress_validation?etudid=%(etudid)s&ue_id=%(ue_id)s&formsemestre_id=%(ds)s" title="supprime cette validation">effacer</a></li>'
|
||||||
% valid
|
% valid
|
||||||
)
|
)
|
||||||
H.append("</ul></div>")
|
H.append("</ul></div>")
|
||||||
@ -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"""
|
"""Suppress a validation (ue_id, etudid) and redirect to formsemestre"""
|
||||||
log("etud_ue_suppress_validation( %s, %s, %s)" % (etudid, formsemestre_id, ue_id))
|
log("etud_ue_suppress_validation( %s, %s, %s)" % (etudid, formsemestre_id, ue_id))
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"DELETE FROM scolar_formsemestre_validation WHERE etudid=%(etudid)s and ue_id=%(ue_id)s",
|
"DELETE FROM scolar_formsemestre_validation WHERE etudid=%(etudid)s and ue_id=%(ue_id)s",
|
||||||
{"etudid": etudid, "ue_id": ue_id},
|
{"etudid": etudid, "ue_id": ue_id},
|
||||||
@ -1311,8 +1310,8 @@ def etud_ue_suppress_validation(context, etudid, formsemestre_id, ue_id, REQUEST
|
|||||||
_invalidate_etud_formation_caches(context, etudid, sem["formation_id"])
|
_invalidate_etud_formation_caches(context, etudid, sem["formation_id"])
|
||||||
|
|
||||||
return REQUEST.RESPONSE.redirect(
|
return REQUEST.RESPONSE.redirect(
|
||||||
context.ScoURL()
|
context.NotesURL()
|
||||||
+ "/Notes/formsemestre_validate_previous_ue?etudid=%s&formsemestre_id=%s"
|
+ "/formsemestre_validate_previous_ue?etudid=%s&formsemestre_id=%s"
|
||||||
% (etudid, formsemestre_id)
|
% (etudid, formsemestre_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1327,7 +1326,7 @@ def check_formation_ues(context, formation_id):
|
|||||||
ue_multiples = {} # { ue_id : [ liste des formsemestre ] }
|
ue_multiples = {} # { ue_id : [ liste des formsemestre ] }
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
# formsemestres utilisant cette ue ?
|
# formsemestres utilisant cette ue ?
|
||||||
sems = SimpleDictFetch(
|
sems = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"""SELECT DISTINCT sem.*
|
"""SELECT DISTINCT sem.*
|
||||||
FROM notes_formsemestre sem, notes_modules mod, notes_moduleimpl mi
|
FROM notes_formsemestre sem, notes_modules mod, notes_moduleimpl mi
|
||||||
|
@ -32,7 +32,7 @@ import operator
|
|||||||
import traceback
|
import traceback
|
||||||
from types import FloatType, IntType, LongType, StringType
|
from types import FloatType, IntType, LongType, StringType
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
|
|
||||||
|
|
||||||
|
183
sco_groups.py
183
sco_groups.py
@ -28,34 +28,46 @@
|
|||||||
"""Gestion des groupes, nouvelle mouture (juin/nov 2009)
|
"""Gestion des groupes, nouvelle mouture (juin/nov 2009)
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
|
|
||||||
* Groupes:
|
|
||||||
|
|
||||||
- changement de groupe d'un seul etudiant:
|
|
||||||
formChangeGroupe: pour l'instant supprimé, pas vraiment utile ?
|
|
||||||
doChangeGroupe
|
|
||||||
|
|
||||||
Optimisation possible:
|
Optimisation possible:
|
||||||
revoir do_evaluation_listeetuds_groups() pour extraire aussi les groupes (de chaque etudiant)
|
revoir do_evaluation_listeetuds_groups() pour extraire aussi les groupes (de chaque etudiant)
|
||||||
et eviter ainsi l'appel ulterieur à get_etud_groups() dans _make_table_notes
|
et éviter ainsi l'appel ulterieur à get_etud_groups() dans _make_table_notes
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
import time
|
||||||
import re, sets
|
import collections
|
||||||
|
import re
|
||||||
|
import sets
|
||||||
import operator
|
import operator
|
||||||
|
|
||||||
# XML generation package (apt-get install jaxml)
|
# XML generation package (apt-get install jaxml)
|
||||||
import jaxml
|
import jaxml
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from scolog import logdb
|
from scolog import logdb
|
||||||
from TrivialFormulator import TrivialFormulator, TF
|
from TrivialFormulator import TrivialFormulator, TF
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import scolars
|
import scolars
|
||||||
import sco_parcours_dut
|
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):
|
||||||
|
"Vrai si l'utilisateur peut changer les groupes dans ce semestre"
|
||||||
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
|
if sem["etat"] != "1":
|
||||||
|
return False # semestre verrouillé
|
||||||
|
authuser = REQUEST.AUTHENTICATED_USER
|
||||||
|
if authuser.has_permission(ScoEtudChangeGroups, context):
|
||||||
|
return True # admin, chef dept
|
||||||
|
uid = str(authuser)
|
||||||
|
if uid in sem["responsables"]:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def checkGroupName(
|
def checkGroupName(
|
||||||
@ -63,13 +75,14 @@ def checkGroupName(
|
|||||||
): # XXX unused: now allow any string as a group or partition name
|
): # XXX unused: now allow any string as a group or partition name
|
||||||
"Raises exception if not a valid group name"
|
"Raises exception if not a valid group name"
|
||||||
if groupName and (
|
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)
|
log("!!! invalid group name: " + groupName)
|
||||||
raise ValueError("invalid group name: " + groupName)
|
raise ValueError("invalid group name: " + groupName)
|
||||||
|
|
||||||
|
|
||||||
partitionEditor = EditableTable(
|
partitionEditor = ndb.EditableTable(
|
||||||
"partition",
|
"partition",
|
||||||
"partition_id",
|
"partition_id",
|
||||||
(
|
(
|
||||||
@ -83,7 +96,7 @@ partitionEditor = EditableTable(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
groupEditor = EditableTable(
|
groupEditor = ndb.EditableTable(
|
||||||
"group_descr", "group_id", ("group_id", "partition_id", "group_name")
|
"group_descr", "group_id", ("group_id", "partition_id", "group_name")
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -92,7 +105,7 @@ group_list = groupEditor.list
|
|||||||
|
|
||||||
def get_group(context, group_id):
|
def get_group(context, group_id):
|
||||||
"""Returns group object, with partition"""
|
"""Returns group object, with partition"""
|
||||||
r = SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT gd.*, p.* FROM group_descr gd, partition p WHERE gd.group_id=%(group_id)s AND p.partition_id = gd.partition_id",
|
"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},
|
{"group_id": group_id},
|
||||||
@ -107,15 +120,17 @@ def group_delete(context, group, force=False):
|
|||||||
# if not group['group_name'] and not force:
|
# if not group['group_name'] and not force:
|
||||||
# raise ValueError('cannot suppress this group')
|
# raise ValueError('cannot suppress this group')
|
||||||
# remove memberships:
|
# remove memberships:
|
||||||
SimpleQuery(
|
ndb.SimpleQuery(
|
||||||
context, "DELETE FROM group_membership WHERE group_id=%(group_id)s", group
|
context, "DELETE FROM group_membership WHERE group_id=%(group_id)s", group
|
||||||
)
|
)
|
||||||
# delete 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):
|
def get_partition(context, partition_id):
|
||||||
r = SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT p.* FROM partition p WHERE p.partition_id = %(partition_id)s",
|
"SELECT p.* FROM partition p WHERE p.partition_id = %(partition_id)s",
|
||||||
{"partition_id": partition_id},
|
{"partition_id": partition_id},
|
||||||
@ -127,7 +142,7 @@ def get_partition(context, partition_id):
|
|||||||
|
|
||||||
def get_partitions_list(context, formsemestre_id, with_default=True):
|
def get_partitions_list(context, formsemestre_id, with_default=True):
|
||||||
"""Liste des partitions pour ce semestre (list of dicts)"""
|
"""Liste des partitions pour ce semestre (list of dicts)"""
|
||||||
partitions = SimpleDictFetch(
|
partitions = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT * FROM partition WHERE formsemestre_id=%(formsemestre_id)s order by numero",
|
"SELECT * FROM partition WHERE formsemestre_id=%(formsemestre_id)s order by numero",
|
||||||
{"formsemestre_id": formsemestre_id},
|
{"formsemestre_id": formsemestre_id},
|
||||||
@ -141,7 +156,7 @@ def get_partitions_list(context, formsemestre_id, with_default=True):
|
|||||||
|
|
||||||
def get_default_partition(context, formsemestre_id):
|
def get_default_partition(context, formsemestre_id):
|
||||||
"""Get partition for 'all' students (this one always exists, with NULL name)"""
|
"""Get partition for 'all' students (this one always exists, with NULL name)"""
|
||||||
r = SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT * FROM partition WHERE formsemestre_id=%(formsemestre_id)s AND partition_name is NULL",
|
"SELECT * FROM partition WHERE formsemestre_id=%(formsemestre_id)s AND partition_name is NULL",
|
||||||
{"formsemestre_id": formsemestre_id},
|
{"formsemestre_id": formsemestre_id},
|
||||||
@ -169,7 +184,7 @@ def get_formsemestre_groups(context, formsemestre_id, with_default=False):
|
|||||||
def get_partition_groups(context, partition):
|
def get_partition_groups(context, partition):
|
||||||
"""List of groups in this partition (list of dicts).
|
"""List of groups in this partition (list of dicts).
|
||||||
Some groups may be empty."""
|
Some groups may be empty."""
|
||||||
return SimpleDictFetch(
|
return ndb.SimpleDictFetch(
|
||||||
context,
|
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",
|
"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,
|
partition,
|
||||||
@ -178,7 +193,7 @@ def get_partition_groups(context, partition):
|
|||||||
|
|
||||||
def get_default_group(context, formsemestre_id, fix_if_missing=False, REQUEST=None):
|
def get_default_group(context, formsemestre_id, fix_if_missing=False, REQUEST=None):
|
||||||
"""Returns group_id for default ('tous') group"""
|
"""Returns group_id for default ('tous') group"""
|
||||||
r = SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
context,
|
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",
|
"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},
|
{"formsemestre_id": formsemestre_id},
|
||||||
@ -210,7 +225,7 @@ def get_default_group(context, formsemestre_id, fix_if_missing=False, REQUEST=No
|
|||||||
|
|
||||||
def get_sem_groups(context, formsemestre_id):
|
def get_sem_groups(context, formsemestre_id):
|
||||||
"""Returns groups for this sem (in all partitions)."""
|
"""Returns groups for this sem (in all partitions)."""
|
||||||
return SimpleDictFetch(
|
return ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT gd.*, p.* FROM group_descr gd, partition p WHERE p.formsemestre_id=%(formsemestre_id)s AND p.partition_id = gd.partition_id",
|
"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},
|
{"formsemestre_id": formsemestre_id},
|
||||||
@ -226,14 +241,14 @@ def get_group_members(context, group_id, etat=None):
|
|||||||
if etat is not None:
|
if etat is not None:
|
||||||
req += " and ins.etat = %(etat)s"
|
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:
|
for etud in r:
|
||||||
scolars.format_etud_ident(etud)
|
scolars.format_etud_ident(etud)
|
||||||
|
|
||||||
r.sort(key=operator.itemgetter("nom_disp", "prenom")) # tri selon nom_usuel ou nom
|
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:
|
for x in r:
|
||||||
x["prenom"] = x["prenom"] or ""
|
x["prenom"] = x["prenom"] or ""
|
||||||
|
|
||||||
@ -287,7 +302,7 @@ def get_group_infos(context, group_id, etat=None): # was _getlisteetud
|
|||||||
else:
|
else:
|
||||||
t["etath"] = "(dem.)"
|
t["etath"] = "(dem.)"
|
||||||
nbdem += 1
|
nbdem += 1
|
||||||
elif t["etat"] == DEF:
|
elif t["etat"] == sco_codes_parcours.DEF:
|
||||||
t["etath"] = "Défaillant"
|
t["etath"] = "Défaillant"
|
||||||
else:
|
else:
|
||||||
t["etath"] = t["etat"]
|
t["etath"] = t["etat"]
|
||||||
@ -322,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"
|
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:
|
if exclude_default:
|
||||||
req += " and p.partition_name is not NULL"
|
req += " and p.partition_name is not NULL"
|
||||||
groups = SimpleDictFetch(
|
groups = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
req + " ORDER BY p.numero",
|
req + " ORDER BY p.numero",
|
||||||
{"etudid": etudid, "formsemestre_id": sem["formsemestre_id"]},
|
{"etudid": etudid, "formsemestre_id": sem["formsemestre_id"]},
|
||||||
@ -350,7 +365,7 @@ def formsemestre_get_etud_groupnames(context, formsemestre_id, attr="group_name"
|
|||||||
"""Recupere les groupes de tous les etudiants d'un semestre
|
"""Recupere les groupes de tous les etudiants d'un semestre
|
||||||
{ etudid : { partition_id : group_name }} (attr=group_name or group_id)
|
{ etudid : { partition_id : group_name }} (attr=group_name or group_id)
|
||||||
"""
|
"""
|
||||||
infos = SimpleDictFetch(
|
infos = ndb.SimpleDictFetch(
|
||||||
context,
|
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",
|
"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},
|
{"formsemestre_id": formsemestre_id},
|
||||||
@ -373,7 +388,7 @@ def etud_add_group_infos(context, etud, sem, sep=" "):
|
|||||||
etud["groupes"] = ""
|
etud["groupes"] = ""
|
||||||
return etud
|
return etud
|
||||||
|
|
||||||
infos = SimpleDictFetch(
|
infos = ndb.SimpleDictFetch(
|
||||||
context,
|
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",
|
"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"]},
|
{"etudid": etud["etudid"], "formsemestre_id": sem["formsemestre_id"]},
|
||||||
@ -400,7 +415,7 @@ def etud_add_group_infos(context, etud, sem, sep=" "):
|
|||||||
|
|
||||||
def get_etud_groups_in_partition(context, partition_id):
|
def get_etud_groups_in_partition(context, partition_id):
|
||||||
"""Returns { etudid : group }, with all students in this partition"""
|
"""Returns { etudid : group }, with all students in this partition"""
|
||||||
infos = SimpleDictFetch(
|
infos = ndb.SimpleDictFetch(
|
||||||
context,
|
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",
|
"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},
|
{"partition_id": partition_id},
|
||||||
@ -419,7 +434,7 @@ def formsemestre_partition_list(context, formsemestre_id, format="xml", REQUEST=
|
|||||||
# Ajoute les groupes
|
# Ajoute les groupes
|
||||||
for p in partitions:
|
for p in partitions:
|
||||||
p["group"] = get_partition_groups(context, p)
|
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
|
def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetGroupesTD
|
||||||
@ -440,8 +455,8 @@ def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetG
|
|||||||
) # > inscrdict
|
) # > inscrdict
|
||||||
etuds_set = set(nt.inscrdict)
|
etuds_set = set(nt.inscrdict)
|
||||||
# XML response:
|
# XML response:
|
||||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||||
doc = jaxml.XML_document(encoding=SCO_ENCODING)
|
doc = jaxml.XML_document(encoding=scu.SCO_ENCODING)
|
||||||
doc._text('<ajax-response><response type="object" id="MyUpdater">')
|
doc._text('<ajax-response><response type="object" id="MyUpdater">')
|
||||||
doc._push()
|
doc._push()
|
||||||
|
|
||||||
@ -458,7 +473,8 @@ def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetG
|
|||||||
doc._push()
|
doc._push()
|
||||||
doc.etud(
|
doc.etud(
|
||||||
etudid=e["etudid"],
|
etudid=e["etudid"],
|
||||||
sexe=scolars.format_sexe(etud["sexe"]),
|
civilite=etud["civilite_str"],
|
||||||
|
sexe=etud["civilite_str"], # compat
|
||||||
nom=scolars.format_nom(etud["nom"]),
|
nom=scolars.format_nom(etud["nom"]),
|
||||||
prenom=scolars.format_prenom(etud["prenom"]),
|
prenom=scolars.format_prenom(etud["prenom"]),
|
||||||
origin=comp_origin(etud, sem),
|
origin=comp_origin(etud, sem),
|
||||||
@ -482,7 +498,7 @@ def XMLgetGroupsInPartition(context, partition_id, REQUEST=None): # was XMLgetG
|
|||||||
doc._push()
|
doc._push()
|
||||||
doc.etud(
|
doc.etud(
|
||||||
etudid=etud["etudid"],
|
etudid=etud["etudid"],
|
||||||
sexe=scolars.format_sexe(etud["sexe"]),
|
sexe=etud["civilite_str"],
|
||||||
nom=scolars.format_nom(etud["nom"]),
|
nom=scolars.format_nom(etud["nom"]),
|
||||||
prenom=scolars.format_prenom(etud["prenom"]),
|
prenom=scolars.format_prenom(etud["prenom"]),
|
||||||
origin=comp_origin(etud, sem),
|
origin=comp_origin(etud, sem),
|
||||||
@ -523,10 +539,10 @@ def set_group(context, etudid, group_id):
|
|||||||
Warning: don't check if group_id exists (the caller should check).
|
Warning: don't check if group_id exists (the caller should check).
|
||||||
"""
|
"""
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
args = {"etudid": etudid, "group_id": group_id}
|
args = {"etudid": etudid, "group_id": group_id}
|
||||||
# déjà inscrit ?
|
# déjà inscrit ?
|
||||||
r = SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT * FROM group_membership gm WHERE etudid=%(etudid)s and group_id=%(group_id)s",
|
"SELECT * FROM group_membership gm WHERE etudid=%(etudid)s and group_id=%(group_id)s",
|
||||||
args,
|
args,
|
||||||
@ -535,7 +551,7 @@ def set_group(context, etudid, group_id):
|
|||||||
if len(r):
|
if len(r):
|
||||||
return False
|
return False
|
||||||
# inscrit
|
# inscrit
|
||||||
SimpleQuery(
|
ndb.SimpleQuery(
|
||||||
context,
|
context,
|
||||||
"INSERT INTO group_membership (etudid, group_id) VALUES (%(etudid)s, %(group_id)s)",
|
"INSERT INTO group_membership (etudid, group_id) VALUES (%(etudid)s, %(group_id)s)",
|
||||||
args,
|
args,
|
||||||
@ -562,7 +578,7 @@ def change_etud_group_in_partition(
|
|||||||
else:
|
else:
|
||||||
partition = get_partition(context, group["partition_id"])
|
partition = get_partition(context, group["partition_id"])
|
||||||
# 1- Supprime membership dans cette partition
|
# 1- Supprime membership dans cette partition
|
||||||
SimpleQuery(
|
ndb.SimpleQuery(
|
||||||
context,
|
context,
|
||||||
"""DELETE FROM group_membership WHERE group_membership_id IN
|
"""DELETE FROM group_membership WHERE group_membership_id IN
|
||||||
(SELECT gm.group_membership_id
|
(SELECT gm.group_membership_id
|
||||||
@ -606,7 +622,7 @@ def setGroups(
|
|||||||
"""
|
"""
|
||||||
partition = get_partition(context, partition_id)
|
partition = get_partition(context, partition_id)
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
if not context.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if not can_change_groups(context, REQUEST, formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
log("***setGroups: partition_id=%s" % partition_id)
|
log("***setGroups: partition_id=%s" % partition_id)
|
||||||
log("groupsLists=%s" % groupsLists)
|
log("groupsLists=%s" % groupsLists)
|
||||||
@ -644,10 +660,10 @@ def setGroups(
|
|||||||
)
|
)
|
||||||
# Retire les anciens membres:
|
# Retire les anciens membres:
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
for etudid in old_members_set:
|
for etudid in old_members_set:
|
||||||
log("removing %s from group %s" % (etudid, group_id))
|
log("removing %s from group %s" % (etudid, group_id))
|
||||||
SimpleQuery(
|
ndb.SimpleQuery(
|
||||||
context,
|
context,
|
||||||
"DELETE FROM group_membership WHERE etudid=%(etudid)s and group_id=%(group_id)s",
|
"DELETE FROM group_membership WHERE etudid=%(etudid)s and group_id=%(group_id)s",
|
||||||
{"etudid": etudid, "group_id": group_id},
|
{"etudid": etudid, "group_id": group_id},
|
||||||
@ -673,7 +689,7 @@ def setGroups(
|
|||||||
if not group_name:
|
if not group_name:
|
||||||
continue
|
continue
|
||||||
# ajax arguments are encoded in utf-8:
|
# 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)
|
group_id = createGroup(context, partition_id, group_name, REQUEST=REQUEST)
|
||||||
# Place dans ce groupe les etudiants indiqués:
|
# Place dans ce groupe les etudiants indiqués:
|
||||||
for etudid in fs[1:-1]:
|
for etudid in fs[1:-1]:
|
||||||
@ -681,7 +697,7 @@ def setGroups(
|
|||||||
context, etudid, group_id, partition, REQUEST=REQUEST
|
context, etudid, group_id, partition, REQUEST=REQUEST
|
||||||
)
|
)
|
||||||
|
|
||||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
||||||
return (
|
return (
|
||||||
'<?xml version="1.0" encoding="utf-8"?><response>Groupes enregistrés</response>'
|
'<?xml version="1.0" encoding="utf-8"?><response>Groupes enregistrés</response>'
|
||||||
)
|
)
|
||||||
@ -693,7 +709,7 @@ def createGroup(context, partition_id, group_name="", default=False, REQUEST=Non
|
|||||||
"""
|
"""
|
||||||
partition = get_partition(context, partition_id)
|
partition = get_partition(context, partition_id)
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
if REQUEST and not context.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if REQUEST and not can_change_groups(context, REQUEST, formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
#
|
#
|
||||||
if group_name:
|
if group_name:
|
||||||
@ -730,7 +746,7 @@ def suppressGroup(context, group_id, partition_id=None, REQUEST=None):
|
|||||||
else:
|
else:
|
||||||
partition_id = group["partition_id"]
|
partition_id = group["partition_id"]
|
||||||
partition = get_partition(context, partition_id)
|
partition = get_partition(context, partition_id)
|
||||||
if not context.Notes.can_change_groups(REQUEST, partition["formsemestre_id"]):
|
if not can_change_groups(context, REQUEST, partition["formsemestre_id"]):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
log(
|
log(
|
||||||
"suppressGroup: group_id=%s group_name=%s partition_name=%s"
|
"suppressGroup: group_id=%s group_name=%s partition_name=%s"
|
||||||
@ -749,7 +765,7 @@ def partition_create(
|
|||||||
redirect=1,
|
redirect=1,
|
||||||
):
|
):
|
||||||
"""Create a new partition"""
|
"""Create a new partition"""
|
||||||
if REQUEST and not context.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if REQUEST and not can_change_groups(context, REQUEST, formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
if partition_name:
|
if partition_name:
|
||||||
partition_name = partition_name.strip()
|
partition_name = partition_name.strip()
|
||||||
@ -783,9 +799,9 @@ def partition_create(
|
|||||||
def getArrowIconsTags(context, REQUEST):
|
def getArrowIconsTags(context, REQUEST):
|
||||||
"""returns html tags for arrows"""
|
"""returns html tags for arrows"""
|
||||||
#
|
#
|
||||||
arrow_up = icontag("arrow_up", title="remonter")
|
arrow_up = scu.icontag("arrow_up", title="remonter")
|
||||||
arrow_down = icontag("arrow_down", title="descendre")
|
arrow_down = scu.icontag("arrow_down", title="descendre")
|
||||||
arrow_none = icontag("arrow_none", title="")
|
arrow_none = scu.icontag("arrow_none", title="")
|
||||||
|
|
||||||
return arrow_up, arrow_down, arrow_none
|
return arrow_up, arrow_down, arrow_none
|
||||||
|
|
||||||
@ -793,11 +809,11 @@ def getArrowIconsTags(context, REQUEST):
|
|||||||
def editPartitionForm(context, formsemestre_id=None, REQUEST=None):
|
def editPartitionForm(context, formsemestre_id=None, REQUEST=None):
|
||||||
"""Form to create/suppress partitions"""
|
"""Form to create/suppress partitions"""
|
||||||
# ad-hoc form
|
# ad-hoc form
|
||||||
if not context.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if not can_change_groups(context, REQUEST, formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
partitions = get_partitions_list(context, formsemestre_id)
|
partitions = get_partitions_list(context, formsemestre_id)
|
||||||
arrow_up, arrow_down, arrow_none = getArrowIconsTags(context, REQUEST)
|
arrow_up, arrow_down, arrow_none = getArrowIconsTags(context, REQUEST)
|
||||||
suppricon = icontag(
|
suppricon = scu.icontag(
|
||||||
"delete_small_img", border="0", alt="supprimer", title="Supprimer"
|
"delete_small_img", border="0", alt="supprimer", title="Supprimer"
|
||||||
)
|
)
|
||||||
#
|
#
|
||||||
@ -805,7 +821,7 @@ def editPartitionForm(context, formsemestre_id=None, REQUEST=None):
|
|||||||
context.sco_header(
|
context.sco_header(
|
||||||
REQUEST, page_title="Partitions...", javascripts=["js/editPartitionForm.js"]
|
REQUEST, page_title="Partitions...", javascripts=["js/editPartitionForm.js"]
|
||||||
),
|
),
|
||||||
"""<script type="text/javascript">
|
r"""<script type="text/javascript">
|
||||||
function checkname() {
|
function checkname() {
|
||||||
var val = document.editpart.partition_name.value.replace(/^\s+/, "").replace(/\s+$/, "");
|
var val = document.editpart.partition_name.value.replace(/^\s+/, "").replace(/\s+$/, "");
|
||||||
if (val.length > 0) {
|
if (val.length > 0) {
|
||||||
@ -816,7 +832,7 @@ def editPartitionForm(context, formsemestre_id=None, REQUEST=None):
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
""",
|
""",
|
||||||
"""<h2>Partitions du semestre</h2>
|
r"""<h2>Partitions du semestre</h2>
|
||||||
<form name="editpart" id="editpart" method="POST" action="partition_create">
|
<form name="editpart" id="editpart" method="POST" action="partition_create">
|
||||||
<div id="epmsg"></div>
|
<div id="epmsg"></div>
|
||||||
<table><tr class="eptit"><th></th><th></th><th></th><th>Partition</th><th>Groupes</th><th></th><th></th><th></th></tr>
|
<table><tr class="eptit"><th></th><th></th><th></th><th>Partition</th><th>Groupes</th><th></th><th></th><th></th></tr>
|
||||||
@ -831,13 +847,13 @@ def editPartitionForm(context, formsemestre_id=None, REQUEST=None):
|
|||||||
)
|
)
|
||||||
if i != 0:
|
if i != 0:
|
||||||
H.append(
|
H.append(
|
||||||
'<a href="partition_move?partition_id=%s&after=0">%s</a>'
|
'<a href="partition_move?partition_id=%s&after=0">%s</a>'
|
||||||
% (p["partition_id"], arrow_up)
|
% (p["partition_id"], arrow_up)
|
||||||
)
|
)
|
||||||
H.append('</td><td class="epnav">')
|
H.append('</td><td class="epnav">')
|
||||||
if i < len(partitions) - 2:
|
if i < len(partitions) - 2:
|
||||||
H.append(
|
H.append(
|
||||||
'<a href="partition_move?partition_id=%s&after=1">%s</a>'
|
'<a href="partition_move?partition_id=%s&after=1">%s</a>'
|
||||||
% (p["partition_id"], arrow_down)
|
% (p["partition_id"], arrow_down)
|
||||||
)
|
)
|
||||||
i += 1
|
i += 1
|
||||||
@ -920,7 +936,7 @@ def partition_set_attr(context, partition_id, attr, value, REQUEST=None):
|
|||||||
|
|
||||||
partition = get_partition(context, partition_id)
|
partition = get_partition(context, partition_id)
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
if not context.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if not can_change_groups(context, REQUEST, formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
|
|
||||||
log("partition_set_attr(%s, %s, %s)" % (partition_id, attr, value))
|
log("partition_set_attr(%s, %s, %s)" % (partition_id, attr, value))
|
||||||
@ -943,7 +959,7 @@ def partition_delete(
|
|||||||
default partition cannot be suppressed (unless force)"""
|
default partition cannot be suppressed (unless force)"""
|
||||||
partition = get_partition(context, partition_id)
|
partition = get_partition(context, partition_id)
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
if not context.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if not can_change_groups(context, REQUEST, formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
|
|
||||||
if not partition["partition_name"] and not force:
|
if not partition["partition_name"] and not force:
|
||||||
@ -986,7 +1002,7 @@ def partition_move(context, partition_id, after=0, REQUEST=None, redirect=1):
|
|||||||
"""Move before/after previous one (decrement/increment numero)"""
|
"""Move before/after previous one (decrement/increment numero)"""
|
||||||
partition = get_partition(context, partition_id)
|
partition = get_partition(context, partition_id)
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
if not context.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if not can_change_groups(context, REQUEST, formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
#
|
#
|
||||||
redirect = int(redirect)
|
redirect = int(redirect)
|
||||||
@ -1021,7 +1037,7 @@ def partition_rename(context, partition_id, REQUEST=None):
|
|||||||
"""Form to rename a partition"""
|
"""Form to rename a partition"""
|
||||||
partition = get_partition(context, partition_id)
|
partition = get_partition(context, partition_id)
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
if not context.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if not can_change_groups(context, REQUEST, formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
H = ["<h2>Renommer une partition</h2>"]
|
H = ["<h2>Renommer une partition</h2>"]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
@ -1072,7 +1088,7 @@ def partition_set_name(context, partition_id, partition_name, REQUEST=None, redi
|
|||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
|
|
||||||
# check unicity
|
# check unicity
|
||||||
r = SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT p.* FROM partition p WHERE p.partition_name = %(partition_name)s AND formsemestre_id = %(formsemestre_id)s",
|
"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},
|
{"partition_name": partition_name, "formsemestre_id": formsemestre_id},
|
||||||
@ -1082,7 +1098,7 @@ def partition_set_name(context, partition_id, partition_name, REQUEST=None, redi
|
|||||||
"Partition %s déjà existante dans ce semestre !" % partition_name
|
"Partition %s déjà existante dans ce semestre !" % partition_name
|
||||||
)
|
)
|
||||||
|
|
||||||
if not context.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if not can_change_groups(context, REQUEST, formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
redirect = int(redirect)
|
redirect = int(redirect)
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
@ -1107,7 +1123,7 @@ def group_set_name(context, group_id, group_name, REQUEST=None, redirect=1):
|
|||||||
if group["group_name"] is None:
|
if group["group_name"] is None:
|
||||||
raise ValueError("can't set a name to default group")
|
raise ValueError("can't set a name to default group")
|
||||||
formsemestre_id = group["formsemestre_id"]
|
formsemestre_id = group["formsemestre_id"]
|
||||||
if not context.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if not can_change_groups(context, REQUEST, formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
redirect = int(redirect)
|
redirect = int(redirect)
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
@ -1124,7 +1140,7 @@ def group_rename(context, group_id, REQUEST=None):
|
|||||||
"""Form to rename a group"""
|
"""Form to rename a group"""
|
||||||
group = get_group(context, group_id)
|
group = get_group(context, group_id)
|
||||||
formsemestre_id = group["formsemestre_id"]
|
formsemestre_id = group["formsemestre_id"]
|
||||||
if not context.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if not can_change_groups(context, REQUEST, formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
H = ["<h2>Renommer un groupe de %s</h2>" % group["partition_name"]]
|
H = ["<h2>Renommer un groupe de %s</h2>" % group["partition_name"]]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
@ -1170,7 +1186,9 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
|
|||||||
"""
|
"""
|
||||||
partition = get_partition(context, partition_id)
|
partition = get_partition(context, partition_id)
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
if not context.Notes.can_change_groups(REQUEST, 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 !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
|
||||||
|
|
||||||
@ -1210,7 +1228,7 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
|
|||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + "\n" + tf[1] + context.sco_footer(REQUEST)
|
return "\n".join(H) + "\n" + tf[1] + context.sco_footer(REQUEST)
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return REQUEST.RESPONSE.redirect(REQUEST.URL1)
|
return REQUEST.RESPONSE.redirect(dest_url)
|
||||||
else:
|
else:
|
||||||
# form submission
|
# form submission
|
||||||
log(
|
log(
|
||||||
@ -1238,34 +1256,33 @@ def groups_auto_repartition(context, partition_id=None, REQUEST=None):
|
|||||||
context.Notes, formsemestre_id
|
context.Notes, formsemestre_id
|
||||||
) # > identdict
|
) # > identdict
|
||||||
identdict = nt.identdict
|
identdict = nt.identdict
|
||||||
# build: { sexe : liste etudids trie par niveau croissant }
|
# build: { civilite : liste etudids trie par niveau croissant }
|
||||||
sexes = sets.Set([x["sexe"] for x in identdict.values()])
|
civilites = sets.Set([x["civilite"] for x in identdict.values()])
|
||||||
listes = {}
|
listes = {}
|
||||||
for sexe in sexes:
|
for civilite in civilites:
|
||||||
listes[sexe] = [
|
listes[civilite] = [
|
||||||
(get_prev_moy(context.Notes, x["etudid"], formsemestre_id), x["etudid"])
|
(get_prev_moy(context.Notes, x["etudid"], formsemestre_id), x["etudid"])
|
||||||
for x in identdict.values()
|
for x in identdict.values()
|
||||||
if x["sexe"] == sexe
|
if x["civilite"] == civilite
|
||||||
]
|
]
|
||||||
listes[sexe].sort()
|
listes[civilite].sort()
|
||||||
log("listes[%s] = %s" % (sexe, listes[sexe]))
|
log("listes[%s] = %s" % (civilite, listes[civilite]))
|
||||||
# affect aux groupes:
|
# affect aux groupes:
|
||||||
n = len(identdict)
|
n = len(identdict)
|
||||||
igroup = 0
|
igroup = 0
|
||||||
nbgroups = len(group_ids)
|
nbgroups = len(group_ids)
|
||||||
while n > 0:
|
while n > 0:
|
||||||
for sexe in sexes:
|
for civilite in civilites:
|
||||||
if len(listes[sexe]):
|
if len(listes[civilite]):
|
||||||
n -= 1
|
n -= 1
|
||||||
etudid = listes[sexe].pop()[1]
|
etudid = listes[civilite].pop()[1]
|
||||||
group_id = group_ids[igroup]
|
group_id = group_ids[igroup]
|
||||||
igroup = (igroup + 1) % nbgroups
|
igroup = (igroup + 1) % nbgroups
|
||||||
change_etud_group_in_partition(
|
change_etud_group_in_partition(
|
||||||
context, etudid, group_id, partition, REQUEST=REQUEST
|
context, etudid, group_id, partition, REQUEST=REQUEST
|
||||||
)
|
)
|
||||||
log("%s in group %s" % (etudid, group_id))
|
log("%s in group %s" % (etudid, group_id))
|
||||||
# envoie sur page edition groupes
|
return REQUEST.RESPONSE.redirect(dest_url)
|
||||||
return REQUEST.RESPONSE.redirect("affectGroups?partition_id=%s" % partition_id)
|
|
||||||
|
|
||||||
|
|
||||||
def get_prev_moy(context, etudid, formsemestre_id):
|
def get_prev_moy(context, etudid, formsemestre_id):
|
||||||
@ -1367,7 +1384,7 @@ def do_evaluation_listeetuds_groups(
|
|||||||
req += " and Isem.etat='I'"
|
req += " and Isem.etat='I'"
|
||||||
req += r
|
req += r
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(req, {"evaluation_id": evaluation_id})
|
cursor.execute(req, {"evaluation_id": evaluation_id})
|
||||||
# log('listeetuds_groups: getallstudents=%s groups=%s' % (getallstudents,groups))
|
# log('listeetuds_groups: getallstudents=%s groups=%s' % (getallstudents,groups))
|
||||||
# log('req=%s' % (req % { 'evaluation_id' : "'"+evaluation_id+"'" }))
|
# log('req=%s' % (req % { 'evaluation_id' : "'"+evaluation_id+"'" }))
|
||||||
@ -1386,7 +1403,7 @@ def do_evaluation_listegroupes(context, evaluation_id, include_default=False):
|
|||||||
else:
|
else:
|
||||||
c = " AND p.partition_name is not NULL"
|
c = " AND p.partition_name is not NULL"
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
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"
|
"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,
|
+ c,
|
||||||
@ -1399,7 +1416,7 @@ def do_evaluation_listegroupes(context, evaluation_id, include_default=False):
|
|||||||
|
|
||||||
def listgroups(context, group_ids):
|
def listgroups(context, group_ids):
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
groups = []
|
groups = []
|
||||||
for group_id in group_ids:
|
for group_id in group_ids:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
@ -1477,7 +1494,7 @@ def form_group_choice(
|
|||||||
|
|
||||||
def make_query_groups(group_ids):
|
def make_query_groups(group_ids):
|
||||||
if group_ids:
|
if group_ids:
|
||||||
return "&".join(["group_ids%3Alist=" + group_id for group_id in group_ids])
|
return "&".join(["group_ids%3Alist=" + group_id for group_id in group_ids])
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
@ -30,11 +30,12 @@
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils as scu
|
||||||
from notesdb import *
|
import notesdb as ndb
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_groups
|
import sco_groups
|
||||||
|
from sco_exceptions import AccessDenied
|
||||||
|
|
||||||
|
|
||||||
def affectGroups(context, partition_id, REQUEST=None):
|
def affectGroups(context, partition_id, REQUEST=None):
|
||||||
@ -44,7 +45,7 @@ def affectGroups(context, partition_id, REQUEST=None):
|
|||||||
# Ported from DTML and adapted to new group management (nov 2009)
|
# Ported from DTML and adapted to new group management (nov 2009)
|
||||||
partition = sco_groups.get_partition(context, partition_id)
|
partition = sco_groups.get_partition(context, partition_id)
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
if not context.Notes.can_change_groups(REQUEST, formsemestre_id):
|
if not sco_groups.can_change_groups(context, REQUEST, formsemestre_id):
|
||||||
raise AccessDenied("vous n'avez pas la permission d'effectuer cette opération")
|
raise AccessDenied("vous n'avez pas la permission d'effectuer cette opération")
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user