# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Emmanuel Viennet emmanuel.viennet@viennet.net
#
##############################################################################
"""Global/Semestre Preferences for ScoDoc (version dec 2008)
Preferences (paramètres) communs à tous les utilisateurs.
Peuvent être définis globalement (pour tous les semestres)
ou bien seulement pour un semestre précis.
Chaque parametre est défini dans la base de données SQL par:
- name : nom du parametre
- value: valeur du parametre, ou NULL si on doit utiliser une valeur par défaut
- formsemestre_id: semestre associé, ou NULL si applicable à tous les semestres
pour lesquels une valeur spécifique n'est pas définie.
Au niveau du code interface, on défini pour chaque préférence:
- name (clé)
- title : titre en français
- initvalue : valeur initiale
- explanation: explication en français
- size: longueur du chap texte
- input_type: textarea, separator, ... type de widget TrivialFormulator a utiliser
- rows, rols: geometrie des textareas
- category: misc ou bul ou page_bulletins ou abs ou general ou portal
ou pdf ou pvpdf ou ...
- only_global (default False): si vraie, ne peut pas etre associée a un seul semestre.
Les titres et sous-titres de chaque catégorie sont définis dans PREFS_CATEGORIES
On peut éditer les préférences d'une ou plusieurs catégories au niveau d'un
semestre ou au niveau global.
* niveau global: changer les valeurs, liste de catégories.
* niveau d'un semestre:
présenter valeur courante: valeur ou "definie globalement" ou par defaut
lien "changer valeur globale"
------------------------------------------------------------------------------
Doc technique:
* Base de données:
Toutes les préférences sont stockées dans la table sco_prefs, qui contient
des tuples (name, value, formsemestre_id).
Si formsemestre_id est NULL, la valeur concerne tous les semestres,
sinon, elle ne concerne que le semestre indiqué.
* Utilisation dans ScoDoc 9
- lire une valeur:
get_preference(name, formsemestre_id)
nb: les valeurs sont des chaines, sauf:
. si le type est spécifié (float ou int)
. les boolcheckbox qui sont des entiers 0 ou 1
- avoir un mapping (read only) de toutes les valeurs:
sco_preferences.SemPreferences(formsemestre_id)
- éditer les preferences globales:
sco_preferences.get_base_preferences(self).edit()
- éditer les preferences d'un semestre:
SemPreferences(formsemestre_id).edit()
* Implémentation: sco_preferences.py
PREF_CATEGORIES : définition des catégories de préférences (pour
dialogues édition)
prefs_definition : pour chaque pref, donne infos pour édition (titre, type...) et
valeur par défaut.
class BasePreferences
Une instance unique par site (département, repéré par URL).
- charge les preferences pour tous le semestres depuis la BD.
.get(formsemestre_id, name)
.is_global(formsemestre_id, name)
.save(formsemestre_id=None, name=None)
.set(formsemestre_id, name, value)
.deleteformsemestre_id, name)
.edit() (HTML dialog)
class SemPreferences(formsemestre_id)
Une instance par semestre, et une instance pour prefs globales.
L'attribut .base_prefs point sur BasePreferences.
.__getitem__ [name]
.is_global(name)
.edit(categories=[])
get_base_preferences(formsemestre_id)
Return base preferences for current scodoc_dept (instance BasePreferences)
"""
import flask
from flask import g, request, current_app
# from flask_login import current_user
from app.models import Departement
from app.scodoc import sco_cache
from app import log
from app.scodoc.sco_exceptions import ScoValueError, ScoException
from app.scodoc.TrivialFormulator import TrivialFormulator
import app.scodoc.notesdb as ndb
from app.scodoc import sco_pdf
import app.scodoc.sco_utils as scu
def clear_base_preferences():
"""Clear cached preferences"""
# usefull only for tests, where the same process may run
# successively on several databases
g._SCO_BASE_PREFERENCES = {} # { dept_id: BasePreferences instance }
def get_base_preferences(dept_id: int = None):
"""Return global preferences for the specified department
or the current departement
"""
if dept_id is None:
dept_id = g.scodoc_dept_id
if not hasattr(g, "_SCO_BASE_PREFERENCES"):
g._SCO_BASE_PREFERENCES = {}
if not dept_id in g._SCO_BASE_PREFERENCES:
g._SCO_BASE_PREFERENCES[dept_id] = BasePreferences(dept_id)
return g._SCO_BASE_PREFERENCES[dept_id]
def get_preference(name, formsemestre_id=None, dept_id=None):
"""Returns value of named preference.
All preferences have a sensible default value, so this
function always returns a usable value for all defined preferences names.
"""
return get_base_preferences(dept_id=dept_id).get(formsemestre_id, name)
def _convert_pref_type(p, pref_spec):
"""p est une ligne de la bd
{'id': , 'dept_id': , 'name': '', 'value': '', 'formsemestre_id': }
converti la valeur chaine en le type désiré spécifié par pref_spec
"""
if "type" in pref_spec:
typ = pref_spec["type"]
if typ == "float":
# special case for float values (where NULL means 0)
p["value"] = float(p["value"] or 0)
elif typ == "int":
p["value"] = int(p["value"] or 0)
else:
raise ValueError("invalid preference type")
if pref_spec.get("input_type", None) == "boolcheckbox":
# boolcheckbox: la valeur stockée en base est une chaine "0" ou "1"
# que l'on ressort en True|False
if p["value"]:
try:
p["value"] = bool(int(p["value"]))
except ValueError:
log(
f"""Warning: invalid value for boolean pref in db: '{p["value"]}'"""
)
p["value"] = False
else:
p["value"] = False # NULL (backward compat)
def _get_pref_default_value_from_config(name, pref_spec):
"""get default value store in application level config.
If not found, use default value hardcoded in pref_spec.
"""
# XXX va changer avec la nouvelle base
# search in scu.CONFIG
if hasattr(scu.CONFIG, name):
value = getattr(scu.CONFIG, name)
log("sco_preferences: found default value in config for %s=%s" % (name, value))
else:
# uses hardcoded default
value = pref_spec["initvalue"]
return value
_INSTALLED_FONTS = ", ".join(sco_pdf.get_available_font_names())
PREF_CATEGORIES = (
# sur page "Paramètres"
("general", {"title": ""}), # voir paramètre titlr de TrivialFormulator
("misc", {"title": "Divers"}),
("apc", {"title": "BUT et Approches par Compétences"}),
("abs", {"title": "Suivi des absences", "related": ("bul",)}),
("portal", {"title": "Liaison avec portail (Apogée, etc)"}),
(
"pdf",
{
"title": "Mise en forme des documents PDF",
"related": ("pvpdf", "bul_margins"),
},
),
(
"pvpdf",
{
"title": "Procès verbaux de jury (documents PDF)",
"related": ("pdf", "bul_margins"),
},
),
# sur page "Réglages des bulletins de notes"
(
"bul",
{
"title": "Réglages des bulletins de notes",
"related": ("abs", "bul_margins", "bul_mail"),
},
),
# sur page "Mise en page des bulletins"
(
"bul_margins",
{
"title": "Marges additionnelles des bulletins, en millimètres",
"subtitle": "Le bulletin de notes notes est toujours redimensionné pour occuper l'espace disponible entre les marges.",
"related": ("bul", "bul_mail", "pdf"),
},
),
(
"bul_mail",
{
"title": "Envoi des bulletins par e-mail",
"related": ("bul", "bul_margins", "pdf"),
},
),
(
"feuilles",
{"title": "Mise en forme des feuilles (Absences, Trombinoscopes, Moodle, ...)"},
),
("pe", {"title": "Avis de poursuites d'études"}),
("edt", {"title": "Connexion avec le logiciel d'emplois du temps"}),
("debug", {"title": "Tests / mise au point"}),
)
class BasePreferences(object):
"""Global preferences"""
_editor = ndb.EditableTable(
"sco_prefs",
"pref_id",
("pref_id", "dept_id", "name", "value", "formsemestre_id"),
filter_dept=True,
sortkey="name",
convert_null_outputs_to_empty=False,
# allow_set_id=True, #sco8
html_quote=False, # car markup pdf reportlab ( etc)
filter_nulls=False,
)
def __init__(self, dept_id: int):
dept = Departement.query.get(dept_id)
if not dept:
raise ScoValueError(f"BasePreferences: Invalid departement: {dept_id}")
self.dept_id = dept.id
self.init()
self.load()
def init(self):
from app.scodoc import sco_bulletins_generator
self.prefs_definition = (
(
"DeptName",
{
"initvalue": "Dept",
"title": "Nom abrégé du département",
"explanation": "acronyme: par exemple R&T, ORTF, HAL",
"size": 12,
"category": "general",
"only_global": True,
},
),
(
"DeptFullName",
{
"initvalue": "nom du département",
"title": "Nom complet du département",
"explanation": "apparaît sur la page d'accueil",
"size": 40,
"category": "general",
"only_global": True,
},
),
(
"UnivName",
{
"initvalue": "",
"title": "Nom de l'Université",
"explanation": "apparait sur les bulletins et PV de jury",
"size": 40,
"category": "general",
"only_global": True,
},
),
(
"InstituteName",
{
"initvalue": "",
"title": "Nom de l'Institut",
"explanation": 'exemple "IUT de Villetaneuse". Peut être utilisé sur les bulletins.',
"size": 40,
"category": "general",
"only_global": True,
},
),
(
"DeptIntranetTitle",
{
"initvalue": "Intranet",
"title": "Nom lien intranet",
"size": 40,
"explanation": 'titre du lien "Intranet" en haut à gauche',
"category": "general",
"only_global": True,
},
),
(
"DeptIntranetURL",
{
"initvalue": "",
"title": """URL de l'"intranet" du département""",
"size": 40,
"explanation": 'lien "Intranet" en haut à gauche',
"category": "general",
"only_global": True,
},
),
(
"emails_notifications",
{
"initvalue": "",
"title": "e-mails à qui notifier les opérations",
"size": 70,
"explanation": "adresses séparées par des virgules; notifie les opérations (saisies de notes, etc).",
"category": "general",
"only_global": False, # peut être spécifique à un semestre
},
),
# ------------------ MISC
(
"use_ue_coefs",
{
"initvalue": 0,
"title": "Utiliser les coefficients d'UE pour calculer la moyenne générale (hors BUT)",
"explanation": """Calcule les moyennes dans chaque UE, puis pondère ces résultats pour obtenir la moyenne générale. Par défaut, le coefficient d'une UE est simplement la somme des coefficients des modules dans lesquels l'étudiant a des notes. Attention: changer ce réglage va modifier toutes les moyennes du semestre !. Aucun effet en BUT.""",
"input_type": "boolcheckbox",
"category": "misc",
"labels": ["non", "oui"],
"only_global": False,
},
),
# ------------------ APC / BUT
(
"but_moy_skip_empty_ues",
{
"initvalue": 0,
"title": "BUT: moyenne générale sans les UE sans notes",
"explanation": """La moyenne générale indicative BUT est basée sur les moyennes d'UE pondérées par leurs ECTS.
Si cette option est cochée, ne prend pas en compte les UEs sans notes. Attention: changer ce réglage va modifier toutes
les moyennes du semestre !. Aucun effet dans les formations non BUT.""",
"input_type": "boolcheckbox",
"category": "apc",
"labels": ["non", "oui"],
"only_global": False,
},
),
(
"but_disable_edit_poids_evaluations",
{
"initvalue": 0,
"title": "Interdire de modifier les poids des évaluations",
"explanation": """empêche la modification des poids des évaluations""",
"input_type": "boolcheckbox",
"category": "apc",
"labels": ["non", "oui"],
"only_global": False,
},
),
# ------------------ Absences
(
"email_chefdpt",
{
"initvalue": "",
"title": "e-mail chef du département",
"size": 40,
"explanation": "utilisé pour envoi mail notification absences",
"category": "abs",
"only_global": True,
},
),
(
"work_saturday",
{
"initvalue": 0,
"title": "Considérer le samedi comme travaillé",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "abs",
"only_global": True, # devrait etre par semestre, mais demanderait modif gestion absences
},
),
(
"abs_require_module", # affecte l'UI mais pas les fonctions de base
{
"initvalue": 0,
"title": "Imposer l'indication du module lors de la saisie des absences",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "abs",
"only_global": False,
},
),
(
"handle_billets_abs",
{
"initvalue": 0,
"title": 'Gestion de "billets" d\'absence',
"explanation": 'fonctions pour traiter les "billets" déclarés par les étudiants sur un portail externe',
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "abs",
"only_global": True,
},
),
(
"abs_notify_chief", # renamed from "send_mail_absence_to_chef"
{
"initvalue": 0,
"title": "Notifier les absences au chef",
"explanation": "Envoyer un mail au chef si un étudiant a beaucoup d'absences",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "abs",
"only_global": True,
},
),
(
"abs_notify_respsem",
{
"initvalue": 0,
"title": "Notifier les absences au dir. des études",
"explanation": "Envoyer un mail au responsable du semestre si un étudiant a beaucoup d'absences",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "abs",
},
),
(
"abs_notify_respeval",
{
"initvalue": 0,
"title": "Notifier les absences aux resp. de modules",
"explanation": "Envoyer un mail à chaque absence aux responsable des modules avec évaluation à cette date",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "abs",
},
),
(
"abs_notify_etud",
{
"initvalue": 0,
"title": "Notifier les absences aux étudiants concernés",
"explanation": "Envoyer un mail à l'étudiant s'il a \"beaucoup\" d'absences",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "abs",
},
),
(
"abs_notify_email",
{
"initvalue": "",
"title": "Notifier à:",
"explanation": "e-mail à qui envoyer des notification d'absences (en sus des autres destinataires éventuels, comme le chef etc.)",
"size": 40,
"category": "abs",
},
),
(
"abs_notify_max_freq",
{
"initvalue": 7,
"title": "Fréquence maximale de notification",
"explanation": "en jours (pas plus de X envois de mail pour chaque étudiant/destinataire)",
"size": 4,
"type": "int",
"convert_numbers": True,
"category": "abs",
},
),
(
"abs_notify_abs_threshold",
{
"initvalue": 10,
"title": "Seuil de première notification",
"explanation": "nb minimum d'absences (en 1/2 journées) avant notification",
"size": 4,
"type": "int",
"convert_numbers": True,
"category": "abs",
},
),
(
"abs_notify_abs_increment",
{
"initvalue": 20, # les notification suivantes seront donc rares
"title": "Seuil notifications suivantes",
"explanation": "nb minimum d'absences (en 1/2 journées supplémentaires)",
"size": 4,
"type": "int",
"convert_numbers": True,
"category": "abs",
},
),
(
"abs_notification_mail_tmpl",
{
"initvalue": """
--- Ceci est un message de notification automatique issu de ScoDoc ---
L'étudiant %(nomprenom)s
L'étudiant %(nomprenom)s
L'étudiant %(nomprenom)s
inscrit en %(inscription)s)
inscrit en %(inscription)s)
inscrit en %(inscription)s)
a cumulé %(nbabsjust)s absences justifiées
a cumulé %(nbabsjust)s absences justifiées
a cumulé %(nbabsjust)s absences justifiées
et %(nbabsnonjust)s absences NON justifiées.
Le compte a pu changer depuis cet envoi, voir la fiche sur %(url_ficheetud)s.
Votre dévoué serveur ScoDoc.
PS: Au dela de %(abs_notify_abs_threshold)s, un email automatique est adressé toutes les %(abs_notify_abs_increment)s absences. Ces valeurs sont modifiables dans les préférences de ScoDoc.
""",
"title": """Message notification e-mail""",
"explanation": """Balises remplacées, voir la documentation""",
"input_type": "textarea",
"rows": 15,
"cols": 64,
"category": "abs",
},
),
# portal
(
"portal_url",
{
"initvalue": "",
"title": "URL du portail",
"size": 40,
"category": "portal",
"only_global": True,
},
),
(
"portal_timeout",
{
"initvalue": 3,
"title": "timeout",
"explanation": "secondes",
"size": 3,
"type": "int",
"convert_numbers": True,
"category": "portal",
"only_global": True,
},
),
(
"portal_dept_name",
{
"initvalue": "Dept",
"title": "Code du département sur le portail",
"category": "portal",
"only_global": True,
},
),
(
"etapes_url",
{
"initvalue": "",
"title": "URL listant les étapes Apogée",
"size": 40,
"category": "portal",
"only_global": True,
"explanation": "par defaut, selon l'api, getEtapes ou scodocEtapes sur l'URL du portail",
},
),
(
"maquette_url",
{
"initvalue": "",
"title": "URL maquettes Apogee",
"size": 40,
"category": "portal",
"only_global": True,
"explanation": "par defaut, scodocMaquette sur l'URL du portail",
},
),
(
"portal_api",
{
"initvalue": 1,
"title": "Version de l'API",
"explanation": "1 ou 2",
"size": 3,
"type": "int",
"convert_numbers": True,
"category": "portal",
"only_global": True,
},
),
(
"etud_url",
{
"initvalue": "",
"title": "URL listant les étudiants Apogée",
"size": 40,
"category": "portal",
"only_global": True,
"explanation": "par defaut, selon l'api, getEtud ou scodocEtudiant sur l'URL du portail",
},
),
(
"photo_url",
{
"initvalue": "",
"title": "URL donnant la photo d'un étudiant avec argument nip=",
"size": 40,
"category": "portal",
"only_global": True,
"explanation": "par defaut, selon l'api, getPhoto ou scodocPhoto sur l'URL du portail",
},
),
(
"xml_etapes_by_dept",
{
"initvalue": 1,
"title": "Etapes séparées par département",
"explanation": "XML getEtapes structuré en départements ?",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "portal",
"only_global": True,
},
),
(
"notify_etud_changes_to",
{
"initvalue": "",
"title": "e-mail à qui notifier les changements d'identité des étudiants",
"explanation": "utile pour mettre à jour manuellement d'autres bases de données",
"size": 40,
"category": "portal",
"only_global": True,
},
),
(
"always_require_ine",
{
"initvalue": 0,
"title": "Impose la présence du code INE",
"explanation": "lors de toute création d'étudiant (manuelle ou non)",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "portal",
"only_global": True,
},
),
(
"always_require_apo_sem_codes",
{
"initvalue": 0,
"title": "Impose la présence des codes Apogée",
"explanation": "lors des créations de semestres",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "portal",
"only_global": True,
},
),
# exports Apogée
(
"export_res_etape",
{
"initvalue": 1,
"title": "Exporter résultat de l'étape",
"explanation": "remplissage maquettes export Apogée",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "portal",
"only_global": True,
},
),
(
"export_res_sem",
{
"initvalue": 1,
"title": "Exporter résultat du semestre",
"explanation": "remplissage maquettes export Apogée",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "portal",
"only_global": True,
},
),
(
"export_res_ues",
{
"initvalue": 1,
"title": "Exporter les résultats d'UE",
"explanation": "remplissage maquettes export Apogée",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "portal",
"only_global": True,
},
),
(
"export_res_modules",
{
"initvalue": 1,
"title": "Exporter les résultats de modules",
"explanation": "remplissage maquettes export Apogée",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "portal",
"only_global": True,
},
),
(
"export_res_sdj",
{
"initvalue": 0,
"title": "Exporter les résultats même sans décision de jury",
"explanation": "si coché, exporte exporte étudiants même si pas décision de jury saisie (sinon laisse vide)",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "portal",
"only_global": True,
},
),
(
"export_res_rat",
{
"initvalue": 1,
"title": "Exporter les RAT comme ATT",
"explanation": "si coché, exporte exporte étudiants en attente de ratrapage comme ATT (sinon laisse vide)",
"input_type": "boolcheckbox",
"labels": ["non", "oui"],
"category": "portal",
"only_global": True,
},
),
# pdf
(
"SCOLAR_FONT",
{
"initvalue": "Helvetica",
"title": "Police de caractère principale",
"explanation": f"pour les pdf (Helvetica est recommandée, parmi {_INSTALLED_FONTS})",
"size": 25,
"category": "pdf",
},
),
(
"SCOLAR_FONT_SIZE",
{
"initvalue": 10,
"title": "Taille des caractères",
"explanation": "pour les pdf",
"size": 4,
"type": "int",
"convert_numbers": True,
"category": "pdf",
},
),
(
"SCOLAR_FONT_SIZE_FOOT",
{
"initvalue": 6,
"title": "Taille des caractères pied de page",
"explanation": "pour les pdf",
"size": 4,
"type": "int",
"convert_numbers": True,
"category": "pdf",
},
),
(
"pdf_footer_x",
{
"initvalue": 20,
"title": "Position horizontale du pied de page pdf (en mm)",
"size": 8,
"type": "float",
"category": "pdf",
},
),
(
"pdf_footer_y",
{
"initvalue": 6.35,
"title": "Position verticale du pied de page pdf (en mm)",
"size": 8,
"type": "float",
"category": "pdf",
},
),
# pvpdf
(
"DirectorName",
{
"initvalue": "",
"title": "Nom du directeur de l'établissement",
"size": 32,
"explanation": "pour les PV de jury",
"category": "pvpdf",
},
),
(
"DirectorTitle",
{
"initvalue": """directeur de l'IUT""",
"title": 'Titre du "directeur"',
"explanation": "titre apparaissant à côté de la signature sur les PV de jury",
"size": 64,
"category": "pvpdf",
},
),
(
"ChiefDeptName",
{
"initvalue": "",
"title": "Nom du chef de département",
"size": 32,
"explanation": "pour les bulletins pdf",
"category": "pvpdf",
},
),
(
"INSTITUTION_NAME",
{
"initvalue": "Institut Universitaire de Technologie - Université Paris 13",
"title": "Nom institution sur pied de pages PV",
"explanation": "(pdf, balises <b> interprétées)",
"input_type": "textarea",
"rows": 4,
"cols": 64,
"category": "pvpdf",
},
),
(
"INSTITUTION_ADDRESS",
{
"initvalue": "Web www.iutv.univ-paris13.fr - 99 avenue Jean-Baptiste Clément - F 93430 Villetaneuse",
"title": "Adresse institution sur pied de pages PV",
"explanation": "(pdf, balises <b> interprétées)",
"input_type": "textarea",
"rows": 4,
"cols": 64,
"category": "pvpdf",
},
),
(
"INSTITUTION_CITY",
{
"initvalue": "Villetaneuse",
"title": "Ville de l'institution",
"explanation": "pour les lettres individuelles",
"size": 64,
"category": "pvpdf",
},
),
(
"PV_INTRO",
{
"initvalue": """
%(DirectorName)s""",
"title": """Signature des lettres individuelles de diplôme""",
"explanation": """%(DirectorName)s et %(DirectorTitle)s remplacés""",
"input_type": "textarea",
"rows": 4,
"cols": 64,
"category": "pvpdf",
},
),
(
"PV_LETTER_PASSAGE_SIGNATURE",
{
"initvalue": """Pour le Directeur de l'IUT
et par délégation
Le Chef du département""",
"title": """Signature des lettres individuelles de passage d'un semestre à l'autre""",
"explanation": """%(DirectorName)s et %(DirectorTitle)s remplacés""",
"input_type": "textarea",
"rows": 4,
"cols": 64,
"category": "pvpdf",
},
),
(
"pv_sig_image_height",
{
"initvalue": 11,
"size": 10,
"title": "Hauteur de l'image de la signature",
"type": "float",
"explanation": "Lorsqu'on donne une image de signature, elle est redimensionnée à cette taille (en millimètres)",
"category": "pvpdf",
},
),
(
"PV_LETTER_TEMPLATE",
{
"initvalue": """
%(titre_formation)s
%(responsable)s
%(ChiefDeptName)s
modification des logos du département (pour documents pdf)
""" # if current_user.is_administrator() # else "", """Ces paramètres s'appliquent par défaut à tous les semestres, sauf si ceux-ci définissent des valeurs spécifiques.
Attention: cliquez sur "Enregistrer les modifications" en bas de page pour appliquer vos changements !
""", ] form = self.build_tf_form() tf = TrivialFormulator( request.base_url, scu.get_request_args(), form, initvalues=self.prefs[None], submitlabel="Enregistrer les modifications", title="Département et institution", before_table="{subtitle}
', }, ) ) form.extend(cat_elems) return form class SemPreferences: """Preferences for a formsemestre""" def __init__(self, formsemestre_id=None, dept_id=None): self.formsemestre_id = formsemestre_id if dept_id is None and g.scodoc_dept is None: self.base_prefs = {} else: self.base_prefs = get_base_preferences(dept_id=dept_id) def __getitem__(self, name): return self.base_prefs.get(self.formsemestre_id, name) def __contains__(self, item): "check if item is in (global) preferences" return item in self.base_prefs def get(self, name, defaultvalue=None): # utilisé seulement par TF try: return self[name] # ignore supplied default value except: return defaultvalue def is_global(self, name): "True if preference defined for all semestres" return self.base_prefs.is_global(self.formsemestre_id, name) # The dialog def edit(self, categories=[]): """Dialog to edit semestre preferences in given categories""" from app.scodoc import html_sco_header from app.scodoc import sco_formsemestre if not self.formsemestre_id: raise ScoValueError( "sem_preferences.edit doit etre appele sur un semestre !" ) # a bug ! sem = sco_formsemestre.get_formsemestre(self.formsemestre_id) H = [ html_sco_header.html_sem_header("Préférences du semestre"), """Les paramètres définis ici ne s'appliqueront qu'à ce semestre.
Attention: cliquez sur "Enregistrer les modifications" en bas de page pour appliquer vos changements !
""", ] # build the form: form = self.base_prefs.build_tf_form( categories=categories, formsemestre_id=self.formsemestre_id ) form.append(("suppress", {"input_type": "hidden"})) form.append(("create_local", {"input_type": "hidden"})) form.append(("destination", {"input_type": "hidden"})) form.append(("formsemestre_id", {"input_type": "hidden"})) tf = TrivialFormulator( request.base_url, scu.get_request_args(), form, initvalues=self, cssclass="sco_pref", submitlabel="Enregistrer les modifications", title="Département et institution", before_table="