"""
Description des options de configuration
"""
import os
from warnings import warn
from marshmallow import Schema, fields, validates_schema, ValidationError, post_load, pre_load
from marshmallow.validate import OneOf, Regexp, Email, Length
from geonature.core.gn_synthese.synthese_config import (
DEFAULT_EXPORT_COLUMNS,
DEFAULT_LIST_COLUMN,
)
from geonature.utils.env import GEONATURE_VERSION, BACKEND_DIR, ROOT_DIR
from geonature.utils.module import iter_modules_dist, get_module_config
from geonature.utils.utilsmails import clean_recipients
from geonature.utils.utilstoml import load_and_validate_toml
[docs]
class EmailStrOrListOfEmailStrField(fields.Field):
[docs]
def _deserialize(self, value, attr, data, **kwargs):
if isinstance(value, str):
value = list(map(lambda x: x.replace("\n", "").strip(), value.split(",")))
if not isinstance(value, list) and all(isinstance(x, str) for x in value):
raise ValidationError("Field should be str or list of str")
self._check_email(value)
return value
[docs]
def _check_email(self, value):
recipients = clean_recipients(value)
for recipient in recipients:
email = recipient[1] if isinstance(recipient, tuple) else recipient
# Validate email with Marshmallow
validator = Email()
validator(email)
[docs]
class CasUserSchemaConf(Schema):
[docs]
URL = fields.Url(load_default="https://inpn.mnhn.fr/authentication/information")
[docs]
BASE_URL = fields.Url(load_default="https://inpn.mnhn.fr/authentication/")
[docs]
ID = fields.String(load_default="mon_id")
[docs]
PASSWORD = fields.String(load_default="mon_pass")
[docs]
class CasFrontend(Schema):
[docs]
CAS_AUTHENTIFICATION = fields.Boolean(load_default=False)
[docs]
CAS_URL_LOGIN = fields.Url(load_default="https://preprod-inpn.mnhn.fr/auth/login")
[docs]
CAS_URL_LOGOUT = fields.Url(load_default="https://preprod-inpn.mnhn.fr/auth/logout")
[docs]
class CasSchemaConf(Schema):
[docs]
CAS_URL_VALIDATION = fields.String(
load_default="https://preprod-inpn.mnhn.fr/auth/serviceValidate"
)
[docs]
CAS_USER_WS = fields.Nested(CasUserSchemaConf, load_default=CasUserSchemaConf().load({}))
[docs]
USERS_CAN_SEE_ORGANISM_DATA = fields.Boolean(load_default=False)
# Quel modules seront associés au JDD récupérés depuis MTD
[docs]
class MTDSchemaConf(Schema):
[docs]
JDD_MODULE_CODE_ASSOCIATION = fields.List(fields.String, load_default=["OCCTAX", "OCCHAB"])
[docs]
ID_INSTANCE_FILTER = fields.Integer(load_default=None)
[docs]
SYNC_LOG_LEVEL = fields.String(load_default="INFO")
[docs]
class BddConfig(Schema):
[docs]
ID_USER_SOCLE_1 = fields.Integer(load_default=7)
[docs]
ID_USER_SOCLE_2 = fields.Integer(load_default=6)
[docs]
class RightsSchemaConf(Schema):
[docs]
NOTHING = fields.Integer(load_default=0)
[docs]
MY_DATA = fields.Integer(load_default=1)
[docs]
MY_ORGANISM_DATA = fields.Integer(load_default=2)
[docs]
ALL_DATA = fields.Integer(load_default=3)
[docs]
class MailConfig(Schema):
[docs]
MAIL_SERVER = fields.String(required=False)
[docs]
MAIL_PORT = fields.Integer(required=False)
[docs]
MAIL_USE_TLS = fields.Boolean(required=False)
[docs]
MAIL_USE_SSL = fields.Boolean(required=False)
[docs]
MAIL_USERNAME = fields.String(required=False)
[docs]
MAIL_PASSWORD = fields.String(required=False)
[docs]
MAIL_DEFAULT_SENDER = fields.String(required=False)
[docs]
MAIL_MAX_EMAILS = fields.Integer(required=False)
[docs]
MAIL_SUPPRESS_SEND = fields.Boolean(required=False)
[docs]
MAIL_ASCII_ATTACHMENTS = fields.Boolean(required=False)
[docs]
ERROR_MAIL_TO = EmailStrOrListOfEmailStrField(load_default=None)
[docs]
class CeleryConfig(Schema):
[docs]
broker_url = fields.String(load_default="redis://localhost:6379/0")
[docs]
result_backend = fields.String(load_default="redis://localhost:6379/0")
[docs]
enable_utc = fields.Boolean(load_default=False)
[docs]
timezone = fields.String(load_default=None)
[docs]
class AccountManagement(Schema):
# Config for sign-up
[docs]
ENABLE_SIGN_UP = fields.Boolean(load_default=False)
[docs]
ENABLE_USER_MANAGEMENT = fields.Boolean(load_default=False)
[docs]
AUTO_ACCOUNT_CREATION = fields.Boolean(load_default=True)
[docs]
AUTO_DATASET_CREATION = fields.Boolean(load_default=True)
[docs]
VALIDATOR_EMAIL = EmailStrOrListOfEmailStrField(load_default=None)
[docs]
ADDON_USER_EMAIL = fields.String(load_default="")
[docs]
DATASET_MODULES_ASSOCIATION = fields.List(fields.String(), load_default=["OCCTAX"])
[docs]
EXTERNAL_LINKS = fields.List(
fields.Dict,
load_default=[],
)
[docs]
class UsersHubConfig(Schema):
[docs]
ADMIN_APPLICATION_LOGIN = fields.String()
[docs]
ADMIN_APPLICATION_PASSWORD = fields.String()
[docs]
URL_USERSHUB = fields.Url()
[docs]
class ServerConfig(Schema):
[docs]
LOG_LEVEL = fields.Integer(load_default=20)
[docs]
class AlembicConfig(Schema):
[docs]
VERSION_LOCATIONS = fields.String()
[docs]
class AdditionalFields(Schema):
[docs]
IMPLEMENTED_MODULES = fields.List(fields.String(), load_default=["OCCTAX"])
[docs]
IMPLEMENTED_OBJECTS = fields.List(
fields.String(), load_default=["OCCTAX_RELEVE", "OCCTAX_OCCURENCE", "OCCTAX_DENOMBREMENT"]
)
[docs]
class HomeConfig(Schema):
[docs]
TITLE = fields.String(load_default="Bienvenue dans GeoNature")
[docs]
INTRODUCTION = fields.String(
load_default="Texte d'introduction, configurable pour le modifier régulièrement ou le masquer"
)
# class a utiliser pour les paramètres que l'on ne veut pas passer au frontend
[docs]
class GnPySchemaConf(Schema):
[docs]
SQLALCHEMY_DATABASE_URI = fields.String(
required=True,
validate=Regexp(
r"^(postgres(?:ql)?)((\+psycopg2)?):\/\/(?:([^@\s]+)@)?([^\/\s]+)(?:\/(\w+))?(?:\?(.+))?",
error="PostgreSQL database URL is invalid. Check for authorized URL here : https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING-URIS",
),
)
[docs]
SQLALCHEMY_TRACK_MODIFICATIONS = fields.Boolean(load_default=True)
[docs]
SESSION_TYPE = fields.String(load_default="filesystem")
[docs]
SECRET_KEY = fields.String(required=True, validate=Length(min=20))
# le cookie expire toute les 7 jours par défaut
[docs]
COOKIE_EXPIRATION = fields.Integer(load_default=3600 * 24 * 7)
[docs]
COOKIE_AUTORENEW = fields.Boolean(load_default=True)
[docs]
TRAP_ALL_EXCEPTIONS = fields.Boolean(load_default=False)
[docs]
SENTRY_DSN = fields.String()
[docs]
ROOT_PATH = fields.String(load_default=BACKEND_DIR)
[docs]
STATIC_FOLDER = fields.String(load_default="static")
[docs]
CUSTOM_STATIC_FOLDER = fields.String(load_default=ROOT_DIR / "custom")
[docs]
CAS = fields.Nested(CasSchemaConf, load_default=CasSchemaConf().load({}))
[docs]
MAIL_ON_ERROR = fields.Boolean(load_default=False)
[docs]
MAIL_CONFIG = fields.Nested(MailConfig, load_default=MailConfig().load({}))
[docs]
CELERY = fields.Nested(CeleryConfig, load_default=CeleryConfig().load({}))
[docs]
ADMIN_APPLICATION_LOGIN = fields.String()
[docs]
ACCOUNT_MANAGEMENT = fields.Nested(AccountManagement, load_default=AccountManagement().load({}))
[docs]
BAD_LOGIN_STATUS_CODE = fields.Integer(load_default=401)
[docs]
USERSHUB = fields.Nested(UsersHubConfig, load_default=UsersHubConfig().load({}))
[docs]
SERVER = fields.Nested(ServerConfig, load_default=ServerConfig().load({}))
[docs]
ALEMBIC = fields.Nested(AlembicConfig, load_default=AlembicConfig().load({}))
@post_load()
[docs]
def folders(self, data, **kwargs):
data["STATIC_FOLDER"] = os.path.join(data["ROOT_PATH"], data["STATIC_FOLDER"])
if "CUSTOM_STATIC_FOLDER" in data:
data["CUSTOM_STATIC_FOLDER"] = os.path.join(
data["ROOT_PATH"], data["CUSTOM_STATIC_FOLDER"]
)
data["MEDIA_FOLDER"] = os.path.join(data["ROOT_PATH"], data["MEDIA_FOLDER"])
return data
@post_load()
[docs]
def unwrap_usershub(self, data, **kwargs):
"""
On met la section [USERSHUB] à la racine de la conf
pour compatibilité et simplicité ave le sous-module d'authentif
"""
for key, value in data["USERSHUB"].items():
data[key] = value
data.pop("USERSHUB")
return data
@validates_schema
[docs]
def validate_enable_usershub_and_mail(self, data, **kwargs):
# si account management = true, URL_USERSHUB et MAIL_CONFIG sont necessaire
if data["ACCOUNT_MANAGEMENT"].get("ENABLE_SIGN_UP", False) or data[
"ACCOUNT_MANAGEMENT"
].get("ENABLE_USER_MANAGEMENT", False):
if (
data["USERSHUB"].get("URL_USERSHUB", None) is None
or data["USERSHUB"].get("ADMIN_APPLICATION_LOGIN", None) is None
or data["USERSHUB"].get("ADMIN_APPLICATION_PASSWORD", None) is None
):
raise ValidationError(
(
"URL_USERSHUB, ADMIN_APPLICATION_LOGIN et ADMIN_APPLICATION_PASSWORD sont necessaires si ENABLE_SIGN_UP=True "
"ou si ENABLE_USER_MANAGEMENT=True"
),
"URL_USERSHUB",
)
if data["MAIL_CONFIG"].get("MAIL_SERVER", None) is None:
raise ValidationError(
"Veuillez remplir la rubrique MAIL_CONFIG si ENABLE_SIGN_UP=True",
"ENABLE_SIGN_UP",
)
[docs]
class GnFrontEndConf(Schema):
[docs]
PROD_MOD = fields.Boolean(load_default=True)
[docs]
DISPLAY_STAT_BLOC = fields.Boolean(load_default=True)
[docs]
STAT_BLOC_TTL = fields.Integer(load_default=3600)
[docs]
DISPLAY_MAP_LAST_OBS = fields.Boolean(load_default=True)
[docs]
MULTILINGUAL = fields.Boolean(load_default=False)
[docs]
ENABLE_PROFILES = fields.Boolean(load_default=True)
# show email on synthese and validation info obs modal
[docs]
DISPLAY_EMAIL_INFO_OBS = fields.Boolean(load_default=True)
[docs]
DISPLAY_EMAIL_DISPLAY_INFO = fields.List(fields.String(), load_default=["NOM_VERN"])
[docs]
class ExportObservationSchema(Schema):
[docs]
label = fields.String(required=True)
[docs]
view_name = fields.String(required=True)
[docs]
geojson_4326_field = fields.String(load_default="geojson_4326")
[docs]
geojson_local_field = fields.String(load_default="geojson_local")
[docs]
class Synthese(Schema):
# --------------------------------------------------------------------
# SYNTHESE - SEARCH FORM
[docs]
AREA_FILTERS = fields.List(
fields.Dict, load_default=[{"label": "Communes", "type_code": "COM"}]
)
# Nombre de résultat à afficher pour la rechercher autocompleté de taxon
[docs]
TAXON_RESULT_NUMBER = fields.Integer(load_default=20)
# Afficher ou non l'arbre taxonomique
[docs]
DISPLAY_TAXON_TREE = fields.Boolean(load_default=True)
# Switch the observer form input in free text input (true) or in select input (false)
[docs]
SEARCH_OBSERVER_WITH_LIST = fields.Boolean(load_default=False)
# Id of the observer list -- utilisateurs.t_menus
[docs]
ID_SEARCH_OBSERVER_LIST = fields.Integer(load_default=1)
# Regulatory or not status list of fields
[docs]
STATUS_FILTERS = fields.List(
fields.Dict,
load_default=[
{
"id": "protections",
"show": True,
"display_name": "Taxons protégés",
"status_types": ["PN", "PR", "PD"],
},
{
"id": "regulations",
"show": True,
"display_name": "Taxons réglementés",
"status_types": ["REGLII", "REGLLUTTE", "REGL", "REGLSO"],
},
{
"id": "znief",
"show": True,
"display_name": "Espèces déterminantes ZNIEFF",
"status_types": ["ZDET"],
},
],
)
# Red lists list of fields
[docs]
RED_LISTS_FILTERS = fields.List(
fields.Dict,
load_default=[
{
"id": "worldwide",
"show": True,
"display_name": "Liste rouge mondiale",
"status_type": "LRM",
},
{
"id": "european",
"show": True,
"display_name": "Liste rouge européenne",
"status_type": "LRE",
},
{
"id": "national",
"show": True,
"display_name": "Liste rouge nationale",
"status_type": "LRN",
},
{
"id": "regional",
"show": True,
"display_name": "Liste rouge régionale",
"status_type": "LRR",
},
],
)
# Filtres par défaut pour la synthese
[docs]
DEFAULT_FILTERS = fields.Dict(load_default={})
# --------------------------------------------------------------------
# SYNTHESE - OBSERVATIONS LIST
# Colonnes affichées par défaut sur la liste des résultats de la synthese
# Champs disponibles: tous ceux de la vue 'v_synthese_for_web_app
[docs]
LIST_COLUMNS_FRONTEND = fields.List(fields.Dict, load_default=DEFAULT_LIST_COLUMN)
# Colonnes affichables sur la liste des résultats de la synthese via la modale de selection des colonnes
[docs]
ADDITIONAL_COLUMNS_FRONTEND = fields.List(fields.Dict, load_default=[])
# --------------------------------------------------------------------
# SYNTHESE - DOWNLOADS (AKA EXPORTS)
[docs]
EXPORT_COLUMNS = fields.List(fields.String(), load_default=DEFAULT_EXPORT_COLUMNS)
[docs]
EXPORT_OBSERVATIONS_CUSTOM_VIEWS = fields.List(
fields.Nested(ExportObservationSchema), load_default=[]
)
# Certaines colonnes sont obligatoires pour effectuer les filtres CRUVED
[docs]
EXPORT_ID_SYNTHESE_COL = fields.String(load_default="id_synthese")
[docs]
EXPORT_ID_DATASET_COL = fields.String(load_default="jdd_id")
[docs]
EXPORT_ID_DIGITISER_COL = fields.String(load_default="id_digitiser")
[docs]
EXPORT_OBSERVERS_COL = fields.String(load_default="observateurs")
[docs]
EXPORT_GEOJSON_4326_COL = fields.String(load_default="geojson_4326")
[docs]
EXPORT_GEOJSON_LOCAL_COL = fields.String(load_default="geojson_local")
# Formats d'export disponibles ["csv", "geojson", "shapefile", "gpkg"]
# Nombre max d'observation dans les exports
[docs]
NB_MAX_OBS_EXPORT = fields.Integer(load_default=50000)
# --------------------------------------------------------------------
# SYNTHESE - OBSERVATION DETAILS
# Liste des id attributs Taxhub à afficher sur la fiche détaile de la synthese
# et sur les filtres taxonomiques avancés
[docs]
ID_ATTRIBUT_TAXHUB = fields.List(fields.Integer(), load_default=[102, 103])
# Display email on synthese and validation info obs modal
[docs]
DISPLAY_EMAIL = fields.Boolean(load_default=True)
# --------------------------------------------------------------------
# SYNTHESE - SHARED PARAMETERS
# Nom des colonnes de la table gn_synthese.synthese que l'on veux retirer des filtres dynamiques
# et de la modale d'information détaillée d'une observation example = "[non_digital_proof]"
[docs]
EXCLUDED_COLUMNS = fields.List(fields.String(), load_default=[])
# Nombre max d'observation à afficher sur la carte
[docs]
NB_MAX_OBS_MAP = fields.Integer(load_default=50000)
# Clusteriser les layers sur la carte
[docs]
ENABLE_LEAFLET_CLUSTER = fields.Boolean(load_default=True)
# Nombre des "dernières observations" affichées à l'arrivée sur la synthese
[docs]
NB_LAST_OBS = fields.Integer(load_default=100)
# Display email on synthese and validation info obs modal
DISPLAY_EMAIL = fields.Boolean(load_default=True)
# Limit comment max length for the discussion tab
[docs]
DISCUSSION_MAX_LENGTH = fields.Integer(load_default=1500)
# Allow disable discussion tab for synthese or validation
[docs]
DISCUSSION_MODULES = fields.List(fields.String(), load_default=["SYNTHESE", "VALIDATION"])
# Allow disable alert synthese module for synthese or validation or any
[docs]
ALERT_MODULES = fields.List(fields.String(), load_default=["SYNTHESE", "VALIDATION"])
# Allow to activate pin tool for any, some or all VALIDATION, SYNTHESE
[docs]
PIN_MODULES = fields.List(fields.String(), load_default=["SYNTHESE", "VALIDATION"])
# Enable areas vizualisation with toggle slide
[docs]
AREA_AGGREGATION_ENABLED = fields.Boolean(load_default=True)
# Choose size of areas
[docs]
AREA_AGGREGATION_TYPE = fields.String(load_default="M10")
# Activate areas mode by default
[docs]
AREA_AGGREGATION_BY_DEFAULT = fields.Boolean(load_default=False)
# Areas legend classes to use
[docs]
AREA_AGGREGATION_LEGEND_CLASSES = fields.List(
fields.Dict(),
load_default=[
{"min": 100, "color": "#800026"},
{"min": 50, "color": "#BD0026"},
{"min": 20, "color": "#E31A1C"},
{"min": 10, "color": "#FC4E2A"},
{"min": 5, "color": "#FD8D3C"},
{"min": 2, "color": "#FEB24C"},
{"min": 1, "color": "#FED976"},
{"min": 0, "color": "#FFEDA0"},
],
)
# Activate the blurring of sensitive observations. Otherwise, exclude them
[docs]
BLUR_SENSITIVE_OBSERVATIONS = fields.Boolean(load_default=True)
@pre_load
[docs]
def warn_deprecated(self, data, **kwargs):
deprecated = {
"EXPORT_ID_SYNTHESE_COL",
"EXPORT_ID_DIGITISER_COL",
"EXPORT_OBSERVERS_COL",
"EXPORT_GEOJSON_4326_COL",
"EXPORT_GEOJSON_LOCAL_COL",
}
for deprecated_field in deprecated & set(data.keys()):
warn(
f"{deprecated_field} is deprecated - "
"Please use `EXPORT_OBSERVATIONS_CUSTOM_VIEWS` parameter to customize your synthese exports "
)
return data
# Map configuration
[docs]
BASEMAP = [
{
"name": "OpenStreetMap",
"url": "//{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png",
"options": {
"attribution": "<a href='https://www.openstreetmap.org/copyright' target='_blank'>© OpenStreetMap contributors</a>",
},
},
{
"name": "OpenTopoMap",
"url": "//a.tile.opentopomap.org/{z}/{x}/{y}.png",
"options": {
"attribution": "Map data: © <a href='https://www.openstreetmap.org/copyright' target='_blank'>OpenStreetMap contributors</a>, SRTM | Map style: © <a href='https://opentopomap.org' target='_blank'>OpenTopoMap</a> (<a href='https://creativecommons.org/licenses/by-sa/3.0/' target='_blank'>CC-BY-SA</a>)",
},
},
{
"name": "GoogleSatellite",
"layer": "//{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}",
"options": {
"subdomains": ["mt0", "mt1", "mt2", "mt3"],
"attribution": "© Google Maps",
},
},
]
[docs]
class MapConfig(Schema):
[docs]
BASEMAP = fields.List(fields.Dict(), load_default=BASEMAP)
[docs]
CENTER = fields.List(fields.Float, load_default=[46.52863469527167, 2.43896484375])
[docs]
ZOOM_LEVEL = fields.Integer(load_default=6)
[docs]
ZOOM_LEVEL_RELEVE = fields.Integer(load_default=15)
[docs]
GEOLOCATION = fields.Boolean(load_default=False)
# zoom appliqué sur la carte lorsque l'on clique sur une liste
# ne s'applique qu'aux points
[docs]
ZOOM_ON_CLICK = fields.Integer(load_default=18)
# Restreindre la recherche OpenStreetMap (sur la carte dans l'encart "Rechercher un lieu")
# à certains pays. Les pays doivent être au format ISO_3166-1 :
# https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 et séparés par une virgule.
# Exemple : OSM_RESTRICT_COUNTRY_CODES = "fr,es,be,ch" (Restreint à France, Espagne, Belgique
# et Suisse)
# Laisser à null pour n'avoir aucune restriction
[docs]
OSM_RESTRICT_COUNTRY_CODES = fields.String(load_default=None)
[docs]
REF_LAYERS = fields.List(
fields.Dict(),
load_default=[
{
"code": "limitesadministratives",
"label": "Limites administratives (IGN)",
"type": "wms",
"url": "https://data.geopf.fr/wms-r",
"activate": False,
"params": {
"service": "wms",
"version": "1.3.0",
"request": "GetMap",
"layers": "LIMITES_ADMINISTRATIVES_EXPRESS.LATEST",
"styles": "normal",
"format": "image/png",
"crs": "CRS:84",
"dpiMode": 7,
},
},
{
"code": "znieff1",
"label": "ZNIEFF1 (INPN)",
"type": "wms",
"url": "https://ws.carmencarto.fr/WMS/119/fxx_inpn",
"activate": False,
"params": {
"service": "wms",
"version": "1.3.0",
"request": "GetMap",
"layers": "znieff1",
"format": "image/png",
"crs": "EPSG:4326",
"opacity": 0.2,
"transparent": True,
},
},
],
)
[docs]
REF_LAYERS_LEGEND = fields.Boolean(load_default=False)
[docs]
class TaxHub(Schema):
[docs]
ID_TYPE_MAIN_PHOTO = fields.Integer(load_default=1)
# class a utiliser pour les paramètres que l'on veut passer au frontend
[docs]
class GnGeneralSchemaConf(Schema):
[docs]
appName = fields.String(load_default="GeoNature2")
[docs]
GEONATURE_VERSION = fields.String(load_default=GEONATURE_VERSION.strip())
[docs]
DEFAULT_LANGUAGE = fields.String(load_default="fr")
[docs]
PASS_METHOD = fields.String(load_default="hash", validate=OneOf(["hash", "md5"]))
[docs]
DEBUG = fields.Boolean(load_default=False)
[docs]
URL_APPLICATION = fields.Url(required=True)
[docs]
API_ENDPOINT = fields.Url(required=True)
[docs]
API_TAXHUB = fields.Url(required=True)
[docs]
CODE_APPLICATION = fields.String(load_default="GN")
[docs]
XML_NAMESPACE = fields.String(load_default="{http://inpn.mnhn.fr/mtd}")
[docs]
MTD_API_ENDPOINT = fields.Url(load_default="https://preprod-inpn.mnhn.fr/mtd")
[docs]
DISABLED_MODULES = fields.List(fields.String(), load_default=[])
[docs]
CAS_PUBLIC = fields.Nested(CasFrontend, load_default=CasFrontend().load({}))
[docs]
RIGHTS = fields.Nested(RightsSchemaConf, load_default=RightsSchemaConf().load({}))
[docs]
FRONTEND = fields.Nested(GnFrontEndConf, load_default=GnFrontEndConf().load({}))
[docs]
SYNTHESE = fields.Nested(Synthese, load_default=Synthese().load({}))
[docs]
MAPCONFIG = fields.Nested(MapConfig, load_default=MapConfig().load({}))
# Ajoute la surchouche 'taxonomique' sur l'API nomenclature
[docs]
ENABLE_NOMENCLATURE_TAXONOMIC_FILTERS = fields.Boolean(load_default=True)
[docs]
BDD = fields.Nested(BddConfig, load_default=BddConfig().load({}))
[docs]
URL_USERSHUB = fields.Url(required=False)
[docs]
ACCOUNT_MANAGEMENT = fields.Nested(AccountManagement, load_default=AccountManagement().load({}))
[docs]
STATIC_URL = fields.String(load_default="/static")
[docs]
MTD = fields.Nested(MTDSchemaConf, load_default=MTDSchemaConf().load({}))
[docs]
NB_MAX_DATA_SENSITIVITY_REPORT = fields.Integer(load_default=1000000)
[docs]
ADDITIONAL_FIELDS = fields.Nested(AdditionalFields, load_default=AdditionalFields().load({}))
[docs]
PUBLIC_ACCESS_USERNAME = fields.String(load_default="")
[docs]
TAXHUB = fields.Nested(TaxHub, load_default=TaxHub().load({}))
[docs]
HOME = fields.Nested(HomeConfig, load_default=HomeConfig().load({}))
[docs]
NOTIFICATIONS_ENABLED = fields.Boolean(load_default=True)
[docs]
PROFILES_REFRESH_CRONTAB = fields.String(load_default="0 3 * * *")
@validates_schema
[docs]
def validate_enable_sign_up(self, data, **kwargs):
# si CAS_PUBLIC = true and ENABLE_SIGN_UP = true
if data["CAS_PUBLIC"]["CAS_AUTHENTIFICATION"] and (
data["ACCOUNT_MANAGEMENT"]["ENABLE_SIGN_UP"]
or data["ACCOUNT_MANAGEMENT"]["ENABLE_USER_MANAGEMENT"]
):
raise ValidationError(
"CAS_PUBLIC et ENABLE_SIGN_UP ou ENABLE_USER_MANAGEMENT ne peuvent être activés ensemble",
"ENABLE_SIGN_UP, ENABLE_USER_MANAGEMENT",
)
@validates_schema
[docs]
def validate_account_autovalidation(self, data, **kwargs):
account_config = data["ACCOUNT_MANAGEMENT"]
if (
account_config["AUTO_ACCOUNT_CREATION"] is False
and account_config["VALIDATOR_EMAIL"] is None
):
raise ValidationError(
"Si AUTO_ACCOUNT_CREATION = False, veuillez remplir le paramètre VALIDATOR_EMAIL",
"AUTO_ACCOUNT_CREATION, VALIDATOR_EMAIL",
)
@post_load
[docs]
def insert_module_config(self, data, **kwargs):
for dist in iter_modules_dist():
module_code = dist.entry_points["code"].load()
if module_code in data["DISABLED_MODULES"]:
continue
data[module_code] = get_module_config(dist)
return data