Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
2bf4449dce | |||
bdc0ad488a | |||
225c97b6dc | |||
aba522a60d | |||
f89fa0bf68 | |||
5f425da6c0 | |||
19913ce89a | |||
31c40b6492 | |||
415810496f |
@ -93,7 +93,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(SCO_SRC_DIR + "/" + FORMAT_FILE):
|
||||||
l = l.strip()
|
l = l.strip()
|
||||||
if l and l[0] != "#":
|
if l and l[0] != "#":
|
||||||
fs = l.split(";")
|
fs = l.split(";")
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "7.19a"
|
SCOVERSION = "8.00a"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
184
ZAbsences.py
@ -45,19 +45,17 @@ L'API de plus bas niveau est en gros:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import urllib
|
import urllib
|
||||||
import datetime
|
|
||||||
import jaxml
|
|
||||||
|
|
||||||
# ---------------
|
|
||||||
from sco_zope import *
|
from sco_zope import *
|
||||||
|
|
||||||
# ---------------
|
# ---------------
|
||||||
import sco_utils as scu
|
|
||||||
import notesdb
|
from notesdb import *
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from scolog import logdb
|
from scolog import logdb
|
||||||
from sco_permissions import ScoAbsAddBillet, ScoAbsChange, ScoView
|
from sco_utils import *
|
||||||
from sco_exceptions import ScoValueError, ScoInvalidDateError
|
|
||||||
|
# import notes_users
|
||||||
from TrivialFormulator import TrivialFormulator, TF
|
from TrivialFormulator import TrivialFormulator, TF
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
import scolars
|
import scolars
|
||||||
@ -203,7 +201,7 @@ class ddmmyyyy:
|
|||||||
return self.prev(self.weekday)
|
return self.prev(self.weekday)
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
"""return a negative integer if self < other,
|
"""return a negative integer if self < other,
|
||||||
zero if self == other, a positive integer if self > other"""
|
zero if self == other, a positive integer if self > other"""
|
||||||
return int(self.time - other.time)
|
return int(self.time - other.time)
|
||||||
|
|
||||||
@ -358,7 +356,7 @@ class ZAbsences(
|
|||||||
estjust = _toboolean(estjust)
|
estjust = _toboolean(estjust)
|
||||||
matin = _toboolean(matin)
|
matin = _toboolean(matin)
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"insert into absences (etudid,jour,estabs,estjust,matin,description, moduleimpl_id) values (%(etudid)s, %(jour)s, TRUE, %(estjust)s, %(matin)s, %(description)s, %(moduleimpl_id)s )",
|
"insert into absences (etudid,jour,estabs,estjust,matin,description, moduleimpl_id) values (%(etudid)s, %(jour)s, TRUE, %(estjust)s, %(matin)s, %(description)s, %(moduleimpl_id)s )",
|
||||||
vars(),
|
vars(),
|
||||||
@ -382,7 +380,7 @@ class ZAbsences(
|
|||||||
raise ScoValueError("date justificatif trop loin dans le futur !")
|
raise ScoValueError("date justificatif trop loin dans le futur !")
|
||||||
matin = _toboolean(matin)
|
matin = _toboolean(matin)
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"insert into absences (etudid,jour,estabs,estjust,matin, description) values (%(etudid)s,%(jour)s, FALSE, TRUE, %(matin)s, %(description)s )",
|
"insert into absences (etudid,jour,estabs,estjust,matin, description) values (%(etudid)s,%(jour)s, FALSE, TRUE, %(matin)s, %(description)s )",
|
||||||
vars(),
|
vars(),
|
||||||
@ -404,7 +402,7 @@ class ZAbsences(
|
|||||||
# unpublished
|
# unpublished
|
||||||
matin = _toboolean(matin)
|
matin = _toboolean(matin)
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
req = "delete from absences where jour=%(jour)s and matin=%(matin)s and etudid=%(etudid)s and estabs"
|
req = "delete from absences where jour=%(jour)s and matin=%(matin)s and etudid=%(etudid)s and estabs"
|
||||||
if moduleimpl_id:
|
if moduleimpl_id:
|
||||||
req += " and moduleimpl_id=%(moduleimpl_id)s"
|
req += " and moduleimpl_id=%(moduleimpl_id)s"
|
||||||
@ -425,7 +423,7 @@ class ZAbsences(
|
|||||||
# unpublished
|
# unpublished
|
||||||
matin = _toboolean(matin)
|
matin = _toboolean(matin)
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"delete from absences where jour=%(jour)s and matin=%(matin)s and etudid=%(etudid)s and ESTJUST AND NOT ESTABS",
|
"delete from absences where jour=%(jour)s and matin=%(matin)s and etudid=%(etudid)s and ESTJUST AND NOT ESTABS",
|
||||||
vars(),
|
vars(),
|
||||||
@ -452,7 +450,7 @@ class ZAbsences(
|
|||||||
# """
|
# """
|
||||||
# # unpublished
|
# # unpublished
|
||||||
# cnx = self.GetDBConnexion()
|
# cnx = self.GetDBConnexion()
|
||||||
# cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
# cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
# # supr les absences non justifiees
|
# # supr les absences non justifiees
|
||||||
# cursor.execute("delete from absences where etudid=%(etudid)s and (not estjust) and moduleimpl_id=(moduleimpl_id)s and jour BETWEEN %(datedebut)s AND %(datefin)s",
|
# cursor.execute("delete from absences where etudid=%(etudid)s and (not estjust) and moduleimpl_id=(moduleimpl_id)s and jour BETWEEN %(datedebut)s AND %(datefin)s",
|
||||||
# vars() )
|
# vars() )
|
||||||
@ -489,7 +487,7 @@ class ZAbsences(
|
|||||||
self._AnnuleAbsence(etudid, jour, matin, moduleimpl_id, REQUEST)
|
self._AnnuleAbsence(etudid, jour, matin, moduleimpl_id, REQUEST)
|
||||||
return
|
return
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
# supr les absences non justifiees
|
# supr les absences non justifiees
|
||||||
for date in dates:
|
for date in dates:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
@ -536,7 +534,7 @@ class ZAbsences(
|
|||||||
else:
|
else:
|
||||||
modul = ""
|
modul = ""
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""SELECT COUNT(*) AS NbAbs FROM (
|
"""SELECT COUNT(*) AS NbAbs FROM (
|
||||||
SELECT DISTINCT A.JOUR, A.MATIN
|
SELECT DISTINCT A.JOUR, A.MATIN
|
||||||
@ -567,7 +565,7 @@ class ZAbsences(
|
|||||||
else:
|
else:
|
||||||
modul = ""
|
modul = ""
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""SELECT COUNT(*) AS NbAbsJust FROM (
|
"""SELECT COUNT(*) AS NbAbsJust FROM (
|
||||||
SELECT DISTINCT A.JOUR, A.MATIN
|
SELECT DISTINCT A.JOUR, A.MATIN
|
||||||
@ -590,7 +588,7 @@ class ZAbsences(
|
|||||||
def _ListeAbsDate(self, etudid, beg_date, end_date):
|
def _ListeAbsDate(self, etudid, beg_date, end_date):
|
||||||
# Liste des absences et justifs entre deux dates
|
# Liste des absences et justifs entre deux dates
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""SELECT jour, matin, estabs, estjust, description FROM ABSENCES A
|
"""SELECT jour, matin, estabs, estjust, description FROM ABSENCES A
|
||||||
WHERE A.ETUDID = %(etudid)s
|
WHERE A.ETUDID = %(etudid)s
|
||||||
@ -600,6 +598,7 @@ class ZAbsences(
|
|||||||
vars(),
|
vars(),
|
||||||
)
|
)
|
||||||
Abs = cursor.dictfetchall()
|
Abs = cursor.dictfetchall()
|
||||||
|
# log('ListeAbsDate: abs=%s' % Abs)
|
||||||
# remove duplicates
|
# remove duplicates
|
||||||
A = {} # { (jour, matin) : abs }
|
A = {} # { (jour, matin) : abs }
|
||||||
for a in Abs:
|
for a in Abs:
|
||||||
@ -626,6 +625,7 @@ class ZAbsences(
|
|||||||
# sort
|
# sort
|
||||||
R = A.values()
|
R = A.values()
|
||||||
R.sort(key=lambda x: (x["begin"]))
|
R.sort(key=lambda x: (x["begin"]))
|
||||||
|
# log('R=%s' % R)
|
||||||
return R
|
return R
|
||||||
|
|
||||||
security.declareProtected(ScoView, "ListeAbsJust")
|
security.declareProtected(ScoView, "ListeAbsJust")
|
||||||
@ -633,7 +633,7 @@ class ZAbsences(
|
|||||||
def ListeAbsJust(self, etudid, datedebut):
|
def ListeAbsJust(self, etudid, datedebut):
|
||||||
"Liste des absences justifiees (par ordre chronologique)"
|
"Liste des absences justifiees (par ordre chronologique)"
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""SELECT DISTINCT A.ETUDID, A.JOUR, A.MATIN FROM ABSENCES A, ABSENCES B
|
"""SELECT DISTINCT A.ETUDID, A.JOUR, A.MATIN FROM ABSENCES A, ABSENCES B
|
||||||
WHERE A.ETUDID = %(etudid)s
|
WHERE A.ETUDID = %(etudid)s
|
||||||
@ -654,7 +654,7 @@ class ZAbsences(
|
|||||||
def ListeAbsNonJust(self, etudid, datedebut):
|
def ListeAbsNonJust(self, etudid, datedebut):
|
||||||
"Liste des absences NON justifiees (par ordre chronologique)"
|
"Liste des absences NON justifiees (par ordre chronologique)"
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""SELECT ETUDID, JOUR, MATIN FROM ABSENCES A
|
"""SELECT ETUDID, JOUR, MATIN FROM ABSENCES A
|
||||||
WHERE A.ETUDID = %(etudid)s
|
WHERE A.ETUDID = %(etudid)s
|
||||||
@ -680,7 +680,7 @@ class ZAbsences(
|
|||||||
Si only_no_abs: seulement les justificatifs correspondant aux jours sans absences relevées.
|
Si only_no_abs: seulement les justificatifs correspondant aux jours sans absences relevées.
|
||||||
"""
|
"""
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
req = """SELECT DISTINCT ETUDID, JOUR, MATIN FROM ABSENCES A
|
req = """SELECT DISTINCT ETUDID, JOUR, MATIN FROM ABSENCES A
|
||||||
WHERE A.ETUDID = %(etudid)s
|
WHERE A.ETUDID = %(etudid)s
|
||||||
AND A.ESTJUST
|
AND A.ESTJUST
|
||||||
@ -704,7 +704,7 @@ class ZAbsences(
|
|||||||
"Description associee a l'absence"
|
"Description associee a l'absence"
|
||||||
if not cursor:
|
if not cursor:
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
a = a.copy()
|
a = a.copy()
|
||||||
# a['jour'] = a['jour'].date()
|
# a['jour'] = a['jour'].date()
|
||||||
if a["matin"]: # devrait etre booleen... :-(
|
if a["matin"]: # devrait etre booleen... :-(
|
||||||
@ -732,6 +732,7 @@ class ZAbsences(
|
|||||||
|
|
||||||
if desc:
|
if desc:
|
||||||
return "(%s) %s" % (desc, module)
|
return "(%s) %s" % (desc, module)
|
||||||
|
return desc
|
||||||
if module:
|
if module:
|
||||||
return module
|
return module
|
||||||
return ""
|
return ""
|
||||||
@ -744,7 +745,7 @@ class ZAbsences(
|
|||||||
is_just: idem
|
is_just: idem
|
||||||
"""
|
"""
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
req = """SELECT DISTINCT etudid, jour, matin FROM ABSENCES A
|
req = """SELECT DISTINCT etudid, jour, matin FROM ABSENCES A
|
||||||
WHERE A.jour = %(date)s
|
WHERE A.jour = %(date)s
|
||||||
"""
|
"""
|
||||||
@ -768,7 +769,7 @@ class ZAbsences(
|
|||||||
def ListeAbsNonJustJour(self, date, am=True, pm=True):
|
def ListeAbsNonJustJour(self, date, am=True, pm=True):
|
||||||
"Liste des absences non justifiees ce jour"
|
"Liste des absences non justifiees ce jour"
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
reqa = ""
|
reqa = ""
|
||||||
if not am:
|
if not am:
|
||||||
reqa += " AND NOT matin "
|
reqa += " AND NOT matin "
|
||||||
@ -848,7 +849,7 @@ class ZAbsences(
|
|||||||
def CalSelectWeek(self, year=None, REQUEST=None):
|
def CalSelectWeek(self, year=None, REQUEST=None):
|
||||||
"display calendar allowing week selection"
|
"display calendar allowing week selection"
|
||||||
if not year:
|
if not year:
|
||||||
year = scu.AnneeScolaire(REQUEST)
|
year = AnneeScolaire(REQUEST)
|
||||||
sems = sco_formsemestre.do_formsemestre_list(self)
|
sems = sco_formsemestre.do_formsemestre_list(self)
|
||||||
if not sems:
|
if not sems:
|
||||||
js = ""
|
js = ""
|
||||||
@ -885,9 +886,10 @@ class ZAbsences(
|
|||||||
security.declareProtected(ScoView, "ListMondays")
|
security.declareProtected(ScoView, "ListMondays")
|
||||||
|
|
||||||
def ListMondays(self, year=None, REQUEST=None):
|
def ListMondays(self, year=None, REQUEST=None):
|
||||||
"""return list of mondays (ISO dates), from september to june"""
|
"""return list of mondays (ISO dates), from september to june
|
||||||
|
"""
|
||||||
if not year:
|
if not year:
|
||||||
year = scu.AnneeScolaire(REQUEST)
|
year = AnneeScolaire(REQUEST)
|
||||||
d = ddmmyyyy("1/9/%d" % year, work_saturday=self.is_work_saturday())
|
d = ddmmyyyy("1/9/%d" % year, work_saturday=self.is_work_saturday())
|
||||||
while d.weekday != 0:
|
while d.weekday != 0:
|
||||||
d = d.next()
|
d = d.next()
|
||||||
@ -932,7 +934,7 @@ class ZAbsences(
|
|||||||
):
|
):
|
||||||
"Saisie hebdomadaire des absences"
|
"Saisie hebdomadaire des absences"
|
||||||
if not moduleimpl_id:
|
if not moduleimpl_id:
|
||||||
moduleimpl_id = None
|
moduleimp_id = None
|
||||||
|
|
||||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||||
self, group_ids, REQUEST=REQUEST
|
self, group_ids, REQUEST=REQUEST
|
||||||
@ -961,10 +963,10 @@ class ZAbsences(
|
|||||||
)[0]
|
)[0]
|
||||||
|
|
||||||
# calcule dates jours de cette semaine
|
# calcule dates jours de cette semaine
|
||||||
# liste de dates iso "yyyy-mm-dd"
|
datessem = [DateDMYtoISO(datelundi)]
|
||||||
datessem = [notesdb.DateDMYtoISO(datelundi)]
|
for jour in self.day_names()[1:]:
|
||||||
for _ in self.day_names()[1:]:
|
|
||||||
datessem.append(self.NextISODay(datessem[-1]))
|
datessem.append(self.NextISODay(datessem[-1]))
|
||||||
|
|
||||||
#
|
#
|
||||||
if groups_infos.tous_les_etuds_du_sem:
|
if groups_infos.tous_les_etuds_du_sem:
|
||||||
gr_tit = "en"
|
gr_tit = "en"
|
||||||
@ -1042,7 +1044,9 @@ class ZAbsences(
|
|||||||
% {"menu_module": menu_module, "url": base_url, "sel": sel}
|
% {"menu_module": menu_module, "url": base_url, "sel": sel}
|
||||||
)
|
)
|
||||||
|
|
||||||
H += self._gen_form_saisie_groupe(etuds, datessem, destination, moduleimpl_id)
|
H += self._gen_form_saisie_groupe(
|
||||||
|
etuds, self.day_names(), datessem, destination, None, moduleimpl_id
|
||||||
|
)
|
||||||
|
|
||||||
H.append(self.sco_footer(REQUEST))
|
H.append(self.sco_footer(REQUEST))
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
@ -1059,7 +1063,8 @@ class ZAbsences(
|
|||||||
moduleimpl_id=None,
|
moduleimpl_id=None,
|
||||||
REQUEST=None,
|
REQUEST=None,
|
||||||
):
|
):
|
||||||
"""Saisie des absences sur une journée sur un semestre (ou intervalle de dates) entier"""
|
"""Saisie des absences sur une journée sur un semestre (ou intervalle de dates) entier
|
||||||
|
"""
|
||||||
# log('SignaleAbsenceGrSemestre: moduleimpl_id=%s destination=%s' % (moduleimpl_id, destination))
|
# log('SignaleAbsenceGrSemestre: moduleimpl_id=%s destination=%s' % (moduleimpl_id, destination))
|
||||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||||
self, group_ids, REQUEST=REQUEST
|
self, group_ids, REQUEST=REQUEST
|
||||||
@ -1078,12 +1083,15 @@ class ZAbsences(
|
|||||||
]
|
]
|
||||||
|
|
||||||
if not moduleimpl_id:
|
if not moduleimpl_id:
|
||||||
moduleimpl_id = None
|
moduleimp_id = None
|
||||||
base_url_noweeks = "SignaleAbsenceGrSemestre?datedebut=%s&datefin=%s&%s&destination=%s" % (
|
base_url_noweeks = (
|
||||||
datedebut,
|
"SignaleAbsenceGrSemestre?datedebut=%s&datefin=%s&%s&destination=%s"
|
||||||
datefin,
|
% (
|
||||||
groups_infos.groups_query_args,
|
datedebut,
|
||||||
urllib.quote(destination),
|
datefin,
|
||||||
|
groups_infos.groups_query_args,
|
||||||
|
urllib.quote(destination),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
base_url = (
|
base_url = (
|
||||||
base_url_noweeks + "&nbweeks=%s" % nbweeks
|
base_url_noweeks + "&nbweeks=%s" % nbweeks
|
||||||
@ -1131,6 +1139,7 @@ class ZAbsences(
|
|||||||
if moduleimpl_id:
|
if moduleimpl_id:
|
||||||
url_link_semaines += "&moduleimpl_id=" + moduleimpl_id
|
url_link_semaines += "&moduleimpl_id=" + moduleimpl_id
|
||||||
#
|
#
|
||||||
|
colnames = [str(x) for x in dates]
|
||||||
dates = [x.ISO() for x in dates]
|
dates = [x.ISO() for x in dates]
|
||||||
dayname = self.day_names()[jourdebut.weekday]
|
dayname = self.day_names()[jourdebut.weekday]
|
||||||
|
|
||||||
@ -1138,9 +1147,9 @@ class ZAbsences(
|
|||||||
gr_tit = "en"
|
gr_tit = "en"
|
||||||
else:
|
else:
|
||||||
if len(groups_infos.group_ids) > 1:
|
if len(groups_infos.group_ids) > 1:
|
||||||
p = "des groupes "
|
p = "des groupes"
|
||||||
else:
|
else:
|
||||||
p = "du groupe "
|
p = "du groupe"
|
||||||
gr_tit = (
|
gr_tit = (
|
||||||
p + '<span class="fontred">' + groups_infos.groups_titles + "</span>"
|
p + '<span class="fontred">' + groups_infos.groups_titles + "</span>"
|
||||||
)
|
)
|
||||||
@ -1208,18 +1217,15 @@ class ZAbsences(
|
|||||||
% {"menu_module": menu_module, "url": base_url, "sel": sel}
|
% {"menu_module": menu_module, "url": base_url, "sel": sel}
|
||||||
)
|
)
|
||||||
|
|
||||||
H += self._gen_form_saisie_groupe(etuds, dates, destination, moduleimpl_id)
|
H += self._gen_form_saisie_groupe(
|
||||||
|
etuds, colnames, dates, destination, dayname, moduleimpl_id
|
||||||
|
)
|
||||||
H.append(self.sco_footer(REQUEST))
|
H.append(self.sco_footer(REQUEST))
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
|
|
||||||
def _gen_form_saisie_groupe(self, etuds, dates, destination="", moduleimpl_id=None):
|
def _gen_form_saisie_groupe(
|
||||||
"""Formulaire saisie absences
|
self, etuds, colnames, dates, destination="", dayname="", moduleimpl_id=None
|
||||||
|
):
|
||||||
Args:
|
|
||||||
etuds: liste des étudiants
|
|
||||||
dates: liste de dates iso, par exemple: [ '2020-12-24', ... ]
|
|
||||||
moduleimpl_id: optionnel, module concerné.
|
|
||||||
"""
|
|
||||||
H = [
|
H = [
|
||||||
"""
|
"""
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -1246,29 +1252,25 @@ class ZAbsences(
|
|||||||
"""
|
"""
|
||||||
% len(etuds)
|
% len(etuds)
|
||||||
]
|
]
|
||||||
# Dates
|
|
||||||
odates = [datetime.date(*[int(x) for x in d.split("-")]) for d in dates]
|
|
||||||
# Titres colonnes
|
# Titres colonnes
|
||||||
noms_jours = [] # eg [ "Lundi", "mardi", "Samedi", ... ]
|
if dayname:
|
||||||
jn = self.day_names()
|
for jour in colnames:
|
||||||
for d in odates:
|
H.append(
|
||||||
idx_jour = d.weekday()
|
'<th colspan="2" width="100px" style="padding-left: 5px; padding-right: 5px;">'
|
||||||
noms_jours.append(jn[idx_jour])
|
+ dayname
|
||||||
for jour in noms_jours:
|
+ "</th>"
|
||||||
|
)
|
||||||
|
H.append("</tr><tr><td> </td>")
|
||||||
|
|
||||||
|
for jour in colnames:
|
||||||
H.append(
|
H.append(
|
||||||
'<th colspan="2" width="100px" style="padding-left: 5px; padding-right: 5px;">'
|
'<th colspan="2" width="100px" style="padding-left: 5px; padding-right: 5px;">'
|
||||||
+ jour
|
+ jour
|
||||||
+ "</th>"
|
+ "</th>"
|
||||||
)
|
)
|
||||||
|
|
||||||
H.append("</tr><tr><td> </td>")
|
H.append("</tr><tr><td> </td>")
|
||||||
for d in odates:
|
H.append("<th>AM</th><th>PM</th>" * len(colnames))
|
||||||
H.append(
|
|
||||||
'<th colspan="2" width="100px" style="padding-left: 5px; padding-right: 5px;">'
|
|
||||||
+ d.strftime("%d/%m/%Y")
|
|
||||||
+ "</th>"
|
|
||||||
)
|
|
||||||
H.append("</tr><tr><td> </td>")
|
|
||||||
H.append("<th>AM</th><th>PM</th>" * len(dates))
|
|
||||||
H.append("</tr>")
|
H.append("</tr>")
|
||||||
#
|
#
|
||||||
if not etuds:
|
if not etuds:
|
||||||
@ -1371,13 +1373,14 @@ class ZAbsences(
|
|||||||
absjust_only=0,
|
absjust_only=0,
|
||||||
REQUEST=None,
|
REQUEST=None,
|
||||||
):
|
):
|
||||||
"""Tables des absences justifiees et non justifiees d'un étudiant sur l'année en cours"""
|
"""Tables des absences justifiees et non justifiees d'un étudiant sur l'année en cours
|
||||||
|
"""
|
||||||
absjust = self.ListeAbsJust(etudid=etudid, datedebut=datedebut)
|
absjust = self.ListeAbsJust(etudid=etudid, datedebut=datedebut)
|
||||||
absnonjust = self.ListeAbsNonJust(etudid=etudid, datedebut=datedebut)
|
absnonjust = self.ListeAbsNonJust(etudid=etudid, datedebut=datedebut)
|
||||||
# examens ces jours là ?
|
# examens ces jours là ?
|
||||||
if with_evals:
|
if with_evals:
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=notesdb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
for a in absnonjust + absjust:
|
for a in absnonjust + absjust:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""select eval.*
|
"""select eval.*
|
||||||
@ -1496,9 +1499,10 @@ class ZAbsences(
|
|||||||
format="html",
|
format="html",
|
||||||
REQUEST=None,
|
REQUEST=None,
|
||||||
):
|
):
|
||||||
"""Liste les absences de groupes"""
|
"""Liste les absences de groupes
|
||||||
datedebut = notesdb.DateDMYtoISO(debut)
|
"""
|
||||||
datefin = notesdb.DateDMYtoISO(fin)
|
datedebut = DateDMYtoISO(debut)
|
||||||
|
datefin = DateDMYtoISO(fin)
|
||||||
# Informations sur les groupes à afficher:
|
# Informations sur les groupes à afficher:
|
||||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||||
self, group_ids, REQUEST=REQUEST
|
self, group_ids, REQUEST=REQUEST
|
||||||
@ -1599,7 +1603,7 @@ class ZAbsences(
|
|||||||
base_url="%s&formsemestre_id=%s&debut=%s&fin=%s"
|
base_url="%s&formsemestre_id=%s&debut=%s&fin=%s"
|
||||||
% (groups_infos.base_url, formsemestre_id, debut, fin),
|
% (groups_infos.base_url, formsemestre_id, debut, fin),
|
||||||
filename="etat_abs_"
|
filename="etat_abs_"
|
||||||
+ scu.make_filename(
|
+ make_filename(
|
||||||
"%s de %s" % (groups_infos.groups_filename, sem["titreannee"])
|
"%s de %s" % (groups_infos.groups_filename, sem["titreannee"])
|
||||||
),
|
),
|
||||||
caption=title,
|
caption=title,
|
||||||
@ -1628,20 +1632,26 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||||||
def EtatAbsencesDate(
|
def EtatAbsencesDate(
|
||||||
self, group_ids=[], date=None, REQUEST=None # list of groups to display
|
self, group_ids=[], date=None, REQUEST=None # list of groups to display
|
||||||
):
|
):
|
||||||
"""Etat des absences pour un groupe à une date donnée"""
|
"""Etat des absences pour un groupe à une date donnée
|
||||||
|
"""
|
||||||
# Informations sur les groupes à afficher:
|
# Informations sur les groupes à afficher:
|
||||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||||
self, group_ids, REQUEST=REQUEST
|
self, group_ids, REQUEST=REQUEST
|
||||||
)
|
)
|
||||||
|
formsemestre_id = groups_infos.formsemestre_id
|
||||||
|
sem = sco_formsemestre.do_formsemestre_list(
|
||||||
|
self, {"formsemestre_id": formsemestre_id}
|
||||||
|
)[0]
|
||||||
H = [self.sco_header(page_title="Etat des absences", REQUEST=REQUEST)]
|
H = [self.sco_header(page_title="Etat des absences", REQUEST=REQUEST)]
|
||||||
if date:
|
if date:
|
||||||
dateiso = notesdb.DateDMYtoISO(date)
|
dateiso = DateDMYtoISO(date)
|
||||||
nbetud = 0
|
nbetud = 0
|
||||||
t_nbabsjustam = 0
|
t_nbabsjustam = 0
|
||||||
t_nbabsam = 0
|
t_nbabsam = 0
|
||||||
t_nbabsjustpm = 0
|
t_nbabsjustpm = 0
|
||||||
t_nbabspm = 0
|
t_nbabspm = 0
|
||||||
H.append("<h2>État des absences le %s</h2>" % date)
|
etuds = self.getEtudInfoGroupes(groups_infos.group_ids)
|
||||||
|
H.append("<h2>Etat des absences le %s</h2>" % date)
|
||||||
H.append(
|
H.append(
|
||||||
"""<table border="0" cellspacing="4" cellpadding="0">
|
"""<table border="0" cellspacing="4" cellpadding="0">
|
||||||
<tr><th> </th>
|
<tr><th> </th>
|
||||||
@ -1728,7 +1738,7 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||||||
etudid=etudid, code_nip=code_nip, REQUEST=REQUEST, filled=True
|
etudid=etudid, code_nip=code_nip, REQUEST=REQUEST, filled=True
|
||||||
)
|
)
|
||||||
if not etuds:
|
if not etuds:
|
||||||
return scu.log_unknown_etud(self, REQUEST=REQUEST)
|
return log_unknown_etud(self, REQUEST=REQUEST)
|
||||||
etud = etuds[0]
|
etud = etuds[0]
|
||||||
# check dates
|
# check dates
|
||||||
begin_date = ParseDateTimeUTC(begin) # may raises ValueError
|
begin_date = ParseDateTimeUTC(begin) # may raises ValueError
|
||||||
@ -1753,7 +1763,7 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||||||
if xml_reply:
|
if xml_reply:
|
||||||
# Renvoie le nouveau billet en XML
|
# Renvoie le nouveau billet en XML
|
||||||
if REQUEST:
|
if REQUEST:
|
||||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
||||||
|
|
||||||
billets = billet_absence_list(cnx, {"billet_id": billet_id})
|
billets = billet_absence_list(cnx, {"billet_id": billet_id})
|
||||||
tab = self._tableBillets(billets, etud=etud)
|
tab = self._tableBillets(billets, etud=etud)
|
||||||
@ -1874,10 +1884,11 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||||||
security.declareProtected(ScoView, "listeBilletsEtud")
|
security.declareProtected(ScoView, "listeBilletsEtud")
|
||||||
|
|
||||||
def listeBilletsEtud(self, etudid=False, REQUEST=None, format="html"):
|
def listeBilletsEtud(self, etudid=False, REQUEST=None, format="html"):
|
||||||
"""Liste billets pour un etudiant"""
|
"""Liste billets pour un etudiant
|
||||||
|
"""
|
||||||
etuds = self.getEtudInfo(etudid=etudid, filled=1, REQUEST=REQUEST)
|
etuds = self.getEtudInfo(etudid=etudid, filled=1, REQUEST=REQUEST)
|
||||||
if not etuds:
|
if not etuds:
|
||||||
return scu.log_unknown_etud(self, format=format, REQUEST=REQUEST)
|
return log_unknown_etud(self, format=format, REQUEST=REQUEST)
|
||||||
|
|
||||||
etud = etuds[0]
|
etud = etuds[0]
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
@ -1888,7 +1899,8 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||||||
security.declareProtected(ScoView, "XMLgetBilletsEtud")
|
security.declareProtected(ScoView, "XMLgetBilletsEtud")
|
||||||
|
|
||||||
def XMLgetBilletsEtud(self, etudid=False, REQUEST=None):
|
def XMLgetBilletsEtud(self, etudid=False, REQUEST=None):
|
||||||
"""Liste billets pour un etudiant"""
|
"""Liste billets pour un etudiant
|
||||||
|
"""
|
||||||
if not self.get_preference("handle_billets_abs"):
|
if not self.get_preference("handle_billets_abs"):
|
||||||
return ""
|
return ""
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
@ -1925,7 +1937,8 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||||||
security.declareProtected(ScoAbsChange, "deleteBilletAbsence")
|
security.declareProtected(ScoAbsChange, "deleteBilletAbsence")
|
||||||
|
|
||||||
def deleteBilletAbsence(self, billet_id, REQUEST=None, dialog_confirmed=False):
|
def deleteBilletAbsence(self, billet_id, REQUEST=None, dialog_confirmed=False):
|
||||||
"""Supprime un billet."""
|
"""Supprime un billet.
|
||||||
|
"""
|
||||||
cnx = self.GetDBConnexion()
|
cnx = self.GetDBConnexion()
|
||||||
billets = billet_absence_list(cnx, {"billet_id": billet_id})
|
billets = billet_absence_list(cnx, {"billet_id": billet_id})
|
||||||
if not billets:
|
if not billets:
|
||||||
@ -2094,8 +2107,8 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||||||
|
|
||||||
Abs = self._ListeAbsDate(etud["etudid"], beg_date, end_date)
|
Abs = self._ListeAbsDate(etud["etudid"], beg_date, end_date)
|
||||||
|
|
||||||
REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
||||||
doc = jaxml.XML_document(encoding=scu.SCO_ENCODING)
|
doc = jaxml.XML_document(encoding=SCO_ENCODING)
|
||||||
doc.absences(etudid=etud["etudid"], beg_date=beg_date, end_date=end_date)
|
doc.absences(etudid=etud["etudid"], beg_date=beg_date, end_date=end_date)
|
||||||
doc._push()
|
doc._push()
|
||||||
for a in Abs:
|
for a in Abs:
|
||||||
@ -2113,7 +2126,7 @@ ou entrez une date pour visualiser les absents un jour donné :
|
|||||||
return repr(doc)
|
return repr(doc)
|
||||||
|
|
||||||
|
|
||||||
_billet_absenceEditor = notesdb.EditableTable(
|
_billet_absenceEditor = EditableTable(
|
||||||
"billet_absence",
|
"billet_absence",
|
||||||
"billet_id",
|
"billet_id",
|
||||||
(
|
(
|
||||||
@ -2197,6 +2210,7 @@ def MonthTableTail():
|
|||||||
def MonthTableBody(
|
def MonthTableBody(
|
||||||
month, year, events=[], halfday=0, trattributes="", work_saturday=False, pad_width=8
|
month, year, events=[], halfday=0, trattributes="", work_saturday=False, pad_width=8
|
||||||
):
|
):
|
||||||
|
# log('XXX events=%s' % events)
|
||||||
firstday, nbdays = calendar.monthrange(year, month)
|
firstday, nbdays = calendar.monthrange(year, month)
|
||||||
localtime = time.localtime()
|
localtime = time.localtime()
|
||||||
current_weeknum = time.strftime("%U", localtime)
|
current_weeknum = time.strftime("%U", localtime)
|
||||||
@ -2429,8 +2443,8 @@ class CAbsSemEtud:
|
|||||||
self.sem = sco_formsemestre.get_formsemestre(
|
self.sem = sco_formsemestre.get_formsemestre(
|
||||||
self.context, self.sem["formsemestre_id"]
|
self.context, self.sem["formsemestre_id"]
|
||||||
)
|
)
|
||||||
debut_sem = notesdb.DateDMYtoISO(self.sem["date_debut"])
|
debut_sem = DateDMYtoISO(self.sem["date_debut"])
|
||||||
fin_sem = notesdb.DateDMYtoISO(self.sem["date_fin"])
|
fin_sem = DateDMYtoISO(self.sem["date_fin"])
|
||||||
|
|
||||||
self._CountAbs = self.context.Absences.CountAbs(
|
self._CountAbs = self.context.Absences.CountAbs(
|
||||||
etudid=self.etudid, debut=debut_sem, fin=fin_sem
|
etudid=self.etudid, debut=debut_sem, fin=fin_sem
|
||||||
|
@ -1617,7 +1617,7 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
|
|||||||
security.declareProtected(ScoView, "view_module_abs")
|
security.declareProtected(ScoView, "view_module_abs")
|
||||||
|
|
||||||
def view_module_abs(self, REQUEST, moduleimpl_id, format="html"):
|
def view_module_abs(self, REQUEST, moduleimpl_id, format="html"):
|
||||||
"""Visualisation des absences a un module"""
|
"""Visulalisation des absences a un module"""
|
||||||
M = self.do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
M = self.do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
sem = sco_formsemestre.get_formsemestre(self, M["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(self, M["formsemestre_id"])
|
||||||
debut_sem = DateDMYtoISO(sem["date_debut"])
|
debut_sem = DateDMYtoISO(sem["date_debut"])
|
||||||
|
63
ZScoDoc.py
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
import time, string, glob, re, inspect
|
import time, string, glob, re, inspect
|
||||||
import urllib, urllib2, cgi, xml
|
import urllib, urllib2, cgi, xml
|
||||||
|
import datetime
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
@ -42,13 +43,22 @@ from zipfile import ZipFile
|
|||||||
import os.path, glob
|
import os.path, glob
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
from email.MIMEText import MIMEText
|
from email.mime.text import MIMEText
|
||||||
from email.MIMEBase import MIMEBase
|
from email.header import Header
|
||||||
from email.Header import Header
|
from email.mime.base import MIMEBase
|
||||||
from email import Encoders
|
|
||||||
|
|
||||||
from sco_zope import *
|
from sco_zope import (
|
||||||
|
ObjectManager,
|
||||||
|
PropertyManager,
|
||||||
|
RoleManager,
|
||||||
|
Item,
|
||||||
|
Persistent,
|
||||||
|
Implicit,
|
||||||
|
ClassSecurityInfo,
|
||||||
|
DTMLFile,
|
||||||
|
Globals,
|
||||||
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
try:
|
try:
|
||||||
@ -56,7 +66,21 @@ try:
|
|||||||
except:
|
except:
|
||||||
import ZPsycopgDA.DA as ZopeDA # interp.py
|
import ZPsycopgDA.DA as ZopeDA # interp.py
|
||||||
|
|
||||||
from sco_utils import *
|
import sco_utils
|
||||||
|
from sco_utils import (
|
||||||
|
SCO_DEFAULT_SQL_USERS_CNX,
|
||||||
|
SCO_ENCODING,
|
||||||
|
CUSTOM_HTML_HEADER_CNX,
|
||||||
|
SCO_USERS_LIST,
|
||||||
|
SCO_WEBSITE,
|
||||||
|
SCO_EXC_MAIL,
|
||||||
|
SCO_DEV_MAIL,
|
||||||
|
scodoc_html2txt,
|
||||||
|
VERSION,
|
||||||
|
SCODOC_CFG_DIR,
|
||||||
|
)
|
||||||
|
from sco_permissions import ScoView, ScoSuperAdmin
|
||||||
|
from sco_exceptions import AccessDenied
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import sco_find_etud
|
import sco_find_etud
|
||||||
from ZScoUsers import pwdFascistCheck
|
from ZScoUsers import pwdFascistCheck
|
||||||
@ -111,7 +135,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 +188,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")
|
||||||
|
|
||||||
@ -264,7 +288,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
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
|
||||||
@ -284,7 +308,6 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
raise ValueError("nom de departement invalide")
|
raise ValueError("nom de departement invalide")
|
||||||
if not pass2:
|
if not pass2:
|
||||||
# 1- Creation de repertoire Dept
|
# 1- Creation de repertoire Dept
|
||||||
log("creating Zope folder " + DeptId)
|
|
||||||
add_method = self.manage_addProduct["OFSP"].manage_addFolder
|
add_method = self.manage_addProduct["OFSP"].manage_addFolder
|
||||||
add_method(DeptId, title="Site dept. " + DeptId)
|
add_method(DeptId, title="Site dept. " + DeptId)
|
||||||
|
|
||||||
@ -292,12 +315,10 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
|||||||
|
|
||||||
if not pass2:
|
if not pass2:
|
||||||
# 2- Creation du repertoire Fotos
|
# 2- Creation du repertoire Fotos
|
||||||
log("creating Zope folder %s/Fotos" % DeptId)
|
|
||||||
add_method = DeptFolder.manage_addProduct["OFSP"].manage_addFolder
|
add_method = DeptFolder.manage_addProduct["OFSP"].manage_addFolder
|
||||||
add_method("Fotos", title="Photos identites " + DeptId)
|
add_method("Fotos", title="Photos identites " + DeptId)
|
||||||
|
|
||||||
# 3- Creation instance ScoDoc
|
# 3- Creation instance ScoDoc
|
||||||
log("creating Zope ZScolar instance")
|
|
||||||
add_method = DeptFolder.manage_addProduct["ScoDoc"].manage_addZScolarForm
|
add_method = DeptFolder.manage_addProduct["ScoDoc"].manage_addZScolarForm
|
||||||
return add_method(DeptId, REQUEST=REQUEST)
|
return add_method(DeptId, REQUEST=REQUEST)
|
||||||
|
|
||||||
@ -649,8 +670,8 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
|||||||
**kv
|
**kv
|
||||||
):
|
):
|
||||||
"Recuperation des exceptions Zope"
|
"Recuperation des exceptions Zope"
|
||||||
sco_exc_mail = SCO_EXC_MAIL
|
sco_exc_mail = SCO_EXC_MAIL # pylint: disable=unused-variable
|
||||||
sco_dev_mail = SCO_DEV_MAIL
|
sco_dev_mail = SCO_DEV_MAIL # pylint: disable=unused-variable
|
||||||
# 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.
|
||||||
@ -717,6 +738,7 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
|||||||
)
|
)
|
||||||
# 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')
|
||||||
|
# pylint: disable=unused-variable
|
||||||
txt_html = self._report_request(REQUEST, fmt="html")
|
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;">
|
||||||
@ -737,6 +759,7 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# --- Mail:
|
# --- Mail:
|
||||||
|
# pylint: disable=unused-variable
|
||||||
error_traceback_txt = scodoc_html2txt(error_tb)
|
error_traceback_txt = scodoc_html2txt(error_tb)
|
||||||
txt = (
|
txt = (
|
||||||
"""
|
"""
|
||||||
@ -755,6 +778,7 @@ 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"""
|
||||||
|
# pylint: disable=unused-variable
|
||||||
AUTHENTICATED_USER = REQUEST.get("AUTHENTICATED_USER", "")
|
AUTHENTICATED_USER = REQUEST.get("AUTHENTICATED_USER", "")
|
||||||
dt = time.asctime()
|
dt = time.asctime()
|
||||||
URL = REQUEST.get("URL", "")
|
URL = REQUEST.get("URL", "")
|
||||||
@ -771,8 +795,7 @@ ErrorType: %(error_type)s
|
|||||||
HTTP_USER_AGENT = "na"
|
HTTP_USER_AGENT = "na"
|
||||||
form = REQUEST.get("form", "")
|
form = REQUEST.get("form", "")
|
||||||
HTTP_X_FORWARDED_FOR = REQUEST.get("HTTP_X_FORWARDED_FOR", "")
|
HTTP_X_FORWARDED_FOR = REQUEST.get("HTTP_X_FORWARDED_FOR", "")
|
||||||
svn_version = get_svn_version(self.file_path)
|
SCOVERSION = sco_utils.get_scodoc_version() or VERSION.SCOVERSION
|
||||||
SCOVERSION = VERSION.SCOVERSION
|
|
||||||
|
|
||||||
txt = (
|
txt = (
|
||||||
"""
|
"""
|
||||||
@ -786,8 +809,6 @@ REFERER: %(REFERER)s
|
|||||||
Form: %(form)s
|
Form: %(form)s
|
||||||
Origin: %(HTTP_X_FORWARDED_FOR)s
|
Origin: %(HTTP_X_FORWARDED_FOR)s
|
||||||
Agent: %(HTTP_USER_AGENT)s
|
Agent: %(HTTP_USER_AGENT)s
|
||||||
|
|
||||||
subversion: %(svn_version)s
|
|
||||||
"""
|
"""
|
||||||
% vars()
|
% vars()
|
||||||
)
|
)
|
||||||
@ -890,7 +911,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(SCODOC_CFG_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
|
||||||
|
|
||||||
|
51
ZScolar.py
@ -52,7 +52,7 @@ log("restarting...")
|
|||||||
|
|
||||||
log("ZScolar home=%s" % file_path)
|
log("ZScolar home=%s" % file_path)
|
||||||
|
|
||||||
|
import sco_utils
|
||||||
from sco_utils import *
|
from sco_utils import *
|
||||||
import notesdb
|
import notesdb
|
||||||
from notesdb import *
|
from notesdb import *
|
||||||
@ -405,9 +405,9 @@ UE11 Découverte métiers <span class="ue_code">(code UCOD46, 16 ECTS, Apo <span
|
|||||||
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-2020</p>
|
||||||
<p>Version %s (subversion %s)</p>
|
<p>Version %s</p>
|
||||||
"""
|
"""
|
||||||
% (SCOVERSION, get_svn_version(file_path))
|
% (sco_utils.get_scodoc_version())
|
||||||
]
|
]
|
||||||
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>'
|
||||||
@ -2037,8 +2037,49 @@ function tweakmenu( gname ) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if not edit:
|
if not edit:
|
||||||
etud = scolars.create_etud(self, cnx, args=tf[2], REQUEST=REQUEST)
|
# creation d'un etudiant
|
||||||
etudid = etud["etudid"]
|
etudid = scolars.etudident_create(
|
||||||
|
cnx, tf[2], context=self, REQUEST=REQUEST
|
||||||
|
)
|
||||||
|
# crée une adresse vide (chaque etudiant doit etre dans la table "adresse" !)
|
||||||
|
adresse_id = scolars.adresse_create(
|
||||||
|
cnx,
|
||||||
|
{
|
||||||
|
"etudid": etudid,
|
||||||
|
"typeadresse": "domicile",
|
||||||
|
"description": "(creation individuelle)",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# event
|
||||||
|
scolars.scolar_events_create(
|
||||||
|
cnx,
|
||||||
|
args={
|
||||||
|
"etudid": etudid,
|
||||||
|
"event_date": time.strftime("%d/%m/%Y"),
|
||||||
|
"formsemestre_id": None,
|
||||||
|
"event_type": "CREATION",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
# log
|
||||||
|
logdb(
|
||||||
|
REQUEST,
|
||||||
|
cnx,
|
||||||
|
method="etudident_edit_form",
|
||||||
|
etudid=etudid,
|
||||||
|
msg="creation initiale",
|
||||||
|
)
|
||||||
|
etud = scolars.etudident_list(cnx, {"etudid": etudid})[0]
|
||||||
|
self.fillEtudsInfo([etud])
|
||||||
|
etud["url"] = "ficheEtud?etudid=%(etudid)s" % etud
|
||||||
|
sco_news.add(
|
||||||
|
self,
|
||||||
|
REQUEST,
|
||||||
|
typ=NEWS_INSCR,
|
||||||
|
object=None, # pas d'object pour ne montrer qu'un etudiant
|
||||||
|
text='Nouvel étudiant <a href="%(url)s">%(nomprenom)s</a>' % etud,
|
||||||
|
url=etud["url"],
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# modif d'un etudiant
|
# modif d'un etudiant
|
||||||
scolars.etudident_edit(cnx, tf[2], context=self, REQUEST=REQUEST)
|
scolars.etudident_edit(cnx, tf[2], context=self, REQUEST=REQUEST)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
|
#!/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%%.*}
|
||||||
@ -24,28 +24,28 @@ 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" ]
|
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" ]
|
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
|
||||||
PSQL=/usr/lib/postgresql/8.1/bin/psql
|
PSQL=/usr/lib/postgresql/8.1/bin/psql
|
||||||
fi
|
fi
|
||||||
|
export PSQL
|
||||||
|
|
||||||
# tcp port for SQL server (under Debian 4, 5432 or 5433 for 8.1 if 7.4 also installed !)
|
# tcp port for SQL server (under Debian 4, 5432 or 5433 for 8.1 if 7.4 also installed !)
|
||||||
# Important note: if changed, you should probably also change it in
|
# Important note: if changed, you should probably also change it in
|
||||||
@ -53,7 +53,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
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
source config.sh
|
source config.sh
|
||||||
source utils.sh
|
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
|
cp "$SCODOC_DIR"/config/etc/scodoc.service /etc/systemd/system
|
||||||
systemctl enable scodoc.service
|
systemctl enable scodoc.service
|
||||||
|
|
||||||
echo "A partir de maintenant, utiliser"
|
echo "A partir de maintenant, utiliser"
|
||||||
|
@ -11,6 +11,6 @@ source utils.sh
|
|||||||
echo 'Creating postgresql database'
|
echo 'Creating postgresql database'
|
||||||
|
|
||||||
# ---
|
# ---
|
||||||
echo 'Creating postgresql database ' $db_name
|
echo 'Creating postgresql database ' "$db_name"
|
||||||
createdb -E UTF-8 -p $POSTGRES_PORT -O $POSTGRES_USER $db_name
|
createdb -E UTF-8 -p "$POSTGRES_PORT" -O "$POSTGRES_USER" "$db_name"
|
||||||
|
|
||||||
|
@ -15,37 +15,19 @@ source utils.sh
|
|||||||
|
|
||||||
check_uid_root "$0"
|
check_uid_root "$0"
|
||||||
|
|
||||||
usage() {
|
|
||||||
echo "$0 [-n DEPT]"
|
|
||||||
echo "(default to interactive mode)"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
[ $# = 0 ] || [ $# = 2 ] || usage
|
|
||||||
|
|
||||||
if [ "$1" = "-n" ]
|
echo -n "Nom du departement (un mot sans ponctuation, exemple \"Info\"): "
|
||||||
then
|
read -r DEPT
|
||||||
interactive=0
|
|
||||||
if [ $# -lt 2 ]
|
|
||||||
then
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
DEPT=$2
|
|
||||||
else
|
|
||||||
interactive=1
|
|
||||||
echo -n "Nom du departement (un mot sans ponctuation, exemple \"Info\"): "
|
|
||||||
read -r DEPT
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! "$DEPT" =~ ^[A-Za-z0-9]+$ ]]
|
if [[ ! "$DEPT" =~ ^[A-Za-z0-9]+$ ]]
|
||||||
then
|
then
|
||||||
echo 'Nom de departement invalide !'
|
echo 'Nom de departement invalide !'
|
||||||
exit 2
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export DEPT
|
export DEPT
|
||||||
|
|
||||||
db_name=SCO$(to_upper "$DEPT")
|
export db_name=SCO$(to_upper "$DEPT")
|
||||||
export db_name
|
|
||||||
|
|
||||||
cfg_pathname="${SCODOC_VAR_DIR}/config/depts/$DEPT".cfg
|
cfg_pathname="${SCODOC_VAR_DIR}/config/depts/$DEPT".cfg
|
||||||
|
|
||||||
@ -59,39 +41,29 @@ fi
|
|||||||
init_postgres_user
|
init_postgres_user
|
||||||
|
|
||||||
# ----------------------- Create database
|
# ----------------------- Create database
|
||||||
su -c ./create_database.sh "$POSTGRES_SUPERUSER"
|
su -c ./create_database.sh $POSTGRES_SUPERUSER
|
||||||
|
|
||||||
# ----------------------- Create tables
|
# ----------------------- Create tables
|
||||||
# POSTGRES_USER == regular unix user (www-data)
|
# POSTGRES_USER == regular unix user (www-data)
|
||||||
if [ "$interactive" = 1 ]
|
su -c ./initialize_database.sh $POSTGRES_USER
|
||||||
then
|
|
||||||
su -c ./initialize_database.sh "$POSTGRES_USER"
|
|
||||||
else
|
|
||||||
su -c ./initialize_database.sh "$POSTGRES_USER" > /dev/null 2>&1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------- Enregistre fichier config
|
# ----------------------- Enregistre fichier config
|
||||||
echo "dbname=${db_name}" > "$cfg_pathname"
|
echo "dbname=$db_name" > "$cfg_pathname"
|
||||||
|
|
||||||
|
# ----------------------- Force mise à jour
|
||||||
if [ "$interactive" = 1 ]
|
echo -n "Voulez vous mettre a jour ScoDoc (tres recommande) ? (y/n) [y] "
|
||||||
|
read -r ans
|
||||||
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
# ----------------------- Force mise à jour
|
(cd "$SCODOC_DIR/config"; ./upgrade.sh)
|
||||||
echo -n "Voulez vous mettre a jour ScoDoc (tres recommande) ? (y/n) [y] "
|
|
||||||
read -r ans
|
|
||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
|
||||||
then
|
|
||||||
(cd "$SCODOC_DIR/config" || terminate "no config directory"; ./upgrade.sh)
|
|
||||||
fi
|
|
||||||
# -----------------------
|
|
||||||
echo
|
|
||||||
echo " Departement $DEPT cree"
|
|
||||||
echo
|
|
||||||
echo " Attention: la base de donnees n'a pas de copies de sauvegarde"
|
|
||||||
echo
|
|
||||||
echo " Maintenant, vous pouvez ajouter le departement via l'application web"
|
|
||||||
echo " en suivant le lien \"Administration de ScoDoc\" sur la page d'accueil."
|
|
||||||
echo
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# -----------------------
|
||||||
|
echo
|
||||||
|
echo " Departement $DEPT cree"
|
||||||
|
echo
|
||||||
|
echo " Attention: la base de donnees n'a pas de copies de sauvegarde"
|
||||||
|
echo
|
||||||
|
echo " Maintenant, vous pouvez ajouter le departement via l'application web"
|
||||||
|
echo " en suivant le lien \"Administration de ScoDoc\" sur la page d'accueil."
|
||||||
|
echo
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
source config.sh
|
source config.sh
|
||||||
source utils.sh
|
source utils.sh
|
||||||
|
|
||||||
check_uid_root $0
|
check_uid_root "$0"
|
||||||
|
|
||||||
# --- Ensure postgres user www-data exists
|
# --- Ensure postgres user www-data exists
|
||||||
init_postgres_user
|
init_postgres_user
|
||||||
@ -21,8 +21,8 @@ db_name=SCOUSERS
|
|||||||
|
|
||||||
echo 'Creating postgresql database ' $db_name
|
echo 'Creating postgresql database ' $db_name
|
||||||
|
|
||||||
su -c "createdb -E UTF-8 -O $POSTGRES_USER -p $POSTGRES_PORT $db_name" $POSTGRES_SUPERUSER
|
su -c "createdb -E UTF-8 -O $POSTGRES_USER -p $POSTGRES_PORT $db_name" "$POSTGRES_SUPERUSER"
|
||||||
|
|
||||||
echo 'Initializing tables in database ' $db_name
|
echo 'Initializing tables in database ' "$db_name"
|
||||||
echo su -c "$PSQL -U $POSTGRES_USER -p $POSTGRES_PORT $db_name < $SCODOC_DIR/misc/create_user_table.sql" $POSTGRES_USER
|
echo su -c "$PSQL -U $POSTGRES_USER -p $POSTGRES_PORT $db_name < $SCODOC_DIR/misc/create_user_table.sql" "$POSTGRES_USER"
|
||||||
su -c "$PSQL -U $POSTGRES_USER -p $POSTGRES_PORT $db_name < $SCODOC_DIR/misc/create_user_table.sql" $POSTGRES_USER
|
su -c "$PSQL -U $POSTGRES_USER -p $POSTGRES_PORT $db_name < $SCODOC_DIR/misc/create_user_table.sql" "$POSTGRES_USER"
|
||||||
|
@ -17,38 +17,23 @@
|
|||||||
source config.sh
|
source config.sh
|
||||||
source utils.sh
|
source utils.sh
|
||||||
|
|
||||||
check_uid_root $0
|
check_uid_root "$0"
|
||||||
usage() {
|
|
||||||
echo "$0 [-n DEPT]"
|
echo
|
||||||
echo "(default to interactive mode)"
|
echo "Ce script supprime la base de donnees ScoDoc d'un departement"
|
||||||
exit 1
|
echo
|
||||||
}
|
echo "Attention: le departement doit au prealable avoir ete supprime via l'interface web !"
|
||||||
[ $# = 0 ] || [ $# = 2 ] || usage
|
echo "faites le AVANT d'executer ce script !!!"
|
||||||
if [ "$1" = "-n" ]
|
echo
|
||||||
then
|
echo -n "Nom du departement a supprimer (un mot sans ponctuation, exemple \"Info\"): "
|
||||||
interactive=0
|
read -r DEPT
|
||||||
if [ $# -lt 2 ]
|
|
||||||
then
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
DEPT=$2
|
|
||||||
else
|
|
||||||
interactive=1
|
|
||||||
echo
|
|
||||||
echo "Ce script supprime la base de donnees ScoDoc d'un departement"
|
|
||||||
echo
|
|
||||||
echo "Attention: le departement doit au prealable avoir ete supprime via l'interface web !"
|
|
||||||
echo "faites le AVANT d'executer ce script !!!"
|
|
||||||
echo
|
|
||||||
echo -n "Nom du departement a supprimer (un mot sans ponctuation, exemple \"Info\"): "
|
|
||||||
read -r DEPT
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! "$DEPT" =~ ^[A-Za-z0-9]+$ ]]
|
if [[ ! "$DEPT" =~ ^[A-Za-z0-9]+$ ]]
|
||||||
then
|
then
|
||||||
echo "Nom de departement invalide !"
|
echo "Nom de departement invalide !"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export DEPT
|
export DEPT
|
||||||
|
|
||||||
cfg_pathname="${SCODOC_VAR_DIR}/config/depts/$DEPT".cfg
|
cfg_pathname="${SCODOC_VAR_DIR}/config/depts/$DEPT".cfg
|
||||||
@ -59,20 +44,17 @@ 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"
|
echo "suppression de la base postgres $db_name"
|
||||||
su -c "dropdb $db_name" "$POSTGRES_SUPERUSER" || terminate "ne peux supprimer base de donnees $db_name"
|
su -c "dropdb $db_name" "$POSTGRES_SUPERUSER" || terminate "ne peux supprimer base de donnees $db_name"
|
||||||
# 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 ]
|
echo -n "Demarrer le serveur ScoDoc ? (y/n) [n]"
|
||||||
|
read -r ans
|
||||||
|
if [ "$(norm_ans "$ans")" = 'Y' ]
|
||||||
then
|
then
|
||||||
echo -n "Demarrer le serveur ScoDoc ? (y/n) [n]"
|
scodocctl start
|
||||||
read -r ans
|
|
||||||
if [ "$(norm_ans "$ans")" = 'Y' ]
|
|
||||||
then
|
|
||||||
scodocctl start
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
exit 0
|
exit 0
|
||||||
else
|
else
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# Avec option:
|
# Avec option:
|
||||||
# -a : sauve aussi les bases de données
|
# -a : sauve aussi les bases de données
|
||||||
#
|
#
|
||||||
DEST_ADDRESS=emmanuel.viennet@univ-paris13.fr
|
DEST_ADDRESS=emmanuel.viennet@gmail.com
|
||||||
|
|
||||||
INSTANCE_DIR=/opt/scodoc
|
INSTANCE_DIR=/opt/scodoc
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ while getopts ":d:aunh" opt; do
|
|||||||
SEND_BY_MAIL=0
|
SEND_BY_MAIL=0
|
||||||
;;
|
;;
|
||||||
d)
|
d)
|
||||||
DEPTS_TO_SAVE=$( join_by ' ' $DEPTS_TO_SAVE $OPTARG )
|
DEPTS_TO_SAVE=$( join_by ' ' "$DEPTS_TO_SAVE" "$OPTARG" )
|
||||||
;;
|
;;
|
||||||
h)
|
h)
|
||||||
echo "Diagnostic installation ScoDoc"
|
echo "Diagnostic installation ScoDoc"
|
||||||
@ -71,7 +71,7 @@ then
|
|||||||
apt-get install sharutils
|
apt-get install sharutils
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir $TMP
|
mkdir "$TMP"
|
||||||
|
|
||||||
# Files to copy:
|
# Files to copy:
|
||||||
FILES="/etc/hosts /etc/debian_version /etc/apt /etc/apache2"
|
FILES="/etc/hosts /etc/debian_version /etc/apt /etc/apache2"
|
||||||
@ -91,33 +91,33 @@ echo "left in ${TMP}"
|
|||||||
# -------------------------------------
|
# -------------------------------------
|
||||||
|
|
||||||
copy_log() {
|
copy_log() {
|
||||||
if [ -e $1 ]
|
if [ -e "$1" ]
|
||||||
then
|
then
|
||||||
cp $1 $TMP/scodoc_logs/
|
cp "$1" "$TMP"/scodoc_logs/
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
mkdir $TMP/scodoc_logs/
|
mkdir "$TMP"/scodoc_logs/
|
||||||
copy_log /opt/scodoc/instance/log/event.log
|
copy_log /opt/scodoc/log/event.log
|
||||||
copy_log /opt/scodoc/instance/log/event.log.1
|
copy_log /opt/scodoc/log/event.log.1
|
||||||
copy_log /opt/scodoc/instance/log/notes.log
|
copy_log /opt/scodoc/log/notes.log
|
||||||
copy_log /opt/scodoc/instance/log/notes.log.1
|
copy_log /opt/scodoc/log/notes.log.1
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------
|
# -------------------------------------
|
||||||
# Linux System Configuration
|
# Linux System Configuration
|
||||||
# -------------------------------------
|
# -------------------------------------
|
||||||
|
|
||||||
iptables -L > $TMP/iptables.out
|
iptables -L > "$TMP"/iptables.out
|
||||||
ip a > $TMP/ifconfig.out
|
ip a > "$TMP"/ifconfig.out
|
||||||
ps auxww > $TMP/ps.out
|
ps auxww > "$TMP"/ps.out
|
||||||
df -h > $TMP/df.out
|
df -h > "$TMP"/df.out
|
||||||
dpkg -l > $TMP/dpkg.lst
|
dpkg -l > "$TMP"/dpkg.lst
|
||||||
|
|
||||||
(cd /opt/scodoc/instance/Products/ScoDoc; svn status > $TMP/svn.status)
|
(cd /opt/scodoc/Products/ScoDoc; svn status > "$TMP"/svn.status)
|
||||||
(cd /opt/scodoc/instance/Products/ScoDoc; svn diff > $TMP/svn.diff)
|
(cd /opt/scodoc/Products/ScoDoc; svn diff > "$TMP"/svn.diff)
|
||||||
|
|
||||||
(cd /opt/scodoc/instance/Products/ScoDoc; svnversion > $TMP/svn.version)
|
(cd /opt/scodoc/Products/ScoDoc; svnversion > "$TMP"/svn.version)
|
||||||
ls -laR /opt/scodoc/instance/Products/ScoDoc > $TMP/ls-laR
|
ls -laR /opt/scodoc/Products/ScoDoc > "$TMP"/ls-laR
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------
|
# -------------------------------------
|
||||||
@ -126,7 +126,7 @@ ls -laR /opt/scodoc/instance/Products/ScoDoc > $TMP/ls-laR
|
|||||||
(su postgres -c "psql -l") > "${TMP}/psql-l.out"
|
(su postgres -c "psql -l") > "${TMP}/psql-l.out"
|
||||||
for dept in "${INSTANCE_DIR}"/var/scodoc/config/depts/*.cfg
|
for dept in "${INSTANCE_DIR}"/var/scodoc/config/depts/*.cfg
|
||||||
do
|
do
|
||||||
cnx=$(cat $dept)
|
cnx=$(cat "$dept")
|
||||||
(su postgres -c "echo '\dt' | psql -d $cnx") > "${TMP}/psql-$(basename ${dept%%.*}).out"
|
(su postgres -c "echo '\dt' | psql -d $cnx") > "${TMP}/psql-$(basename ${dept%%.*}).out"
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -137,14 +137,14 @@ done
|
|||||||
# copy files:
|
# copy files:
|
||||||
for f in $FILES
|
for f in $FILES
|
||||||
do
|
do
|
||||||
cp -R $f $TMP
|
cp -R "$f" "$TMP"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------
|
# -------------------------------------
|
||||||
# Optionally save dept(s) database(s)
|
# Optionally save dept(s) database(s)
|
||||||
# -------------------------------------
|
# -------------------------------------
|
||||||
DEPTS_TO_SAVE=$(echo ${DEPTS_TO_SAVE} | tr ' ' '\n' | sort | uniq)
|
DEPTS_TO_SAVE=$(echo "${DEPTS_TO_SAVE}" | tr ' ' '\n' | sort | uniq)
|
||||||
|
|
||||||
# Dump database of a dept (eg "RT")
|
# Dump database of a dept (eg "RT")
|
||||||
function dump_dept_db {
|
function dump_dept_db {
|
||||||
@ -176,10 +176,10 @@ fi
|
|||||||
# Archive all stuff to /tmp
|
# Archive all stuff to /tmp
|
||||||
# -------------------------------------
|
# -------------------------------------
|
||||||
|
|
||||||
tar cfz $TMP.tgz $TMP
|
tar cfz "$TMP".tgz "$TMP"
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Fichier de diagnostic: $TMP.tgz"
|
echo "Fichier de diagnostic: "$TMP".tgz"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# If no mail, stop here
|
# If no mail, stop here
|
||||||
@ -197,9 +197,9 @@ fi
|
|||||||
|
|
||||||
#requires: basename,date,md5sum,sed,sendmail,uuencode
|
#requires: basename,date,md5sum,sed,sendmail,uuencode
|
||||||
function fappend {
|
function fappend {
|
||||||
echo "$2">>$1;
|
echo "$2">>"$1";
|
||||||
}
|
}
|
||||||
YYYYMMDD=`date +%Y%m%d`
|
YYYYMMDD=$(date +%Y%m%d)
|
||||||
|
|
||||||
# CHANGE THESE
|
# CHANGE THESE
|
||||||
TOEMAIL=$DEST_ADDRESS
|
TOEMAIL=$DEST_ADDRESS
|
||||||
@ -212,45 +212,45 @@ MIMETYPE="application/gnutar" #if not sure, use http://www.webmaster-toolkit.com
|
|||||||
|
|
||||||
# DON'T CHANGE ANYTHING BELOW
|
# DON'T CHANGE ANYTHING BELOW
|
||||||
TMP="/tmp/tmpfil_123"$RANDOM;
|
TMP="/tmp/tmpfil_123"$RANDOM;
|
||||||
BOUNDARY=`date +%s|md5sum`
|
BOUNDARY=$(date +%s|md5sum)
|
||||||
BOUNDARY=${BOUNDARY:0:32}
|
BOUNDARY=${BOUNDARY:0:32}
|
||||||
FILENAME=`basename $ATTACHMENT`
|
FILENAME=$(basename "$ATTACHMENT")
|
||||||
|
|
||||||
rm -rf $TMP;
|
rm -rf "$TMP"
|
||||||
cat $ATTACHMENT|uuencode --base64 $FILENAME>$TMP;
|
uuencode --base64 "$FILENAME" < "$ATTACHMENT" >"$TMP"
|
||||||
sed -i -e '1,1d' -e '$d' $TMP;#removes first & last lines from $TMP
|
sed -i -e '1,1d' -e '$d' "$TMP"; #removes first & last lines from "$TMP"
|
||||||
DATA=`cat $TMP`
|
DATA=$(cat "$TMP")
|
||||||
|
|
||||||
rm -rf $TMP;
|
rm -rf "$TMP";
|
||||||
fappend $TMP "From: $FREMAIL";
|
fappend "$TMP" "From: $FREMAIL";
|
||||||
fappend $TMP "To: $TOEMAIL";
|
fappend "$TMP" "To: $TOEMAIL";
|
||||||
fappend $TMP "Reply-To: $FREMAIL";
|
fappend "$TMP" "Reply-To: $FREMAIL";
|
||||||
fappend $TMP "Subject: $SUBJECT";
|
fappend "$TMP" "Subject: $SUBJECT";
|
||||||
fappend $TMP "Content-Type: multipart/mixed; boundary=\""$BOUNDARY"\"";
|
fappend "$TMP" "Content-Type: multipart/mixed; boundary=\""$BOUNDARY"\"";
|
||||||
fappend $TMP "";
|
fappend "$TMP" "";
|
||||||
fappend $TMP "This is a MIME formatted message. If you see this text it means that your";
|
fappend "$TMP" "This is a MIME formatted message. If you see this text it means that your";
|
||||||
fappend $TMP "email software does not support MIME formatted messages.";
|
fappend "$TMP" "email software does not support MIME formatted messages.";
|
||||||
fappend $TMP "";
|
fappend "$TMP" "";
|
||||||
fappend $TMP "--$BOUNDARY";
|
fappend "$TMP" "--$BOUNDARY";
|
||||||
fappend $TMP "Content-Type: text/plain; charset=ISO-8859-1; format=flowed";
|
fappend "$TMP" "Content-Type: text/plain; charset=ISO-8859-1; format=flowed";
|
||||||
fappend $TMP "Content-Transfer-Encoding: 7bit";
|
fappend "$TMP" "Content-Transfer-Encoding: 7bit";
|
||||||
fappend $TMP "Content-Disposition: inline";
|
fappend "$TMP" "Content-Disposition: inline";
|
||||||
fappend $TMP "";
|
fappend "$TMP" "";
|
||||||
fappend $TMP "$MSGBODY";
|
fappend "$TMP" "$MSGBODY";
|
||||||
fappend $TMP "";
|
fappend "$TMP" "";
|
||||||
fappend $TMP "";
|
fappend "$TMP" "";
|
||||||
fappend $TMP "--$BOUNDARY";
|
fappend "$TMP" "--$BOUNDARY";
|
||||||
fappend $TMP "Content-Type: $MIMETYPE; name=\"$FILENAME\"";
|
fappend "$TMP" "Content-Type: $MIMETYPE; name=\"$FILENAME\"";
|
||||||
fappend $TMP "Content-Transfer-Encoding: base64";
|
fappend "$TMP" "Content-Transfer-Encoding: base64";
|
||||||
fappend $TMP "Content-Disposition: attachment; filename=\"$FILENAME\";";
|
fappend "$TMP" "Content-Disposition: attachment; filename=\"$FILENAME\";";
|
||||||
fappend $TMP "";
|
fappend "$TMP" "";
|
||||||
fappend $TMP "$DATA";
|
fappend "$TMP" "$DATA";
|
||||||
fappend $TMP "";
|
fappend "$TMP" "";
|
||||||
fappend $TMP "";
|
fappend "$TMP" "";
|
||||||
fappend $TMP "--$BOUNDARY--";
|
fappend "$TMP" "--$BOUNDARY--";
|
||||||
fappend $TMP "";
|
fappend "$TMP" "";
|
||||||
fappend $TMP "";
|
fappend "$TMP" "";
|
||||||
#cat $TMP>out.txt
|
#cat "$TMP">out.txt
|
||||||
cat $TMP|sendmail -t -f none@example.com;
|
cat "$TMP"|sendmail -t -f none@example.com;
|
||||||
rm $TMP;
|
rm "$TMP";
|
||||||
|
|
||||||
|
@ -15,15 +15,15 @@ then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
echo "Changing to directory " $SCODOC_DIR/config
|
echo "Changing to directory " "$SCODOC_DIR"/config
|
||||||
cd $SCODOC_DIR/config
|
cd "$SCODOC_DIR"/config || { echo "directory does not exist"; exit 1; }
|
||||||
|
|
||||||
echo "Stopping ScoDoc..."
|
echo "Stopping ScoDoc..."
|
||||||
scodocctl stop
|
scodocctl stop
|
||||||
|
|
||||||
# DROITS
|
# DROITS
|
||||||
echo -n "Verification des droits: proprietaire www-data ? (y/n) [y] "
|
echo -n "Verification des droits: proprietaire www-data ? (y/n) [y] "
|
||||||
read ans
|
read -r ans
|
||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
echo 'changing owner to www-data'
|
echo 'changing owner to www-data'
|
||||||
@ -31,7 +31,7 @@ then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo -n 'Suppression des backups des sources (*~) ? (y/n) [y] '
|
echo -n 'Suppression des backups des sources (*~) ? (y/n) [y] '
|
||||||
read ans
|
read -r ans
|
||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
/bin/rm -f ../*~ ../*/*~
|
/bin/rm -f ../*~ ../*/*~
|
||||||
@ -40,7 +40,7 @@ fi
|
|||||||
|
|
||||||
# SVN
|
# SVN
|
||||||
echo -n "svn update ? (y/n) [y] "
|
echo -n "svn update ? (y/n) [y] "
|
||||||
read ans
|
read -r ans
|
||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
echo 'Updating from SVN...'
|
echo 'Updating from SVN...'
|
||||||
@ -50,7 +50,7 @@ fi
|
|||||||
|
|
||||||
# DEPARTEMENTS (maintenant inutile car dans /var)
|
# DEPARTEMENTS (maintenant inutile car dans /var)
|
||||||
echo -n "Supprimer les (anciennes) configs de departements ? (y/n) [y] "
|
echo -n "Supprimer les (anciennes) configs de departements ? (y/n) [y] "
|
||||||
read ans
|
read -r ans
|
||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
echo "moving " depts/*.cfg "to /tmp"
|
echo "moving " depts/*.cfg "to /tmp"
|
||||||
@ -59,7 +59,7 @@ fi
|
|||||||
|
|
||||||
# .../var/
|
# .../var/
|
||||||
echo -n "Supprimer et recréer .../var (archives, photos, configs, ...) ? (y/n) [y] "
|
echo -n "Supprimer et recréer .../var (archives, photos, configs, ...) ? (y/n) [y] "
|
||||||
read ans
|
read -r ans
|
||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
echo "moving ../../../var/scodoc to /tmp"
|
echo "moving ../../../var/scodoc to /tmp"
|
||||||
@ -73,7 +73,7 @@ fi
|
|||||||
|
|
||||||
# LOGS ZOPE
|
# LOGS ZOPE
|
||||||
echo -n "Effacer les logs de Zope et ScoDoc ? (y/n) [y] "
|
echo -n "Effacer les logs de Zope et ScoDoc ? (y/n) [y] "
|
||||||
read ans
|
read -r ans
|
||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
(cd ../../../log/; ./purge)
|
(cd ../../../log/; ./purge)
|
||||||
@ -81,7 +81,7 @@ fi
|
|||||||
|
|
||||||
# IMAGE Data.fs
|
# IMAGE Data.fs
|
||||||
echo -n "Recopier le Data.fs original ? (y/n) [y] "
|
echo -n "Recopier le Data.fs original ? (y/n) [y] "
|
||||||
read ans
|
read -r ans
|
||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
echo "moving Data.fs to /tmp"
|
echo "moving Data.fs to /tmp"
|
||||||
|
50
config/get_scodoc_version.sh
Executable file
@ -0,0 +1,50 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Get version information
|
||||||
|
# Use VERSION.py, last commit, diff, and last upstream commit date
|
||||||
|
|
||||||
|
|
||||||
|
source config.sh
|
||||||
|
source utils.sh
|
||||||
|
|
||||||
|
# Source code version:
|
||||||
|
x=$(grep SCOVERSION ../VERSION.py) || terminate "can't access VERSION.py" 1
|
||||||
|
x=${x#*\"}
|
||||||
|
src_version=${x%\"*}
|
||||||
|
|
||||||
|
# last commit
|
||||||
|
git_last_commit_hash=$(git log -1 --format=%h)
|
||||||
|
git_last_commit_date=$(git log -1 --format=%ci)
|
||||||
|
|
||||||
|
git_up_commit_hash=$(git log -1 --format=%h origin/ScoDoc8)
|
||||||
|
git_up_commit_date=$(git log -1 --format=%ci origin/ScoDoc8)
|
||||||
|
|
||||||
|
# Check if git has local changes
|
||||||
|
nchanges=$(git status --porcelain | grep -c -v '^??')
|
||||||
|
if [ "$nchanges" -gt 0 ]
|
||||||
|
then
|
||||||
|
has_local_changes="yes"
|
||||||
|
else
|
||||||
|
has_local_changes="no"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Synthetic one-line version:
|
||||||
|
sco_version="$src_version ($git_up_commit_hash) $git_up_commit_date"
|
||||||
|
if [ "$has_local_changes" = "yes" ]
|
||||||
|
then
|
||||||
|
sco_version="$sco_version (modified)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
if [ "$1" = "-s" ]
|
||||||
|
then
|
||||||
|
echo "$sco_version"
|
||||||
|
else
|
||||||
|
echo src_version: "$src_version"
|
||||||
|
echo git_last_commit_hash: "$git_last_commit_hash"
|
||||||
|
echo git_last_commit_date: "$git_last_commit_date"
|
||||||
|
echo git_up_commit_hash: "$git_up_commit_hash"
|
||||||
|
echo git_up_commit_date: "$git_up_commit_date"
|
||||||
|
echo has_local_diffs: "$has_local_changes"
|
||||||
|
echo sco_version: "$sco_version"
|
||||||
|
fi
|
@ -8,15 +8,16 @@
|
|||||||
source config.sh
|
source config.sh
|
||||||
source utils.sh
|
source utils.sh
|
||||||
|
|
||||||
if [ $(id -nu) != $POSTGRES_USER ]
|
if [ "$(id -nu)" != "$POSTGRES_USER" ]
|
||||||
then
|
then
|
||||||
echo "$0: script must be runned as user $POSTGRES_USER"
|
echo "$0: script must be runned as user $POSTGRES_USER"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo 'Initializing tables in database ' $db_name
|
# shellcheck disable=SC2154
|
||||||
$PSQL -U $POSTGRES_USER -p $POSTGRES_PORT $db_name -f $SCODOC_DIR/misc/createtables.sql
|
echo 'Initializing tables in database ' "$db_name"
|
||||||
|
$PSQL -U "$POSTGRES_USER" -p "$POSTGRES_PORT" "$db_name" -f "$SCODOC_DIR"/misc/createtables.sql
|
||||||
|
|
||||||
|
|
||||||
# Set DeptName in preferences:
|
# Set DeptName in preferences:
|
||||||
echo "insert into sco_prefs (name, value) values ('DeptName', '"${DEPT}\'\) | $PSQL -U $POSTGRES_USER -p $POSTGRES_PORT $db_name
|
echo "insert into sco_prefs (name, value) values ('DeptName', '"${DEPT}\'\) | $PSQL -U "$POSTGRES_USER" -p "$POSTGRES_PORT" "$db_name"
|
@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
#
|
#
|
||||||
# ScoDoc: install third-party software necessary for our installation
|
# ScoDoc: install third-party software necessary for our installation
|
||||||
# starting for a minimal Debian (Stretch, 9.0) install.
|
# starting for a minimal Debian (Buster, 10.0) install.
|
||||||
#
|
#
|
||||||
# E. Viennet, Jun 2008, Apr 2009, Sept 2011, Sept 2013, Nov 2013, Mar 2017, Jul 2017, Jun 2019, Oct 2019
|
# E. Viennet, Jun 2008, Apr 2009, Sept 2011, Sept 2013, Nov 2013, Mar 2017, Jul 2017,
|
||||||
|
# Jun 2019, Oct 2019, Dec 2020
|
||||||
#
|
#
|
||||||
|
|
||||||
source config.sh
|
source config.sh
|
||||||
@ -12,16 +13,14 @@ source utils.sh
|
|||||||
|
|
||||||
check_uid_root $0
|
check_uid_root $0
|
||||||
|
|
||||||
PYTHON=/opt/zope213/bin/python
|
|
||||||
|
|
||||||
# ------------ Safety checks
|
# ------------ Safety checks
|
||||||
if [ ${debian_version} != "10" ]
|
if [ "${debian_version}" != "10" ]
|
||||||
then
|
then
|
||||||
echo "Version du systeme Linux Debian incompatible"
|
echo "Version du systeme Linux Debian incompatible"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $(arch) != "x86_64" ]
|
if [ "$(arch)" != "x86_64" ]
|
||||||
then
|
then
|
||||||
echo "Version du systeme Linux Debian incompatible (pas X86 64 bits)"
|
echo "Version du systeme Linux Debian incompatible (pas X86 64 bits)"
|
||||||
exit 1
|
exit 1
|
||||||
@ -29,8 +28,8 @@ fi
|
|||||||
|
|
||||||
# ------------ Permissions & directories
|
# ------------ Permissions & directories
|
||||||
# source dir should be writable by scodoc to write bytecode files
|
# source dir should be writable by scodoc to write bytecode files
|
||||||
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
|
chgrp -R www-data "${SCODOC_VAR_DIR}"/photos
|
||||||
chmod -R g+w "${SCODOC_VAR_DIR}"/photos
|
chmod -R g+w "${SCODOC_VAR_DIR}"/photos
|
||||||
@ -53,8 +52,8 @@ fi
|
|||||||
|
|
||||||
for locname in en_US.UTF-8 en_US.ISO-8859-15 en_US.ISO-8859-1
|
for locname in en_US.UTF-8 en_US.ISO-8859-15 en_US.ISO-8859-1
|
||||||
do
|
do
|
||||||
outname=$(echo ${locname//-/} | tr '[A-Z]' '[a-z]')
|
outname=$(echo ${locname//-/} | tr 'A-Z' 'a-z')
|
||||||
if [ $(locale -a | egrep -i ^${outname}$ | wc -l) -lt 1 ]
|
if [ "$(locale -a | grep -E -i ^${outname}$ | wc -l)" -lt 1 ]
|
||||||
then
|
then
|
||||||
echo adding $locname
|
echo adding $locname
|
||||||
echo "$locname ${locname##*.}" >> /etc/locale.gen
|
echo "$locname ${locname##*.}" >> /etc/locale.gen
|
||||||
@ -86,7 +85,7 @@ apt-get -y install postgresql
|
|||||||
apt-get -y install graphviz
|
apt-get -y install graphviz
|
||||||
|
|
||||||
# ------------ INSTALL DES EXTENSIONS PYTHON (2.7)
|
# ------------ INSTALL DES EXTENSIONS PYTHON (2.7)
|
||||||
|
# XXX to fix: pip in our env
|
||||||
apt-get -y install python-docutils
|
apt-get -y install python-docutils
|
||||||
apt-get -y install python-jaxml
|
apt-get -y install python-jaxml
|
||||||
apt-get -y install python-psycopg2
|
apt-get -y install python-psycopg2
|
||||||
@ -96,20 +95,21 @@ 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
|
||||||
|
|
||||||
|
# XXX to fix: mx not needed anymore !
|
||||||
apt-get -y install python-egenix-mxtools python-egenix-mxdatetime
|
apt-get -y install python-egenix-mxtools python-egenix-mxdatetime
|
||||||
|
|
||||||
|
|
||||||
# ------------
|
# ------------
|
||||||
SVNVERSION=$(cd ..; svnversion)
|
SVNVERSION=$(cd ..; svnversion)
|
||||||
SVERSION=$(curl --silent http://scodoc.iutv.univ-paris13.fr/scodoc-installmgr/version?mode=install\&svn=$SVNVERSION)
|
SVERSION=$(curl --silent http://scodoc.iutv.univ-paris13.fr/scodoc-installmgr/version?mode=install\&svn="$SVNVERSION")
|
||||||
echo $SVERSION > "${SCODOC_VERSION_DIR}/scodoc.sn"
|
echo "$SVERSION" > "${SCODOC_VERSION_DIR}/scodoc.sn"
|
||||||
|
|
||||||
|
|
||||||
# ------------ POSTFIX
|
# ------------ POSTFIX
|
||||||
echo
|
echo
|
||||||
echo "ScoDoc a besoin de pouvoir envoyer des messages par mail."
|
echo "ScoDoc a besoin de pouvoir envoyer des messages par mail."
|
||||||
echo -n "Voulez vous configurer la messagerie (tres recommande) ? (y/n) [y] "
|
echo -n "Voulez vous configurer la messagerie (tres recommande) ? (y/n) [y] "
|
||||||
read ans
|
read -r ans
|
||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
apt-get -y install postfix
|
apt-get -y install postfix
|
||||||
@ -119,7 +119,7 @@ fi
|
|||||||
echo
|
echo
|
||||||
echo "Le firewall aide a proteger votre serveur d'intrusions indesirables."
|
echo "Le firewall aide a proteger votre serveur d'intrusions indesirables."
|
||||||
echo -n "Voulez vous configurer un firewall minimal (ufw) ? (y/n) [n] "
|
echo -n "Voulez vous configurer un firewall minimal (ufw) ? (y/n) [n] "
|
||||||
read ans
|
read -r ans
|
||||||
if [ "$(norm_ans "$ans")" = 'Y' ]
|
if [ "$(norm_ans "$ans")" = 'Y' ]
|
||||||
then
|
then
|
||||||
echo 'Installation du firewall IP ufw (voir documentation Debian)'
|
echo 'Installation du firewall IP ufw (voir documentation Debian)'
|
||||||
@ -144,16 +144,16 @@ a2enmod rewrite
|
|||||||
echo
|
echo
|
||||||
echo "La configuration du serveur web va modifier votre installation Apache pour supporter ScoDoc."
|
echo "La configuration du serveur web va modifier votre installation Apache pour supporter ScoDoc."
|
||||||
echo -n "Voulez vous configurer le serveur web Apache maintenant (tres conseille) ? (y/n) [y] "
|
echo -n "Voulez vous configurer le serveur web Apache maintenant (tres conseille) ? (y/n) [y] "
|
||||||
read ans
|
read -r ans
|
||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
echo "Configuration d'Apache"
|
echo "Configuration d'Apache"
|
||||||
server_name=""
|
server_name=""
|
||||||
while [ -z $server_name ]
|
while [ -z "$server_name" ]
|
||||||
do
|
do
|
||||||
echo "Le nom de votre serveur doit normalement etre connu dans le DNS."
|
echo "Le nom de votre serveur doit normalement etre connu dans le DNS."
|
||||||
echo -n "Nom complet de votre serveur (exemple: notes.univ.fr): "
|
echo -n "Nom complet de votre serveur (exemple: notes.univ.fr): "
|
||||||
read server_name
|
read -r server_name
|
||||||
done
|
done
|
||||||
# --- CERTIFICATS AUTO-SIGNES
|
# --- CERTIFICATS AUTO-SIGNES
|
||||||
echo
|
echo
|
||||||
@ -161,7 +161,7 @@ then
|
|||||||
echo "auto-signes, qui ne seront pas reconnus comme de confiance"
|
echo "auto-signes, qui ne seront pas reconnus comme de confiance"
|
||||||
echo "par les navigateurs, mais offrent une certaine securite."
|
echo "par les navigateurs, mais offrent une certaine securite."
|
||||||
echo -n 'Voulez vous generer des certificats ssl auto-signes ? (y/n) [y] '
|
echo -n 'Voulez vous generer des certificats ssl auto-signes ? (y/n) [y] '
|
||||||
read ans
|
read -r ans
|
||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
# attention: utilise dans scodoc-site-ssl.orig
|
# attention: utilise dans scodoc-site-ssl.orig
|
||||||
@ -177,7 +177,7 @@ then
|
|||||||
fi
|
fi
|
||||||
# ---
|
# ---
|
||||||
echo 'generation de /etc/apache2/sites-available/scodoc-site-ssl'
|
echo 'generation de /etc/apache2/sites-available/scodoc-site-ssl'
|
||||||
cat $SCODOC_DIR/config/etc/scodoc-site-ssl-apache2.4.orig | sed -e "s:YOUR\.FULL\.HOST\.NAME:$server_name:g" > /etc/apache2/sites-available/scodoc-site-ssl.conf
|
cat "$SCODOC_DIR"/config/etc/scodoc-site-ssl-apache2.4.orig | sed -e "s:YOUR\.FULL\.HOST\.NAME:$server_name:g" > /etc/apache2/sites-available/scodoc-site-ssl.conf
|
||||||
echo 'activation du site...'
|
echo 'activation du site...'
|
||||||
a2ensite scodoc-site-ssl
|
a2ensite scodoc-site-ssl
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ then
|
|||||||
then
|
then
|
||||||
mv $fn $fn.bak
|
mv $fn $fn.bak
|
||||||
fi
|
fi
|
||||||
cp $SCODOC_DIR/config/etc/scodoc-site.orig $fn
|
cp "$SCODOC_DIR"/config/etc/scodoc-site.orig $fn
|
||||||
|
|
||||||
if [ -z "$(grep Listen /etc/apache2/ports.conf | grep 443)" ]
|
if [ -z "$(grep Listen /etc/apache2/ports.conf | grep 443)" ]
|
||||||
then
|
then
|
||||||
@ -221,7 +221,7 @@ 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)'
|
echo 'Installation du demarrage automatique de ScoDoc (systemd)'
|
||||||
cp $SCODOC_DIR/config/etc/scodoc.service /etc/systemd/system
|
cp "$SCODOC_DIR"/config/etc/scodoc.service /etc/systemd/system
|
||||||
systemctl enable scodoc.service
|
systemctl enable scodoc.service
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -232,8 +232,8 @@ echo -n "Mises a jour hebdomadaires (tres recommande) ? (y/n) [y] "
|
|||||||
read ans
|
read ans
|
||||||
if [ "$(norm_ans "$ans")" != 'N' ]
|
if [ "$(norm_ans "$ans")" != 'N' ]
|
||||||
then
|
then
|
||||||
cp $SCODOC_DIR/config/etc/scodoc-updater.service /etc/systemd/system
|
cp "$SCODOC_DIR"/config/etc/scodoc-updater.service /etc/systemd/system
|
||||||
cp $SCODOC_DIR/config/etc/scodoc-updater.timer /etc/systemd/system
|
cp "$SCODOC_DIR"/config/etc/scodoc-updater.timer /etc/systemd/system
|
||||||
systemctl enable scodoc-updater.timer
|
systemctl enable scodoc-updater.timer
|
||||||
systemctl start scodoc-updater.timer
|
systemctl start scodoc-updater.timer
|
||||||
fi
|
fi
|
||||||
|
0
config/migre-7-a-8.sh
Normal file → Executable file
@ -8,7 +8,7 @@ PG_DUMPFILE=$1
|
|||||||
# Check locale of installation. If invalid, reinitialize all system
|
# Check locale of installation. If invalid, reinitialize all system
|
||||||
|
|
||||||
is_latin1=$(psql -l | grep postgres | grep iso88591 | wc -l)
|
is_latin1=$(psql -l | grep postgres | grep iso88591 | wc -l)
|
||||||
if [ $is_latin1 -gt 1 ]
|
if [ "$is_latin1" -gt 1 ]
|
||||||
then
|
then
|
||||||
echo "Recreating postgres cluster using UTF-8"
|
echo "Recreating postgres cluster using UTF-8"
|
||||||
|
|
||||||
@ -20,8 +20,8 @@ fi
|
|||||||
|
|
||||||
# Drop all current ScoDoc databases, if any:
|
# Drop all current ScoDoc databases, if any:
|
||||||
for f in $(psql -l --no-align --field-separator . | grep SCO | cut -f 1 -d.); do
|
for f in $(psql -l --no-align --field-separator . | grep SCO | cut -f 1 -d.); do
|
||||||
echo dropping $f
|
echo dropping "$f"
|
||||||
dropdb $f
|
dropdb "$f"
|
||||||
done
|
done
|
||||||
echo "Restoring postgres data..."
|
echo "Restoring postgres data..."
|
||||||
psql -f "$PG_DUMPFILE" postgres
|
psql -f "$PG_DUMPFILE" postgres
|
||||||
|
@ -57,7 +57,7 @@ then
|
|||||||
echo "Opening tgz archive..."
|
echo "Opening tgz archive..."
|
||||||
tmp=$(mktemp -d)
|
tmp=$(mktemp -d)
|
||||||
chmod a+rx "$tmp"
|
chmod a+rx "$tmp"
|
||||||
cd "$tmp" || terminate "directory error"
|
cd "$tmp" || { echo "Fatal error: directory not available"; exit 1; }
|
||||||
tar xfz "$SRC"
|
tar xfz "$SRC"
|
||||||
SRC=$(ls -1d "$tmp"/*)
|
SRC=$(ls -1d "$tmp"/*)
|
||||||
IS_TMP=1
|
IS_TMP=1
|
||||||
@ -83,18 +83,18 @@ su -c "$SCODOC_DIR/config/psql_restore_databases.sh $PG_DUMPFILE" postgres
|
|||||||
#
|
#
|
||||||
echo Copying data files...
|
echo Copying data files...
|
||||||
|
|
||||||
rm -rf "${INSTANCE_DIR:?}/var"
|
rm -rf "$INSTANCE_DIR/var"
|
||||||
$COPY "$SRC/var" "$INSTANCE_DIR"
|
$COPY "$SRC/var" "$INSTANCE_DIR"
|
||||||
|
|
||||||
if [ ! -e "${SCODOC_VAR_DIR:?}/config/" ]
|
if [ ! -e "${SCODOC_VAR_DIR}/config/" ]
|
||||||
then
|
then
|
||||||
mkdir "${SCODOC_VAR_DIR:?}/config/"
|
mkdir "${SCODOC_VAR_DIR}/config/"
|
||||||
chown www-data.www-data "${SCODOC_VAR_DIR:?}/config/"
|
chown www-data.www-data "${SCODOC_VAR_DIR}/config/"
|
||||||
chmod 775 "${SCODOC_VAR_DIR:?}/config/"
|
chmod 775 "${SCODOC_VAR_DIR}/config/"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -rf "${SCODOC_DIR:?}/config/depts"
|
rm -rf "$SCODOC_DIR/config/depts"
|
||||||
if [ -e "${SRC:?}/depts" ]
|
if [ -e "$SRC/depts" ]
|
||||||
then
|
then
|
||||||
# legacy depts => move them to var
|
# legacy depts => move them to var
|
||||||
$COPY "$SRC/depts" "${SCODOC_VAR_DIR}/config/"
|
$COPY "$SRC/depts" "${SCODOC_VAR_DIR}/config/"
|
||||||
@ -107,7 +107,7 @@ then
|
|||||||
$COPY "$SRC/photos" "${SCODOC_VAR_DIR}/"
|
$COPY "$SRC/photos" "${SCODOC_VAR_DIR}/"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -rf "${SCODOC_DIR:?}/logos"
|
rm -rf "$SCODOC_DIR/logos"
|
||||||
$COPY "$SRC/logos" "$SCODOC_DIR/"
|
$COPY "$SRC/logos" "$SCODOC_DIR/"
|
||||||
|
|
||||||
mv "$SCODOC_DIR/config/scodoc_config.py" "$SCODOC_DIR/config/scodoc_config.py.$(date +%Y%m%d-%H%M%S)"
|
mv "$SCODOC_DIR/config/scodoc_config.py" "$SCODOC_DIR/config/scodoc_config.py.$(date +%Y%m%d-%H%M%S)"
|
||||||
@ -119,7 +119,7 @@ then
|
|||||||
iconv -f iso8859-15 -t utf-8 "$SCODOC_DIR/config/scodoc_config.py.orig" > "$SCODOC_DIR/config/scodoc_config.py"
|
iconv -f iso8859-15 -t utf-8 "$SCODOC_DIR/config/scodoc_config.py.orig" > "$SCODOC_DIR/config/scodoc_config.py"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -rf "${INSTANCE_DIR:?}/log"
|
rm -rf "$INSTANCE_DIR/log"
|
||||||
$COPY "$SRC/log" "$INSTANCE_DIR/"
|
$COPY "$SRC/log" "$INSTANCE_DIR/"
|
||||||
|
|
||||||
# Fix file ownership and access rights
|
# Fix file ownership and access rights
|
||||||
@ -130,13 +130,13 @@ chown -R www-data.root "$SCODOC_DIR"
|
|||||||
chmod -R 775 "$SCODOC_DIR"
|
chmod -R 775 "$SCODOC_DIR"
|
||||||
|
|
||||||
# Remove tmp directory
|
# Remove tmp directory
|
||||||
if [ "$IS_TMP" = "1" ]
|
if [ $IS_TMP = "1" ]
|
||||||
then
|
then
|
||||||
rm -rf "${tmp}"
|
rm -rf "$tmp"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Mise a jour BD ScoDoc
|
# Mise a jour BD ScoDoc
|
||||||
cd ${SCODOC_DIR:?}/config || terminate "no config directory"
|
cd "$SCODOC_DIR"/config || { echo "Fatal error: invalid directory"; exit 2; }
|
||||||
./upgrade.sh
|
./upgrade.sh
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#
|
#
|
||||||
source utils.sh
|
source utils.sh
|
||||||
|
|
||||||
|
check_uid_root "$0"
|
||||||
|
|
||||||
# Destination directory
|
# Destination directory
|
||||||
if [ ! $# -eq 1 ]
|
if [ ! $# -eq 1 ]
|
||||||
then
|
then
|
||||||
@ -34,9 +36,6 @@ fi
|
|||||||
INSTANCE_DIR=/opt/scodoc
|
INSTANCE_DIR=/opt/scodoc
|
||||||
SCODOC_DIR="$INSTANCE_DIR/Products/ScoDoc"
|
SCODOC_DIR="$INSTANCE_DIR/Products/ScoDoc"
|
||||||
|
|
||||||
source utils.sh
|
|
||||||
check_uid_root "$0"
|
|
||||||
|
|
||||||
echo "Stopping ScoDoc..."
|
echo "Stopping ScoDoc..."
|
||||||
scodocctl stop
|
scodocctl stop
|
||||||
|
|
||||||
@ -44,9 +43,9 @@ scodocctl stop
|
|||||||
echo "Dumping SQL database..."
|
echo "Dumping SQL database..."
|
||||||
chown postgres "$DEST"
|
chown postgres "$DEST"
|
||||||
su -c "pg_dumpall > \"$DEST\"/scodoc.dump.txt" postgres
|
su -c "pg_dumpall > \"$DEST\"/scodoc.dump.txt" postgres
|
||||||
if [ ! "$?" -eq 0 ]
|
if [ ! $? -eq 0 ]
|
||||||
then
|
then
|
||||||
printf "Error dumping postgresql database\nPlease check that SQL server is running\nAborting."
|
printf "Error dumping postgresql database\nPlease check that SQL server is running\nAborting.\n"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
chown root "$DEST"
|
chown root "$DEST"
|
||||||
@ -86,6 +85,6 @@ cp -rp "$INSTANCE_DIR/log" "$DEST"
|
|||||||
echo
|
echo
|
||||||
echo "Archiving backup files in a $DEST.tgz..."
|
echo "Archiving backup files in a $DEST.tgz..."
|
||||||
base=$(basename "$DEST")
|
base=$(basename "$DEST")
|
||||||
(cd "$DEST"/.. || terminate "directory error"; tar cfz "$DEST".tgz "$base")
|
(cd "$DEST"/..; tar cfz "$DEST".tgz "$base")
|
||||||
|
|
||||||
echo "Done (you can copy " "$DEST"".tgz to destination machine)."
|
echo "Done (you can copy " "$DEST"".tgz to destination machine)."
|
||||||
|
128
config/scodoc_config_tmpl.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#
|
||||||
|
# Configuration globale de ScoDoc (version juin 2009)
|
||||||
|
# Ce fichier est copié dans /opt/scodoc/var/scodoc/config
|
||||||
|
# par les scripts d'installation/mise à jour.
|
||||||
|
|
||||||
|
# La plupart des réglages sont stoqués en base de donnée et accessibles via le web
|
||||||
|
# (pages de paramètres ou préférences).
|
||||||
|
# Les valeurs indiquées ici sont les valeurs initiales que prendront
|
||||||
|
# les paramètres lors de la création d'un nouveau département,
|
||||||
|
# elles ne sont plus utilisées ensuite.
|
||||||
|
|
||||||
|
# Nota: il y a aussi des réglages dans sco_utils.py, mais ils nécessitent
|
||||||
|
# souvent de comprendre le code qui les utilise pour ne pas faire d'erreur: attention.
|
||||||
|
|
||||||
|
|
||||||
|
class CFG:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG = CFG()
|
||||||
|
|
||||||
|
# set to 1 if you want to require INE:
|
||||||
|
# CONFIG.always_require_ine = 0
|
||||||
|
|
||||||
|
# The base URL, use only if you are behind a proxy
|
||||||
|
# eg "https://scodoc.example.net/ScoDoc"
|
||||||
|
# CONFIG.ABSOLUTE_URL = ""
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# -------------- Documents PDF
|
||||||
|
# -----------------------------------------------------
|
||||||
|
|
||||||
|
# Taille du l'image logo: largeur/hauteur (ne pas oublier le . !!!)
|
||||||
|
# W/H XXX provisoire: utilisera PIL pour connaitre la taille de l'image
|
||||||
|
# CONFIG.LOGO_FOOTER_ASPECT = 326 / 96.0
|
||||||
|
# Taille dans le document en millimetres
|
||||||
|
# CONFIG.LOGO_FOOTER_HEIGHT = 10
|
||||||
|
# Proportions logo (donné ici pour IUTV)
|
||||||
|
# CONFIG.LOGO_HEADER_ASPECT = 549 / 346.0
|
||||||
|
# Taille verticale dans le document en millimetres
|
||||||
|
# CONFIG.LOGO_HEADER_HEIGHT = 28
|
||||||
|
|
||||||
|
# Pied de page PDF : un format Python, %(xxx)s est remplacé par la variable xxx.
|
||||||
|
# Les variables définies sont:
|
||||||
|
# day : Day of the month as a decimal number [01,31]
|
||||||
|
# month : Month as a decimal number [01,12].
|
||||||
|
# year : Year without century as a decimal number [00,99].
|
||||||
|
# Year : Year with century as a decimal number.
|
||||||
|
# hour : Hour (24-hour clock) as a decimal number [00,23].
|
||||||
|
# minute: Minute as a decimal number [00,59].
|
||||||
|
#
|
||||||
|
# server_url: URL du serveur ScoDoc
|
||||||
|
# scodoc_name: le nom du logiciel (ScoDoc actuellement, voir VERSION.py)
|
||||||
|
|
||||||
|
# CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s"
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# ------------- Calcul bonus modules optionnels (sport, culture...) -------------
|
||||||
|
#
|
||||||
|
|
||||||
|
# CONFIG.compute_bonus = bonus_sport.bonus_iutv
|
||||||
|
# Mettre "bonus_demo" pour logguer des informations utiles au developpement...
|
||||||
|
|
||||||
|
#
|
||||||
|
# ------------- Capitalisation des UEs -------------
|
||||||
|
# Deux écoles:
|
||||||
|
# - règle "DUT": capitalisation des UE obtenues avec moyenne UE >= 10 ET de toutes les UE
|
||||||
|
# des semestres validés (ADM, ADC, AJ). (conforme à l'arrêté d'août 2005)
|
||||||
|
#
|
||||||
|
# - règle "LMD": capitalisation uniquement des UE avec moy. > 10
|
||||||
|
|
||||||
|
# Si vrai, capitalise toutes les UE des semestres validés (règle "DUT").
|
||||||
|
# CONFIG.CAPITALIZE_ALL_UES = True
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------
|
||||||
|
#
|
||||||
|
# -------------- Personnalisation des pages
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# Nom (chemin complet) d'un fichier .html à inclure juste après le <body>
|
||||||
|
# le <body> des pages ScoDoc
|
||||||
|
# CONFIG.CUSTOM_HTML_HEADER = ""
|
||||||
|
|
||||||
|
# Fichier html a inclure en fin des pages (juste avant le </body>)
|
||||||
|
# CONFIG.CUSTOM_HTML_FOOTER = ""
|
||||||
|
|
||||||
|
# Fichier .html à inclure dans la pages connexion/déconnexion (accueil)
|
||||||
|
# si on veut que ce soit différent (par défaut la même chose)
|
||||||
|
# CONFIG.CUSTOM_HTML_HEADER_CNX = CONFIG.CUSTOM_HTML_HEADER
|
||||||
|
# CONFIG.CUSTOM_HTML_FOOTER_CNX = CONFIG.CUSTOM_HTML_FOOTER
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# -------------- Noms de Lycées
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# Fichier de correspondance codelycee -> noms
|
||||||
|
# (chemin relatif au repertoire d'install des sources)
|
||||||
|
# CONFIG.ETABL_FILENAME = "config/etablissements.csv"
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------
|
||||||
|
# -------------- Divers:
|
||||||
|
# ----------------------------------------------------
|
||||||
|
# True for UCAC (étudiants camerounais sans prénoms)
|
||||||
|
# CONFIG.ALLOW_NULL_PRENOM = False
|
||||||
|
|
||||||
|
# Taille max des fichiers archive etudiants (en octets)
|
||||||
|
# CONFIG.ETUD_MAX_FILE_SIZE = 10 * 1024 * 1024
|
||||||
|
|
||||||
|
# Si pas de photo et portail, publie l'url (était vrai jusqu'en oct 2016)
|
||||||
|
# CONFIG.PUBLISH_PORTAL_PHOTO_URL = False
|
||||||
|
|
||||||
|
# Si > 0: longueur minimale requise des nouveaux mots de passe
|
||||||
|
# (le test cracklib.FascistCheck s'appliquera dans tous les cas)
|
||||||
|
# CONFIG.MIN_PASSWORD_LENGTH = 0
|
||||||
|
|
||||||
|
|
||||||
|
# Ce dictionnaire est fusionné à celui de sco_codes_parcours
|
||||||
|
# pour définir les codes jury et explications associées
|
||||||
|
# CONFIG.CODES_EXPL = {
|
||||||
|
# # AJ : 'Ajourné (échec)',
|
||||||
|
# }
|
@ -4,7 +4,7 @@
|
|||||||
# ScoDoc: reglage du mot de passe admin Zope
|
# ScoDoc: reglage du mot de passe admin Zope
|
||||||
# (in Zope terminology, an emergency user)
|
# (in Zope terminology, an emergency user)
|
||||||
#
|
#
|
||||||
# Doit être lancé par l'utilisateur unix root dans le repertoire .../config
|
# Doit <EFBFBD>tre lanc<6E> par l'utilisateur unix root dans le repertoire .../config
|
||||||
# ^^^^^^^^^^^^^^^^^^^^^
|
# ^^^^^^^^^^^^^^^^^^^^^
|
||||||
# E. Viennet, Juin 2008, Jul 2019
|
# E. Viennet, Juin 2008, Jul 2019
|
||||||
#
|
#
|
||||||
@ -22,14 +22,14 @@ fi
|
|||||||
echo "Creation d'un utilisateur d'urgence pour ScoDoc"
|
echo "Creation d'un utilisateur d'urgence pour ScoDoc"
|
||||||
echo "(utile en cas de perte de votre mot de passe admin)"
|
echo "(utile en cas de perte de votre mot de passe admin)"
|
||||||
|
|
||||||
if [ ${debian_version} != "10" ]
|
if [ "${debian_version}" != "10" ]
|
||||||
then
|
then
|
||||||
mdir=/opt/zope213/lib/python2.7/site-packages/Zope2-2.13.21-py2.7.egg/Zope2/utilities
|
mdir=/opt/zope213/lib/python2.7/site-packages/Zope2-2.13.21-py2.7.egg/Zope2/utilities
|
||||||
else
|
else
|
||||||
mdir=/opt/zope213/lib/python2.7/site-packages/Zope2/utilities
|
mdir=/opt/zope213/lib/python2.7/site-packages/Zope2/utilities
|
||||||
fi
|
fi
|
||||||
|
|
||||||
python $mdir/zpasswd.py $SCODOC_DIR/../../access
|
python $mdir/zpasswd.py "$SCODOC_DIR"/../../access
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "redemarrer scodoc pour prendre en compte le mot de passe"
|
echo "redemarrer scodoc pour prendre en compte le mot de passe"
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Upgrade ScoDoc installation using SVN
|
# Upgrade ScoDoc installation using GIT
|
||||||
# SVN must be properly configured and have read access to ScoDoc repository
|
# GIT must be properly configured and have read access to ScoDoc repository
|
||||||
# This script STOP and RESTART ScoDoc and should be runned as root
|
# This script STOP and RESTART ScoDoc and should be runned as root
|
||||||
#
|
#
|
||||||
# Upgrade also the Linux system using apt.
|
# Upgrade also the Linux system using apt.
|
||||||
#
|
#
|
||||||
# Script for ScoDoc 7 (Debian 7, 8, 9, 10)
|
# Script for ScoDoc 8 (10)
|
||||||
#
|
#
|
||||||
# E. Viennet, sep 2013, mar 2017, jun 2019, aug 2020
|
# E. Viennet, sep 2013, mar 2017, jun 2019, aug 2020, dec 2020
|
||||||
|
|
||||||
cd /opt/scodoc/Products/ScoDoc/config
|
cd /opt/scodoc/Products/ScoDoc/config || { echo "Invalid directory"; exit 1; }
|
||||||
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
|
||||||
@ -31,8 +31,8 @@ fi
|
|||||||
scodocctl stop
|
scodocctl stop
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Using SVN to update $SCODOC_DIR..."
|
echo "Using git to update $SCODOC_DIR..."
|
||||||
(cd "$SCODOC_DIR"; svn update)
|
(cd "$SCODOC_DIR"; git checkout ScoDoc8; git pull origin master)
|
||||||
|
|
||||||
SVNVERSION=$(cd ..; svnversion)
|
SVNVERSION=$(cd ..; svnversion)
|
||||||
|
|
||||||
@ -72,13 +72,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
|
||||||
@ -118,6 +118,19 @@ if [ $? -ne 0 ]
|
|||||||
then
|
then
|
||||||
/opt/zope213/bin/pip install requests
|
/opt/zope213/bin/pip install requests
|
||||||
fi
|
fi
|
||||||
|
/opt/zope213/bin/python -c "import attrdict" >& /dev/null
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
/opt/zope213/bin/pip install attrdict
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check that local configuration file is installed
|
||||||
|
LOCAL_CONFIG_FILENAME="/opt/scodoc/var/scodoc/config/scodoc_local.py"
|
||||||
|
if [ ! -e "$LOCAL_CONFIG_FILENAME" ]
|
||||||
|
then
|
||||||
|
cp "$SCODOC_DIR"/config/scodoc_config_tmpl.py "$LOCAL_CONFIG_FILENAME"
|
||||||
|
chmod 600 "$LOCAL_CONFIG_FILENAME"
|
||||||
|
fi
|
||||||
|
|
||||||
# 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 +141,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
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
# Misc utilities for ScoDoc install shell scripts
|
# Misc utilities for ScoDoc install shell scripts
|
||||||
|
|
||||||
to_lower() {
|
to_lower() {
|
||||||
echo $1 | tr "[:upper:]" "[:lower:]"
|
echo "$1" | tr "[:upper:]" "[:lower:]"
|
||||||
}
|
}
|
||||||
|
|
||||||
to_upper() {
|
to_upper() {
|
||||||
echo $1 | tr "[:lower:]" "[:upper:]"
|
echo "$1" | tr "[:lower:]" "[:upper:]"
|
||||||
}
|
}
|
||||||
|
|
||||||
norm_ans() {
|
norm_ans() {
|
||||||
x=$(to_upper $1 | tr O Y)
|
x=$(to_upper "$1" | tr O Y)
|
||||||
echo ${x:0:1}
|
echo "${x:0:1}"
|
||||||
}
|
}
|
||||||
|
|
||||||
check_uid_root() {
|
check_uid_root() {
|
||||||
@ -23,10 +23,11 @@ check_uid_root() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
terminate() {
|
terminate() {
|
||||||
|
status=${2:-1} # default: exit 1
|
||||||
echo
|
echo
|
||||||
echo "Erreur: $1"
|
echo "Erreur: $1"
|
||||||
echo
|
echo
|
||||||
exit 1
|
exit $status
|
||||||
}
|
}
|
||||||
|
|
||||||
# Start/stop scodoc, using sysv or systemd
|
# Start/stop scodoc, using sysv or systemd
|
||||||
@ -44,7 +45,7 @@ scodocctl() {
|
|||||||
systemctl $1 scodoc
|
systemctl $1 scodoc
|
||||||
else
|
else
|
||||||
echo "(using legacy SystemV)"
|
echo "(using legacy SystemV)"
|
||||||
/etc/init.d/scodoc $1
|
/etc/init.d/scodoc "$1"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ init_postgres_user() { # run as root
|
|||||||
then
|
then
|
||||||
# add database user
|
# add database user
|
||||||
echo "Creating postgresql user $POSTGRES_USER"
|
echo "Creating postgresql user $POSTGRES_USER"
|
||||||
su -c "createuser -p $POSTGRES_PORT --no-superuser --no-createdb --no-adduser --no-createrole ${POSTGRES_USER}" $POSTGRES_SUPERUSER
|
su -c "createuser -p $POSTGRES_PORT --no-superuser --no-createdb --no-adduser --no-createrole ${POSTGRES_USER}" "$POSTGRES_SUPERUSER"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,8 +70,8 @@ gen_passwd() {
|
|||||||
password=""
|
password=""
|
||||||
while [ "$n" -le "$PASSWORD_LENGTH" ]
|
while [ "$n" -le "$PASSWORD_LENGTH" ]
|
||||||
do
|
do
|
||||||
password="$password${ALLOWABLE_ASCII:$(($RANDOM%${#ALLOWABLE_ASCII})):1}"
|
password="$password${ALLOWABLE_ASCII:$((RANDOM%${#ALLOWABLE_ASCII})):1}"
|
||||||
n=$((n+1))
|
n=$((n+1))
|
||||||
done
|
done
|
||||||
echo $password
|
echo "$password"
|
||||||
}
|
}
|
||||||
|
6
debug.py
@ -31,8 +31,6 @@ nt = context.Notes._getNotesCache().get_NotesTable(context.Notes, formsemestre_i
|
|||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import pdb
|
|
||||||
|
|
||||||
from notesdb import *
|
from notesdb import *
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
from sco_utils import *
|
from sco_utils import *
|
||||||
@ -80,9 +78,6 @@ class FakeUser:
|
|||||||
def has_permission(self, op, context):
|
def has_permission(self, op, context):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def has_role(self, role):
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class DummyResponse:
|
class DummyResponse:
|
||||||
"""Emulation vide de Reponse http Zope"""
|
"""Emulation vide de Reponse http Zope"""
|
||||||
@ -109,7 +104,6 @@ class DummyRequest:
|
|||||||
self.URL1 = self.URL
|
self.URL1 = self.URL
|
||||||
self.URL0 = self.URL
|
self.URL0 = self.URL
|
||||||
self.BASE0 = "localhost"
|
self.BASE0 = "localhost"
|
||||||
self.REMOTE_HOST = "localhost"
|
|
||||||
self.REMOTE_ADDR = "127.0.0.1"
|
self.REMOTE_ADDR = "127.0.0.1"
|
||||||
self.HTTP_REFERER = ""
|
self.HTTP_REFERER = ""
|
||||||
self.REQUEST_METHOD = "get"
|
self.REQUEST_METHOD = "get"
|
||||||
|
@ -394,7 +394,7 @@ CREATE TABLE notes_formsemestre (
|
|||||||
elt_annee_apo text -- code element annee Apogee, eg VRT1A ou V2INLA,V2INCA
|
elt_annee_apo text -- code element annee Apogee, eg VRT1A ou V2INLA,V2INCA
|
||||||
) WITH OIDS;
|
) WITH OIDS;
|
||||||
|
|
||||||
-- id des utilisateurs responsables (aka directeurs des etudes) du semestre:
|
-- id des utilsateurs responsables (aka directeurs des etudes) du semestre:
|
||||||
CREATE TABLE notes_formsemestre_responsables (
|
CREATE TABLE notes_formsemestre_responsables (
|
||||||
formsemestre_id text REFERENCES notes_formsemestre(formsemestre_id) ON DELETE CASCADE,
|
formsemestre_id text REFERENCES notes_formsemestre(formsemestre_id) ON DELETE CASCADE,
|
||||||
responsable_id text NOT NULL,
|
responsable_id text NOT NULL,
|
||||||
|
@ -51,5 +51,5 @@ telephone; text; adresse; 1; num. telephone (fixe)
|
|||||||
telephonemobile; text; adresse; 1; num. telephone (mobile)
|
telephonemobile; text; adresse; 1; num. telephone (mobile)
|
||||||
#
|
#
|
||||||
# Pas tout à fait admission:
|
# Pas tout à fait admission:
|
||||||
debouche;text; admissions;1;(OBSOLETE, ne plus utiliser) situation APRES être passé par chez nous;
|
debouche;text; admissions;1;situation APRES être passé par chez nous;
|
||||||
|
|
||||||
|
11
notes_log.py
@ -2,10 +2,11 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import pdb, os, sys, time, re, inspect
|
import pdb, os, sys, time, re, inspect
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
|
||||||
from email.MIMEText import MIMEText
|
|
||||||
from email.Header import Header
|
|
||||||
import traceback
|
import traceback
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from email.mime.base import MIMEBase
|
||||||
|
from email.header import Header
|
||||||
|
|
||||||
# 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)
|
||||||
@ -34,7 +35,7 @@ class _logguer:
|
|||||||
if LOG_FILENAME:
|
if LOG_FILENAME:
|
||||||
path = os.path.join(self.directory, LOG_FILENAME)
|
path = os.path.join(self.directory, LOG_FILENAME)
|
||||||
self.file = open(path, "a")
|
self.file = open(path, "a")
|
||||||
self("new _logguer (%s)" % path)
|
self("new _logguer")
|
||||||
else:
|
else:
|
||||||
self.file = None # logging disabled
|
self.file = None # logging disabled
|
||||||
|
|
||||||
@ -88,7 +89,7 @@ def retreive_dept():
|
|||||||
return ""
|
return ""
|
||||||
try:
|
try:
|
||||||
url = REQUEST.URL
|
url = REQUEST.URL
|
||||||
m = re.match("^.*ScoDoc/(\w+).*$", url)
|
m = re.match(r"^.*ScoDoc/(\w+).*$", url)
|
||||||
return m.group(1)
|
return m.group(1)
|
||||||
except:
|
except:
|
||||||
return ""
|
return ""
|
||||||
|
@ -248,7 +248,8 @@ def DBDelete(cnx, table, colid, val, commit=False):
|
|||||||
|
|
||||||
|
|
||||||
class EditableTable:
|
class EditableTable:
|
||||||
"""--- generic class: SQL table with create/edit/list/delete"""
|
""" --- generic class: SQL table with create/edit/list/delete
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -376,11 +377,7 @@ class EditableTable:
|
|||||||
# format value
|
# format value
|
||||||
for title in vals.keys():
|
for title in vals.keys():
|
||||||
if self.input_formators.has_key(title):
|
if self.input_formators.has_key(title):
|
||||||
try:
|
vals[title] = self.input_formators[title](vals[title])
|
||||||
vals[title] = self.input_formators[title](vals[title])
|
|
||||||
except:
|
|
||||||
log("exception while converting %s=%s" % (title, vals[title]))
|
|
||||||
raise
|
|
||||||
DBUpdateArgs(
|
DBUpdateArgs(
|
||||||
cnx,
|
cnx,
|
||||||
self.table_name,
|
self.table_name,
|
||||||
|
@ -50,7 +50,7 @@ DONNEE_MANQUANTE = (
|
|||||||
# ----------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------
|
||||||
def get_code_latex_from_modele(fichier):
|
def get_code_latex_from_modele(fichier):
|
||||||
"""Lit le code latex à partir d'un modèle. Renvoie une chaine unicode.
|
"""Lit le code latex à partir d'un modèle. Renvoie une chaine unicode.
|
||||||
|
|
||||||
Le fichier doit contenir le chemin relatif
|
Le fichier doit contenir le chemin relatif
|
||||||
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)
|
||||||
@ -85,7 +85,7 @@ def get_tags_latex(code_latex):
|
|||||||
à la lecture d'un modèle d'avis pe).
|
à la lecture d'un modèle d'avis pe).
|
||||||
Ces tags sont répérés par les balises **, débutant et finissant le tag
|
Ces tags sont répérés par les balises **, débutant et finissant le tag
|
||||||
et sont renvoyés sous la forme d'une liste.
|
et sont renvoyés sous la forme d'une liste.
|
||||||
|
|
||||||
result: liste de chaines unicode
|
result: liste de chaines unicode
|
||||||
"""
|
"""
|
||||||
if code_latex:
|
if code_latex:
|
||||||
@ -144,7 +144,7 @@ def comp_latex_parcourstimeline(etudiant, promo, taille=17):
|
|||||||
|
|
||||||
# ----------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------
|
||||||
def interprete_tag_latex(tag):
|
def interprete_tag_latex(tag):
|
||||||
"""Découpe les tags latex de la forme S1:groupe:dut:min et renvoie si possible
|
"""Découpe les tags latex de la forme S1:groupe:dut:min et renvoie si possible
|
||||||
le résultat sous la forme d'un quadruplet.
|
le résultat sous la forme d'un quadruplet.
|
||||||
"""
|
"""
|
||||||
infotag = tag.split(":")
|
infotag = tag.split(":")
|
||||||
@ -164,7 +164,7 @@ def get_code_latex_avis_etudiant(
|
|||||||
donnees_etudiant, un_avis_latex, annotationPE, footer_latex, prefs
|
donnees_etudiant, un_avis_latex, annotationPE, footer_latex, prefs
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Renvoie le code latex permettant de générer l'avis d'un étudiant en utilisant ses
|
Renvoie le code latex permettant de générer l'avis d'un étudiant en utilisant ses
|
||||||
donnees_etudiant contenu dans le dictionnaire de synthèse du jury PE et en suivant un
|
donnees_etudiant contenu dans le dictionnaire de synthèse du jury PE et en suivant un
|
||||||
fichier modele donné
|
fichier modele donné
|
||||||
|
|
||||||
@ -228,8 +228,8 @@ def get_code_latex_avis_etudiant(
|
|||||||
|
|
||||||
# ----------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------
|
||||||
def get_annotation_PE(context, etudid, tag_annotation_pe):
|
def get_annotation_PE(context, etudid, tag_annotation_pe):
|
||||||
"""Renvoie l'annotation PE dans la liste de ces annotations ;
|
"""Renvoie l'annotation PE dans la liste de ces annotations ;
|
||||||
Cette annotation est reconnue par la présence d'un tag **PE**
|
Cette annotation est reconnue par la présence d'un tag **PE**
|
||||||
(cf. context.get_preferences -> pe_tag_annotation_avis_latex).
|
(cf. context.get_preferences -> pe_tag_annotation_avis_latex).
|
||||||
|
|
||||||
Result: chaine unicode
|
Result: chaine unicode
|
||||||
@ -269,8 +269,8 @@ def get_annotation_PE(context, etudid, tag_annotation_pe):
|
|||||||
|
|
||||||
# ----------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------
|
||||||
def str_from_syntheseJury(donnees_etudiant, aggregat, groupe, tag_scodoc, champ):
|
def str_from_syntheseJury(donnees_etudiant, aggregat, groupe, tag_scodoc, champ):
|
||||||
"""Extrait du dictionnaire de synthèse du juryPE pour un étudiant donnée,
|
"""Extrait du dictionnaire de synthèse du juryPE pour un étudiant donnée,
|
||||||
une valeur indiquée par un champ ;
|
une valeur indiquée par un champ ;
|
||||||
si champ est une liste, renvoie la liste des valeurs extraites.
|
si champ est une liste, renvoie la liste des valeurs extraites.
|
||||||
|
|
||||||
Result: chaine unicode ou liste de chaines unicode
|
Result: chaine unicode ou liste de chaines unicode
|
||||||
@ -322,7 +322,7 @@ def str_from_syntheseJury(donnees_etudiant, aggregat, groupe, tag_scodoc, champ)
|
|||||||
|
|
||||||
# ----------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------
|
||||||
def get_bilanParTag(donnees_etudiant, groupe="groupe"):
|
def get_bilanParTag(donnees_etudiant, groupe="groupe"):
|
||||||
"""Renvoie le code latex d'un tableau récapitulant, pour tous les tags trouvés dans
|
"""Renvoie le code latex d'un tableau récapitulant, pour tous les tags trouvés dans
|
||||||
les données étudiants, ses résultats.
|
les données étudiants, ses résultats.
|
||||||
result: chaine unicode
|
result: chaine unicode
|
||||||
"""
|
"""
|
||||||
@ -460,11 +460,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(SCO_SRC_DIR, 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(SCO_SRC_DIR, 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:
|
||||||
@ -474,8 +474,7 @@ def get_templates_from_distrib(template="avis"):
|
|||||||
|
|
||||||
# ----------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------
|
||||||
def table_syntheseAnnotationPE(context, syntheseJury, tag_annotation_pe):
|
def table_syntheseAnnotationPE(context, syntheseJury, tag_annotation_pe):
|
||||||
"""Génère un fichier excel synthétisant les annotations PE telles qu'inscrites dans les fiches de chaque étudiant
|
"""Génère un fichier excel synthétisant les annotations PE telles qu'inscrites dans les fiches de chaque étudiant"""
|
||||||
"""
|
|
||||||
sT = SeqGenTable() # le fichier excel à générer
|
sT = SeqGenTable() # le fichier excel à générer
|
||||||
|
|
||||||
# Les etudids des étudiants à afficher, triés par ordre alphabétiques de nom+prénom
|
# Les etudids des étudiants à afficher, triés par ordre alphabétiques de nom+prénom
|
||||||
|
10
pe_tools.py
@ -97,7 +97,7 @@ def print_semestres_description(sems, avec_affichage_debug=False):
|
|||||||
|
|
||||||
# ----------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------
|
||||||
def calcul_age(born):
|
def calcul_age(born):
|
||||||
"""Calcule l'age à partir de la date de naissance sous forme d'une chaine de caractère 'jj/mm/aaaa'.
|
"""Calcule l'age à partir de la date de naissance sous forme d'une chaine de caractère 'jj/mm/aaaa'.
|
||||||
Aucun test de validité sur le format de la date n'est fait.
|
Aucun test de validité sur le format de la date n'est fait.
|
||||||
"""
|
"""
|
||||||
if not isinstance(born, str) or born == "":
|
if not isinstance(born, str) or born == "":
|
||||||
@ -122,8 +122,7 @@ def remove_accents(input_unicode_str):
|
|||||||
|
|
||||||
|
|
||||||
def escape_for_latex(s):
|
def escape_for_latex(s):
|
||||||
"""Protège les caractères pour inclusion dans du source LaTeX
|
"""Protège les caractères pour inclusion dans du source LaTeX"""
|
||||||
"""
|
|
||||||
if not s:
|
if not s:
|
||||||
return ""
|
return ""
|
||||||
conv = {
|
conv = {
|
||||||
@ -162,8 +161,7 @@ def list_directory_filenames(path):
|
|||||||
|
|
||||||
|
|
||||||
def add_local_file_to_zip(zipfile, ziproot, pathname, path_in_zip):
|
def add_local_file_to_zip(zipfile, ziproot, pathname, path_in_zip):
|
||||||
"""Read pathname server file and add content to zip under path_in_zip
|
"""Read pathname server file and add content to zip under path_in_zip"""
|
||||||
"""
|
|
||||||
rooted_path_in_zip = os.path.join(ziproot, path_in_zip)
|
rooted_path_in_zip = os.path.join(ziproot, path_in_zip)
|
||||||
data = open(pathname).read()
|
data = open(pathname).read()
|
||||||
zipfile.writestr(rooted_path_in_zip, data)
|
zipfile.writestr(rooted_path_in_zip, data)
|
||||||
@ -177,7 +175,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(SCO_SRC_DIR, "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
|
||||||
|
@ -32,10 +32,9 @@
|
|||||||
Il suffit d'appeler abs_notify() après chaque ajout d'absence.
|
Il suffit d'appeler abs_notify() après chaque ajout d'absence.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
from email.MIMEText import MIMEText
|
from email.mime.text import MIMEText
|
||||||
from email.Header import Header
|
from email.header import Header
|
||||||
from email import Encoders
|
|
||||||
|
|
||||||
from notesdb import *
|
from notesdb import *
|
||||||
from sco_utils import *
|
from sco_utils import *
|
||||||
@ -47,7 +46,7 @@ import sco_formsemestre
|
|||||||
|
|
||||||
def abs_notify(context, etudid, date):
|
def abs_notify(context, etudid, date):
|
||||||
"""Check if notifications are requested and send them
|
"""Check if notifications are requested and send them
|
||||||
Considère le nombre d'absence dans le semestre courant
|
Considère le nombre d'absence dans le semestre courant
|
||||||
(s'il n'y a pas de semestre courant, ne fait rien,
|
(s'il n'y a pas de semestre courant, ne fait rien,
|
||||||
car l'etudiant n'est pas inscrit au moment de l'absence!).
|
car l'etudiant n'est pas inscrit au moment de l'absence!).
|
||||||
"""
|
"""
|
||||||
@ -64,8 +63,7 @@ def abs_notify(context, etudid, date):
|
|||||||
|
|
||||||
|
|
||||||
def do_abs_notify(context, sem, etudid, date, nbabs, nbabsjust):
|
def do_abs_notify(context, sem, etudid, date, nbabs, nbabsjust):
|
||||||
"""Given new counts of absences, check if notifications are requested and send them.
|
"""Given new counts of absences, check if notifications are requested and send them."""
|
||||||
"""
|
|
||||||
# prefs fallback to global pref if sem is None:
|
# prefs fallback to global pref if sem is None:
|
||||||
if sem:
|
if sem:
|
||||||
formsemestre_id = sem["formsemestre_id"]
|
formsemestre_id = sem["formsemestre_id"]
|
||||||
@ -131,8 +129,7 @@ def abs_notify_send(
|
|||||||
|
|
||||||
|
|
||||||
def abs_notify_get_destinations(context, sem, prefs, etudid, date, nbabs, nbabsjust):
|
def abs_notify_get_destinations(context, sem, prefs, etudid, date, nbabs, nbabsjust):
|
||||||
"""Returns set of destination emails to be notified
|
"""Returns set of destination emails to be notified"""
|
||||||
"""
|
|
||||||
formsemestre_id = sem["formsemestre_id"]
|
formsemestre_id = sem["formsemestre_id"]
|
||||||
|
|
||||||
destinations = [] # list of email address to notify
|
destinations = [] # list of email address to notify
|
||||||
@ -176,8 +173,8 @@ def abs_notify_is_above_threshold(context, etudid, nbabs, nbabsjust, formsemestr
|
|||||||
|
|
||||||
nbabs: nombre d'absence (de tous types, unité de compte = demi-journée)
|
nbabs: nombre d'absence (de tous types, unité de compte = demi-journée)
|
||||||
nbabsjust: nombre d'absences justifiées
|
nbabsjust: nombre d'absences justifiées
|
||||||
|
|
||||||
(nbabs > abs_notify_abs_threshold)
|
(nbabs > abs_notify_abs_threshold)
|
||||||
(nbabs - nbabs_last_notified) > abs_notify_abs_increment
|
(nbabs - nbabs_last_notified) > abs_notify_abs_increment
|
||||||
"""
|
"""
|
||||||
abs_notify_abs_threshold = context.get_preference(
|
abs_notify_abs_threshold = context.get_preference(
|
||||||
@ -282,8 +279,7 @@ def retreive_current_formsemestre(context, etudid, cur_date):
|
|||||||
|
|
||||||
|
|
||||||
def mod_with_evals_at_date(context, date_abs, etudid):
|
def mod_with_evals_at_date(context, date_abs, etudid):
|
||||||
"""Liste des moduleimpls avec des evaluations a la date indiquée
|
"""Liste des moduleimpls avec des evaluations a la date indiquée"""
|
||||||
"""
|
|
||||||
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"""
|
||||||
|
@ -53,7 +53,8 @@ def doSignaleAbsence(
|
|||||||
description=None,
|
description=None,
|
||||||
REQUEST=None,
|
REQUEST=None,
|
||||||
): # etudid implied
|
): # etudid implied
|
||||||
"""Signalement d'une absence"""
|
"""Signalement d'une absence
|
||||||
|
"""
|
||||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
|
|
||||||
@ -123,7 +124,8 @@ def doSignaleAbsence(
|
|||||||
|
|
||||||
|
|
||||||
def SignaleAbsenceEtud(context, REQUEST=None): # etudid implied
|
def SignaleAbsenceEtud(context, REQUEST=None): # etudid implied
|
||||||
"""Formulaire individuel simple de signalement d'une absence"""
|
"""Formulaire individuel simple de signalement d'une absence
|
||||||
|
"""
|
||||||
# brute-force portage from very old dtml code ...
|
# brute-force portage from very old dtml code ...
|
||||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
@ -160,10 +162,7 @@ def SignaleAbsenceEtud(context, REQUEST=None): # etudid implied
|
|||||||
% etud,
|
% etud,
|
||||||
"""<a href="%s/ficheEtud?etudid=%s">""" % (context.ScoURL(), etud["etudid"]),
|
"""<a href="%s/ficheEtud?etudid=%s">""" % (context.ScoURL(), etud["etudid"]),
|
||||||
sco_photos.etud_photo_html(
|
sco_photos.etud_photo_html(
|
||||||
context,
|
context, etudid=etudid, title="fiche de " + etud["nomprenom"], REQUEST=REQUEST
|
||||||
etudid=etudid,
|
|
||||||
title="fiche de " + etud["nomprenom"],
|
|
||||||
REQUEST=REQUEST,
|
|
||||||
),
|
),
|
||||||
"""</a></td></tr></table>""",
|
"""</a></td></tr></table>""",
|
||||||
"""
|
"""
|
||||||
@ -208,7 +207,8 @@ 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, REQUEST=None
|
||||||
): # etudid implied
|
): # etudid implied
|
||||||
"""Justification d'une absence"""
|
"""Justification d'une absence
|
||||||
|
"""
|
||||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
description_abs = description
|
description_abs = description
|
||||||
@ -274,7 +274,8 @@ def doJustifAbsence(
|
|||||||
|
|
||||||
|
|
||||||
def JustifAbsenceEtud(context, REQUEST=None): # etudid implied
|
def JustifAbsenceEtud(context, REQUEST=None): # etudid implied
|
||||||
"""Formulaire individuel simple de justification d'une absence"""
|
"""Formulaire individuel simple de justification d'une absence
|
||||||
|
"""
|
||||||
# brute-force portage from very old dtml code ...
|
# brute-force portage from very old dtml code ...
|
||||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
@ -289,10 +290,7 @@ def JustifAbsenceEtud(context, REQUEST=None): # etudid implied
|
|||||||
% etud,
|
% etud,
|
||||||
"""<a href="%s/ficheEtud?etudid=%s">""" % (context.ScoURL(), etud["etudid"]),
|
"""<a href="%s/ficheEtud?etudid=%s">""" % (context.ScoURL(), etud["etudid"]),
|
||||||
sco_photos.etud_photo_html(
|
sco_photos.etud_photo_html(
|
||||||
context,
|
context, etudid=etudid, title="fiche de " + etud["nomprenom"], REQUEST=REQUEST
|
||||||
etudid=etudid,
|
|
||||||
title="fiche de " + etud["nomprenom"],
|
|
||||||
REQUEST=REQUEST,
|
|
||||||
),
|
),
|
||||||
"""</a></td></tr></table>""",
|
"""</a></td></tr></table>""",
|
||||||
"""
|
"""
|
||||||
@ -331,7 +329,8 @@ Raison: <input type="text" name="description" size="42"/> (optionnel)
|
|||||||
def doAnnuleAbsence(
|
def doAnnuleAbsence(
|
||||||
context, datedebut, datefin, demijournee, REQUEST=None
|
context, datedebut, datefin, demijournee, 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, REQUEST=REQUEST)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
|
|
||||||
@ -379,7 +378,8 @@ autre absence pour <b>%(nomprenom)s</b></a></li>
|
|||||||
|
|
||||||
|
|
||||||
def AnnuleAbsenceEtud(context, REQUEST=None): # etudid implied
|
def AnnuleAbsenceEtud(context, REQUEST=None): # etudid implied
|
||||||
"""Formulaire individuel simple d'annulation d'une absence"""
|
"""Formulaire individuel simple d'annulation d'une absence
|
||||||
|
"""
|
||||||
# brute-force portage from very old dtml code ...
|
# brute-force portage from very old dtml code ...
|
||||||
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
etud = context.getEtudInfo(filled=1, REQUEST=REQUEST)[0]
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
@ -395,10 +395,7 @@ def AnnuleAbsenceEtud(context, REQUEST=None): # etudid implied
|
|||||||
% etud, # "
|
% etud, # "
|
||||||
"""<a href="%s/ficheEtud?etudid=%s">""" % (context.ScoURL(), etud["etudid"]),
|
"""<a href="%s/ficheEtud?etudid=%s">""" % (context.ScoURL(), etud["etudid"]),
|
||||||
sco_photos.etud_photo_html(
|
sco_photos.etud_photo_html(
|
||||||
context,
|
context, etudid=etudid, title="fiche de " + etud["nomprenom"], REQUEST=REQUEST
|
||||||
etudid=etudid,
|
|
||||||
title="fiche de " + etud["nomprenom"],
|
|
||||||
REQUEST=REQUEST,
|
|
||||||
),
|
),
|
||||||
"""</a></td></tr></table>""",
|
"""</a></td></tr></table>""",
|
||||||
"""<p>A n'utiliser que suite à une erreur de saisie ou lorsqu'il s'avère que l'étudiant était en fait présent. </p>
|
"""<p>A n'utiliser que suite à une erreur de saisie ou lorsqu'il s'avère que l'étudiant était en fait présent. </p>
|
||||||
@ -467,7 +464,8 @@ def AnnuleAbsenceEtud(context, REQUEST=None): # etudid implied
|
|||||||
def doAnnuleJustif(
|
def doAnnuleJustif(
|
||||||
context, datedebut0, datefin0, demijournee, REQUEST=None
|
context, datedebut0, datefin0, demijournee, REQUEST=None
|
||||||
): # etudid implied
|
): # etudid implied
|
||||||
"""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 = context.DateRangeISO(datedebut0, datefin0)
|
||||||
@ -571,7 +569,8 @@ def formChoixSemestreGroupe(context, all=False):
|
|||||||
|
|
||||||
|
|
||||||
def CalAbs(context, REQUEST=None): # etud implied
|
def CalAbs(context, REQUEST=None): # etud implied
|
||||||
"""Calendrier des absences d un etudiant"""
|
"""Calendrier des absences d un etudiant
|
||||||
|
"""
|
||||||
# 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"]
|
||||||
@ -622,10 +621,7 @@ def CalAbs(context, REQUEST=None): # etud implied
|
|||||||
context.ScoURL(),
|
context.ScoURL(),
|
||||||
etudid,
|
etudid,
|
||||||
sco_photos.etud_photo_html(
|
sco_photos.etud_photo_html(
|
||||||
context,
|
context, etudid=etudid, title="fiche de " + etud["nomprenom"], REQUEST=REQUEST
|
||||||
etudid=etudid,
|
|
||||||
title="fiche de " + etud["nomprenom"],
|
|
||||||
REQUEST=REQUEST,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
CalHTML,
|
CalHTML,
|
||||||
|
@ -28,11 +28,11 @@
|
|||||||
"""Génération des bulletins de notes
|
"""Génération des bulletins de notes
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
import email
|
||||||
from email.MIMEText import MIMEText
|
from email.mime.multipart import MIMEMultipart
|
||||||
from email.MIMEBase import MIMEBase
|
from email.mime.text import MIMEText
|
||||||
from email.Header import Header
|
from email.mime.base import MIMEBase
|
||||||
from email import Encoders
|
from email.header import Header
|
||||||
|
|
||||||
import htmlutils, time
|
import htmlutils, time
|
||||||
from reportlab.lib.colors import Color
|
from reportlab.lib.colors import Color
|
||||||
@ -331,7 +331,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,
|
||||||
@ -435,15 +435,8 @@ def _ue_mod_bulletin(context, etudid, formsemestre_id, ue_id, modimpls, nt, vers
|
|||||||
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:
|
mod["mod_moy_txt"] = ""
|
||||||
mod["mod_moy_txt"] = fmt_note(mod_moy)
|
mod["mod_coef_txt"] = ""
|
||||||
mod["mod_coef_txt"] = "Malus"
|
|
||||||
elif mod_moy < 0:
|
|
||||||
mod["mod_moy_txt"] = fmt_note(-mod_moy)
|
|
||||||
mod["mod_coef_txt"] = "Bonus"
|
|
||||||
else:
|
|
||||||
mod["mod_moy_txt"] = "-"
|
|
||||||
mod["mod_coef_txt"] = "-"
|
|
||||||
else:
|
else:
|
||||||
mod["mod_coef_txt"] = fmt_coef(modimpl["module"]["coefficient"])
|
mod["mod_coef_txt"] = 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'
|
||||||
@ -997,7 +990,7 @@ def mail_bulletin(context, formsemestre_id, I, pdfdata, filename, recipient_addr
|
|||||||
att = MIMEBase("application", "pdf")
|
att = MIMEBase("application", "pdf")
|
||||||
att.add_header("Content-Disposition", "attachment", filename=filename)
|
att.add_header("Content-Disposition", "attachment", filename=filename)
|
||||||
att.set_payload(pdfdata)
|
att.set_payload(pdfdata)
|
||||||
Encoders.encode_base64(att)
|
email.encoders.encode_base64(att)
|
||||||
msg.attach(att)
|
msg.attach(att)
|
||||||
log("mail bulletin a %s" % msg["To"])
|
log("mail bulletin a %s" % msg["To"])
|
||||||
context.sendEmail(msg)
|
context.sendEmail(msg)
|
||||||
|
@ -48,22 +48,10 @@ Balises img: actuellement interdites.
|
|||||||
"""
|
"""
|
||||||
import traceback, re
|
import traceback, re
|
||||||
|
|
||||||
import sco_utils as scu
|
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_pdf
|
from sco_pdf import *
|
||||||
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
|
||||||
from sco_permissions import ScoEtudInscrit
|
|
||||||
from sco_codes_parcours import (
|
|
||||||
UE_COLORS,
|
|
||||||
UE_DEFAULT_COLOR,
|
|
||||||
UE_ELECTIVE,
|
|
||||||
UE_SPORT,
|
|
||||||
UE_STANDARD,
|
|
||||||
)
|
|
||||||
import sco_bulletins_generator
|
import sco_bulletins_generator
|
||||||
import sco_bulletins_pdf
|
import sco_bulletins_pdf
|
||||||
import sco_groups
|
import sco_groups
|
||||||
@ -283,6 +271,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
context = self.context
|
context = self.context
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
# Colonnes à afficher:
|
# Colonnes à afficher:
|
||||||
@ -339,8 +328,8 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
linktmpl = (
|
linktmpl = (
|
||||||
'<span onclick="toggle_vis_ue(this);" class="toggle_ue">%s</span> '
|
'<span onclick="toggle_vis_ue(this);" class="toggle_ue">%s</span> '
|
||||||
)
|
)
|
||||||
minuslink = linktmpl % scu.icontag("minus_img", border="0", alt="-")
|
minuslink = linktmpl % icontag("minus_img", border="0", alt="-")
|
||||||
pluslink = linktmpl % scu.icontag("plus_img", border="0", alt="+")
|
pluslink = linktmpl % icontag("plus_img", border="0", alt="+")
|
||||||
|
|
||||||
# 1er ligne titres
|
# 1er ligne titres
|
||||||
t = {
|
t = {
|
||||||
@ -395,7 +384,9 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
P.append(t)
|
P.append(t)
|
||||||
|
|
||||||
# Rangs dans les partitions:
|
# Rangs dans les partitions:
|
||||||
partitions, _ = sco_groups.get_formsemestre_groups(context, formsemestre_id)
|
partitions, partitions_etud_groups = sco_groups.get_formsemestre_groups(
|
||||||
|
context, formsemestre_id
|
||||||
|
)
|
||||||
for partition in partitions:
|
for partition in partitions:
|
||||||
if partition["bul_show_rank"]:
|
if partition["bul_show_rank"]:
|
||||||
partition_id = partition["partition_id"]
|
partition_id = partition["partition_id"]
|
||||||
@ -495,16 +486,16 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
t["_css_row_class"] += " notes_bulletin_row_ue_cur"
|
t["_css_row_class"] += " notes_bulletin_row_ue_cur"
|
||||||
t["_titre_help"] = "(en cours, non prise en compte)"
|
t["_titre_help"] = "(en cours, non prise en compte)"
|
||||||
if prefs["bul_show_minmax"]:
|
if prefs["bul_show_minmax"]:
|
||||||
t["min"] = scu.fmt_note(ue["min"])
|
t["min"] = fmt_note(ue["min"])
|
||||||
t["max"] = scu.fmt_note(ue["max"])
|
t["max"] = fmt_note(ue["max"])
|
||||||
if prefs["bul_show_moypromo"]:
|
if prefs["bul_show_moypromo"]:
|
||||||
t["moy"] = scu.fmt_note(ue["moy"]).replace("NA", "-")
|
t["moy"] = fmt_note(ue["moy"]).replace("NA", "-")
|
||||||
# Cas particulier des UE sport (bonus)
|
# Cas particulier des UE sport (bonus)
|
||||||
if ue["type"] == UE_SPORT and not ue_descr:
|
if ue["type"] == UE_SPORT and not ue_descr:
|
||||||
del t["module"]
|
del t["module"]
|
||||||
del t["coef"]
|
del t["coef"]
|
||||||
t["_pdf_style"].append(("SPAN", (colidx["note"], 0), (-1, 0)))
|
t["_pdf_style"].append(("SPAN", (colidx["note"], 0), (-1, 0)))
|
||||||
# t["_module_colspan"] = 3 # non car bug si aucune colonne additionnelle
|
# t["_module_colspan"] = 3 # non car bug si aucune colonne additionnelle
|
||||||
# UE électives
|
# UE électives
|
||||||
if ue["type"] == UE_ELECTIVE:
|
if ue["type"] == UE_ELECTIVE:
|
||||||
t["module"] += " <i>(élective)</i>"
|
t["module"] += " <i>(élective)</i>"
|
||||||
@ -553,7 +544,8 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
rowstyle="",
|
rowstyle="",
|
||||||
hidden=False,
|
hidden=False,
|
||||||
):
|
):
|
||||||
"""Liste dans la table les descriptions des modules et, si version != short, des évaluations."""
|
"""Liste dans la table les descriptions des modules et, si version != short, des évaluations.
|
||||||
|
"""
|
||||||
if ue_type == "cur": # UE courante non prise en compte (car capitalisee)
|
if ue_type == "cur": # UE courante non prise en compte (car capitalisee)
|
||||||
pdf_style_bg = [("BACKGROUND", (0, 0), (-1, 0), self.PDF_UE_CUR_BG)]
|
pdf_style_bg = [("BACKGROUND", (0, 0), (-1, 0), self.PDF_UE_CUR_BG)]
|
||||||
else:
|
else:
|
||||||
@ -604,10 +596,10 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
"_pdf_style": pdf_style,
|
"_pdf_style": pdf_style,
|
||||||
}
|
}
|
||||||
if prefs["bul_show_minmax_mod"]:
|
if prefs["bul_show_minmax_mod"]:
|
||||||
t["min"] = scu.fmt_note(mod["stats"]["min"])
|
t["min"] = fmt_note(mod["stats"]["min"])
|
||||||
t["max"] = scu.fmt_note(mod["stats"]["max"])
|
t["max"] = fmt_note(mod["stats"]["max"])
|
||||||
if prefs["bul_show_moypromo"]:
|
if prefs["bul_show_moypromo"]:
|
||||||
t["moy"] = scu.fmt_note(mod["stats"]["moy"]).replace("NA", "-")
|
t["moy"] = fmt_note(mod["stats"]["moy"]).replace("NA", "-")
|
||||||
P.append(t)
|
P.append(t)
|
||||||
|
|
||||||
if self.version != "short":
|
if self.version != "short":
|
||||||
@ -668,15 +660,12 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
t["note"] = "<i>" + e["note_txt"] + "</i>"
|
t["note"] = "<i>" + e["note_txt"] + "</i>"
|
||||||
else:
|
else:
|
||||||
t["_module_colspan"] = 2
|
t["_module_colspan"] = 2
|
||||||
if prefs["bul_show_minmax_eval"] or prefs["bul_show_moypromo"]:
|
if prefs["bul_show_minmax_eval"]:
|
||||||
etat = sco_evaluations.do_evaluation_etat(
|
etat = sco_evaluations.do_evaluation_etat(
|
||||||
self.context, e["evaluation_id"]
|
self.context, e["evaluation_id"]
|
||||||
)
|
)
|
||||||
if prefs["bul_show_minmax_eval"]:
|
t["min"] = fmt_note(etat["mini"])
|
||||||
t["min"] = scu.fmt_note(etat["mini"])
|
t["max"] = fmt_note(etat["maxi"])
|
||||||
t["max"] = scu.fmt_note(etat["maxi"])
|
|
||||||
if prefs["bul_show_moypromo"]:
|
|
||||||
t["moy"] = scu.fmt_note(etat["moy"])
|
|
||||||
P.append(t)
|
P.append(t)
|
||||||
nbeval += 1
|
nbeval += 1
|
||||||
return nbeval
|
return nbeval
|
||||||
|
@ -116,7 +116,8 @@ CODES_EXPL = {
|
|||||||
RAT: "En attente d'un rattrapage",
|
RAT: "En attente d'un rattrapage",
|
||||||
DEF: "Défaillant",
|
DEF: "Défaillant",
|
||||||
}
|
}
|
||||||
# Nota: ces explications sont personnalisables via le fichier de config scodoc_config.py
|
# Nota: ces explications sont personnalisables via le fichier
|
||||||
|
# de config locale /opt/scodoc/var/scodoc/config/scodoc_local.py
|
||||||
# variable: CONFIG.CODES_EXP
|
# variable: CONFIG.CODES_EXP
|
||||||
|
|
||||||
CODES_SEM_VALIDES = {ADM: True, ADC: True, ADJ: True} # semestre validé
|
CODES_SEM_VALIDES = {ADM: True, ADC: True, ADJ: True} # semestre validé
|
||||||
|
@ -315,7 +315,7 @@ def do_moduleimpl_moyennes(context, nt, mod):
|
|||||||
notes.append(0.0)
|
notes.append(0.0)
|
||||||
coefs.append(0.0)
|
coefs.append(0.0)
|
||||||
coefs_mask.append(0)
|
coefs_mask.append(0)
|
||||||
if nb_notes > 0 or formula_use_abs:
|
if nb_notes > 0:
|
||||||
user_moy = compute_user_formula(
|
user_moy = compute_user_formula(
|
||||||
context,
|
context,
|
||||||
sem,
|
sem,
|
||||||
|
109
sco_config.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Configuration de ScoDoc (version 2020)
|
||||||
|
NE PAS MODIFIER localement ce fichier !
|
||||||
|
mais éditer /opt/scodoc/var/scodoc/config/scodoc_local.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
from attrdict import AttrDict
|
||||||
|
import bonus_sport
|
||||||
|
|
||||||
|
CONFIG = AttrDict()
|
||||||
|
|
||||||
|
# set to 1 if you want to require INE:
|
||||||
|
CONFIG.always_require_ine = 0
|
||||||
|
|
||||||
|
# The base URL, use only if you are behind a proxy
|
||||||
|
# eg "https://scodoc.example.net/ScoDoc"
|
||||||
|
CONFIG.ABSOLUTE_URL = ""
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# -------------- Documents PDF
|
||||||
|
# -----------------------------------------------------
|
||||||
|
|
||||||
|
# Taille du l'image logo: largeur/hauteur (ne pas oublier le . !!!)
|
||||||
|
# W/H XXX provisoire: utilisera PIL pour connaitre la taille de l'image
|
||||||
|
CONFIG.LOGO_FOOTER_ASPECT = 326 / 96.0
|
||||||
|
# Taille dans le document en millimetres
|
||||||
|
CONFIG.LOGO_FOOTER_HEIGHT = 10
|
||||||
|
# Proportions logo (donné ici pour IUTV)
|
||||||
|
CONFIG.LOGO_HEADER_ASPECT = 549 / 346.0
|
||||||
|
# Taille verticale dans le document en millimetres
|
||||||
|
CONFIG.LOGO_HEADER_HEIGHT = 28
|
||||||
|
|
||||||
|
|
||||||
|
# Pied de page PDF : un format Python, %(xxx)s est remplacé par la variable xxx.
|
||||||
|
# Les variables définies sont:
|
||||||
|
# day : Day of the month as a decimal number [01,31]
|
||||||
|
# month : Month as a decimal number [01,12].
|
||||||
|
# year : Year without century as a decimal number [00,99].
|
||||||
|
# Year : Year with century as a decimal number.
|
||||||
|
# hour : Hour (24-hour clock) as a decimal number [00,23].
|
||||||
|
# minute: Minute as a decimal number [00,59].
|
||||||
|
#
|
||||||
|
# server_url: URL du serveur ScoDoc
|
||||||
|
# scodoc_name: le nom du logiciel (ScoDoc actuellement, voir VERSION.py)
|
||||||
|
CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s"
|
||||||
|
|
||||||
|
#
|
||||||
|
# ------------- Calcul bonus modules optionnels (sport, culture...) -------------
|
||||||
|
#
|
||||||
|
|
||||||
|
CONFIG.compute_bonus = bonus_sport.bonus_iutv
|
||||||
|
# Mettre "bonus_demo" pour logguer des informations utiles au developpement...
|
||||||
|
|
||||||
|
# ------------- Capitalisation des UEs -------------
|
||||||
|
# Deux écoles:
|
||||||
|
# - règle "DUT": capitalisation des UE obtenues avec moyenne UE >= 10 ET de toutes les UE
|
||||||
|
# des semestres validés (ADM, ADC, AJ). (conforme à l'arrêté d'août 2005)
|
||||||
|
#
|
||||||
|
# - règle "LMD": capitalisation uniquement des UE avec moy. > 10
|
||||||
|
|
||||||
|
# Si vrai, capitalise toutes les UE des semestres validés (règle "DUT").
|
||||||
|
# CONFIG.CAPITALIZE_ALL_UES = True
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# -------------- Personnalisation des pages
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# Nom (chemin complet) d'un fichier .html à inclure juste après le <body>
|
||||||
|
# le <body> des pages ScoDoc
|
||||||
|
CONFIG.CUSTOM_HTML_HEADER = ""
|
||||||
|
|
||||||
|
# Fichier html a inclure en fin des pages (juste avant le </body>)
|
||||||
|
CONFIG.CUSTOM_HTML_FOOTER = ""
|
||||||
|
|
||||||
|
# Fichier .html à inclure dans la pages connexion/déconnexion (accueil)
|
||||||
|
# si on veut que ce soit différent (par défaut la même chose)
|
||||||
|
CONFIG.CUSTOM_HTML_HEADER_CNX = CONFIG.CUSTOM_HTML_HEADER
|
||||||
|
CONFIG.CUSTOM_HTML_FOOTER_CNX = CONFIG.CUSTOM_HTML_FOOTER
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# -------------- Noms de Lycées
|
||||||
|
# -----------------------------------------------------
|
||||||
|
|
||||||
|
# Fichier de correspondance codelycee -> noms
|
||||||
|
# (chemin relatif au repertoire d'install des sources)
|
||||||
|
CONFIG.ETABL_FILENAME = "config/etablissements.csv"
|
||||||
|
|
||||||
|
# ----------------------------------------------------
|
||||||
|
# -------------- Divers:
|
||||||
|
# ----------------------------------------------------
|
||||||
|
# True for UCAC (étudiants camerounais sans prénoms)
|
||||||
|
CONFIG.ALLOW_NULL_PRENOM = False
|
||||||
|
|
||||||
|
# Taille max des fichiers archive etudiants (en octets)
|
||||||
|
# CONFIG.ETUD_MAX_FILE_SIZE = 10 * 1024 * 1024
|
||||||
|
|
||||||
|
# Si pas de photo et portail, publie l'url (était vrai jusqu'en oct 2016)
|
||||||
|
CONFIG.PUBLISH_PORTAL_PHOTO_URL = False
|
||||||
|
|
||||||
|
# Si > 0: longueur minimale requise des nouveaux mots de passe
|
||||||
|
# (le test cracklib.FascistCheck s'appliquera dans tous les cas)
|
||||||
|
CONFIG.MIN_PASSWORD_LENGTH = 0
|
||||||
|
|
||||||
|
# Ce dictionnaire est fusionné à celui de sco_codes_parcours
|
||||||
|
# pour définir les codes jury et explications associées
|
||||||
|
CONFIG.CODES_EXPL = {
|
||||||
|
# AJ : 'Ajourné (échec)',
|
||||||
|
}
|
44
sco_config_load.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Chargement de la configuration locale
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import sco_utils
|
||||||
|
from sco_utils import log, SCODOC_CFG_DIR
|
||||||
|
import sco_config
|
||||||
|
|
||||||
|
# scodoc_local defines a CONFIG object
|
||||||
|
# here we check if there is a local config file
|
||||||
|
|
||||||
|
|
||||||
|
def load_local_configuration():
|
||||||
|
"""Load local configuration file (if exists)
|
||||||
|
and merge it with CONFIG.
|
||||||
|
"""
|
||||||
|
# this path should be synced with upgrade.sh
|
||||||
|
LOCAL_CONFIG_FILENAME = os.path.join(SCODOC_CFG_DIR, "scodoc_local.py")
|
||||||
|
LOCAL_CONFIG = None
|
||||||
|
if os.path.exists(LOCAL_CONFIG_FILENAME):
|
||||||
|
if not SCODOC_CFG_DIR in sys.path:
|
||||||
|
sys.path.insert(1, SCODOC_CFG_DIR)
|
||||||
|
try:
|
||||||
|
from scodoc_local import CONFIG as LOCAL_CONFIG
|
||||||
|
|
||||||
|
log("imported %s" % LOCAL_CONFIG_FILENAME)
|
||||||
|
except ImportError:
|
||||||
|
log("Error: can't import %s" % LOCAL_CONFIG_FILENAME)
|
||||||
|
del sys.path[1]
|
||||||
|
if LOCAL_CONFIG is None:
|
||||||
|
return
|
||||||
|
# Now merges local config in our CONFIG
|
||||||
|
for x in [x for x in dir(LOCAL_CONFIG) if x[0] != "_"]:
|
||||||
|
v = getattr(LOCAL_CONFIG, x)
|
||||||
|
if not v in sco_config.CONFIG:
|
||||||
|
log("Warning: local config setting unused parameter %s (skipped)" % x)
|
||||||
|
else:
|
||||||
|
if v != sco_config.CONFIG[x]:
|
||||||
|
log("Setting parameter %s from %s" % (x, LOCAL_CONFIG_FILENAME))
|
||||||
|
sco_config.CONFIG[x] = v
|
@ -28,14 +28,12 @@
|
|||||||
"""
|
"""
|
||||||
Rapport (table) avec dernier semestre fréquenté et débouché de chaque étudiant
|
Rapport (table) avec dernier semestre fréquenté et débouché de chaque étudiant
|
||||||
"""
|
"""
|
||||||
from types import StringType
|
|
||||||
import safehtml
|
import safehtml
|
||||||
|
|
||||||
import sco_utils as scu
|
from notesdb import *
|
||||||
import notesdb
|
from sco_utils import *
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
import VERSION
|
|
||||||
from sco_exceptions import AccessDenied
|
|
||||||
from scolog import logdb
|
from scolog import logdb
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
@ -44,7 +42,8 @@ import sco_tag_module
|
|||||||
|
|
||||||
|
|
||||||
def report_debouche_date(context, start_year=None, format="html", REQUEST=None):
|
def report_debouche_date(context, start_year=None, format="html", REQUEST=None):
|
||||||
"""Rapport (table) pour les débouchés des étudiants sortis à partir de l'année indiquée."""
|
"""Rapport (table) pour les débouchés des étudiants sortis à partir de l'année indiquée.
|
||||||
|
"""
|
||||||
if not start_year:
|
if not start_year:
|
||||||
return report_debouche_ask_date(context, REQUEST=REQUEST)
|
return report_debouche_ask_date(context, REQUEST=REQUEST)
|
||||||
if format == "xls":
|
if format == "xls":
|
||||||
@ -55,8 +54,8 @@ def report_debouche_date(context, start_year=None, format="html", REQUEST=None):
|
|||||||
etudids = get_etudids_with_debouche(context, start_year)
|
etudids = get_etudids_with_debouche(context, start_year)
|
||||||
tab = table_debouche_etudids(context, etudids, keep_numeric=keep_numeric)
|
tab = table_debouche_etudids(context, etudids, keep_numeric=keep_numeric)
|
||||||
|
|
||||||
tab.filename = scu.make_filename("debouche_scodoc_%s" % start_year)
|
tab.filename = make_filename("debouche_scodoc_%s" % start_year)
|
||||||
tab.origin = "Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + ""
|
tab.origin = "Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + ""
|
||||||
tab.caption = "Récapitulatif débouchés à partir du 1/1/%s." % start_year
|
tab.caption = "Récapitulatif débouchés à partir du 1/1/%s." % start_year
|
||||||
tab.base_url = "%s?start_year=%s" % (REQUEST.URL0, start_year)
|
tab.base_url = "%s?start_year=%s" % (REQUEST.URL0, start_year)
|
||||||
return tab.make_page(
|
return tab.make_page(
|
||||||
@ -78,7 +77,7 @@ def get_etudids_with_debouche(context, start_year):
|
|||||||
start_date = str(start_year) + "-01-01"
|
start_date = str(start_year) + "-01-01"
|
||||||
# Recupere tous les etudid avec un debouché renseigné et une inscription dans un semestre
|
# Recupere tous les etudid avec un debouché renseigné et une inscription dans un semestre
|
||||||
# posterieur à la date de depart:
|
# posterieur à la date de depart:
|
||||||
# r = notesdb.SimpleDictFetch(context,
|
# r = SimpleDictFetch(context,
|
||||||
# """SELECT DISTINCT i.etudid
|
# """SELECT DISTINCT i.etudid
|
||||||
# FROM notes_formsemestre_inscription i, admissions adm, notes_formsemestre s
|
# FROM notes_formsemestre_inscription i, admissions adm, notes_formsemestre s
|
||||||
# WHERE adm.debouche is not NULL
|
# WHERE adm.debouche is not NULL
|
||||||
@ -87,7 +86,7 @@ def get_etudids_with_debouche(context, start_year):
|
|||||||
# """,
|
# """,
|
||||||
# {'start_date' : start_date })
|
# {'start_date' : start_date })
|
||||||
|
|
||||||
r = notesdb.SimpleDictFetch(
|
r = SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"""SELECT DISTINCT i.etudid
|
"""SELECT DISTINCT i.etudid
|
||||||
FROM notes_formsemestre_inscription i, notes_formsemestre s, itemsuivi it
|
FROM notes_formsemestre_inscription i, notes_formsemestre s, itemsuivi it
|
||||||
@ -101,7 +100,8 @@ def get_etudids_with_debouche(context, start_year):
|
|||||||
|
|
||||||
|
|
||||||
def table_debouche_etudids(context, etudids, keep_numeric=True):
|
def table_debouche_etudids(context, etudids, keep_numeric=True):
|
||||||
"""Rapport pour ces etudiants"""
|
"""Rapport pour ces etudiants
|
||||||
|
"""
|
||||||
L = []
|
L = []
|
||||||
for etudid in etudids:
|
for etudid in etudids:
|
||||||
etud = context.getEtudInfo(filled=1, etudid=etudid)[0]
|
etud = context.getEtudInfo(filled=1, etudid=etudid)[0]
|
||||||
@ -122,7 +122,7 @@ def table_debouche_etudids(context, etudids, keep_numeric=True):
|
|||||||
"_prenom_target": "ficheEtud?etudid=" + etud["etudid"],
|
"_prenom_target": "ficheEtud?etudid=" + etud["etudid"],
|
||||||
"_nom_td_attrs": 'id="%s" class="etudinfo"' % (etud["etudid"]),
|
"_nom_td_attrs": 'id="%s" class="etudinfo"' % (etud["etudid"]),
|
||||||
# 'debouche' : etud['debouche'],
|
# 'debouche' : etud['debouche'],
|
||||||
"moy": scu.fmt_note(nt.get_etud_moy_gen(etudid), keep_numeric=keep_numeric),
|
"moy": fmt_note(nt.get_etud_moy_gen(etudid), keep_numeric=keep_numeric),
|
||||||
"rang": nt.get_etud_rang(etudid),
|
"rang": nt.get_etud_rang(etudid),
|
||||||
"effectif": len(nt.T),
|
"effectif": len(nt.T),
|
||||||
"semestre_id": last_sem["semestre_id"],
|
"semestre_id": last_sem["semestre_id"],
|
||||||
@ -189,7 +189,8 @@ def table_debouche_etudids(context, etudids, keep_numeric=True):
|
|||||||
|
|
||||||
|
|
||||||
def report_debouche_ask_date(context, REQUEST=None):
|
def report_debouche_ask_date(context, REQUEST=None):
|
||||||
"""Formulaire demande date départ"""
|
"""Formulaire demande date départ
|
||||||
|
"""
|
||||||
return (
|
return (
|
||||||
context.sco_header(REQUEST)
|
context.sco_header(REQUEST)
|
||||||
+ """<form method="GET">
|
+ """<form method="GET">
|
||||||
@ -222,17 +223,14 @@ def report_debouche_ask_date(context, REQUEST=None):
|
|||||||
# admission_edit(cnx, adm)
|
# admission_edit(cnx, adm)
|
||||||
|
|
||||||
|
|
||||||
_itemsuiviEditor = notesdb.EditableTable(
|
_itemsuiviEditor = EditableTable(
|
||||||
"itemsuivi",
|
"itemsuivi",
|
||||||
"itemsuivi_id",
|
"itemsuivi_id",
|
||||||
("itemsuivi_id", "etudid", "item_date", "situation"),
|
("itemsuivi_id", "etudid", "item_date", "situation"),
|
||||||
sortkey="item_date desc",
|
sortkey="item_date desc",
|
||||||
convert_null_outputs_to_empty=True,
|
convert_null_outputs_to_empty=True,
|
||||||
output_formators={
|
output_formators={"situation": safehtml.HTML2SafeHTML, "item_date": DateISOtoDMY},
|
||||||
"situation": safehtml.HTML2SafeHTML,
|
input_formators={"item_date": DateDMYtoISO},
|
||||||
"item_date": notesdb.DateISOtoDMY,
|
|
||||||
},
|
|
||||||
input_formators={"item_date": notesdb.DateDMYtoISO},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
_itemsuivi_create = _itemsuiviEditor.create
|
_itemsuivi_create = _itemsuiviEditor.create
|
||||||
@ -242,7 +240,8 @@ _itemsuivi_edit = _itemsuiviEditor.edit
|
|||||||
|
|
||||||
|
|
||||||
class ItemSuiviTag(sco_tag_module.ScoTag):
|
class ItemSuiviTag(sco_tag_module.ScoTag):
|
||||||
"""Les tags sur les items"""
|
"""Les tags sur les items
|
||||||
|
"""
|
||||||
|
|
||||||
tag_table = "itemsuivi_tags" # table (tag_id, title)
|
tag_table = "itemsuivi_tags" # table (tag_id, title)
|
||||||
assoc_table = "itemsuivi_tags_assoc" # table (tag_id, object_id)
|
assoc_table = "itemsuivi_tags_assoc" # table (tag_id, object_id)
|
||||||
@ -260,7 +259,8 @@ def itemsuivi_get(cnx, itemsuivi_id, ignore_errors=False):
|
|||||||
|
|
||||||
|
|
||||||
def itemsuivi_suppress(context, itemsuivi_id, REQUEST=None):
|
def itemsuivi_suppress(context, itemsuivi_id, REQUEST=None):
|
||||||
"""Suppression d'un item"""
|
"""Suppression d'un item
|
||||||
|
"""
|
||||||
if not context.can_edit_suivi(REQUEST):
|
if not context.can_edit_suivi(REQUEST):
|
||||||
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 !")
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
@ -285,7 +285,7 @@ def itemsuivi_create(
|
|||||||
log("created itemsuivi %s for %s" % (itemsuivi_id, etudid))
|
log("created itemsuivi %s for %s" % (itemsuivi_id, etudid))
|
||||||
item = itemsuivi_get(cnx, itemsuivi_id)
|
item = itemsuivi_get(cnx, itemsuivi_id)
|
||||||
if format == "json":
|
if format == "json":
|
||||||
return scu.sendJSON(REQUEST, item)
|
return sendJSON(REQUEST, item)
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
||||||
@ -313,7 +313,7 @@ def itemsuivi_set_situation(context, object, value, REQUEST=None):
|
|||||||
item = itemsuivi_get(cnx, itemsuivi_id)
|
item = itemsuivi_get(cnx, itemsuivi_id)
|
||||||
item["situation"] = situation
|
item["situation"] = situation
|
||||||
_itemsuivi_edit(cnx, item)
|
_itemsuivi_edit(cnx, item)
|
||||||
return situation or scu.IT_SITUATION_MISSING_STR
|
return situation or IT_SITUATION_MISSING_STR
|
||||||
|
|
||||||
|
|
||||||
def itemsuivi_list_etud(context, etudid, format=None, REQUEST=None):
|
def itemsuivi_list_etud(context, etudid, format=None, REQUEST=None):
|
||||||
@ -323,13 +323,13 @@ def itemsuivi_list_etud(context, etudid, format=None, REQUEST=None):
|
|||||||
for it in items:
|
for it in items:
|
||||||
it["tags"] = ", ".join(itemsuivi_tag_list(context, it["itemsuivi_id"]))
|
it["tags"] = ", ".join(itemsuivi_tag_list(context, it["itemsuivi_id"]))
|
||||||
if format == "json":
|
if format == "json":
|
||||||
return scu.sendJSON(REQUEST, items)
|
return sendJSON(REQUEST, items)
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
def itemsuivi_tag_list(context, itemsuivi_id):
|
def itemsuivi_tag_list(context, itemsuivi_id):
|
||||||
"""les noms de tags associés à cet item"""
|
"""les noms de tags associés à cet item"""
|
||||||
r = notesdb.SimpleDictFetch(
|
r = SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"""SELECT t.title
|
"""SELECT t.title
|
||||||
FROM itemsuivi_tags_assoc a, itemsuivi_tags t
|
FROM itemsuivi_tags_assoc a, itemsuivi_tags t
|
||||||
@ -344,17 +344,17 @@ def itemsuivi_tag_list(context, itemsuivi_id):
|
|||||||
def itemsuivi_tag_search(context, term, REQUEST=None):
|
def itemsuivi_tag_search(context, term, REQUEST=None):
|
||||||
"""List all used tag names (for auto-completion)"""
|
"""List all used tag names (for auto-completion)"""
|
||||||
# restrict charset to avoid injections
|
# restrict charset to avoid injections
|
||||||
if not scu.ALPHANUM_EXP.match(term.decode(scu.SCO_ENCODING)):
|
if not ALPHANUM_EXP.match(term.decode(SCO_ENCODING)):
|
||||||
data = []
|
data = []
|
||||||
else:
|
else:
|
||||||
r = notesdb.SimpleDictFetch(
|
r = SimpleDictFetch(
|
||||||
context,
|
context,
|
||||||
"SELECT title FROM itemsuivi_tags WHERE title LIKE %(term)s",
|
"SELECT title FROM itemsuivi_tags WHERE title LIKE %(term)s",
|
||||||
{"term": term + "%"},
|
{"term": term + "%"},
|
||||||
)
|
)
|
||||||
data = [x["title"] for x in r]
|
data = [x["title"] for x in r]
|
||||||
|
|
||||||
return scu.sendJSON(REQUEST, data)
|
return sendJSON(REQUEST, data)
|
||||||
|
|
||||||
|
|
||||||
def itemsuivi_tag_set(context, itemsuivi_id="", taglist=[], REQUEST=None):
|
def itemsuivi_tag_set(context, itemsuivi_id="", taglist=[], REQUEST=None):
|
||||||
@ -372,7 +372,7 @@ def itemsuivi_tag_set(context, itemsuivi_id="", taglist=[], REQUEST=None):
|
|||||||
# log('itemsuivi_tag_set: itemsuivi_id=%s taglist=%s' % (itemsuivi_id, taglist))
|
# log('itemsuivi_tag_set: itemsuivi_id=%s taglist=%s' % (itemsuivi_id, taglist))
|
||||||
# Sanity check:
|
# Sanity check:
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
_ = itemsuivi_get(cnx, itemsuivi_id)
|
item = itemsuivi_get(cnx, itemsuivi_id)
|
||||||
|
|
||||||
newtags = set(taglist)
|
newtags = set(taglist)
|
||||||
oldtags = set(itemsuivi_tag_list(context, itemsuivi_id))
|
oldtags = set(itemsuivi_tag_list(context, itemsuivi_id))
|
||||||
|
@ -50,13 +50,13 @@ pg_dump SCORT | psql ANORT
|
|||||||
import fcntl
|
import fcntl
|
||||||
import subprocess
|
import subprocess
|
||||||
import requests
|
import requests
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
from email.MIMEText import MIMEText
|
from email.mime.text import MIMEText
|
||||||
from email.MIMEBase import MIMEBase
|
from email.mime.base import MIMEBase
|
||||||
from email.Header import Header
|
from email.header import Header
|
||||||
from email import Encoders
|
|
||||||
|
|
||||||
from notesdb import *
|
from notesdb import *
|
||||||
|
import sco_utils
|
||||||
from sco_utils import *
|
from sco_utils import *
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
|
|
||||||
@ -64,8 +64,7 @@ SCO_DUMP_LOCK = "/tmp/scodump.lock"
|
|||||||
|
|
||||||
|
|
||||||
def sco_dump_and_send_db(context, REQUEST=None):
|
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 = SimpleQuery(context, "SELECT current_database()", {})
|
||||||
@ -150,9 +149,8 @@ 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_TOOLS_DIR, "anonymize_db.py")
|
||||||
cmd = os.path.join(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])
|
out = subprocess.check_output([cmd, ano_db_name])
|
||||||
@ -171,8 +169,7 @@ def _get_scodoc_serial(context):
|
|||||||
|
|
||||||
|
|
||||||
def _send_db(context, REQUEST, ano_db_name):
|
def _send_db(context, REQUEST, ano_db_name):
|
||||||
"""Dump this (anonymized) database and send it to tech support
|
"""Dump this (anonymized) database and send it to tech support"""
|
||||||
"""
|
|
||||||
log("dumping anonymized database {}".format(ano_db_name))
|
log("dumping anonymized database {}".format(ano_db_name))
|
||||||
try:
|
try:
|
||||||
data = subprocess.check_output("pg_dump {} | gzip".format(ano_db_name), shell=1)
|
data = subprocess.check_output("pg_dump {} | gzip".format(ano_db_name), shell=1)
|
||||||
@ -195,7 +192,7 @@ def _send_db(context, REQUEST, ano_db_name):
|
|||||||
"nomcomplet"
|
"nomcomplet"
|
||||||
],
|
],
|
||||||
"sco_version": SCOVERSION,
|
"sco_version": SCOVERSION,
|
||||||
"sco_subversion": get_svn_version(SCO_CONFIG_DIR),
|
"sco_fullversion": sco_utils.get_scodoc_version(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return r
|
return r
|
||||||
|
@ -27,23 +27,15 @@
|
|||||||
|
|
||||||
"""Evaluations
|
"""Evaluations
|
||||||
"""
|
"""
|
||||||
import time
|
|
||||||
import urllib
|
|
||||||
import operator
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
from notes_log import log, logCallStack
|
from notes_log import log, logCallStack
|
||||||
import sco_utils as scu
|
from sco_utils import *
|
||||||
from notesdb import ScoDocCursor
|
from notesdb import *
|
||||||
from sco_exceptions import AccessDenied, ScoValueError
|
|
||||||
import VERSION
|
|
||||||
from gen_tables import GenTable
|
from gen_tables import GenTable
|
||||||
from TrivialFormulator import TrivialFormulator
|
|
||||||
import sco_news
|
import sco_news
|
||||||
import sco_formsemestre
|
import sco_formsemestre
|
||||||
import sco_groups
|
import sco_groups
|
||||||
import ZAbsences
|
import ZAbsences
|
||||||
import sco_evaluations
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@ -55,7 +47,7 @@ def notes_moyenne_median_mini_maxi(notes):
|
|||||||
notes = [
|
notes = [
|
||||||
x
|
x
|
||||||
for x in notes
|
for x in notes
|
||||||
if (x != None) and (x != scu.NOTES_NEUTRALISE) and (x != scu.NOTES_ATTENTE)
|
if (x != None) and (x != NOTES_NEUTRALISE) and (x != NOTES_ATTENTE)
|
||||||
]
|
]
|
||||||
n = len(notes)
|
n = len(notes)
|
||||||
if not n:
|
if not n:
|
||||||
@ -144,8 +136,8 @@ def do_evaluation_etat(
|
|||||||
NotesDB = context._notes_getall(evaluation_id) # { etudid : value }
|
NotesDB = context._notes_getall(evaluation_id) # { etudid : value }
|
||||||
notes = [x["value"] for x in NotesDB.values()]
|
notes = [x["value"] for x in NotesDB.values()]
|
||||||
nb_abs = len([x for x in notes if x is None])
|
nb_abs = len([x for x in notes if x is None])
|
||||||
nb_neutre = len([x for x in notes if x == scu.NOTES_NEUTRALISE])
|
nb_neutre = len([x for x in notes if x == NOTES_NEUTRALISE])
|
||||||
nb_att = len([x for x in notes if x == scu.NOTES_ATTENTE])
|
nb_att = len([x for x in notes if x == NOTES_ATTENTE])
|
||||||
moy_num, median_num, mini_num, maxi_num = notes_moyenne_median_mini_maxi(notes)
|
moy_num, median_num, mini_num, maxi_num = notes_moyenne_median_mini_maxi(notes)
|
||||||
if moy_num is None:
|
if moy_num is None:
|
||||||
median, moy = "", ""
|
median, moy = "", ""
|
||||||
@ -153,10 +145,10 @@ def do_evaluation_etat(
|
|||||||
mini, maxi = "", ""
|
mini, maxi = "", ""
|
||||||
mini_num, maxi_num = None, None
|
mini_num, maxi_num = None, None
|
||||||
else:
|
else:
|
||||||
median = scu.fmt_note(median_num)
|
median = fmt_note(median_num)
|
||||||
moy = scu.fmt_note(moy_num)
|
moy = fmt_note(moy_num)
|
||||||
mini = scu.fmt_note(mini_num)
|
mini = fmt_note(mini_num)
|
||||||
maxi = scu.fmt_note(maxi_num)
|
maxi = fmt_note(maxi_num)
|
||||||
# cherche date derniere modif note
|
# cherche date derniere modif note
|
||||||
if len(NotesDB):
|
if len(NotesDB):
|
||||||
t = [x["date"] for x in NotesDB.values()]
|
t = [x["date"] for x in NotesDB.values()]
|
||||||
@ -167,7 +159,7 @@ def do_evaluation_etat(
|
|||||||
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 = context.do_moduleimpl_list(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"] == MODULE_MALUS # True si module de malus
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
# Si partition_id is None, prend 'all' ou bien la premiere:
|
# Si partition_id is None, prend 'all' ou bien la premiere:
|
||||||
if partition_id is None:
|
if partition_id is None:
|
||||||
@ -194,8 +186,8 @@ def do_evaluation_etat(
|
|||||||
|
|
||||||
# On considere une note "manquante" lorsqu'elle n'existe pas
|
# On considere une note "manquante" lorsqu'elle n'existe pas
|
||||||
# ou qu'elle est en attente (ATT)
|
# ou qu'elle est en attente (ATT)
|
||||||
GrNbMissing = scu.DictDefault() # group_id : nb notes manquantes
|
GrNbMissing = DictDefault() # group_id : nb notes manquantes
|
||||||
GrNotes = scu.DictDefault(defaultvalue=[]) # group_id: liste notes valides
|
GrNotes = DictDefault(defaultvalue=[]) # group_id: liste notes valides
|
||||||
TotalNbMissing = 0
|
TotalNbMissing = 0
|
||||||
TotalNbAtt = 0
|
TotalNbAtt = 0
|
||||||
groups = {} # group_id : group
|
groups = {} # group_id : group
|
||||||
@ -209,14 +201,14 @@ def do_evaluation_etat(
|
|||||||
isMissing = False
|
isMissing = False
|
||||||
if NotesDB.has_key(i["etudid"]):
|
if NotesDB.has_key(i["etudid"]):
|
||||||
val = NotesDB[i["etudid"]]["value"]
|
val = NotesDB[i["etudid"]]["value"]
|
||||||
if val == scu.NOTES_ATTENTE:
|
if val == NOTES_ATTENTE:
|
||||||
isMissing = True
|
isMissing = True
|
||||||
TotalNbAtt += 1
|
TotalNbAtt += 1
|
||||||
if group:
|
if group:
|
||||||
GrNotes[group["group_id"]].append(val)
|
GrNotes[group["group_id"]].append(val)
|
||||||
else:
|
else:
|
||||||
if group:
|
if group:
|
||||||
_ = GrNotes[group["group_id"]] # create group
|
junk = GrNotes[group["group_id"]] # create group
|
||||||
isMissing = True
|
isMissing = True
|
||||||
if isMissing:
|
if isMissing:
|
||||||
TotalNbMissing += 1
|
TotalNbMissing += 1
|
||||||
@ -227,7 +219,7 @@ def do_evaluation_etat(
|
|||||||
gr_incomplets.sort()
|
gr_incomplets.sort()
|
||||||
if (
|
if (
|
||||||
(TotalNbMissing > 0)
|
(TotalNbMissing > 0)
|
||||||
and (E["evaluation_type"] != scu.EVALUATION_RATTRAPAGE)
|
and (E["evaluation_type"] != EVALUATION_RATTRAPAGE)
|
||||||
and not is_malus
|
and not is_malus
|
||||||
):
|
):
|
||||||
complete = False
|
complete = False
|
||||||
@ -252,15 +244,15 @@ def do_evaluation_etat(
|
|||||||
"group_id": group_id,
|
"group_id": group_id,
|
||||||
"group_name": groups[group_id]["group_name"],
|
"group_name": groups[group_id]["group_name"],
|
||||||
"gr_moy_num": gr_moy,
|
"gr_moy_num": gr_moy,
|
||||||
"gr_moy": scu.fmt_note(gr_moy),
|
"gr_moy": fmt_note(gr_moy),
|
||||||
"gr_median_num": gr_median,
|
"gr_median_num": gr_median,
|
||||||
"gr_median": scu.fmt_note(gr_median),
|
"gr_median": fmt_note(gr_median),
|
||||||
"gr_mini": scu.fmt_note(gr_mini),
|
"gr_mini": fmt_note(gr_mini),
|
||||||
"gr_maxi": scu.fmt_note(gr_maxi),
|
"gr_maxi": fmt_note(gr_maxi),
|
||||||
"gr_mini_num": gr_mini,
|
"gr_mini": gr_mini,
|
||||||
"gr_maxi_num": gr_maxi,
|
"gr_maxi": gr_maxi,
|
||||||
"gr_nb_notes": len(notes),
|
"gr_nb_notes": len(notes),
|
||||||
"gr_nb_att": len([x for x in notes if x == scu.NOTES_ATTENTE]),
|
"gr_nb_att": len([x for x in notes if x == NOTES_ATTENTE]),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
gr_moyennes.sort(key=operator.itemgetter("group_name"))
|
gr_moyennes.sort(key=operator.itemgetter("group_name"))
|
||||||
@ -345,7 +337,7 @@ def do_evaluation_list_in_sem(context, formsemestre_id):
|
|||||||
'visibulletin': 1} ]
|
'visibulletin': 1} ]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
req = "select E.* from notes_evaluation E, notes_moduleimpl MI where MI.formsemestre_id = %(formsemestre_id)s and MI.moduleimpl_id = E.moduleimpl_id order by moduleimpl_id, numero desc, jour desc, heure_debut desc"
|
req = "select E.* from notes_evaluation E, notes_moduleimpl MI where MI.formsemestre_id = %(formsemestre_id)s and MI.moduleimpl_id = E.moduleimpl_id"
|
||||||
cnx = context.GetDBConnexion()
|
cnx = context.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
|
||||||
cursor.execute(req, {"formsemestre_id": formsemestre_id})
|
cursor.execute(req, {"formsemestre_id": formsemestre_id})
|
||||||
@ -388,7 +380,7 @@ def _eval_etat(evals):
|
|||||||
nb_evals_en_cours += 1
|
nb_evals_en_cours += 1
|
||||||
dates.append(e["etat"]["last_modif"])
|
dates.append(e["etat"]["last_modif"])
|
||||||
|
|
||||||
dates = scu.sort_dates(dates)
|
dates = sort_dates(dates)
|
||||||
|
|
||||||
if len(dates):
|
if len(dates):
|
||||||
last_modif = dates[-1] # date de derniere modif d'une note dans un module
|
last_modif = dates[-1] # date de derniere modif d'une note dans un module
|
||||||
@ -519,18 +511,18 @@ def evaluation_date_first_completion(context, evaluation_id):
|
|||||||
if not etat["evalcomplete"]:
|
if not etat["evalcomplete"]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# XXX inachevé ou à revoir ?
|
E = context.do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
||||||
|
M = context.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
|
formsemestre_id = M["formsemestre_id"]
|
||||||
|
|
||||||
# Il faut considerer les inscriptions au semestre
|
# Il faut considerer les inscriptions au semestre
|
||||||
# (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]
|
insem = context.do_formsemestre_inscription_listinscrits(formsemestre_id)
|
||||||
# M = context.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
insmod = context.do_moduleimpl_inscription_list(moduleimpl_id=E["moduleimpl_id"])
|
||||||
# formsemestre_id = M["formsemestre_id"]
|
insmodset = set([x["etudid"] for x in insmod])
|
||||||
# insem = context.do_formsemestre_inscription_listinscrits(formsemestre_id)
|
|
||||||
# insmod = context.do_moduleimpl_inscription_list(moduleimpl_id=E["moduleimpl_id"])
|
|
||||||
# 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]
|
||||||
|
|
||||||
notes = context._notes_getall(evaluation_id, filter_suppressed=False).values()
|
notes = context._notes_getall(evaluation_id, filter_suppressed=False).values()
|
||||||
notes_log = context._notes_getall(
|
notes_log = context._notes_getall(
|
||||||
@ -568,8 +560,8 @@ def formsemestre_evaluations_delai_correction(
|
|||||||
for e in evals:
|
for e in evals:
|
||||||
M = context.do_moduleimpl_list(moduleimpl_id=e["moduleimpl_id"])[0]
|
M = context.do_moduleimpl_list(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"] != EVALUATION_NORMALE) or (
|
||||||
Mod["module_type"] == scu.MODULE_MALUS
|
Mod["module_type"] == MODULE_MALUS
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
e["date_first_complete"] = evaluation_date_first_completion(
|
e["date_first_complete"] = evaluation_date_first_completion(
|
||||||
@ -620,8 +612,8 @@ def formsemestre_evaluations_delai_correction(
|
|||||||
caption="Correction des évaluations du semestre",
|
caption="Correction des évaluations du semestre",
|
||||||
preferences=context.get_preferences(formsemestre_id),
|
preferences=context.get_preferences(formsemestre_id),
|
||||||
base_url="%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id),
|
base_url="%s?formsemestre_id=%s" % (REQUEST.URL0, formsemestre_id),
|
||||||
origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
|
origin="Généré par %s le " % VERSION.SCONAME + timedate_human_repr() + "",
|
||||||
filename=scu.make_filename("evaluations_delais_" + sem["titreannee"]),
|
filename=make_filename("evaluations_delais_" + sem["titreannee"]),
|
||||||
)
|
)
|
||||||
return tab.make_page(context, format=format, REQUEST=REQUEST)
|
return tab.make_page(context, format=format, REQUEST=REQUEST)
|
||||||
|
|
||||||
@ -735,6 +727,7 @@ def evaluation_describe(context, evaluation_id="", edit_in_place=True, REQUEST=N
|
|||||||
M = context.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = context.do_moduleimpl_list(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"]
|
||||||
|
sem = sco_formsemestre.get_formsemestre(context, 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"]
|
||||||
@ -754,13 +747,13 @@ def evaluation_describe(context, evaluation_id="", edit_in_place=True, REQUEST=N
|
|||||||
etit = E["description"] or ""
|
etit = E["description"] or ""
|
||||||
if etit:
|
if etit:
|
||||||
etit = ' "' + etit + '"'
|
etit = ' "' + etit + '"'
|
||||||
if Mod["module_type"] == scu.MODULE_MALUS:
|
if Mod["module_type"] == MODULE_MALUS:
|
||||||
etit += ' <span class="eval_malus">(points de malus)</span>'
|
etit += ' <span class="eval_malus">(points de malus)</span>'
|
||||||
H = [
|
H = [
|
||||||
'<span class="eval_title">Evaluation%s</span><p><b>Module : %s</b></p>'
|
'<span class="eval_title">Evaluation%s</span><p><b>Module : %s</b></p>'
|
||||||
% (etit, mod_descr)
|
% (etit, mod_descr)
|
||||||
]
|
]
|
||||||
if Mod["module_type"] == scu.MODULE_MALUS:
|
if Mod["module_type"] == MODULE_MALUS:
|
||||||
# Indique l'UE
|
# Indique l'UE
|
||||||
ue = context.do_ue_list(args={"ue_id": Mod["ue_id"]})[0]
|
ue = context.do_ue_list(args={"ue_id": Mod["ue_id"]})[0]
|
||||||
H.append("<p><b>UE : %(acronyme)s</b></p>" % ue)
|
H.append("<p><b>UE : %(acronyme)s</b></p>" % ue)
|
||||||
@ -811,9 +804,9 @@ def evaluation_create_form(
|
|||||||
moduleimpl_id = the_eval["moduleimpl_id"]
|
moduleimpl_id = the_eval["moduleimpl_id"]
|
||||||
#
|
#
|
||||||
M = context.do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
M = context.do_moduleimpl_withmodule_list(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"] == 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 = NOTES_PRECISION # le plus petit bareme possible
|
||||||
if not readonly:
|
if not readonly:
|
||||||
try:
|
try:
|
||||||
context._evaluation_check_write_access(REQUEST, moduleimpl_id=moduleimpl_id)
|
context._evaluation_check_write_access(REQUEST, moduleimpl_id=moduleimpl_id)
|
||||||
@ -860,16 +853,17 @@ def evaluation_create_form(
|
|||||||
# Note maximale actuelle dans cette eval ?
|
# Note maximale actuelle dans cette eval ?
|
||||||
etat = do_evaluation_etat(context, evaluation_id)
|
etat = do_evaluation_etat(context, evaluation_id)
|
||||||
if etat["maxi_num"] is not None:
|
if etat["maxi_num"] is not None:
|
||||||
min_note_max = max(scu.NOTES_PRECISION, etat["maxi_num"])
|
min_note_max = max(NOTES_PRECISION, etat["maxi_num"])
|
||||||
else:
|
else:
|
||||||
min_note_max = scu.NOTES_PRECISION
|
min_note_max = NOTES_PRECISION
|
||||||
#
|
#
|
||||||
if min_note_max > scu.NOTES_PRECISION:
|
if min_note_max > NOTES_PRECISION:
|
||||||
min_note_max_str = scu.fmt_note(min_note_max)
|
min_note_max_str = fmt_note(min_note_max)
|
||||||
else:
|
else:
|
||||||
min_note_max_str = "0"
|
min_note_max_str = "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]
|
||||||
|
sem = sco_formsemestre.get_formsemestre(context, M["formsemestre_id"])
|
||||||
#
|
#
|
||||||
help = """<div class="help"><p class="help">
|
help = """<div class="help"><p class="help">
|
||||||
Le coefficient d'une évaluation n'est utilisé que pour pondérer les évaluations au sein d'un module.
|
Le coefficient d'une évaluation n'est utilisé que pour pondérer les évaluations au sein d'un module.
|
||||||
@ -979,7 +973,7 @@ def evaluation_create_form(
|
|||||||
"title": "Notes de 0 à",
|
"title": "Notes de 0 à",
|
||||||
"explanation": "barème (note max actuelle: %s)" % min_note_max_str,
|
"explanation": "barème (note max actuelle: %s)" % min_note_max_str,
|
||||||
"allow_null": False,
|
"allow_null": False,
|
||||||
"max_value": scu.NOTES_MAX,
|
"max_value": NOTES_MAX,
|
||||||
"min_value": min_note_max,
|
"min_value": min_note_max,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -1014,7 +1008,7 @@ def evaluation_create_form(
|
|||||||
{
|
{
|
||||||
"input_type": "menu",
|
"input_type": "menu",
|
||||||
"title": "Modalité",
|
"title": "Modalité",
|
||||||
"allowed_values": (scu.EVALUATION_NORMALE, scu.EVALUATION_RATTRAPAGE),
|
"allowed_values": (EVALUATION_NORMALE, EVALUATION_RATTRAPAGE),
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"labels": ("Normale", "Rattrapage"),
|
"labels": ("Normale", "Rattrapage"),
|
||||||
},
|
},
|
||||||
|
@ -644,12 +644,6 @@ def formsemestre_description_table(
|
|||||||
ModInscrits = context.do_moduleimpl_inscription_list(
|
ModInscrits = context.do_moduleimpl_inscription_list(
|
||||||
moduleimpl_id=M["moduleimpl_id"]
|
moduleimpl_id=M["moduleimpl_id"]
|
||||||
)
|
)
|
||||||
enseignants = ", ".join(
|
|
||||||
[
|
|
||||||
context.Users.user_info(m["ens_id"], REQUEST)["nomprenom"]
|
|
||||||
for m in M["ens"]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
l = {
|
l = {
|
||||||
"UE": M["ue"]["acronyme"],
|
"UE": M["ue"]["acronyme"],
|
||||||
"Code": M["module"]["code"],
|
"Code": M["module"]["code"],
|
||||||
@ -658,8 +652,6 @@ def formsemestre_description_table(
|
|||||||
"Inscrits": len(ModInscrits),
|
"Inscrits": len(ModInscrits),
|
||||||
"Responsable": context.Users.user_info(M["responsable_id"])["nomprenom"],
|
"Responsable": context.Users.user_info(M["responsable_id"])["nomprenom"],
|
||||||
"_Responsable_class": "scotext",
|
"_Responsable_class": "scotext",
|
||||||
"Enseignants": enseignants,
|
|
||||||
"_Enseignants_class": "scotext",
|
|
||||||
"Coef.": M["module"]["coefficient"],
|
"Coef.": M["module"]["coefficient"],
|
||||||
# 'ECTS' : M['module']['ects'],
|
# 'ECTS' : M['module']['ects'],
|
||||||
# Lien sur titre -> module
|
# Lien sur titre -> module
|
||||||
@ -697,7 +689,7 @@ def formsemestre_description_table(
|
|||||||
columns_ids = ["UE", "Code", "Module", "Coef."]
|
columns_ids = ["UE", "Code", "Module", "Coef."]
|
||||||
if context.get_preference("bul_show_ects", formsemestre_id):
|
if context.get_preference("bul_show_ects", formsemestre_id):
|
||||||
columns_ids += ["ects"]
|
columns_ids += ["ects"]
|
||||||
columns_ids += ["Inscrits", "Responsable", "Enseignants"]
|
columns_ids += ["Inscrits", "Responsable"]
|
||||||
if with_evals:
|
if with_evals:
|
||||||
columns_ids += [
|
columns_ids += [
|
||||||
"jour",
|
"jour",
|
||||||
@ -907,12 +899,6 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||||||
<th class="resp">Responsable</th>
|
<th class="resp">Responsable</th>
|
||||||
<th class="evals">Evaluations</th></tr>"""
|
<th class="evals">Evaluations</th></tr>"""
|
||||||
)
|
)
|
||||||
mails_enseignants = set(
|
|
||||||
[
|
|
||||||
context.Users.user_info(ens_id, REQUEST)["email"]
|
|
||||||
for ens_id in sem["responsables"]
|
|
||||||
]
|
|
||||||
) # adr. mail des enseignants
|
|
||||||
for M in Mlist:
|
for M in Mlist:
|
||||||
Mod = M["module"]
|
Mod = M["module"]
|
||||||
ModDescr = (
|
ModDescr = (
|
||||||
@ -929,12 +915,6 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||||||
ModInscrits = context.do_moduleimpl_inscription_list(
|
ModInscrits = context.do_moduleimpl_inscription_list(
|
||||||
moduleimpl_id=M["moduleimpl_id"]
|
moduleimpl_id=M["moduleimpl_id"]
|
||||||
)
|
)
|
||||||
mails_enseignants.add(
|
|
||||||
context.Users.user_info(M["responsable_id"], REQUEST)["email"]
|
|
||||||
)
|
|
||||||
mails_enseignants |= set(
|
|
||||||
[context.Users.user_info(m["ens_id"], REQUEST)["email"] for m in M["ens"]]
|
|
||||||
)
|
|
||||||
ue = M["ue"]
|
ue = M["ue"]
|
||||||
if prev_ue_id != ue["ue_id"]:
|
if prev_ue_id != ue["ue_id"]:
|
||||||
prev_ue_id = ue["ue_id"]
|
prev_ue_id = ue["ue_id"]
|
||||||
@ -1059,11 +1039,5 @@ def formsemestre_status(context, formsemestre_id=None, REQUEST=None):
|
|||||||
)
|
)
|
||||||
# --- LISTE DES ETUDIANTS
|
# --- LISTE DES ETUDIANTS
|
||||||
H += ['<div id="groupes">', context.make_listes_sem(sem, REQUEST), "</div>"]
|
H += ['<div id="groupes">', context.make_listes_sem(sem, REQUEST), "</div>"]
|
||||||
# --- Lien mail enseignants:
|
|
||||||
adrlist = list(mails_enseignants - set([""]))
|
|
||||||
if adrlist:
|
|
||||||
H.append(
|
|
||||||
'<p><a class="stdlink" href="mailto:?cc=%s">Courrier aux %d enseignants du semestre</a></p>'
|
|
||||||
% (",".join(adrlist), len(adrlist))
|
|
||||||
)
|
|
||||||
return "".join(H) + context.sco_footer(REQUEST)
|
return "".join(H) + context.sco_footer(REQUEST)
|
||||||
|
@ -431,10 +431,10 @@ def groups_table(
|
|||||||
format: csv, json, xml, xls, allxls, xlsappel, moodlecsv, pdf
|
format: csv, json, xml, xls, allxls, xlsappel, moodlecsv, pdf
|
||||||
Si with_codes, ajoute 4 colonnes avec les codes etudid, NIP, INE et etape
|
Si with_codes, ajoute 4 colonnes avec les codes etudid, NIP, INE et etape
|
||||||
"""
|
"""
|
||||||
# log(
|
log(
|
||||||
# "enter groups_table %s: %s"
|
"enter groups_table %s: %s"
|
||||||
# % (groups_infos.members[0]["nom"], groups_infos.members[0].get("etape", "-"))
|
% (groups_infos.members[0]["nom"], groups_infos.members[0].get("etape", "-"))
|
||||||
# )
|
)
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
authuser = REQUEST.AUTHENTICATED_USER
|
||||||
|
|
||||||
with_codes = int(with_codes)
|
with_codes = int(with_codes)
|
||||||
@ -798,11 +798,6 @@ def tab_absences_html(context, groups_infos, etat=None, REQUEST=None):
|
|||||||
"<h3>Absences</h3>",
|
"<h3>Absences</h3>",
|
||||||
'<ul class="ul_abs">',
|
'<ul class="ul_abs">',
|
||||||
"<li>",
|
"<li>",
|
||||||
form_choix_saisie_semaine(
|
|
||||||
context, groups_infos, REQUEST=REQUEST
|
|
||||||
), # Ajout Le Havre
|
|
||||||
"</li>",
|
|
||||||
"<li>",
|
|
||||||
form_choix_jour_saisie_hebdo(context, groups_infos, REQUEST=REQUEST),
|
form_choix_jour_saisie_hebdo(context, groups_infos, REQUEST=REQUEST),
|
||||||
"</li>",
|
"</li>",
|
||||||
"""<li><a class="stdlink" href="Absences/EtatAbsencesGr?%s&debut=%s&fin=%s">Etat des absences du groupe</a></li>"""
|
"""<li><a class="stdlink" href="Absences/EtatAbsencesGr?%s&debut=%s&fin=%s">Etat des absences du groupe</a></li>"""
|
||||||
@ -893,37 +888,6 @@ def form_choix_jour_saisie_hebdo(context, groups_infos, REQUEST=None):
|
|||||||
return "\n".join(FA)
|
return "\n".join(FA)
|
||||||
|
|
||||||
|
|
||||||
# Ajout Le Havre
|
|
||||||
# Formulaire saisie absences semaine
|
|
||||||
def form_choix_saisie_semaine(context, groups_infos, REQUEST=None):
|
|
||||||
authuser = REQUEST.AUTHENTICATED_USER
|
|
||||||
if not authuser.has_permission(ScoAbsChange, context):
|
|
||||||
return ""
|
|
||||||
sem = groups_infos.formsemestre
|
|
||||||
# construit l'URL "destination"
|
|
||||||
# (a laquelle on revient apres saisie absences)
|
|
||||||
query_args = cgi.parse_qs(REQUEST.QUERY_STRING)
|
|
||||||
moduleimpl_id = query_args.get("moduleimpl_id", [""])[0]
|
|
||||||
if "head_message" in query_args:
|
|
||||||
del query_args["head_message"]
|
|
||||||
destination = "%s?%s" % (REQUEST.URL, urllib.urlencode(query_args, True))
|
|
||||||
destination = destination.replace(
|
|
||||||
"%", "%%"
|
|
||||||
) # car ici utilisee dans un format string !
|
|
||||||
|
|
||||||
DateJour = time.strftime("%d/%m/%Y")
|
|
||||||
datelundi = ZAbsences.ddmmyyyy(DateJour).prev_monday()
|
|
||||||
FA = [] # formulaire avec menu saisi hebdo des absences
|
|
||||||
FA.append('<form action="Absences/SignaleAbsenceGrHebdo" method="get">')
|
|
||||||
FA.append('<input type="hidden" name="datelundi" value="%s"/>' % datelundi)
|
|
||||||
FA.append('<input type="hidden" name="moduleimpl_id" value="%s"/>' % moduleimpl_id)
|
|
||||||
FA.append('<input type="hidden" name="destination" value="%s"/>' % destination)
|
|
||||||
FA.append(groups_infos.get_form_elem())
|
|
||||||
FA.append('<input type="submit" class="button" value="Saisie à la semaine" />')
|
|
||||||
FA.append("</form>")
|
|
||||||
return "\n".join(FA)
|
|
||||||
|
|
||||||
|
|
||||||
def export_groups_as_moodle_csv(context, formsemestre_id=None, REQUEST=None):
|
def export_groups_as_moodle_csv(context, formsemestre_id=None, REQUEST=None):
|
||||||
"""Export all students/groups, in a CSV format suitable for Moodle
|
"""Export all students/groups, in a CSV format suitable for Moodle
|
||||||
Each (student,group) will be listed on a separate line
|
Each (student,group) will be listed on a separate line
|
||||||
|
@ -39,8 +39,7 @@ TITLES = ("user_name", "nom", "prenom", "email", "roles", "dept")
|
|||||||
|
|
||||||
|
|
||||||
def generate_excel_sample():
|
def generate_excel_sample():
|
||||||
"""generates an excel document suitable to import users
|
"""generates an excel document suitable to import users"""
|
||||||
"""
|
|
||||||
style = sco_excel.Excel_MakeStyle(bold=True)
|
style = sco_excel.Excel_MakeStyle(bold=True)
|
||||||
titles = TITLES
|
titles = TITLES
|
||||||
titlesStyles = [style] * len(titles)
|
titlesStyles = [style] * len(titles)
|
||||||
@ -105,7 +104,7 @@ def import_users(U, auth_dept="", context=None):
|
|||||||
- créer utilisateur et mettre le mot de passe
|
- créer utilisateur et mettre le mot de passe
|
||||||
- envoyer mot de passe par mail
|
- envoyer mot de passe par mail
|
||||||
|
|
||||||
En cas d'erreur: supprimer tous les utilisateurs que l'on vient de créer.
|
En cas d'erreur: supprimer tous les utilisateurs que l'on vient de créer.
|
||||||
"""
|
"""
|
||||||
created = [] # liste de uid créés
|
created = [] # liste de uid créés
|
||||||
try:
|
try:
|
||||||
@ -164,11 +163,11 @@ def generate_password():
|
|||||||
return "".join(RNG.sample(l, PASSLEN))
|
return "".join(RNG.sample(l, PASSLEN))
|
||||||
|
|
||||||
|
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
import email
|
||||||
from email.MIMEText import MIMEText
|
from email.mime.multipart import MIMEMultipart
|
||||||
from email.MIMEBase import MIMEBase
|
from email.mime.text import MIMEText
|
||||||
from email.Header import Header
|
from email.mime.base import MIMEBase
|
||||||
from email import Encoders
|
from email.header import Header
|
||||||
|
|
||||||
|
|
||||||
def mail_password(u, context=None, reset=False):
|
def mail_password(u, context=None, reset=False):
|
||||||
|
@ -262,11 +262,7 @@ def moduleimpl_status(context, moduleimpl_id=None, partition_id=None, REQUEST=No
|
|||||||
H.append(
|
H.append(
|
||||||
"""Afficher les groupes de <select name="partition_id" onchange="document.f.submit();">"""
|
"""Afficher les groupes de <select name="partition_id" onchange="document.f.submit();">"""
|
||||||
)
|
)
|
||||||
been_selected = False
|
|
||||||
for partition in partitions:
|
for partition in partitions:
|
||||||
if not partition_id and not been_selected:
|
|
||||||
selected = "selected"
|
|
||||||
been_selected = True
|
|
||||||
if partition["partition_id"] == partition_id:
|
if partition["partition_id"] == partition_id:
|
||||||
selected = "selected"
|
selected = "selected"
|
||||||
else:
|
else:
|
||||||
@ -341,11 +337,12 @@ def moduleimpl_status(context, moduleimpl_id=None, partition_id=None, REQUEST=No
|
|||||||
% etat["last_modif"].strftime("%d/%m/%Y à %Hh%M")
|
% etat["last_modif"].strftime("%d/%m/%Y à %Hh%M")
|
||||||
)
|
)
|
||||||
H.append('<span class="evalindex_cont">')
|
H.append('<span class="evalindex_cont">')
|
||||||
if has_expression or True:
|
if has_expression:
|
||||||
H.append(
|
H.append(
|
||||||
"""<span class="evalindex" title="Indice dans les vecteurs (formules)">%2d</span>"""
|
"""<span class="evalindex" title="Indice dans les vecteurs (formules)">%02d</span>"""
|
||||||
% eval_index
|
% eval_index
|
||||||
)
|
)
|
||||||
|
|
||||||
# Fleches:
|
# Fleches:
|
||||||
H.append('<span class="eval_arrows_chld">')
|
H.append('<span class="eval_arrows_chld">')
|
||||||
if eval_index != (len(ModEvals) - 1) and caneditevals:
|
if eval_index != (len(ModEvals) - 1) and caneditevals:
|
||||||
|
11
sco_news.py
@ -33,11 +33,9 @@ from cStringIO import StringIO
|
|||||||
import datetime, re
|
import datetime, re
|
||||||
import time
|
import time
|
||||||
from stripogram import html2text, html2safehtml
|
from stripogram import html2text, html2safehtml
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
from email.MIMEText import MIMEText
|
from email.mime.text import MIMEText
|
||||||
from email.Header import Header
|
from email.header import Header
|
||||||
from email import Encoders
|
|
||||||
|
|
||||||
|
|
||||||
from notesdb import *
|
from notesdb import *
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
@ -252,8 +250,7 @@ def scolar_news_summary_rss(context, title, sco_url, n=5):
|
|||||||
|
|
||||||
|
|
||||||
def _send_news_by_mail(context, n):
|
def _send_news_by_mail(context, n):
|
||||||
"""Notify by email
|
"""Notify by email"""
|
||||||
"""
|
|
||||||
infos = _get_formsemestre_infos_from_news(context, n)
|
infos = _get_formsemestre_infos_from_news(context, n)
|
||||||
formsemestre_id = infos.get("formsemestre_id", None)
|
formsemestre_id = infos.get("formsemestre_id", None)
|
||||||
prefs = context.get_preferences(formsemestre_id=formsemestre_id)
|
prefs = context.get_preferences(formsemestre_id=formsemestre_id)
|
||||||
|
@ -53,7 +53,7 @@ from PIL import Image as PILImage
|
|||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
import glob
|
import glob
|
||||||
|
|
||||||
from sco_utils import CONFIG, SCO_SRCDIR
|
from sco_utils import CONFIG, SCO_SRC_DIR
|
||||||
from notes_log import log
|
from notes_log import log
|
||||||
|
|
||||||
import scolars
|
import scolars
|
||||||
@ -62,7 +62,7 @@ from scolog import logdb
|
|||||||
|
|
||||||
# Full paths on server's filesystem. Something like "/opt/scodoc/var/scodoc/photos"
|
# Full paths on server's filesystem. Something like "/opt/scodoc/var/scodoc/photos"
|
||||||
PHOTO_DIR = os.path.join(os.environ["INSTANCE_HOME"], "var", "scodoc", "photos")
|
PHOTO_DIR = os.path.join(os.environ["INSTANCE_HOME"], "var", "scodoc", "photos")
|
||||||
ICONS_DIR = os.path.join(SCO_SRCDIR, "static", "icons")
|
ICONS_DIR = os.path.join(SCO_SRC_DIR, "static", "icons")
|
||||||
UNKNOWN_IMAGE_PATH = os.path.join(ICONS_DIR, "unknown.jpg")
|
UNKNOWN_IMAGE_PATH = os.path.join(ICONS_DIR, "unknown.jpg")
|
||||||
UNKNOWN_IMAGE_URL = "get_photo_image?etudid=" # with empty etudid => unknown face image
|
UNKNOWN_IMAGE_URL = "get_photo_image?etudid=" # with empty etudid => unknown face image
|
||||||
IMAGE_EXT = ".jpg"
|
IMAGE_EXT = ".jpg"
|
||||||
|
@ -37,9 +37,9 @@ import datetime
|
|||||||
|
|
||||||
import sco_utils
|
import sco_utils
|
||||||
from sco_utils import ScoEtudInscrit, log, ScoValueError, DictDefault
|
from sco_utils import ScoEtudInscrit, log, ScoValueError, DictDefault
|
||||||
from sco_utils import SCO_TMPDIR, SCO_ENCODING
|
from sco_utils import SCO_TMP_DIR, SCO_ENCODING
|
||||||
|
|
||||||
SCO_CACHE_ETAPE_FILENAME = os.path.join(SCO_TMPDIR, "last_etapes.xml")
|
SCO_CACHE_ETAPE_FILENAME = os.path.join(SCO_TMP_DIR, "last_etapes.xml")
|
||||||
|
|
||||||
|
|
||||||
def has_portal(context):
|
def has_portal(context):
|
||||||
|
@ -49,7 +49,7 @@ Chaque parametre est défini dans la base de données SQL par:
|
|||||||
Au niveau du code interface, on défini pour chaque préférence:
|
Au niveau du code interface, on défini pour chaque préférence:
|
||||||
- name (clé)
|
- name (clé)
|
||||||
- title : titre en français
|
- title : titre en français
|
||||||
- initvalue : valeur initiale, chargée depuis config/scodoc_config.py
|
- initvalue : valeur initiale
|
||||||
- explanation: explication en français
|
- explanation: explication en français
|
||||||
- size: longueur du chap texte
|
- size: longueur du chap texte
|
||||||
- input_type: textarea,separator,... type de widget TrivialFormulator a utiliser
|
- input_type: textarea,separator,... type de widget TrivialFormulator a utiliser
|
||||||
@ -90,13 +90,6 @@ sinon, elle ne concerne que le semestre indiqué.
|
|||||||
- editer les preferences d'un semestre:
|
- editer les preferences d'un semestre:
|
||||||
sem_preferences(context,formsemestre_id).edit()
|
sem_preferences(context,formsemestre_id).edit()
|
||||||
|
|
||||||
* Valeurs par défaut:
|
|
||||||
On a deux valeurs par défaut possibles:
|
|
||||||
- via le fichier scodoc_config.py, qui peut être modifié localement.
|
|
||||||
- si rien dans scodoc_config.py, la valeur définie par
|
|
||||||
sco_preferences.py est utilisée (ne pas modifier ce fichier).
|
|
||||||
|
|
||||||
|
|
||||||
* Implémentation: sco_preferences.py
|
* Implémentation: sco_preferences.py
|
||||||
|
|
||||||
PREF_CATEGORIES : définition des catégories de préférences (pour
|
PREF_CATEGORIES : définition des catégories de préférences (pour
|
||||||
|
@ -764,17 +764,12 @@ def _list_notes_evals(context, evals, etudid):
|
|||||||
"""
|
"""
|
||||||
L = []
|
L = []
|
||||||
for e in evals:
|
for e in evals:
|
||||||
if (
|
if e["etat"]["evalcomplete"]:
|
||||||
e["etat"]["evalcomplete"]
|
|
||||||
or e["etat"]["evalattente"]
|
|
||||||
or e["publish_incomplete"]
|
|
||||||
):
|
|
||||||
NotesDB = context._notes_getall(e["evaluation_id"])
|
NotesDB = context._notes_getall(e["evaluation_id"])
|
||||||
if NotesDB.has_key(etudid):
|
if NotesDB.has_key(etudid):
|
||||||
val = NotesDB[etudid]["value"]
|
val = NotesDB[etudid]["value"]
|
||||||
else:
|
else:
|
||||||
# Note manquante mais prise en compte immédiate: affiche ATT
|
val = None
|
||||||
val = NOTES_ATTENTE
|
|
||||||
val_fmt = fmt_note(val, keep_numeric=True)
|
val_fmt = fmt_note(val, keep_numeric=True)
|
||||||
L.append(val_fmt)
|
L.append(val_fmt)
|
||||||
return L
|
return L
|
||||||
@ -783,15 +778,9 @@ def _list_notes_evals(context, evals, etudid):
|
|||||||
def _list_notes_evals_titles(context, codemodule, evals):
|
def _list_notes_evals_titles(context, codemodule, evals):
|
||||||
"""Liste des titres des evals completes"""
|
"""Liste des titres des evals completes"""
|
||||||
L = []
|
L = []
|
||||||
eval_index = len(evals) - 1
|
|
||||||
for e in evals:
|
for e in evals:
|
||||||
if (
|
if e["etat"]["evalcomplete"]:
|
||||||
e["etat"]["evalcomplete"]
|
L.append(codemodule + "-" + DateISOtoDMY(e["jour"]))
|
||||||
or e["etat"]["evalattente"]
|
|
||||||
or e["publish_incomplete"]
|
|
||||||
):
|
|
||||||
L.append(codemodule + "-" + str(eval_index) + "-" + e["jour"].isoformat())
|
|
||||||
eval_index -= 1
|
|
||||||
return L
|
return L
|
||||||
|
|
||||||
|
|
||||||
@ -799,11 +788,7 @@ def _list_notes_evals_stats(context, evals, key):
|
|||||||
"""Liste des stats (moy, ou rien!) des evals completes"""
|
"""Liste des stats (moy, ou rien!) des evals completes"""
|
||||||
L = []
|
L = []
|
||||||
for e in evals:
|
for e in evals:
|
||||||
if (
|
if e["etat"]["evalcomplete"]:
|
||||||
e["etat"]["evalcomplete"]
|
|
||||||
or e["etat"]["evalattente"]
|
|
||||||
or e["publish_incomplete"]
|
|
||||||
):
|
|
||||||
if key == "moy":
|
if key == "moy":
|
||||||
val = e["etat"]["moy_num"]
|
val = e["etat"]["moy_num"]
|
||||||
L.append(fmt_note(val, keep_numeric=True))
|
L.append(fmt_note(val, keep_numeric=True))
|
||||||
|
@ -28,8 +28,6 @@
|
|||||||
"""Synchronisation des listes d'étudiants avec liste portail (Apogée)
|
"""Synchronisation des listes d'étudiants avec liste portail (Apogée)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import time
|
|
||||||
import pprint
|
|
||||||
|
|
||||||
from sco_utils import ScoEtudInscrit, annee_scolaire_debut, log, ScoValueError
|
from sco_utils import ScoEtudInscrit, annee_scolaire_debut, log, ScoValueError
|
||||||
from notesdb import ScoDocCursor
|
from notesdb import ScoDocCursor
|
||||||
@ -44,6 +42,8 @@ import sco_formsemestre_inscriptions
|
|||||||
import sco_formsemestre_status
|
import sco_formsemestre_status
|
||||||
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
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
# Clés utilisées pour la synchro
|
# Clés utilisées pour la synchro
|
||||||
EKEY_APO = "nip"
|
EKEY_APO = "nip"
|
||||||
EKEY_SCO = "code_nip"
|
EKEY_SCO = "code_nip"
|
||||||
@ -695,7 +695,7 @@ def do_import_etud_admission(
|
|||||||
"codelycee": get_opt_str(etud, "lycee"),
|
"codelycee": get_opt_str(etud, "lycee"),
|
||||||
"boursier": get_opt_str(etud, "bourse"),
|
"boursier": get_opt_str(etud, "bourse"),
|
||||||
}
|
}
|
||||||
log("do_import_etud_admission: etud=%s" % pprint.pformat(etud))
|
log("do_import_etud_admission: etud=%s" % etud)
|
||||||
al = scolars.admission_list(cnx, args={"etudid": etudid})
|
al = scolars.admission_list(cnx, args={"etudid": etudid})
|
||||||
if not al:
|
if not al:
|
||||||
scolars.admission_create(cnx, args) # -> adm_id
|
scolars.admission_create(cnx, args) # -> adm_id
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
""" Verification version logiciel vs version "stable" sur serveur
|
""" Verification version logiciel vs version "stable" sur serveur
|
||||||
N'effectue pas la mise à jour automatiquement, mais permet un affichage d'avertissement.
|
N'effectue pas la mise à jour automatiquement, mais permet un affichage d'avertissement.
|
||||||
"""
|
"""
|
||||||
|
import sco_utils
|
||||||
from sco_utils import *
|
from sco_utils import *
|
||||||
|
|
||||||
# Appel renvoyant la subversion "stable"
|
# Appel renvoyant la subversion "stable"
|
||||||
@ -66,65 +66,66 @@ def is_up_to_date(context):
|
|||||||
"""True if up_to_date
|
"""True if up_to_date
|
||||||
Returns status, message
|
Returns status, message
|
||||||
"""
|
"""
|
||||||
global _LAST_UP_TO_DATE_REQUEST, _UP_TO_DATE, _UP_TO_DATE_MSG
|
log("Warning: is_up_to_date not implemented for ScoDoc8")
|
||||||
if _LAST_UP_TO_DATE_REQUEST and (
|
return True, "unimplemented"
|
||||||
datetime.datetime.now() - _LAST_UP_TO_DATE_REQUEST
|
# global _LAST_UP_TO_DATE_REQUEST, _UP_TO_DATE, _UP_TO_DATE_MSG
|
||||||
) < datetime.timedelta(1):
|
# if _LAST_UP_TO_DATE_REQUEST and (
|
||||||
# requete deja effectuee aujourd'hui:
|
# datetime.datetime.now() - _LAST_UP_TO_DATE_REQUEST
|
||||||
return _UP_TO_DATE, _UP_TO_DATE_MSG
|
# ) < datetime.timedelta(1):
|
||||||
|
# # requete deja effectuee aujourd'hui:
|
||||||
|
# return _UP_TO_DATE, _UP_TO_DATE_MSG
|
||||||
|
|
||||||
last_stable_ver = get_last_stable_version()
|
# last_stable_ver = get_last_stable_version()
|
||||||
cur_ver = get_svn_version(context.file_path) # in sco_utils
|
# cur_ver = sco_utils.get_scodoc_version()
|
||||||
cur_ver2 = cur_ver
|
# cur_ver2 = cur_ver
|
||||||
cur_ver_num = -1
|
# cur_ver_num = -1
|
||||||
# Convert versions to integers:
|
# # Convert versions to integers:
|
||||||
try:
|
# try:
|
||||||
# cur_ver can be "1234" or "1234M' or '1234:1245M'...
|
# # cur_ver can be "1234" or "1234M' or '1234:1245M'...
|
||||||
fs = cur_ver.split(":", 1)
|
# fs = cur_ver.split(":", 1)
|
||||||
if len(fs) > 1:
|
# if len(fs) > 1:
|
||||||
cur_ver2 = fs[-1]
|
# cur_ver2 = fs[-1]
|
||||||
m = re.match(r"([0-9]*)", cur_ver2)
|
# m = re.match(r"([0-9]*)", cur_ver2)
|
||||||
if not m:
|
# if not m:
|
||||||
raise ValueError(
|
# raise ValueError(
|
||||||
"invalid svn version"
|
# "invalid svn version"
|
||||||
) # should never occur, regexp always (maybe empty) match
|
# ) # should never occur, regexp always (maybe empty) match
|
||||||
cur_ver_num = int(m.group(1))
|
# cur_ver_num = int(m.group(1))
|
||||||
except:
|
# except:
|
||||||
log('Warning: no numeric subversion ! (cur_ver="%s")' % cur_ver)
|
# log('Warning: no numeric subversion ! (cur_ver="%s")' % cur_ver)
|
||||||
return _UP_TO_DATE, _UP_TO_DATE_MSG # silently ignore misconfiguration ?
|
# return _UP_TO_DATE, _UP_TO_DATE_MSG # silently ignore misconfiguration ?
|
||||||
try:
|
# try:
|
||||||
last_stable_ver_num = int(last_stable_ver)
|
# last_stable_ver_num = int(last_stable_ver)
|
||||||
except:
|
# except:
|
||||||
log("Warning: last_stable_version returned by server is invalid !")
|
# log("Warning: last_stable_version returned by server is invalid !")
|
||||||
return (
|
# return (
|
||||||
_UP_TO_DATE,
|
# _UP_TO_DATE,
|
||||||
_UP_TO_DATE_MSG,
|
# _UP_TO_DATE_MSG,
|
||||||
) # should ignore this error (maybe server is unreachable)
|
# ) # should ignore this error (maybe server is unreachable)
|
||||||
#
|
# #
|
||||||
if cur_ver_num < last_stable_ver_num:
|
# if cur_ver_num < last_stable_ver_num:
|
||||||
_UP_TO_DATE = False
|
# _UP_TO_DATE = False
|
||||||
_UP_TO_DATE_MSG = "Version %s disponible (version %s installée)" % (
|
# _UP_TO_DATE_MSG = "Version %s disponible (version %s installée)" % (
|
||||||
last_stable_ver,
|
# last_stable_ver,
|
||||||
cur_ver_num,
|
# cur_ver_num,
|
||||||
)
|
# )
|
||||||
log(
|
# log(
|
||||||
"Warning: ScoDoc installation is not up-to-date, should upgrade\n%s"
|
# "Warning: ScoDoc installation is not up-to-date, should upgrade\n%s"
|
||||||
% _UP_TO_DATE_MSG
|
# % _UP_TO_DATE_MSG
|
||||||
)
|
# )
|
||||||
else:
|
# else:
|
||||||
_UP_TO_DATE = True
|
# _UP_TO_DATE = True
|
||||||
_UP_TO_DATE_MSG = ""
|
# _UP_TO_DATE_MSG = ""
|
||||||
log(
|
# log(
|
||||||
"ScoDoc is up-to-date (cur_ver: %s, using %s=%s)"
|
# "ScoDoc is up-to-date (cur_ver: %s, using %s=%s)"
|
||||||
% (cur_ver, cur_ver2, cur_ver_num)
|
# % (cur_ver, cur_ver2, cur_ver_num)
|
||||||
)
|
# )
|
||||||
|
|
||||||
return _UP_TO_DATE, _UP_TO_DATE_MSG
|
# return _UP_TO_DATE, _UP_TO_DATE_MSG
|
||||||
|
|
||||||
|
|
||||||
def html_up_to_date_box(context):
|
def html_up_to_date_box(context):
|
||||||
"""
|
""""""
|
||||||
"""
|
|
||||||
status, msg = is_up_to_date(context)
|
status, msg = is_up_to_date(context)
|
||||||
if status:
|
if status:
|
||||||
return ""
|
return ""
|
||||||
|
145
sco_utils.py
@ -186,53 +186,84 @@ def get_mention(moy):
|
|||||||
return NOTES_MENTIONS_LABS[bisect.bisect_right(NOTES_MENTIONS_TH, moy)]
|
return NOTES_MENTIONS_LABS[bisect.bisect_right(NOTES_MENTIONS_TH, moy)]
|
||||||
|
|
||||||
|
|
||||||
|
class DictDefault(dict): # obsolete, use collections.defaultdict
|
||||||
|
"""A dictionnary with default value for all keys
|
||||||
|
Each time a non existent key is requested, it is added to the dict.
|
||||||
|
(used in python 2.4, can't use new __missing__ method)
|
||||||
|
"""
|
||||||
|
|
||||||
|
defaultvalue = 0
|
||||||
|
|
||||||
|
def __init__(self, defaultvalue=0, kv_dict={}):
|
||||||
|
dict.__init__(self)
|
||||||
|
self.defaultvalue = defaultvalue
|
||||||
|
self.update(kv_dict)
|
||||||
|
|
||||||
|
def __getitem__(self, k):
|
||||||
|
if self.has_key(k):
|
||||||
|
return self.get(k)
|
||||||
|
value = copy.copy(self.defaultvalue)
|
||||||
|
self[k] = value
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class WrapDict:
|
||||||
|
"""Wrap a dict so that getitem returns '' when values are None"""
|
||||||
|
|
||||||
|
def __init__(self, adict, NoneValue=""):
|
||||||
|
self.dict = adict
|
||||||
|
self.NoneValue = NoneValue
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
value = self.dict[key]
|
||||||
|
if value is None:
|
||||||
|
return self.NoneValue
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def group_by_key(d, key):
|
||||||
|
g = DictDefault(defaultvalue=[])
|
||||||
|
for e in d:
|
||||||
|
g[e[key]].append(e)
|
||||||
|
return g
|
||||||
|
|
||||||
|
|
||||||
# ----- Global lock for critical sections (except notes_tables caches)
|
# ----- Global lock for critical sections (except notes_tables caches)
|
||||||
GSL = thread.allocate_lock() # Global ScoDoc Lock
|
GSL = thread.allocate_lock() # Global ScoDoc Lock
|
||||||
|
|
||||||
if "INSTANCE_HOME" in os.environ:
|
if "INSTANCE_HOME" in os.environ:
|
||||||
# ----- Repertoire "var" (local)
|
# ----- Repertoire "var" (local)
|
||||||
SCODOC_VAR_DIR = os.path.join(os.environ["INSTANCE_HOME"], "var", "scodoc")
|
SCODOC_VAR_DIR = os.path.join(os.environ["INSTANCE_HOME"], "var", "scodoc")
|
||||||
|
# ----- Repertoire "config" modifiable
|
||||||
|
# /opt/scodoc/var/scodoc/config
|
||||||
|
SCODOC_CFG_DIR = os.path.join(SCODOC_VAR_DIR, "config")
|
||||||
# ----- Version information
|
# ----- Version information
|
||||||
SCODOC_VERSION_DIR = os.path.join(SCODOC_VAR_DIR, "config", "version")
|
SCODOC_VERSION_DIR = os.path.join(SCODOC_CFG_DIR, "version")
|
||||||
# ----- Repertoire tmp
|
# ----- Repertoire tmp
|
||||||
SCO_TMPDIR = os.path.join(SCODOC_VAR_DIR, "tmp")
|
SCO_TMP_DIR = os.path.join(SCODOC_VAR_DIR, "tmp")
|
||||||
if not os.path.exists(SCO_TMPDIR):
|
if not os.path.exists(SCO_TMP_DIR):
|
||||||
os.mkdir(SCO_TMPDIR, 0o755)
|
os.mkdir(SCO_TMP_DIR, 0o755)
|
||||||
# ----- Les logos: /opt/scodoc/var/scodoc/config/logos
|
# ----- Les logos: /opt/scodoc/var/scodoc/config/logos
|
||||||
SCODOC_LOGOS_DIR = os.path.join(SCODOC_VAR_DIR, "config", "logos")
|
SCODOC_LOGOS_DIR = os.path.join(SCODOC_CFG_DIR, "logos")
|
||||||
|
|
||||||
# ----- Repertoire "config" (devrait s'appeler "tools"...)
|
# Dans les sources:
|
||||||
SCO_CONFIG_DIR = os.path.join(
|
SCO_SRC_DIR = os.path.join(os.environ["INSTANCE_HOME"], "Products", "ScoDoc")
|
||||||
os.environ["INSTANCE_HOME"], "Products", "ScoDoc", "config"
|
# - Les outils distribués
|
||||||
)
|
SCO_TOOLS_DIR = os.path.join(SCO_SRC_DIR, "config")
|
||||||
|
|
||||||
|
|
||||||
# ----- Lecture du fichier de configuration
|
# ----- Lecture du fichier de configuration
|
||||||
SCO_SRCDIR = os.path.split(VERSION.__file__)[0]
|
import sco_config
|
||||||
if SCO_SRCDIR:
|
import sco_config_load
|
||||||
SCO_SRCDIR += "/"
|
|
||||||
else:
|
|
||||||
SCO_SRCDIR = "/opt/scodoc/Products/ScoDoc/" # debug mode
|
|
||||||
CONFIG = None
|
|
||||||
try:
|
|
||||||
_config_filename = SCO_SRCDIR + "config/scodoc_config.py"
|
|
||||||
_config_text = open(_config_filename).read()
|
|
||||||
except:
|
|
||||||
sys.stderr.write("sco_utils: cannot open configuration file %s" % _config_filename)
|
|
||||||
raise
|
|
||||||
|
|
||||||
try:
|
|
||||||
exec(_config_text)
|
|
||||||
except:
|
|
||||||
sys.stderr.write("sco_utils: error in configuration file %s" % _config_filename)
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
sco_config_load.load_local_configuration()
|
||||||
|
CONFIG = sco_config.CONFIG
|
||||||
if hasattr(CONFIG, "CODES_EXPL"):
|
if hasattr(CONFIG, "CODES_EXPL"):
|
||||||
CODES_EXPL.update(
|
CODES_EXPL.update(
|
||||||
CONFIG.CODES_EXPL
|
CONFIG.CODES_EXPL
|
||||||
) # permet de customiser les explications de codes
|
) # permet de customiser les explications de codes
|
||||||
|
|
||||||
|
|
||||||
if CONFIG.CUSTOM_HTML_HEADER:
|
if CONFIG.CUSTOM_HTML_HEADER:
|
||||||
CUSTOM_HTML_HEADER = open(CONFIG.CUSTOM_HTML_HEADER).read()
|
CUSTOM_HTML_HEADER = open(CONFIG.CUSTOM_HTML_HEADER).read()
|
||||||
else:
|
else:
|
||||||
@ -297,50 +328,6 @@ JSON_MIMETYPE = "application/json"
|
|||||||
|
|
||||||
LOGOS_IMAGES_ALLOWED_TYPES = ("jpg", "png") # remind that PIL does not read pdf
|
LOGOS_IMAGES_ALLOWED_TYPES = ("jpg", "png") # remind that PIL does not read pdf
|
||||||
|
|
||||||
|
|
||||||
class DictDefault(dict): # obsolete, use collections.defaultdict
|
|
||||||
"""A dictionnary with default value for all keys
|
|
||||||
Each time a non existent key is requested, it is added to the dict.
|
|
||||||
(used in python 2.4, can't use new __missing__ method)
|
|
||||||
"""
|
|
||||||
|
|
||||||
defaultvalue = 0
|
|
||||||
|
|
||||||
def __init__(self, defaultvalue=0, kv_dict={}):
|
|
||||||
dict.__init__(self)
|
|
||||||
self.defaultvalue = defaultvalue
|
|
||||||
self.update(kv_dict)
|
|
||||||
|
|
||||||
def __getitem__(self, k):
|
|
||||||
if self.has_key(k):
|
|
||||||
return self.get(k)
|
|
||||||
value = copy.copy(self.defaultvalue)
|
|
||||||
self[k] = value
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
class WrapDict:
|
|
||||||
"""Wrap a dict so that getitem returns '' when values are None"""
|
|
||||||
|
|
||||||
def __init__(self, adict, NoneValue=""):
|
|
||||||
self.dict = adict
|
|
||||||
self.NoneValue = NoneValue
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
value = self.dict[key]
|
|
||||||
if value is None:
|
|
||||||
return self.NoneValue
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
def group_by_key(d, key):
|
|
||||||
g = DictDefault(defaultvalue=[])
|
|
||||||
for e in d:
|
|
||||||
g[e[key]].append(e)
|
|
||||||
return g
|
|
||||||
|
|
||||||
|
|
||||||
# Admissions des étudiants
|
# Admissions des étudiants
|
||||||
# Différents types de voies d'admission:
|
# Différents types de voies d'admission:
|
||||||
# (stocké en texte libre dans la base, mais saisie par menus pour harmoniser)
|
# (stocké en texte libre dans la base, mais saisie par menus pour harmoniser)
|
||||||
@ -610,15 +597,9 @@ def sendResult(REQUEST, data, name=None, format=None, force_outer_xml_tag=True):
|
|||||||
raise ValueError("invalid format: %s" % format)
|
raise ValueError("invalid format: %s" % format)
|
||||||
|
|
||||||
|
|
||||||
# Get SVN version
|
def get_scodoc_version():
|
||||||
def get_svn_version(path):
|
"return a string identifying ScoDoc version"
|
||||||
if os.path.exists("/usr/bin/svnversion"):
|
return os.popen("cd %s; ./get_scodoc_version.sh -s" % SCO_TOOLS_DIR).read().strip()
|
||||||
try:
|
|
||||||
return os.popen("svnversion " + path).read().strip()
|
|
||||||
except:
|
|
||||||
return "non disponible (erreur de lecture)"
|
|
||||||
else:
|
|
||||||
return "non disponible"
|
|
||||||
|
|
||||||
|
|
||||||
# Simple string manipulations
|
# Simple string manipulations
|
||||||
@ -791,7 +772,7 @@ def icontag(name, file_format="png", **attrs):
|
|||||||
"""
|
"""
|
||||||
if ("width" not in attrs) or ("height" not in attrs):
|
if ("width" not in attrs) or ("height" not in attrs):
|
||||||
if name not in ICONSIZES:
|
if name not in ICONSIZES:
|
||||||
img_file = SCO_SRCDIR + "/static/icons/%s.%s" % (name, file_format)
|
img_file = SCO_SRC_DIR + "/static/icons/%s.%s" % (name, file_format)
|
||||||
im = PILImage.open(img_file)
|
im = PILImage.open(img_file)
|
||||||
width, height = im.size[0], im.size[1]
|
width, height = im.size[0], im.size[1]
|
||||||
ICONSIZES[name] = (width, height) # cache
|
ICONSIZES[name] = (width, height) # cache
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
"""Imports et configuration des composants Zope
|
"""Imports et configuration des composants Zope
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Allows code linting on platforms without Zope:
|
||||||
|
# pylint: disable=import-error
|
||||||
from OFS.SimpleItem import Item # Basic zope object
|
from OFS.SimpleItem import Item # Basic zope object
|
||||||
from OFS.PropertyManager import PropertyManager # provide the 'Properties' tab with the
|
from OFS.PropertyManager import PropertyManager # provide the 'Properties' tab with the
|
||||||
|
|
||||||
|
68
scolars.py
@ -25,7 +25,7 @@
|
|||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
""" Accès donnees etudiants
|
""" Acces donnees etudiants
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from sco_utils import *
|
from sco_utils import *
|
||||||
@ -35,18 +35,17 @@ from TrivialFormulator import TrivialFormulator
|
|||||||
import safehtml
|
import safehtml
|
||||||
from scolog import logdb
|
from scolog import logdb
|
||||||
from notes_table import *
|
from notes_table import *
|
||||||
import sco_news
|
|
||||||
|
|
||||||
# XXXXXXXXX HACK: zope 2.7.7 bug turaround ?
|
# XXXXXXXXX HACK: zope 2.7.7 bug turaround ?
|
||||||
import locale
|
import locale
|
||||||
|
|
||||||
locale.setlocale(locale.LC_ALL, ("en_US", SCO_ENCODING))
|
locale.setlocale(locale.LC_ALL, ("en_US", SCO_ENCODING))
|
||||||
|
|
||||||
from email.MIMEMultipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
from email.MIMEText import MIMEText
|
from email.mime.text import MIMEText
|
||||||
from email.MIMEBase import MIMEBase
|
from email.header import Header
|
||||||
from email.Header import Header
|
from email.mime.base import MIMEBase
|
||||||
from email import Encoders
|
|
||||||
|
|
||||||
abbrvmonthsnames = [
|
abbrvmonthsnames = [
|
||||||
"Jan ",
|
"Jan ",
|
||||||
@ -618,59 +617,6 @@ def make_etud_args(etudid=None, code_nip=None, REQUEST=None, raise_exc=True):
|
|||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
def create_etud(context, cnx, args={}, REQUEST=None):
|
|
||||||
"""Creation d'un étudiant. génère aussi évenement et "news".
|
|
||||||
|
|
||||||
Args:
|
|
||||||
args: dict avec les attributs de l'étudiant
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
etud, l'étudiant créé.
|
|
||||||
"""
|
|
||||||
# creation d'un etudiant
|
|
||||||
etudid = etudident_create(cnx, args, context=context, REQUEST=REQUEST)
|
|
||||||
# crée une adresse vide (chaque etudiant doit etre dans la table "adresse" !)
|
|
||||||
_ = adresse_create(
|
|
||||||
cnx,
|
|
||||||
{
|
|
||||||
"etudid": etudid,
|
|
||||||
"typeadresse": "domicile",
|
|
||||||
"description": "(creation individuelle)",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
# event
|
|
||||||
scolar_events_create(
|
|
||||||
cnx,
|
|
||||||
args={
|
|
||||||
"etudid": etudid,
|
|
||||||
"event_date": time.strftime("%d/%m/%Y"),
|
|
||||||
"formsemestre_id": None,
|
|
||||||
"event_type": "CREATION",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
# log
|
|
||||||
logdb(
|
|
||||||
REQUEST,
|
|
||||||
cnx,
|
|
||||||
method="etudident_edit_form",
|
|
||||||
etudid=etudid,
|
|
||||||
msg="creation initiale",
|
|
||||||
)
|
|
||||||
etud = scolars.etudident_list(cnx, {"etudid": etudid})[0]
|
|
||||||
context.fillEtudsInfo([etud])
|
|
||||||
etud["url"] = "ficheEtud?etudid=%(etudid)s" % etud
|
|
||||||
sco_news.add(
|
|
||||||
context,
|
|
||||||
REQUEST,
|
|
||||||
typ=sco_news.NEWS_INSCR,
|
|
||||||
object=None, # pas d'object pour ne montrer qu'un etudiant
|
|
||||||
text='Nouvel étudiant <a href="%(url)s">%(nomprenom)s</a>' % etud,
|
|
||||||
url=etud["url"],
|
|
||||||
)
|
|
||||||
return etud
|
|
||||||
|
|
||||||
|
|
||||||
# ---------- "EVENTS"
|
# ---------- "EVENTS"
|
||||||
_scolar_eventsEditor = EditableTable(
|
_scolar_eventsEditor = EditableTable(
|
||||||
"scolar_events",
|
"scolar_events",
|
||||||
@ -766,7 +712,7 @@ appreciations_edit = _appreciationsEditor.edit
|
|||||||
|
|
||||||
# -------- Noms des Lycées à partir du code
|
# -------- Noms des Lycées à partir du code
|
||||||
def read_etablissements():
|
def read_etablissements():
|
||||||
filename = SCO_SRCDIR + "/" + CONFIG.ETABL_FILENAME
|
filename = SCO_SRC_DIR + "/" + CONFIG.ETABL_FILENAME
|
||||||
log("reading %s" % filename)
|
log("reading %s" % filename)
|
||||||
f = open(filename)
|
f = open(filename)
|
||||||
L = [x[:-1].split(";") for x in f]
|
L = [x[:-1].split(";") for x in f]
|
||||||
|
@ -1 +0,0 @@
|
|||||||
#
|
|
@ -1,399 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""Creation environnement pour test.
|
|
||||||
A utiliser avec debug.py (côté serveur).
|
|
||||||
|
|
||||||
La classe ScoFake offre un ensemble de raccourcis permettant d'écrire
|
|
||||||
facilement des tests ou de reproduire des bugs.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
from functools import wraps
|
|
||||||
import sys
|
|
||||||
import string
|
|
||||||
import collections
|
|
||||||
import pprint
|
|
||||||
import random
|
|
||||||
|
|
||||||
random.seed(12345) # tests reproductibles
|
|
||||||
|
|
||||||
from debug import REQUEST
|
|
||||||
|
|
||||||
import sco_utils
|
|
||||||
from notes_log import log
|
|
||||||
from sco_exceptions import ScoValueError
|
|
||||||
import scolars
|
|
||||||
import sco_formsemestre
|
|
||||||
import sco_formsemestre_inscriptions
|
|
||||||
import sco_formsemestre_validation
|
|
||||||
import sco_synchro_etuds
|
|
||||||
import sco_edit_formation
|
|
||||||
import sco_edit_ue
|
|
||||||
import sco_codes_parcours
|
|
||||||
import sco_saisie_notes
|
|
||||||
|
|
||||||
DEMODIR = sco_utils.SCO_SRCDIR + "/scotests/demo/"
|
|
||||||
NOMS = [x.strip() for x in open(DEMODIR + "/noms.txt").readlines()]
|
|
||||||
PRENOMS_H = [x.strip() for x in open(DEMODIR + "/prenoms-h.txt").readlines()]
|
|
||||||
PRENOMS_F = [x.strip() for x in open(DEMODIR + "/prenoms-f.txt").readlines()]
|
|
||||||
# nb: en python2, les chaines ci-dessus sont en utf8
|
|
||||||
|
|
||||||
|
|
||||||
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
|
|
||||||
return "".join(random.choice(chars) for _ in range(size))
|
|
||||||
|
|
||||||
|
|
||||||
def logging_meth(func):
|
|
||||||
@wraps(func)
|
|
||||||
def wrapper_logging_meth(self, *args, **kwargs):
|
|
||||||
r = func(self, *args, **kwargs)
|
|
||||||
self.log("%s(%s) -> \n%s" % (func.__name__, kwargs, pprint.pformat(r)))
|
|
||||||
return r
|
|
||||||
|
|
||||||
return wrapper_logging_meth
|
|
||||||
|
|
||||||
|
|
||||||
class ScoFake:
|
|
||||||
def __init__(self, context, verbose=True):
|
|
||||||
self.context = context
|
|
||||||
self.verbose = verbose
|
|
||||||
|
|
||||||
def log(self, msg):
|
|
||||||
if self.verbose:
|
|
||||||
print("ScoFake: " + str(msg), file=sys.stderr)
|
|
||||||
sys.stderr.flush()
|
|
||||||
log("ScoFake: " + str(msg))
|
|
||||||
|
|
||||||
def sexenomprenom(self):
|
|
||||||
"""un nom et un prenom au hasard,
|
|
||||||
toujours en majuscules.
|
|
||||||
"""
|
|
||||||
sexe = random.choice(("M", "F"))
|
|
||||||
if "e" in sexe.lower() or "f" in sexe.lower():
|
|
||||||
prenom = random.choice(PRENOMS_F)
|
|
||||||
else:
|
|
||||||
prenom = random.choice(PRENOMS_H)
|
|
||||||
return sexe, random.choice(NOMS).upper(), prenom.upper()
|
|
||||||
|
|
||||||
@logging_meth
|
|
||||||
def create_etud(
|
|
||||||
self,
|
|
||||||
cnx=None,
|
|
||||||
code_nip="",
|
|
||||||
nom="",
|
|
||||||
prenom="",
|
|
||||||
code_ine="",
|
|
||||||
sexe="",
|
|
||||||
etape="TST1",
|
|
||||||
email="test@localhost",
|
|
||||||
emailperso="perso@localhost",
|
|
||||||
date_naissance="01/01/2001",
|
|
||||||
lieu_naissance="Paris",
|
|
||||||
dept_naissance="75",
|
|
||||||
domicile="1, rue du test",
|
|
||||||
codepostaldomicile="75123",
|
|
||||||
villedomicile="TestCity",
|
|
||||||
paysdomicile="France",
|
|
||||||
telephone="0102030405",
|
|
||||||
typeadresse="domicile",
|
|
||||||
boursier=None,
|
|
||||||
description="etudiant test",
|
|
||||||
):
|
|
||||||
"""Crée un étudiant"""
|
|
||||||
if not cnx:
|
|
||||||
cnx = self.context.GetDBConnexion()
|
|
||||||
if code_nip == "":
|
|
||||||
code_nip = str(random.randint(10000, 99999))
|
|
||||||
if not sexe or not nom or not prenom:
|
|
||||||
r_sexe, r_nom, r_prenom = self.sexenomprenom()
|
|
||||||
if not sexe:
|
|
||||||
sexe = r_sexe
|
|
||||||
if not nom:
|
|
||||||
nom = r_nom
|
|
||||||
if not prenom:
|
|
||||||
prenom = r_prenom
|
|
||||||
etud = scolars.create_etud(self.context, cnx, args=locals(), REQUEST=REQUEST)
|
|
||||||
inscription = "2020" # pylint: disable=unused-variable
|
|
||||||
sco_synchro_etuds.do_import_etud_admission(
|
|
||||||
self.context, cnx, etud["etudid"], locals()
|
|
||||||
)
|
|
||||||
return etud
|
|
||||||
|
|
||||||
@logging_meth
|
|
||||||
def create_formation(
|
|
||||||
self,
|
|
||||||
acronyme="test",
|
|
||||||
titre="Formation test",
|
|
||||||
titre_officiel="Le titre officiel de la formation test",
|
|
||||||
type_parcours=sco_codes_parcours.ParcoursDUT.TYPE_PARCOURS,
|
|
||||||
formation_code=None,
|
|
||||||
code_specialite=None,
|
|
||||||
):
|
|
||||||
"""Crée une formation"""
|
|
||||||
if acronyme == "":
|
|
||||||
acronyme = "TEST" + str(random.randint(100000, 999999))
|
|
||||||
oid = self.context.do_formation_create(locals(), REQUEST=REQUEST)
|
|
||||||
oids = self.context.formation_list(args={"formation_id": oid})
|
|
||||||
if not oids:
|
|
||||||
raise ScoValueError("formation not created !")
|
|
||||||
return oids[0]
|
|
||||||
|
|
||||||
@logging_meth
|
|
||||||
def create_ue(
|
|
||||||
self,
|
|
||||||
formation_id=None,
|
|
||||||
acronyme=None,
|
|
||||||
numero=None,
|
|
||||||
titre="",
|
|
||||||
type=None,
|
|
||||||
ue_code=None,
|
|
||||||
ects=None,
|
|
||||||
is_external=None,
|
|
||||||
code_apogee=None,
|
|
||||||
coefficient=None,
|
|
||||||
):
|
|
||||||
"""Crée une UE"""
|
|
||||||
if numero is None:
|
|
||||||
numero = sco_edit_ue.next_ue_numero(self.context, formation_id, 0)
|
|
||||||
oid = self.context.do_ue_create(locals(), REQUEST)
|
|
||||||
oids = self.context.do_ue_list(args={"ue_id": oid})
|
|
||||||
if not oids:
|
|
||||||
raise ScoValueError("ue not created !")
|
|
||||||
return oids[0]
|
|
||||||
|
|
||||||
@logging_meth
|
|
||||||
def create_matiere(self, ue_id=None, titre=None, numero=None):
|
|
||||||
oid = self.context.do_matiere_create(locals(), REQUEST)
|
|
||||||
oids = self.context.do_matiere_list(args={"matiere_id": oid})
|
|
||||||
if not oids:
|
|
||||||
raise ScoValueError("matiere not created !")
|
|
||||||
return oids[0]
|
|
||||||
|
|
||||||
@logging_meth
|
|
||||||
def create_module(
|
|
||||||
self,
|
|
||||||
titre=None,
|
|
||||||
code=None,
|
|
||||||
heures_cours=None,
|
|
||||||
heures_td=None,
|
|
||||||
heures_tp=None,
|
|
||||||
coefficient=None,
|
|
||||||
ue_id=None,
|
|
||||||
formation_id=None,
|
|
||||||
matiere_id=None,
|
|
||||||
semestre_id=1,
|
|
||||||
numero=None,
|
|
||||||
abbrev=None,
|
|
||||||
ects=None,
|
|
||||||
code_apogee=None,
|
|
||||||
module_type=None,
|
|
||||||
):
|
|
||||||
oid = self.context.do_module_create(locals(), REQUEST)
|
|
||||||
oids = self.context.do_module_list(args={"module_id": oid})
|
|
||||||
if not oids:
|
|
||||||
raise ScoValueError("module not created ! (oid=%s)" % oid)
|
|
||||||
return oids[0]
|
|
||||||
|
|
||||||
@logging_meth
|
|
||||||
def create_formsemestre(
|
|
||||||
self,
|
|
||||||
formation_id=None,
|
|
||||||
semestre_id=None,
|
|
||||||
titre=None,
|
|
||||||
date_debut=None,
|
|
||||||
date_fin=None,
|
|
||||||
etat=None,
|
|
||||||
gestion_compensation=None,
|
|
||||||
bul_hide_xml=None,
|
|
||||||
gestion_semestrielle=None,
|
|
||||||
bul_bgcolor=None,
|
|
||||||
modalite=None,
|
|
||||||
resp_can_edit=None,
|
|
||||||
resp_can_change_ens=None,
|
|
||||||
ens_can_edit_eval=None,
|
|
||||||
elt_sem_apo=None,
|
|
||||||
elt_annee_apo=None,
|
|
||||||
etapes=None,
|
|
||||||
responsables=["bach"],
|
|
||||||
):
|
|
||||||
oid = self.context.do_formsemestre_create(locals(), REQUEST)
|
|
||||||
# oids = self.context.do_formsemestre_list(args={"formsemestre_id": oid})
|
|
||||||
oids = sco_formsemestre.do_formsemestre_list(
|
|
||||||
self.context, args={"formsemestre_id": oid}
|
|
||||||
) # API inconsistency
|
|
||||||
if not oids:
|
|
||||||
raise ScoValueError("formsemestre not created !")
|
|
||||||
return oids[0]
|
|
||||||
|
|
||||||
@logging_meth
|
|
||||||
def create_moduleimpl(
|
|
||||||
self,
|
|
||||||
module_id=None,
|
|
||||||
formsemestre_id=None,
|
|
||||||
responsable_id=None,
|
|
||||||
):
|
|
||||||
oid = self.context.do_moduleimpl_create(locals())
|
|
||||||
oids = self.context.do_moduleimpl_list(moduleimpl_id=oid) # API inconsistency
|
|
||||||
if not oids:
|
|
||||||
raise ScoValueError("moduleimpl not created !")
|
|
||||||
return oids[0]
|
|
||||||
|
|
||||||
@logging_meth
|
|
||||||
def inscrit_etudiant(self, sem, etud):
|
|
||||||
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
|
|
||||||
self.context,
|
|
||||||
sem["formsemestre_id"],
|
|
||||||
etud["etudid"],
|
|
||||||
etat="I",
|
|
||||||
etape=etud.get("etape", None),
|
|
||||||
REQUEST=REQUEST,
|
|
||||||
method="test_inscrit_etudiant",
|
|
||||||
)
|
|
||||||
|
|
||||||
@logging_meth
|
|
||||||
def create_evaluation(
|
|
||||||
self,
|
|
||||||
moduleimpl_id=None,
|
|
||||||
jour=None,
|
|
||||||
heure_debut="8h00",
|
|
||||||
heure_fin="9h00",
|
|
||||||
description=None,
|
|
||||||
note_max=20,
|
|
||||||
coefficient=None,
|
|
||||||
visibulletin=None,
|
|
||||||
publish_incomplete=None,
|
|
||||||
evaluation_type=None,
|
|
||||||
numero=None,
|
|
||||||
REQUEST=REQUEST,
|
|
||||||
):
|
|
||||||
args = locals()
|
|
||||||
del args["self"]
|
|
||||||
oid = self.context.do_evaluation_create(**args)
|
|
||||||
oids = self.context.do_evaluation_list(args={"evaluation_id": oid})
|
|
||||||
if not oids:
|
|
||||||
raise ScoValueError("evaluation not created !")
|
|
||||||
return oids[0]
|
|
||||||
|
|
||||||
@logging_meth
|
|
||||||
def create_note(
|
|
||||||
self,
|
|
||||||
evaluation=None,
|
|
||||||
etud=None,
|
|
||||||
note=None,
|
|
||||||
comment=None,
|
|
||||||
uid="bach",
|
|
||||||
):
|
|
||||||
return sco_saisie_notes._notes_add(
|
|
||||||
self.context,
|
|
||||||
uid,
|
|
||||||
evaluation["evaluation_id"],
|
|
||||||
[(etud["etudid"], note)],
|
|
||||||
comment=comment,
|
|
||||||
)
|
|
||||||
|
|
||||||
def setup_formation(self, nb_semestre=1, nb_ue_per_semestre=2, nb_module_per_ue=2):
|
|
||||||
"""Création d'une formation, avec UE, modules et évaluations.
|
|
||||||
|
|
||||||
Formation avec `nb_semestre` comportant chacun `nb_ue_per_semestre` UE
|
|
||||||
et dans chaque UE `nb_module_per_ue` modules (on a une seule matière par UE).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
formation (dict), liste d'ue (dicts), liste de modules.
|
|
||||||
"""
|
|
||||||
f = self.create_formation(acronyme="")
|
|
||||||
ue_list = []
|
|
||||||
mod_list = []
|
|
||||||
for semestre_id in range(1, nb_semestre + 1):
|
|
||||||
for n in range(1, nb_ue_per_semestre + 1):
|
|
||||||
ue = self.create_ue(
|
|
||||||
formation_id=f["formation_id"],
|
|
||||||
acronyme="TSU%s%s" % (semestre_id, n),
|
|
||||||
titre="ue test %s%s" % (semestre_id, n),
|
|
||||||
)
|
|
||||||
ue_list.append(ue)
|
|
||||||
mat = self.create_matiere(ue_id=ue["ue_id"], titre="matière test")
|
|
||||||
for _ in range(nb_module_per_ue):
|
|
||||||
mod = self.create_module(
|
|
||||||
matiere_id=mat["matiere_id"],
|
|
||||||
semestre_id=semestre_id,
|
|
||||||
code="TSM%s" % len(mod_list),
|
|
||||||
coefficient=1.0,
|
|
||||||
titre="module test",
|
|
||||||
ue_id=ue["ue_id"], # faiblesse de l'API
|
|
||||||
formation_id=f["formation_id"], # faiblesse de l'API
|
|
||||||
)
|
|
||||||
mod_list.append(mod)
|
|
||||||
return f, ue_list, mod_list
|
|
||||||
|
|
||||||
def setup_formsemestre(
|
|
||||||
self,
|
|
||||||
f,
|
|
||||||
mod_list,
|
|
||||||
semestre_id=1,
|
|
||||||
date_debut="01/01/2020",
|
|
||||||
date_fin="30/06/2020",
|
|
||||||
nb_evaluations_per_module=1,
|
|
||||||
):
|
|
||||||
"""Création semestre, avec modules et évaluations."""
|
|
||||||
sem = self.create_formsemestre(
|
|
||||||
formation_id=f["formation_id"],
|
|
||||||
semestre_id=semestre_id,
|
|
||||||
date_debut=date_debut,
|
|
||||||
date_fin=date_fin,
|
|
||||||
)
|
|
||||||
eval_list = []
|
|
||||||
for mod in mod_list:
|
|
||||||
if mod["semestre_id"] == semestre_id:
|
|
||||||
mi = self.create_moduleimpl(
|
|
||||||
module_id=mod["module_id"],
|
|
||||||
formsemestre_id=sem["formsemestre_id"],
|
|
||||||
responsable_id="bach",
|
|
||||||
)
|
|
||||||
for e_idx in range(1, nb_evaluations_per_module + 1):
|
|
||||||
e = self.create_evaluation(
|
|
||||||
moduleimpl_id=mi["moduleimpl_id"],
|
|
||||||
jour=date_debut,
|
|
||||||
description="evaluation test %s" % e_idx,
|
|
||||||
coefficient=1.0,
|
|
||||||
)
|
|
||||||
eval_list.append(e)
|
|
||||||
return sem, eval_list
|
|
||||||
|
|
||||||
def set_etud_notes_sem(
|
|
||||||
self, sem, eval_list, etuds, notes=None, random_min=0, random_max=20
|
|
||||||
):
|
|
||||||
"""Met des notes aux étudiants indiqués des evals indiquées.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
sem: dict
|
|
||||||
eval_list: list of dicts
|
|
||||||
etuds: list of dicts
|
|
||||||
notes: liste des notes (float).
|
|
||||||
Si non spécifié, tire au hasard dans `[random_min, random_max]`
|
|
||||||
"""
|
|
||||||
set_random = notes is None
|
|
||||||
for e in eval_list:
|
|
||||||
if set_random:
|
|
||||||
notes = [float(random.randint(random_min, random_max)) for _ in etuds]
|
|
||||||
for etud, note in zip(etuds, notes):
|
|
||||||
self.create_note(evaluation=e, etud=etud, note=note)
|
|
||||||
|
|
||||||
def set_code_jury(
|
|
||||||
self,
|
|
||||||
sem,
|
|
||||||
etud,
|
|
||||||
code_etat=sco_codes_parcours.ADM,
|
|
||||||
devenir=sco_codes_parcours.NEXT,
|
|
||||||
assidu=True,
|
|
||||||
):
|
|
||||||
"""Affecte décision de jury"""
|
|
||||||
sco_formsemestre_validation.formsemestre_validation_etud_manu(
|
|
||||||
self.context,
|
|
||||||
formsemestre_id=sem["formsemestre_id"],
|
|
||||||
etudid=etud["etudid"],
|
|
||||||
code_etat=code_etat,
|
|
||||||
devenir=devenir,
|
|
||||||
assidu=assidu,
|
|
||||||
REQUEST=REQUEST,
|
|
||||||
)
|
|
@ -1,53 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Lancement d'un python scodoc interactif
|
|
||||||
# dans l'environnement d'un département
|
|
||||||
# et avec chargement des scripts indiqués
|
|
||||||
# via from ... import *
|
|
||||||
#
|
|
||||||
# Si -r est utilisé, veiller à créer au préalable
|
|
||||||
# le département via l'interface web (Zope)
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
echo "Usage: $0 [-r] dept [script...]"
|
|
||||||
echo "Lance un environnement interactif python/ScoDoc"
|
|
||||||
echo " -r: supprime et recrée le département (attention: efface la base !)"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
cd /opt/scodoc/Products/ScoDoc || exit 2
|
|
||||||
source config/utils.sh
|
|
||||||
|
|
||||||
if [ $# -lt 1 ]
|
|
||||||
then
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$1" = "-r" ]
|
|
||||||
then
|
|
||||||
shift
|
|
||||||
recreate_dept=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
DEPT="$1"
|
|
||||||
shift
|
|
||||||
|
|
||||||
if [ "$recreate_dept" = 1 ]
|
|
||||||
then
|
|
||||||
(cd config || terminate "no config directory"; ./delete_dept.sh -n "$DEPT") || terminate "error deleting dept $DEPT"
|
|
||||||
(cd config || terminate "no config directory"; ./create_dept.sh -n "$DEPT") || terminate "error creating dept $DEPT"
|
|
||||||
# systemctl start scodoc
|
|
||||||
fi
|
|
||||||
|
|
||||||
cmd="from __future__ import print_function;from Zope2 import configure;configure('/opt/scodoc/etc/zope.conf');import Zope2; app=Zope2.app();from debug import *;context = go_dept(app, '""$DEPT""');"
|
|
||||||
|
|
||||||
for f in "$@"
|
|
||||||
do
|
|
||||||
cmd="${cmd}exec(open(\"${f}\").read());"
|
|
||||||
done
|
|
||||||
|
|
||||||
/opt/zope213/bin/python -i -c "$cmd"
|
|
||||||
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""Test de base de ScoDoc
|
|
||||||
|
|
||||||
Création 10 étudiants, formation, semestre, inscription etudiant, creation 1 evaluation, saisie 10 notes.
|
|
||||||
|
|
||||||
Utiliser comme:
|
|
||||||
scotests/scointeractive.sh -r TEST00 scotests/test_basic.py
|
|
||||||
|
|
||||||
"""
|
|
||||||
import random
|
|
||||||
|
|
||||||
import scotests.sco_fake_gen as sco_fake_gen # pylint: disable=import-error
|
|
||||||
import sco_utils
|
|
||||||
|
|
||||||
G = sco_fake_gen.ScoFake(context.Notes) # pylint: disable=undefined-variable
|
|
||||||
G.verbose = False
|
|
||||||
|
|
||||||
# --- Création d'étudiants
|
|
||||||
etuds = [G.create_etud(code_nip=None) for _ in range(10)]
|
|
||||||
|
|
||||||
# --- Création d'une formation
|
|
||||||
f = G.create_formation(acronyme="")
|
|
||||||
ue = G.create_ue(formation_id=f["formation_id"], acronyme="TST1", titre="ue test")
|
|
||||||
mat = G.create_matiere(ue_id=ue["ue_id"], titre="matière test")
|
|
||||||
mod = G.create_module(
|
|
||||||
matiere_id=mat["matiere_id"],
|
|
||||||
code="TSM1",
|
|
||||||
coefficient=1.0,
|
|
||||||
titre="module test",
|
|
||||||
ue_id=ue["ue_id"], # faiblesse de l'API
|
|
||||||
formation_id=f["formation_id"], # faiblesse de l'API
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Mise place d'un semestre
|
|
||||||
sem = G.create_formsemestre(
|
|
||||||
formation_id=f["formation_id"],
|
|
||||||
semestre_id=1,
|
|
||||||
date_debut="01/01/2020",
|
|
||||||
date_fin="30/06/2020",
|
|
||||||
)
|
|
||||||
|
|
||||||
mi = G.create_moduleimpl(
|
|
||||||
module_id=mod["module_id"],
|
|
||||||
formsemestre_id=sem["formsemestre_id"],
|
|
||||||
responsable_id="bach",
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Inscription des étudiants
|
|
||||||
for etud in etuds:
|
|
||||||
G.inscrit_etudiant(sem, etud)
|
|
||||||
|
|
||||||
# --- Creation évaluation
|
|
||||||
e = G.create_evaluation(
|
|
||||||
moduleimpl_id=mi["moduleimpl_id"],
|
|
||||||
jour="01/01/2020",
|
|
||||||
description="evaluation test",
|
|
||||||
coefficient=1.0,
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Saisie notes
|
|
||||||
for etud in etuds:
|
|
||||||
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
|
||||||
evaluation=e, etud=etud, note=float(random.randint(0, 20))
|
|
||||||
)
|
|
@ -1,68 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""Test notes bonus/malus
|
|
||||||
|
|
||||||
Création 10 étudiants, puis formation en 4 semestre.
|
|
||||||
Le premier étudiant redouble sa deuxième année.
|
|
||||||
|
|
||||||
Utiliser comme:
|
|
||||||
scotests/scointeractive.sh -r TEST00 scotests/test_bonusmalus.py
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
import scotests.sco_fake_gen as sco_fake_gen # pylint: disable=import-error
|
|
||||||
import sco_utils as scu
|
|
||||||
|
|
||||||
G = sco_fake_gen.ScoFake(context.Notes) # pylint: disable=undefined-variable
|
|
||||||
G.verbose = False
|
|
||||||
|
|
||||||
# --- Création d'étudiants
|
|
||||||
etuds = [G.create_etud(code_nip=None) for _ in range(10)]
|
|
||||||
|
|
||||||
# --- Mise en place formation 1 semestre
|
|
||||||
f, ue_list, mod_list = G.setup_formation(nb_semestre=1)
|
|
||||||
|
|
||||||
# --- Ajoute module malus à la premiere matiere de la première UE
|
|
||||||
mod_malus = G.create_module(
|
|
||||||
titre="MALUS",
|
|
||||||
code="MAL",
|
|
||||||
coefficient=10,
|
|
||||||
ue_id=ue_list[0]["ue_id"],
|
|
||||||
matiere_id=mod_list[0]["matiere_id"],
|
|
||||||
formation_id=f["formation_id"],
|
|
||||||
semestre_id=1,
|
|
||||||
module_type=scu.MODULE_MALUS,
|
|
||||||
)
|
|
||||||
mod_list.append(mod_malus)
|
|
||||||
|
|
||||||
# --- Crée le semestre
|
|
||||||
|
|
||||||
semestre_id, date_debut, date_fin = (1, "01/09/2019", "15/01/2020")
|
|
||||||
sem, eval_list = G.setup_formsemestre(
|
|
||||||
f, mod_list, semestre_id=semestre_id, date_debut=date_debut, date_fin=date_fin
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Recupère le module de malus
|
|
||||||
modimpls = context.Notes.do_moduleimpl_list(formsemestre_id=sem["formsemestre_id"])
|
|
||||||
# de façon tout à fait inefficace ;-)
|
|
||||||
moduleimpl_malus = [m for m in modimpls if m["module_id"] == mod_malus["module_id"]][0]
|
|
||||||
# et l'évaluation de malus, de la même façon:
|
|
||||||
eval_malus = [
|
|
||||||
e for e in eval_list if e["moduleimpl_id"] == moduleimpl_malus["moduleimpl_id"]
|
|
||||||
][0]
|
|
||||||
eval_normales = [
|
|
||||||
e for e in eval_list if e["moduleimpl_id"] != moduleimpl_malus["moduleimpl_id"]
|
|
||||||
]
|
|
||||||
|
|
||||||
# --- Affect des malus entre -10 et +10
|
|
||||||
n = len(etuds)
|
|
||||||
malus = [((x / (n - 1.0)) * 20) - 10 for x in range(n)]
|
|
||||||
for etud, note in zip(etuds, malus):
|
|
||||||
G.create_note(evaluation=e, etud=etud, note=note)
|
|
||||||
|
|
||||||
# --- Inscrit les étudiants et affecte des notes aléatoires aux évaluations normales
|
|
||||||
for etud in etuds:
|
|
||||||
G.inscrit_etudiant(sem, etud)
|
|
||||||
G.set_etud_notes_sem(sem, eval_normales, etuds)
|
|
@ -1,78 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""Test jury et capitalisation
|
|
||||||
|
|
||||||
Création 10 étudiants, puis formation en 4 semestre.
|
|
||||||
Le premier étudiant redouble sa deuxième année.
|
|
||||||
|
|
||||||
Utiliser comme:
|
|
||||||
scotests/scointeractive.sh -r TEST00 scotests/test_capitalisation.py
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
import scotests.sco_fake_gen as sco_fake_gen # pylint: disable=import-error
|
|
||||||
import sco_utils
|
|
||||||
import sco_codes_parcours
|
|
||||||
|
|
||||||
G = sco_fake_gen.ScoFake(context.Notes) # pylint: disable=undefined-variable
|
|
||||||
G.verbose = False
|
|
||||||
|
|
||||||
# --- Création d'étudiants
|
|
||||||
etuds = [G.create_etud(code_nip=None) for _ in range(10)]
|
|
||||||
|
|
||||||
# --- Mise en place formation 4 semestre
|
|
||||||
f, ue_list, mod_list = G.setup_formation(nb_semestre=4)
|
|
||||||
|
|
||||||
# --- Crée les 4 semestre et affecte des notes aléatoires
|
|
||||||
sems, evals = [], []
|
|
||||||
for semestre_id, date_debut, date_fin in [
|
|
||||||
(1, "01/09/2019", "15/01/2020"),
|
|
||||||
(2, "16/01/2020", "30/06/2020"),
|
|
||||||
(3, "01/09/2020", "15/01/2021"),
|
|
||||||
(4, "16/01/2021", "30/06/2021"),
|
|
||||||
]:
|
|
||||||
sem, eval_list = G.setup_formsemestre(
|
|
||||||
f, mod_list, semestre_id=semestre_id, date_debut=date_debut, date_fin=date_fin
|
|
||||||
)
|
|
||||||
sems.append(sem)
|
|
||||||
evals.append(eval_list) # liste des listes d'evaluations
|
|
||||||
for etud in etuds:
|
|
||||||
G.inscrit_etudiant(sem, etud)
|
|
||||||
G.set_etud_notes_sem(sem, eval_list, etuds)
|
|
||||||
|
|
||||||
|
|
||||||
# def evals_premiere_ue(eval_list):
|
|
||||||
# return
|
|
||||||
|
|
||||||
|
|
||||||
# Le premier étudiant va redoubler sa deuxième année
|
|
||||||
# on crée 2 semestres supplémentaires auxquels on n'inscrit que lui
|
|
||||||
# puis on ajuste ses notes de S3, S4 et S3bis, S4bis
|
|
||||||
etud = etuds[0] # l'étudiant redoublant
|
|
||||||
for semestre_id, date_debut, date_fin in [
|
|
||||||
(3, "01/09/2022", "15/01/2023"),
|
|
||||||
(4, "16/01/2023", "30/06/2023"),
|
|
||||||
]:
|
|
||||||
sem, eval_list = G.setup_formsemestre(
|
|
||||||
f, mod_list, semestre_id=semestre_id, date_debut=date_debut, date_fin=date_fin
|
|
||||||
)
|
|
||||||
sems.append(sem)
|
|
||||||
evals.append(eval_list) # liste des listes d'evaluations
|
|
||||||
G.inscrit_etudiant(sem, etud)
|
|
||||||
|
|
||||||
# Donne 11.5 aux evals UE1 de son premier S3:
|
|
||||||
G.set_etud_notes_sem(sems[3 - 1], evals[3 - 1][:2], [etud], [11.5])
|
|
||||||
# et 8 aux evals de l'UE2:
|
|
||||||
G.set_etud_notes_sem(sems[3 - 1], evals[3 - 1][2:], [etud], [8.0])
|
|
||||||
|
|
||||||
# et 9 en UE1 de son second S3:
|
|
||||||
# G.set_etud_notes_sem(sems[5 - 1], evals[5 - 1][:2], [etud], [9.0])
|
|
||||||
# et 12 en U2 de son second S3:
|
|
||||||
G.set_etud_notes_sem(sems[5 - 1], evals[5 - 1][2:], [etud], [12.0])
|
|
||||||
|
|
||||||
# Jury: S1/ADM, S2/ADJ, S3/AJ, S4/AJ
|
|
||||||
G.set_code_jury(sems[0], etud, code_etat=sco_codes_parcours.ADM)
|
|
||||||
G.set_code_jury(sems[1], etud, code_etat=sco_codes_parcours.ADJ)
|
|
||||||
G.set_code_jury(sems[2], etud, code_etat=sco_codes_parcours.AJ)
|
|
||||||
G.set_code_jury(sems[3], etud, code_etat=sco_codes_parcours.AJ)
|
|
@ -1338,7 +1338,6 @@ span.evalindex_cont {
|
|||||||
}
|
}
|
||||||
span.evalindex {
|
span.evalindex {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 80%;
|
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
.eval_arrows_chld {
|
.eval_arrows_chld {
|
||||||
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |