Compare commits

...

2 Commits

Author SHA1 Message Date
Jean-Marie PLACE
ba3832bf29 nettoyage 2022-04-10 11:01:28 +02:00
Jean-Marie PLACE
17611cad03 WIP 2022-04-09 11:27:15 +02:00
16 changed files with 435 additions and 65 deletions

View File

@ -21,6 +21,7 @@ import jwt
from app import db, login
from app.models import Departement
from app.models import SHORT_STR_LEN
from app.models.config import SiteConfig
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_roles_default import SCO_ROLES_DEFAULTS
@ -36,8 +37,8 @@ def is_valid_password(cleartxt):
"""
if (
hasattr(scu.CONFIG, "MIN_PASSWORD_LENGTH")
and scu.CONFIG.MIN_PASSWORD_LENGTH > 0
and len(cleartxt) < scu.CONFIG.MIN_PASSWORD_LENGTH
and SiteConfig.MIN_PASSWORD_LENGTH.get_value() > 0
and len(cleartxt) < SiteConfig.MIN_PASSWORD_LENGTH.get_value()
):
return False # invalid: too short
try:

View File

@ -32,10 +32,12 @@ Formulaires configuration Exports Apogée (codes)
from flask import flash, url_for, redirect, request, render_template
from flask_wtf import FlaskForm
from wtforms import BooleanField, SelectField, SubmitField
from wtforms import SelectField, SubmitField, StringField, BooleanField, IntegerField
import app
from app.models import ScoDocSiteConfig
import app.scodoc.sco_utils as scu
from app.models.config import SiteConfig
class BonusConfigurationForm(FlaskForm):
@ -56,6 +58,24 @@ class ScoDocConfigurationForm(FlaskForm):
enable_entreprises = BooleanField("activer le module <em>entreprises</em>")
submit_scodoc = SubmitField("Valider")
cancel_scodoc = SubmitField("Annuler", render_kw={"formnovalidate": True})
default_pdf_footer_template = StringField(label="Pied de page par défaut des documents PDF")
custom_html_header = StringField(label="Fichier d'entete html")
custom_html_footer = StringField(label="fichier pied de page html")
custom_html_header_cnx = StringField(label="Fichier d'entete html (connexion)")
custom_html_footer_cnx = StringField(label="fichier pied de page html (connexion)")
capitalize_all_ues = BooleanField(label="Capitalise toutes les UE des semestres validés (règles DUT)")
allow_null_prenom = BooleanField(label="Autorise les étudiants sans prénom (UCAC)")
publish_portal_photo_url = BooleanField(label="Si pas de photo et portail, publie l'url (était vrai jusqu'en oct 2016)")
logo_header_height = IntegerField(label="hauteur en mm du logo d'entête")
logo_footer_height = IntegerField(label="hauteur en mm du logo de pied de page")
alwways_require_ine = BooleanField(label="Rendre l'INE obligatoire")
etud_max_filesize = IntegerField(label="Taille maximale des fichiers archives étudiants en octets")
submit = SubmitField("Valider")
cancel = SubmitField("Annuler", render_kw={"formnovalidate": True})
def configuration():
@ -72,6 +92,8 @@ def configuration():
if request.method == "POST" and (
form_bonus.cancel_bonus.data or form_scodoc.cancel_scodoc.data
): # cancel button
form = ScoDocConfigurationForm(data=SiteConfig.get_editable_data())
if request.method == "POST" and form.cancel.data: # cancel button
return redirect(url_for("scodoc.index"))
if form_bonus.submit_bonus.data and form_bonus.validate():
if (
@ -83,6 +105,16 @@ def configuration():
)
app.clear_scodoc_cache()
flash(f"Fonction bonus sport&culture configurée.")
if form.validate_on_submit():
modified = set()
for c in SiteConfig:
if c.editable():
if form.data[c.db_name()] != c.get_value():
c.set_value(form.data[c.db_name()])
app.clear_scodoc_cache()
modified.add(c)
flash(f"Fonction bonus sport&culture configurée.")
return redirect(url_for("scodoc.index"))
elif form_scodoc.submit_scodoc.data and form_scodoc.validate():
if ScoDocSiteConfig.enable_entreprises(

View File

@ -2,6 +2,7 @@
"""Model : site config WORK IN PROGRESS #WIP
"""
from enum import Enum
from flask import flash
from app import db, log
@ -47,6 +48,264 @@ def code_scodoc_to_apo_default(code):
return CODES_SCODOC_TO_APO.get(code, "DEF")
class SiteConfig(Enum):
BONUS_SPORT = {
"editable": True,
"db_name": "bonus_sport_func_name",
"default": None,
"type": str,
}
FOOTER_TEMPLATE = {
"editable": True,
"db_name": "default_pdf_footer_template",
"default": "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s",
"type": str,
}
LOGO_HEADER_HEIGHT = {
"editable": True,
"db_name": "logo_header_height",
"default": 28,
"type": int,
}
LOGO_FOOTER_HEIGHT = {
"editable": True,
"db_name": "logo_footer_height",
"default": 10,
"type": str,
}
CUSTOM_HTML_HEADER = {
"editable": True,
"db_name": "custom_html_header",
"default": "",
"type": str,
}
CUSTOM_HTML_FOOTER = {
"editable": True,
"db_name": "custom_html_footer",
"default": "",
"type": str,
}
CUSTOM_HTML_HEADER_CNX = {
"editable": True,
"db_name": "custom_html_header_cnx",
"default": "",
"type": str,
}
CUSTOM_HTML_FOOTER_CNX = {
"editable": True,
"db_name": "custom_html_footer_cnx",
"default": "",
"type": str,
}
ETUD_MAX_FILE_SIZE = {
"editable": True,
"db_name": "etud_max_filesize",
"default": 10 * 1024 * 1024,
"type": int,
}
CAPITALIZE_ALL_UES = {
"editable": True,
"db_name": "capitalize_all_ues",
"default": True,
"type": bool,
}
ALLOW_NULL_PRENOM = {
"editable": True,
"db_name": "allow_null_prenom",
"default": False,
"type": bool,
}
ALWAYS_REQUIRE_INE = {
"editable": True,
"db_name": "alwways_require_ine",
"default": False,
"type": bool,
}
PUBLISH_PORTAL_PHOTO_URL = {
"editable": True,
"db_name": "publish_portal_photo_url",
"default": False,
"type": bool,
}
MIN_PASSWORD_LENGTH = {
"editable": True,
"db_name": "publish_portal_photo_url",
"default": 0,
"type": int,
}
@classmethod
def get_editable_data(cls):
data = {}
for c in SiteConfig:
if c.editable():
data[c.value["db_name"]] = c.get_value()
return data
def db_name(self):
return self.value["db_name"]
def default(self):
return self.value["default"]
def editable(self):
return self.value["editable"]
def type(self):
return self.value["type"]
def get_value(self):
"""Lit valeur de configuration (sinon valeur par défaut)"""
cfg = ScoDocSiteConfig.query.filter_by(name=self.value["db_name"]).first()
if not cfg:
return self.value["default"]
else:
value = cfg.value
if self.value["type"] == str:
return value
if self.value["type"] == bool:
return value.lower() == "true"
if self.value["type"] == int:
return int(value)
def set_value(self, value):
"""Enregistre nouvelle valeur de configuration"""
if value != self.get_value():
cfg = ScoDocSiteConfig.query.filter_by(name=self.value["db_name"]).first()
if cfg is None:
cfg = ScoDocSiteConfig(self.value["db_name"], value)
else:
cfg.value = str(value)
db.session.add(cfg)
db.session.commit()
NAMES = {c.db_name(): c for c in SiteConfig}
class SiteConfig(Enum):
BONUS_SPORT = {
"editable": True,
"db_name": "bonus_sport_func_name",
"default": None,
"type": str,
}
FOOTER_TEMPLATE = {
"editable": True,
"db_name": "default_pdf_footer_template",
"default": "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s",
"type": str,
}
CUSTOM_HTML_HEADER = {
"editable": True,
"db_name": "custom_html_header",
"default": "",
"type": str,
}
CUSTOM_HTML_FOOTER = {
"editable": True,
"db_name": "custom_html_footer",
"default": "",
"type": str,
}
CUSTOM_HTML_HEADER_CNX = {
"editable": True,
"db_name": "custom_html_header_cnx",
"default": "",
"type": str,
}
CUSTOM_HTML_FOOTER_CNX = {
"editable": True,
"db_name": "custom_html_footer_cnx",
"default": "",
"type": str,
}
ETUD_MAX_FILE_SIZE = {
"editable": True,
"db_name": "etud_max_filesize",
"default": 10 * 1024 * 1024,
"type": int,
}
CAPITALIZE_ALL_UES = {
"editable": True,
"db_name": "capitalize_all_ues",
"default": True,
"type": bool,
}
ALLOW_NULL_PRENOM = {
"editable": True,
"db_name": "allow_null_prenom",
"default": False,
"type": bool,
}
ALWAYS_REQUIRE_INE = {
"editable": True,
"db_name": "alwways_require_ine",
"default": False,
"type": bool,
}
PUBLISH_PORTAL_PHOTO_URL = {
"editable": True,
"db_name": "publish_portal_photo_url",
"default": False,
"type": bool,
}
MIN_PASSWORD_LENGTH = {
"editable": True,
"db_name": "publish_portal_photo_url",
"default": 0,
"type": int,
}
@classmethod
def get_editable_data(cls):
data = {}
for c in SiteConfig:
if c.editable():
data[c.value["db_name"]] = c.get_value()
return data
def db_name(self):
return self.value["db_name"]
def default(self):
return self.value["default"]
def editable(self):
return self.value["editable"]
def type(self):
return self.value["type"]
def get_value(self):
"""Lit valeur de configuration (sinon valeur par défaut)"""
cfg = ScoDocSiteConfig.query.filter_by(name=self.value["db_name"]).first()
if not cfg:
return self.value["default"]
else:
value = cfg.value
if self.value["type"] == str:
return value
if self.value["type"] == bool:
return value.lower() == "true"
if self.value["type"] == int:
return int(value)
def set_value(self, value):
"""Enregistre nouvelle valeur de configuration"""
if value != self.get_value():
cfg = ScoDocSiteConfig.query.filter_by(name=self.value["db_name"]).first()
if cfg is None:
cfg = ScoDocSiteConfig(self.value["db_name"], value)
else:
cfg.value = str(value)
db.session.add(cfg)
db.session.commit()
NAMES = {c.db_name(): c for c in SiteConfig}
class ScoDocSiteConfig(db.Model):
"""Config. d'un site
Nouveau en ScoDoc 9: va regrouper les paramètres qui dans les versions
@ -84,7 +343,7 @@ class ScoDocSiteConfig(db.Model):
def get_dict(cls) -> dict:
"Returns all data as a dict name = value"
return {
c.name: cls.NAMES.get(c.name, lambda x: x)(c.value)
c.name: NAMES.get(c.name, lambda x: x)(c.value)
for c in ScoDocSiteConfig.query.all()
}
@ -95,12 +354,12 @@ class ScoDocSiteConfig(db.Model):
"""
if class_name not in cls.get_bonus_sport_class_names():
raise NameError("invalid class name for bonus_sport")
c = ScoDocSiteConfig.query.filter_by(name=cls.BONUS_SPORT).first()
c = ScoDocSiteConfig.query.filter_by(name=SiteConfig.BONUS_SPORT.db_name()).first()
if c:
log("setting to " + class_name)
c.value = class_name
else:
c = ScoDocSiteConfig(cls.BONUS_SPORT, class_name)
c = ScoDocSiteConfig(SiteConfig.BONUS_SPORT.db_name(), class_name)
db.session.add(c)
db.session.commit()
@ -127,7 +386,7 @@ class ScoDocSiteConfig(db.Model):
and flash a warning.
"""
if not class_name: # None or ""
c = ScoDocSiteConfig.query.filter_by(name=cls.BONUS_SPORT).first()
c = ScoDocSiteConfig.query.filter_by(name=SiteConfig.BONUS_SPORT.db_name()).first()
if c is None:
return None
class_name = c.value
@ -136,7 +395,7 @@ class ScoDocSiteConfig(db.Model):
klass = bonus_spo.get_bonus_class_dict().get(class_name)
if klass is None:
flash(
f"""Fonction de calcul bonus sport inexistante: {class_name}.
f"""Fonction de calcul bonus sport inexistante: {class_name}.
Changez ou contactez votre administrateur local."""
)
return klass
@ -158,6 +417,43 @@ class ScoDocSiteConfig(db.Model):
class_list.sort(key=lambda x: x[1].replace(" du ", " de "))
return [("", "")] + class_list
@classmethod
def get_bonus_sport_func(cls):
"""Fonction bonus_sport ScoDoc 7 XXX
Transitoire pour les tests durant la transition #sco92
"""
"""returns bonus func with specified name.
If name not specified, return the configured function.
None if no bonus function configured.
Raises ScoValueError if func_name not found in module bonus_sport.
"""
from app.scodoc import bonus_sport
# c = ScoDocSiteConfig.query.filter_by(name=Config.BONUS_SPORT.db_name()).first()
# if c is None:
# return None
# func_name = c.value
func_name = ScoDocSiteConfig.get_config_value(SiteConfig.BONUS_SPORT)
if func_name == "": # pas de bonus défini
return None
try:
return getattr(bonus_sport, func_name)
except AttributeError:
raise ScoValueError(
f"""Fonction de calcul de l'UE bonus inexistante: "{func_name}".
(contacter votre administrateur local)."""
)
@classmethod
def get_config_value(cls, conf: SiteConfig):
"""Lit valeur de configuration (sinon valeur par défaut)"""
return conf.get_value()
@classmethod
def set_config_value(cls, conf: SiteConfig, value):
"""Enregistre nouvelle valeur de configuration"""
conf.set_value(value)
@classmethod
def get_code_apo(cls, code: str) -> str:
"""La représentation d'un code pour les exports Apogée.

View File

@ -35,6 +35,7 @@ from flask import g, request
from flask_login import current_user
import app.scodoc.sco_utils as scu
from app.models.config import SiteConfig
from app.scodoc import sco_import_etuds
from app.scodoc import sco_groups
from app.scodoc import sco_trombino
@ -150,7 +151,7 @@ def etud_upload_file_form(etudid):
% etud,
"""<p>Le fichier ne doit pas dépasser %sMo.</p>
"""
% (scu.CONFIG.ETUD_MAX_FILE_SIZE // (1024 * 1024)),
% (SiteConfig.ETUD_MAX_FILE_SIZE.get_value() // (1024 * 1024)),
]
tf = TrivialFormulator(
request.base_url,
@ -193,7 +194,7 @@ def etud_upload_file_form(etudid):
def _store_etud_file_to_new_archive(etud_archive_id, data, filename, description=""):
"""Store data to new archive."""
filesize = len(data)
if filesize < 10 or filesize > scu.CONFIG.ETUD_MAX_FILE_SIZE:
if filesize < 10 or filesize > SiteConfig.ETUD_MAX_FILE_SIZE.get_value():
return 0, "Fichier image de taille invalide ! (%d)" % filesize
archive_id = EtudsArchive.create_obj_archive(etud_archive_id, description)
EtudsArchive.store(archive_id, filename, data)

View File

@ -6,7 +6,7 @@
mais éditer /opt/scodoc-data/config/scodoc_local.py
"""
from app.scodoc import bonus_sport
# from app.scodoc import bonus_sport
class AttrDict(dict):
@ -26,13 +26,13 @@ CONFIG.always_require_ine = 0
# 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
# CONFIG.LOGO_FOOTER_ASPECT = 326 / 96.0
# Taille dans le document en millimetres
CONFIG.LOGO_FOOTER_HEIGHT = 10
# CONFIG.LOGO_FOOTER_HEIGHT = 10
# Proportions logo (donné ici pour IUTV)
CONFIG.LOGO_HEADER_ASPECT = 549 / 346.0
# CONFIG.LOGO_HEADER_ASPECT = 549 / 346.0
# Taille verticale dans le document en millimetres
CONFIG.LOGO_HEADER_HEIGHT = 28
# CONFIG.LOGO_HEADER_HEIGHT = 28
# Pied de page PDF : un format Python, %(xxx)s est remplacé par la variable xxx.
@ -59,22 +59,22 @@ CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = (
# - 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
# 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 = ""
# CONFIG.CUSTOM_HTML_HEADER = ""
# Fichier html a inclure en fin des pages (juste avant le </body>)
CONFIG.CUSTOM_HTML_FOOTER = ""
# 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
# CONFIG.CUSTOM_HTML_HEADER_CNX = CONFIG.CUSTOM_HTML_HEADER
# CONFIG.CUSTOM_HTML_FOOTER_CNX = CONFIG.CUSTOM_HTML_FOOTER
# -----------------------------------------------------
# -------------- Noms de Lycées
@ -88,17 +88,17 @@ CONFIG.ETABL_FILENAME = "etablissements.csv"
# -------------- Divers:
# ----------------------------------------------------
# True for UCAC (étudiants camerounais sans prénoms)
CONFIG.ALLOW_NULL_PRENOM = False
# CONFIG.ALLOW_NULL_PRENOM = False
# Taille max des fichiers archive etudiants (en octets)
CONFIG.ETUD_MAX_FILE_SIZE = 10 * 1024 * 1024
# 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
# 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
# CONFIG.MIN_PASSWORD_LENGTH = 0
# Ce dictionnaire est fusionné à celui de sco_codes_parcours
# pour définir les codes jury et explications associées

View File

@ -78,6 +78,7 @@
import re
import app.scodoc.sco_utils as scu
from app.models.config import SiteConfig
from app.scodoc import sco_archives
from app.scodoc import sco_apogee_csv
from app.scodoc.sco_exceptions import ScoValueError
@ -110,7 +111,7 @@ def apo_csv_store(csv_data: str, annee_scolaire, sem_id):
"""
# sanity check
filesize = len(csv_data)
if filesize < 10 or filesize > scu.CONFIG.ETUD_MAX_FILE_SIZE:
if filesize < 10 or filesize > SiteConfig.ETUD_MAX_FILE_SIZE.get_value():
raise ScoValueError("Fichier csv de taille invalide ! (%d)" % filesize)
if not annee_scolaire:

View File

@ -37,6 +37,7 @@ from flask import url_for, g
from app import email
from app import log
from app.models.config import SiteConfig
from app.models import Admission
from app.models.etudiants import make_etud_args
import app.scodoc.sco_utils as scu
@ -266,7 +267,7 @@ def check_nom_prenom(cnx, nom="", prenom="", etudid=None):
Returns:
True | False, NbHomonyms
"""
if not nom or (not prenom and not scu.CONFIG.ALLOW_NULL_PRENOM):
if not nom or (not prenom and not SiteConfig.ALLOW_NULL_PRENOM.get_value()):
return False, 0
nom = nom.lower().strip()
if prenom:

View File

@ -49,6 +49,7 @@ from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre, formsemestre
from app.models import GROUPNAME_STR_LEN, SHORT_STR_LEN
from app.models.config import SiteConfig
from app.models.groups import Partition
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
@ -257,7 +258,7 @@ def get_group_members(group_id, etat=None):
r.sort(key=operator.itemgetter("nom_disp", "prenom")) # tri selon nom_usuel ou nom
if scu.CONFIG.ALLOW_NULL_PRENOM:
if SiteConfig.ALLOW_NULL_PRENOM.get_value():
for x in r:
x["prenom"] = x["prenom"] or ""

View File

@ -285,6 +285,13 @@ class Logo:
dt = path.stat().st_mtime
return path.stat().st_mtime
def compute_width(self, height):
if isinstance(self.aspect_ratio, str):
return (
"Logo not initialized: call the select or create function before access"
)
return self.aspect_ratio * height
def guess_image_type(stream) -> str:
"guess image type from header in stream"

View File

@ -55,6 +55,8 @@ from reportlab.lib import styles
from flask import g
import app.scodoc.sco_utils as scu
from app.models.config import ScoDocSiteConfig, SiteConfig
from app.scodoc.sco_utils import CONFIG
from app import log
from app.scodoc.sco_exceptions import ScoGenError, ScoValueError
@ -64,9 +66,6 @@ PAGE_HEIGHT = defaultPageSize[1]
PAGE_WIDTH = defaultPageSize[0]
DEFAULT_PDF_FOOTER_TEMPLATE = CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE
def SU(s):
"convert s from string to string suitable for ReportLab"
if not s:
@ -223,7 +222,7 @@ class ScoDocPageTemplate(PageTemplate):
subject=None,
margins=(0, 0, 0, 0), # additional margins in mm (left,top,right, bottom)
server_name="",
footer_template=DEFAULT_PDF_FOOTER_TEMPLATE,
footer_template=None,
filigranne=None,
preferences=None, # dictionnary with preferences, required
):
@ -231,6 +230,10 @@ class ScoDocPageTemplate(PageTemplate):
# defered import (solve circular dependency ->sco_logo ->scodoc, ->sco_pdf
from app.scodoc.sco_logos import find_logo
if footer_template is None:
footer_template = ScoDocSiteConfig.get_config_value(
SiteConfig.FOOTER_TEMPLATE
)
self.preferences = preferences
self.pagesbookmarks = pagesbookmarks or {}
self.pdfmeta_author = author
@ -416,7 +419,7 @@ def pdf_basic_page(
document,
title=title,
author="%s %s (E. Viennet)" % (sco_version.SCONAME, sco_version.SCOVERSION),
footer_template="Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s",
footer_template=ScoDocSiteConfig.get_default_pdf_footer_template(),
preferences=preferences,
)
)

View File

@ -59,6 +59,7 @@ from flask.helpers import make_response, url_for
from app import log
from app import db
from app.models import Identite
from app.models.config import SiteConfig
from app.scodoc import sco_etud
from app.scodoc import sco_portal_apogee
from app.scodoc import sco_preferences
@ -117,7 +118,7 @@ def etud_photo_url(etud: dict, size="small", fast=False) -> str:
if not new_path:
# copy failed, can we use external url ?
# nb: rarement utile, car le portail est rarement accessible sans authentification
if scu.CONFIG.PUBLISH_PORTAL_PHOTO_URL:
if SiteConfig.PUBLISH_PORTAL_PHOTO_URL.get_value():
photo_url = ext_url
else:
photo_url = UNKNOWN_IMAGE_URL

View File

@ -43,6 +43,7 @@ from reportlab.lib.colors import Color
from flask import g
import app.scodoc.sco_utils as scu
from app.models.config import SiteConfig
from app.scodoc import sco_bulletins_pdf
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_formsemestre
@ -53,13 +54,15 @@ import sco_version
from app.scodoc.sco_logos import find_logo
from app.scodoc.sco_pdf import SU
LOGO_FOOTER_ASPECT = scu.CONFIG.LOGO_FOOTER_ASPECT # XXX A AUTOMATISER
LOGO_FOOTER_HEIGHT = scu.CONFIG.LOGO_FOOTER_HEIGHT * mm
LOGO_FOOTER_WIDTH = LOGO_FOOTER_HEIGHT * scu.CONFIG.LOGO_FOOTER_ASPECT
# LOGO_FOOTER_HEIGHT = SiteConfig.LOGO_FOOTER_HEIGHT.get_value() * mm
LOGO_FOOTER_HEIGHT = 10 * mm
# LOGO_FOOTER_ASPECT = scu.CONFIG.LOGO_FOOTER_ASPECT # XXX A AUTOMATISER
# LOGO_FOOTER_WIDTH = LOGO_FOOTER_HEIGHT * scu.CONFIG.LOGO_FOOTER_ASPECT
LOGO_HEADER_ASPECT = scu.CONFIG.LOGO_HEADER_ASPECT # XXX logo IUTV (A AUTOMATISER)
LOGO_HEADER_HEIGHT = scu.CONFIG.LOGO_HEADER_HEIGHT * mm
LOGO_HEADER_WIDTH = LOGO_HEADER_HEIGHT * scu.CONFIG.LOGO_HEADER_ASPECT
# LOGO_HEADER_HEIGHT = SiteConfig.LOGO_HEADER_HEIGHT.get_value() * mm
LOGO_HEADER_HEIGHT = 28 * mm
# LOGO_HEADER_ASPECT = scu.CONFIG.LOGO_HEADER_ASPECT # XXX logo IUTV (A AUTOMATISER)
# LOGO_HEADER_WIDTH = LOGO_HEADER_HEIGHT * scu.CONFIG.LOGO_HEADER_ASPECT
def pageFooter(canvas, doc, logo, preferences, with_page_numbers=True):
@ -225,7 +228,7 @@ class CourrierIndividuelTemplate(PageTemplate):
self.logo_footer = Image(
footer.filepath,
height=LOGO_FOOTER_HEIGHT,
width=LOGO_FOOTER_WIDTH,
width=footer.compute_width(LOGO_FOOTER_HEIGHT),
)
header = find_logo(logoname="header", dept_id=g.scodoc_dept_id)
@ -233,7 +236,7 @@ class CourrierIndividuelTemplate(PageTemplate):
self.logo_header = Image(
header.filepath,
height=LOGO_HEADER_HEIGHT,
width=LOGO_HEADER_WIDTH,
width=header.compute_width(LOGO_HEADER_HEIGHT),
)
def beforeDrawPage(self, canvas, doc):

View File

@ -61,7 +61,6 @@ from app.scodoc import sco_exceptions
from app.scodoc import sco_xml
import sco_version
# ----- CALCUL ET PRESENTATION DES NOTES
NOTES_PRECISION = 1e-4 # evite eventuelles erreurs d'arrondis
NOTES_MIN = 0.0 # valeur minimale admise pour une note (sauf malus, dans [-20, 20])
@ -119,7 +118,7 @@ IT_SITUATION_MISSING_STR = (
"____" # shown on ficheEtud (devenir) in place of empty situation
)
RANG_ATTENTE_STR = "(attente)" # rang affiché sur bulletins quand notes en attente
RANG_ATTENTE_STR = "(attente)" # rang affiché sur bulletins quand notes en attente
# borne supérieure de chaque mention
NOTES_MENTIONS_TH = (
@ -316,7 +315,6 @@ LOGO_FILE_PREFIX = "logo_"
# ----- Les outils distribués
SCO_TOOLS_DIR = os.path.join(Config.SCODOC_DIR, "tools")
# ----- Lecture du fichier de configuration
from app.scodoc import sco_config
from app.scodoc import sco_config_load
@ -328,29 +326,30 @@ if hasattr(CONFIG, "CODES_EXPL"):
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:
CUSTOM_HTML_HEADER = ""
if CONFIG.CUSTOM_HTML_HEADER_CNX:
CUSTOM_HTML_HEADER_CNX = open(CONFIG.CUSTOM_HTML_HEADER_CNX).read()
else:
CUSTOM_HTML_HEADER_CNX = ""
def include_html(config):
setting = config.get_value()
if setting:
return open(setting).read()
else:
return ""
if CONFIG.CUSTOM_HTML_FOOTER:
CUSTOM_HTML_FOOTER = open(CONFIG.CUSTOM_HTML_FOOTER).read()
else:
CUSTOM_HTML_FOOTER = ""
if CONFIG.CUSTOM_HTML_FOOTER_CNX:
CUSTOM_HTML_FOOTER_CNX = open(CONFIG.CUSTOM_HTML_FOOTER_CNX).read()
else:
CUSTOM_HTML_FOOTER_CNX = ""
def get_custom_html():
from app.models.config import SiteConfig
return ("", "", "", "")
# TODO
# return (
# include_html(SiteConfig.CUSTOM_HTML_HEADER),
# include_html(SiteConfig.CUSTOM_HTML_FOOTER),
# include_html(SiteConfig.CUSTOM_HTML_HEADER_CNX),
# include_html(SiteConfig.CUSTOM_HTML_FOOTER_CNX),
# )
SCO_ENCODING = "utf-8" # used by Excel, XML, PDF, ...
SCO_DEFAULT_SQL_USER = "scodoc" # should match Zope process UID
SCO_DEFAULT_SQL_PORT = "5432"
SCO_DEFAULT_SQL_USERS_CNX = "dbname=SCOUSERS port=%s" % SCO_DEFAULT_SQL_PORT
@ -415,6 +414,7 @@ TYPES_ADMISSION = (TYPE_ADMISSION_DEFAULT, "APB", "APB-PC", "CEF", "Direct")
BULLETINS_VERSIONS = ("short", "selectedevals", "long")
# Support for ScoDoc7 compatibility

View File

@ -30,17 +30,38 @@
{{ form_bonus.hidden_tag() }}
<div class="row">
<div class="col-md-4">
{{ wtf.quick_form(form_bonus) }}
{{ render_field(form.bonus_sport_func_name) }}
</div>
</div>
<div id="bonus_description"></div>
</form>
<div class="row">
<div class="col-md-12">
{{ render_field(form.default_pdf_footer_template) }}
{{ render_field(form.custom_html_header) }}
{{ render_field(form.custom_html_header_cnx) }}
{{ render_field(form.custom_html_footer) }}
{{ render_field(form.custom_html_footer_cnx) }}
{{ render_field(form.capitalize_all_ues) }}
{{ render_field(form.allow_null_prenom) }}
{{ render_field(form.publish_portal_photo_url) }}
{{ render_field(form.alwways_require_ine) }}
{{ render_field(form.etud_max_filesize) }}
{{ render_field(form.logo_header_height) }}
{{ render_field(form.logo_footer_height) }}
{{ render_field(form.submit, with_label=False) }}
{{ render_field(form.cancel, with_label=False) }}
</div>
</div>
</section>
<section>
<h2>Gestion des images: logos, signatures, ...</h2>
<div class="sco_help">Ces images peuvent être intégrées dans les documents
<div class="sco_help">Ces images peuvent être intégrées dans les documents
générés par ScoDoc: bulletins, PV, etc.
</div>
<p><a class="stdlink" href="{{url_for('scodoc.configure_logos')}}">configuration des images et logos</a>
@ -54,7 +75,7 @@
<h2>Utilisateurs</h2>
<section>
<p><a class="stdlink" href="{{url_for('auth.reset_standard_roles_permissions')}}">remettre
<p><a class="stdlink" href="{{url_for('auth.reset_standard_roles_permissions')}}">remettre
les permissions des rôles standards à leurs valeurs par défaut</a> (efface les modifications apportées)
</p>
</section>

View File

@ -50,6 +50,7 @@ from app.decorators import (
admin_required,
login_required,
)
from app.models.config import SiteConfig
from app.models.etudiants import Identite
from app.models.etudiants import make_etud_args
@ -1325,7 +1326,7 @@ def _etudident_create_or_edit_form(edit):
{
"size": 25,
"title": "Prénom",
"allow_null": scu.CONFIG.ALLOW_NULL_PRENOM,
"allow_null": SiteConfig.ALLOW_NULL_PRENOM.get_value(),
},
),
(

View File

@ -66,6 +66,7 @@ CONFIG.LOGO_HEADER_HEIGHT = 28 # taille verticale dans le document en millimetr
CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = (
"Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s"
)
# 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"
#