forked from ScoDoc/ScoDoc
Work in progress: new updater and code cleaning
This commit is contained in:
parent
1c718dffde
commit
415810496f
@ -93,7 +93,7 @@ ADMISSION_MODIFIABLE_FIELDS = (
|
||||
def sco_import_format(with_codesemestre=True):
|
||||
"returns tuples (Attribut, Type, Table, AllowNulls, Description)"
|
||||
r = []
|
||||
for l in open(SCO_SRCDIR + "/" + FORMAT_FILE):
|
||||
for l in open(SCO_SRC_DIR + "/" + FORMAT_FILE):
|
||||
l = l.strip()
|
||||
if l and l[0] != "#":
|
||||
fs = l.split(";")
|
||||
|
55
ZScoDoc.py
55
ZScoDoc.py
@ -33,6 +33,7 @@
|
||||
|
||||
import time, string, glob, re, inspect
|
||||
import urllib, urllib2, cgi, xml
|
||||
import datetime
|
||||
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
@ -42,13 +43,22 @@ from zipfile import ZipFile
|
||||
import os.path, glob
|
||||
import traceback
|
||||
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
from email.MIMEText import MIMEText
|
||||
from email.MIMEBase import MIMEBase
|
||||
from email.Header import Header
|
||||
from email import Encoders
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.base import MIMEBase
|
||||
from email.header import Header
|
||||
|
||||
from sco_zope import *
|
||||
from sco_zope import (
|
||||
ObjectManager,
|
||||
PropertyManager,
|
||||
RoleManager,
|
||||
Item,
|
||||
Persistent,
|
||||
Implicit,
|
||||
ClassSecurityInfo,
|
||||
DTMLFile,
|
||||
Globals,
|
||||
)
|
||||
|
||||
#
|
||||
try:
|
||||
@ -56,7 +66,21 @@ try:
|
||||
except:
|
||||
import ZPsycopgDA.DA as ZopeDA # interp.py
|
||||
|
||||
from sco_utils import *
|
||||
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,
|
||||
get_svn_version,
|
||||
VERSION,
|
||||
SCODOC_CFG_DIR,
|
||||
)
|
||||
from sco_permissions import ScoView, ScoSuperAdmin
|
||||
from sco_exceptions import AccessDenied
|
||||
from notes_log import log
|
||||
import sco_find_etud
|
||||
from ZScoUsers import pwdFascistCheck
|
||||
@ -111,7 +135,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
||||
def _check_users_folder(self, REQUEST=None):
|
||||
"""Vérifie UserFolder et le crée s'il le faut"""
|
||||
try:
|
||||
udb = self.UsersDB
|
||||
self.UsersDB
|
||||
return "<!-- uf ok -->"
|
||||
except:
|
||||
e = self._check_admin_perm(REQUEST)
|
||||
@ -164,11 +188,11 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
||||
pass
|
||||
# add missing getAuthFailedMessage (bug in exUserFolder ?)
|
||||
try:
|
||||
x = self.getAuthFailedMessage
|
||||
self.getAuthFailedMessage
|
||||
except:
|
||||
log("adding getAuthFailedMessage to Zope install")
|
||||
parent = self.aq_parent
|
||||
from OFS.DTMLMethod import addDTMLMethod
|
||||
from OFS.DTMLMethod import addDTMLMethod # pylint: disable=import-error
|
||||
|
||||
addDTMLMethod(parent, "getAuthFailedMessage", file="Identification")
|
||||
|
||||
@ -264,7 +288,7 @@ class ZScoDoc(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Imp
|
||||
r = []
|
||||
for folder in folders:
|
||||
try:
|
||||
s = folder.Scolarite
|
||||
_ = folder.Scolarite
|
||||
r.append(folder)
|
||||
except:
|
||||
pass
|
||||
@ -646,8 +670,8 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
||||
**kv
|
||||
):
|
||||
"Recuperation des exceptions Zope"
|
||||
sco_exc_mail = SCO_EXC_MAIL
|
||||
sco_dev_mail = SCO_DEV_MAIL
|
||||
sco_exc_mail = SCO_EXC_MAIL # pylint: disable=unused-variable
|
||||
sco_dev_mail = SCO_DEV_MAIL # pylint: disable=unused-variable
|
||||
# neat (or should I say dirty ?) hack to get REQUEST
|
||||
# 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.
|
||||
@ -714,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 ?)
|
||||
# log('exc B')
|
||||
# pylint: disable=unused-variable
|
||||
txt_html = self._report_request(REQUEST, fmt="html")
|
||||
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;">
|
||||
@ -734,6 +759,7 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
|
||||
pass
|
||||
|
||||
# --- Mail:
|
||||
# pylint: disable=unused-variable
|
||||
error_traceback_txt = scodoc_html2txt(error_tb)
|
||||
txt = (
|
||||
"""
|
||||
@ -752,6 +778,7 @@ ErrorType: %(error_type)s
|
||||
|
||||
def _report_request(self, REQUEST, fmt="txt"):
|
||||
"""string describing current request for bug reports"""
|
||||
# pylint: disable=unused-variable
|
||||
AUTHENTICATED_USER = REQUEST.get("AUTHENTICATED_USER", "")
|
||||
dt = time.asctime()
|
||||
URL = REQUEST.get("URL", "")
|
||||
@ -887,7 +914,7 @@ subversion: %(svn_version)s
|
||||
"""Liste de id de departements definis par create_dept.sh
|
||||
(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]
|
||||
return ids
|
||||
|
||||
|
128
config/scodoc_config_tmpl.py
Normal file
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)',
|
||||
# }
|
@ -118,6 +118,19 @@ if [ $? -ne 0 ]
|
||||
then
|
||||
/opt/zope213/bin/pip install requests
|
||||
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)
|
||||
su -c $'psql -c \'alter role "www-data" with CREATEDB;\'' "$POSTGRES_SUPERUSER"
|
||||
|
@ -2,10 +2,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pdb, os, sys, time, re, inspect
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
from email.MIMEText import MIMEText
|
||||
from email.Header import Header
|
||||
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
|
||||
# (logging to SQL is done in scolog)
|
||||
@ -88,7 +89,7 @@ def retreive_dept():
|
||||
return ""
|
||||
try:
|
||||
url = REQUEST.URL
|
||||
m = re.match("^.*ScoDoc/(\w+).*$", url)
|
||||
m = re.match(r"^.*ScoDoc/(\w+).*$", url)
|
||||
return m.group(1)
|
||||
except:
|
||||
return ""
|
||||
|
@ -460,11 +460,11 @@ def get_templates_from_distrib(template="avis"):
|
||||
|
||||
if template in ["avis", "footer"]:
|
||||
# pas de preference pour le template: utilise fichier du serveur
|
||||
p = os.path.join(SCO_SRCDIR, pe_local_tmpl)
|
||||
p = os.path.join(SCO_SRC_DIR, pe_local_tmpl)
|
||||
if os.path.exists(p):
|
||||
template_latex = get_code_latex_from_modele(p)
|
||||
else:
|
||||
p = os.path.join(SCO_SRCDIR, pe_default_tmpl)
|
||||
p = os.path.join(SCO_SRC_DIR, pe_default_tmpl)
|
||||
if os.path.exists(p):
|
||||
template_latex = get_code_latex_from_modele(p)
|
||||
else:
|
||||
@ -474,8 +474,7 @@ def get_templates_from_distrib(template="avis"):
|
||||
|
||||
# ----------------------------------------------------------------------------------------
|
||||
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
|
||||
|
||||
# Les etudids des étudiants à afficher, triés par ordre alphabétiques de nom+prénom
|
||||
|
@ -122,8 +122,7 @@ def remove_accents(input_unicode_str):
|
||||
|
||||
|
||||
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:
|
||||
return ""
|
||||
conv = {
|
||||
@ -162,8 +161,7 @@ def list_directory_filenames(path):
|
||||
|
||||
|
||||
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)
|
||||
data = open(pathname).read()
|
||||
zipfile.writestr(rooted_path_in_zip, data)
|
||||
@ -177,7 +175,7 @@ def add_pe_stuff_to_zip(context, zipfile, ziproot):
|
||||
|
||||
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_pathnames = list_directory_filenames(
|
||||
distrib_dir
|
||||
|
@ -32,10 +32,9 @@
|
||||
Il suffit d'appeler abs_notify() après chaque ajout d'absence.
|
||||
"""
|
||||
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
from email.MIMEText import MIMEText
|
||||
from email.Header import Header
|
||||
from email import Encoders
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.header import Header
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
@ -64,8 +63,7 @@ def abs_notify(context, etudid, date):
|
||||
|
||||
|
||||
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:
|
||||
if sem:
|
||||
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):
|
||||
"""Returns set of destination emails to be notified
|
||||
"""
|
||||
"""Returns set of destination emails to be notified"""
|
||||
formsemestre_id = sem["formsemestre_id"]
|
||||
|
||||
destinations = [] # list of email address to notify
|
||||
@ -282,8 +279,7 @@ def retreive_current_formsemestre(context, etudid, cur_date):
|
||||
|
||||
|
||||
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
|
||||
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"""
|
||||
|
@ -28,11 +28,11 @@
|
||||
"""Génération des bulletins de notes
|
||||
|
||||
"""
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
from email.MIMEText import MIMEText
|
||||
from email.MIMEBase import MIMEBase
|
||||
from email.Header import Header
|
||||
from email import Encoders
|
||||
import email
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.base import MIMEBase
|
||||
from email.header import Header
|
||||
|
||||
import htmlutils, time
|
||||
from reportlab.lib.colors import Color
|
||||
@ -331,7 +331,7 @@ def formsemestre_bulletinetud_dict(
|
||||
context, ue_status["formsemestre_id"]
|
||||
) # > toutes notes
|
||||
|
||||
u["modules_capitalized"], junk = _ue_mod_bulletin(
|
||||
u["modules_capitalized"], _ = _ue_mod_bulletin(
|
||||
context,
|
||||
etudid,
|
||||
formsemestre_id,
|
||||
@ -990,7 +990,7 @@ def mail_bulletin(context, formsemestre_id, I, pdfdata, filename, recipient_addr
|
||||
att = MIMEBase("application", "pdf")
|
||||
att.add_header("Content-Disposition", "attachment", filename=filename)
|
||||
att.set_payload(pdfdata)
|
||||
Encoders.encode_base64(att)
|
||||
email.encoders.encode_base64(att)
|
||||
msg.attach(att)
|
||||
log("mail bulletin a %s" % msg["To"])
|
||||
context.sendEmail(msg)
|
||||
|
@ -116,7 +116,8 @@ CODES_EXPL = {
|
||||
RAT: "En attente d'un rattrapage",
|
||||
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
|
||||
|
||||
CODES_SEM_VALIDES = {ADM: True, ADC: True, ADJ: True} # semestre validé
|
||||
|
109
sco_config.py
Normal file
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
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
|
@ -50,11 +50,10 @@ pg_dump SCORT | psql ANORT
|
||||
import fcntl
|
||||
import subprocess
|
||||
import requests
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
from email.MIMEText import MIMEText
|
||||
from email.MIMEBase import MIMEBase
|
||||
from email.Header import Header
|
||||
from email import Encoders
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.base import MIMEBase
|
||||
from email.header import Header
|
||||
|
||||
from notesdb import *
|
||||
from sco_utils import *
|
||||
@ -64,8 +63,7 @@ SCO_DUMP_LOCK = "/tmp/scodump.lock"
|
||||
|
||||
|
||||
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")]
|
||||
# get currect (dept) DB name:
|
||||
cursor = SimpleQuery(context, "SELECT current_database()", {})
|
||||
@ -150,9 +148,8 @@ def _duplicate_db(db_name, ano_db_name):
|
||||
|
||||
|
||||
def _anonymize_db(ano_db_name):
|
||||
"""Anonymize a departement database
|
||||
"""
|
||||
cmd = os.path.join(SCO_CONFIG_DIR, "anonymize_db.py")
|
||||
"""Anonymize a departement database"""
|
||||
cmd = os.path.join(SCO_TOOLS_DIR, "anonymize_db.py")
|
||||
log("_anonymize_db: {}".format(cmd))
|
||||
try:
|
||||
out = subprocess.check_output([cmd, ano_db_name])
|
||||
@ -171,8 +168,7 @@ def _get_scodoc_serial(context):
|
||||
|
||||
|
||||
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))
|
||||
try:
|
||||
data = subprocess.check_output("pg_dump {} | gzip".format(ano_db_name), shell=1)
|
||||
@ -195,7 +191,7 @@ def _send_db(context, REQUEST, ano_db_name):
|
||||
"nomcomplet"
|
||||
],
|
||||
"sco_version": SCOVERSION,
|
||||
"sco_subversion": get_svn_version(SCO_CONFIG_DIR),
|
||||
"sco_subversion": get_svn_version(SCO_TOOLS_DIR),
|
||||
},
|
||||
)
|
||||
return r
|
||||
|
11
sco_news.py
11
sco_news.py
@ -33,11 +33,9 @@ from cStringIO import StringIO
|
||||
import datetime, re
|
||||
import time
|
||||
from stripogram import html2text, html2safehtml
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
from email.MIMEText import MIMEText
|
||||
from email.Header import Header
|
||||
from email import Encoders
|
||||
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.header import Header
|
||||
|
||||
from notesdb import *
|
||||
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):
|
||||
"""Notify by email
|
||||
"""
|
||||
"""Notify by email"""
|
||||
infos = _get_formsemestre_infos_from_news(context, n)
|
||||
formsemestre_id = infos.get("formsemestre_id", None)
|
||||
prefs = context.get_preferences(formsemestre_id=formsemestre_id)
|
||||
|
@ -53,7 +53,7 @@ from PIL import Image as PILImage
|
||||
from cStringIO import StringIO
|
||||
import glob
|
||||
|
||||
from sco_utils import CONFIG, SCO_SRCDIR
|
||||
from sco_utils import CONFIG, SCO_SRC_DIR
|
||||
from notes_log import log
|
||||
|
||||
import scolars
|
||||
@ -62,7 +62,7 @@ from scolog import logdb
|
||||
|
||||
# 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")
|
||||
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_URL = "get_photo_image?etudid=" # with empty etudid => unknown face image
|
||||
IMAGE_EXT = ".jpg"
|
||||
|
@ -37,9 +37,9 @@ import datetime
|
||||
|
||||
import sco_utils
|
||||
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):
|
||||
|
@ -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:
|
||||
- name (clé)
|
||||
- title : titre en français
|
||||
- initvalue : valeur initiale, chargée depuis config/scodoc_config.py
|
||||
- initvalue : valeur initiale
|
||||
- explanation: explication en français
|
||||
- size: longueur du chap texte
|
||||
- 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:
|
||||
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
|
||||
|
||||
PREF_CATEGORIES : définition des catégories de préférences (pour
|
||||
|
133
sco_utils.py
133
sco_utils.py
@ -186,53 +186,84 @@ def get_mention(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)
|
||||
GSL = thread.allocate_lock() # Global ScoDoc Lock
|
||||
|
||||
if "INSTANCE_HOME" in os.environ:
|
||||
# ----- Repertoire "var" (local)
|
||||
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
|
||||
SCODOC_VERSION_DIR = os.path.join(SCODOC_VAR_DIR, "config", "version")
|
||||
SCODOC_VERSION_DIR = os.path.join(SCODOC_CFG_DIR, "version")
|
||||
# ----- Repertoire tmp
|
||||
SCO_TMPDIR = os.path.join(SCODOC_VAR_DIR, "tmp")
|
||||
if not os.path.exists(SCO_TMPDIR):
|
||||
os.mkdir(SCO_TMPDIR, 0o755)
|
||||
SCO_TMP_DIR = os.path.join(SCODOC_VAR_DIR, "tmp")
|
||||
if not os.path.exists(SCO_TMP_DIR):
|
||||
os.mkdir(SCO_TMP_DIR, 0o755)
|
||||
# ----- 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"...)
|
||||
SCO_CONFIG_DIR = os.path.join(
|
||||
os.environ["INSTANCE_HOME"], "Products", "ScoDoc", "config"
|
||||
)
|
||||
# Dans les sources:
|
||||
SCO_SRC_DIR = os.path.join(os.environ["INSTANCE_HOME"], "Products", "ScoDoc")
|
||||
# - Les outils distribués
|
||||
SCO_TOOLS_DIR = os.path.join(SCO_SRC_DIR, "config")
|
||||
|
||||
|
||||
# ----- Lecture du fichier de configuration
|
||||
SCO_SRCDIR = os.path.split(VERSION.__file__)[0]
|
||||
if SCO_SRCDIR:
|
||||
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
|
||||
import sco_config
|
||||
import sco_config_load
|
||||
|
||||
sco_config_load.load_local_configuration()
|
||||
CONFIG = sco_config.CONFIG
|
||||
if hasattr(CONFIG, "CODES_EXPL"):
|
||||
CODES_EXPL.update(
|
||||
CONFIG.CODES_EXPL
|
||||
) # permet de customiser les explications de codes
|
||||
|
||||
|
||||
if CONFIG.CUSTOM_HTML_HEADER:
|
||||
CUSTOM_HTML_HEADER = open(CONFIG.CUSTOM_HTML_HEADER).read()
|
||||
else:
|
||||
@ -297,50 +328,6 @@ JSON_MIMETYPE = "application/json"
|
||||
|
||||
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
|
||||
# Différents types de voies d'admission:
|
||||
# (stocké en texte libre dans la base, mais saisie par menus pour harmoniser)
|
||||
@ -791,7 +778,7 @@ def icontag(name, file_format="png", **attrs):
|
||||
"""
|
||||
if ("width" not in attrs) or ("height" not in attrs):
|
||||
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)
|
||||
width, height = im.size[0], im.size[1]
|
||||
ICONSIZES[name] = (width, height) # cache
|
||||
|
@ -28,6 +28,8 @@
|
||||
"""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.PropertyManager import PropertyManager # provide the 'Properties' tab with the
|
||||
|
||||
|
11
scolars.py
11
scolars.py
@ -42,11 +42,10 @@ import locale
|
||||
|
||||
locale.setlocale(locale.LC_ALL, ("en_US", SCO_ENCODING))
|
||||
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
from email.MIMEText import MIMEText
|
||||
from email.MIMEBase import MIMEBase
|
||||
from email.Header import Header
|
||||
from email import Encoders
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.header import Header
|
||||
from email.mime.base import MIMEBase
|
||||
|
||||
abbrvmonthsnames = [
|
||||
"Jan ",
|
||||
@ -713,7 +712,7 @@ appreciations_edit = _appreciationsEditor.edit
|
||||
|
||||
# -------- Noms des Lycées à partir du code
|
||||
def read_etablissements():
|
||||
filename = SCO_SRCDIR + "/" + CONFIG.ETABL_FILENAME
|
||||
filename = SCO_SRC_DIR + "/" + CONFIG.ETABL_FILENAME
|
||||
log("reading %s" % filename)
|
||||
f = open(filename)
|
||||
L = [x[:-1].split(";") for x in f]
|
||||
|
Loading…
Reference in New Issue
Block a user