ScoDoc-Lille/app/models/config.py
Jean-Marie PLACE ba3832bf29 nettoyage
2022-04-10 11:01:28 +02:00

506 lines
15 KiB
Python

# -*- coding: UTF-8 -*
"""Model : site config WORK IN PROGRESS #WIP
"""
from enum import Enum
from flask import flash
from app import db, log
from app.comp import bonus_spo
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc.sco_codes_parcours import (
ADC,
ADJ,
ADM,
AJ,
ATB,
ATJ,
ATT,
CMP,
DEF,
DEM,
NAR,
RAT,
)
CODES_SCODOC_TO_APO = {
ADC: "ADMC",
ADJ: "ADM",
ADM: "ADM",
AJ: "AJ",
ATB: "AJAC",
ATJ: "AJAC",
ATT: "AJAC",
CMP: "COMP",
DEF: "NAR",
DEM: "NAR",
NAR: "NAR",
RAT: "ATT",
"NOTES_FMT": "%3.2f",
}
def code_scodoc_to_apo_default(code):
"""Conversion code jury ScoDoc en code Apogée
(codes par défaut, c'est configurable via ScoDocSiteConfig.get_code_apo)
"""
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
antérieures étaient dans scodoc_config.py
"""
__tablename__ = "scodoc_site_config"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), nullable=False, index=True)
value = db.Column(db.Text())
BONUS_SPORT = "bonus_sport_func_name"
NAMES = {
BONUS_SPORT: str,
"always_require_ine": bool,
"SCOLAR_FONT": str,
"SCOLAR_FONT_SIZE": str,
"SCOLAR_FONT_SIZE_FOOT": str,
"INSTITUTION_NAME": str,
"INSTITUTION_ADDRESS": str,
"INSTITUTION_CITY": str,
"DEFAULT_PDF_FOOTER_TEMPLATE": str,
"enable_entreprises": bool,
}
def __init__(self, name, value):
self.name = name
self.value = value
def __repr__(self):
return f"<{self.__class__.__name__}('{self.name}', '{self.value}')>"
@classmethod
def get_dict(cls) -> dict:
"Returns all data as a dict name = value"
return {
c.name: NAMES.get(c.name, lambda x: x)(c.value)
for c in ScoDocSiteConfig.query.all()
}
@classmethod
def set_bonus_sport_class(cls, class_name):
"""Record bonus_sport config.
If class_name not defined, raise NameError
"""
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=SiteConfig.BONUS_SPORT.db_name()).first()
if c:
log("setting to " + class_name)
c.value = class_name
else:
c = ScoDocSiteConfig(SiteConfig.BONUS_SPORT.db_name(), class_name)
db.session.add(c)
db.session.commit()
@classmethod
def get_bonus_sport_class_name(cls):
"""Get configured bonus function name, or None if None."""
klass = cls.get_bonus_sport_class_from_name()
if klass is None:
return ""
else:
return klass.name
@classmethod
def get_bonus_sport_class(cls):
"""Get configured bonus function, or None if None."""
return cls.get_bonus_sport_class_from_name()
@classmethod
def get_bonus_sport_class_from_name(cls, class_name=None):
"""returns bonus class with specified name.
If name not specified, return the configured function.
None if no bonus function configured.
If class_name not found in module bonus_sport, returns None
and flash a warning.
"""
if not class_name: # None or ""
c = ScoDocSiteConfig.query.filter_by(name=SiteConfig.BONUS_SPORT.db_name()).first()
if c is None:
return None
class_name = c.value
if class_name == "": # pas de bonus défini
return None
klass = bonus_spo.get_bonus_class_dict().get(class_name)
if klass is None:
flash(
f"""Fonction de calcul bonus sport inexistante: {class_name}.
Changez là ou contactez votre administrateur local."""
)
return klass
@classmethod
def get_bonus_sport_class_names(cls) -> list:
"""List available bonus class names
(starting with empty string to represent "no bonus function").
"""
return [""] + sorted(bonus_spo.get_bonus_class_dict().keys())
@classmethod
def get_bonus_sport_class_list(cls) -> list[tuple]:
"""List available bonus class names
(starting with empty string to represent "no bonus function").
"""
d = bonus_spo.get_bonus_class_dict()
class_list = [(name, d[name].displayed_name) for name in d.keys()]
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.
Par exemple, à l'iUT du H., le code ADM est réprésenté par VAL
Les codes par défaut sont donnés dans sco_apogee_csv.
"""
cfg = ScoDocSiteConfig.query.filter_by(name=code).first()
if not cfg:
code_apo = code_scodoc_to_apo_default(code)
else:
code_apo = cfg.value
return code_apo
@classmethod
def set_code_apo(cls, code: str, code_apo: str):
"""Enregistre nouvelle représentation du code"""
if code_apo != cls.get_code_apo(code):
cfg = ScoDocSiteConfig.query.filter_by(name=code).first()
if cfg is None:
cfg = ScoDocSiteConfig(code, code_apo)
else:
cfg.value = code_apo
db.session.add(cfg)
db.session.commit()
@classmethod
def is_entreprises_enabled(cls) -> bool:
"""True si on doit activer le module entreprise"""
cfg = ScoDocSiteConfig.query.filter_by(name="enable_entreprises").first()
if (cfg is None) or not cfg.value:
return False
return True
@classmethod
def enable_entreprises(cls, enabled=True) -> bool:
"""Active (ou déactive) le module entreprises. True si changement."""
if enabled != ScoDocSiteConfig.is_entreprises_enabled():
cfg = ScoDocSiteConfig.query.filter_by(name="enable_entreprises").first()
if cfg is None:
cfg = ScoDocSiteConfig(
name="enable_entreprises", value="on" if enabled else ""
)
else:
cfg.value = "on" if enabled else ""
db.session.add(cfg)
db.session.commit()
return True
return False