Skip to content

Commit

Permalink
Config in toml file (#517)
Browse files Browse the repository at this point in the history
Configuration is now moved in `config/taxhub_config.toml`. Include new parameter `API_PREFIX` for retro-compatibility for GeoNature-Atlas and Occtax-mobile. Include a marshmallow validation schema. 

---------

Co-authored-by: Jacques Fize <4259846+jacquesfize@users.noreply.github.com>
  • Loading branch information
amandine-sahl and jacquesfize committed Aug 6, 2024
1 parent 1985fb7 commit da6f9dd
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 26 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:
- master
- hotfixes
- develop
- flask-admin

jobs:
build:
Expand Down Expand Up @@ -89,17 +90,17 @@ jobs:
flask db autoupgrade
flask db status
env:
TAXHUB_SETTINGS: test_config.py
TAXHUB_CONFIG_FILE: config/test_config.toml
- name: Install taxref
run: |
flask taxref import-v17
env:
TAXHUB_SETTINGS: test_config.py
TAXHUB_CONFIG_FILE: config/test_config.toml
- name: Test with pytest
run: |
pytest -v --cov --cov-report xml
env:
TAXHUB_SETTINGS: test_config.py
TAXHUB_CONFIG_FILE: config/test_config.toml
- name: Upload coverage to Codecov
if: ${{ matrix.name == '11' && matrix.sqlalchemy-version == '1.4' }}
uses: codecov/codecov-action@v3
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,4 @@ target/

/docs/changelog.html

/apptax/*_config.py
config/*_config.toml
15 changes: 7 additions & 8 deletions apptax/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
taxhub_routes = [
("apptax.taxonomie.routesbibnoms:adresses", "/api/bibnoms"),
("apptax.taxonomie.routestaxref:adresses", "/api/taxref"),
("apptax.taxonomie.routesbibattributs:adresses", "/api/bibattributs"),
("apptax.taxonomie.routesbiblistes:adresses", "/api/biblistes"),
("apptax.taxonomie.routestmedias:adresses", "/api/tmedias"),
("apptax.taxonomie.routesbdcstatuts:adresses", "/api/bdc_statuts"),
("apptax.admin.admin:adresses", "/"),
taxhub_api_routes = [
("apptax.taxonomie.routesbibnoms:adresses", "/bibnoms"),
("apptax.taxonomie.routestaxref:adresses", "/taxref"),
("apptax.taxonomie.routesbibattributs:adresses", "/bibattributs"),
("apptax.taxonomie.routesbiblistes:adresses", "/biblistes"),
("apptax.taxonomie.routestmedias:adresses", "/tmedias"),
("apptax.taxonomie.routesbdcstatuts:adresses", "/bdc_statuts"),
]
22 changes: 15 additions & 7 deletions apptax/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
from pypnusershub.login_manager import login_manager

from apptax.admin.admin import taxhub_admin, taxhub_admin_addview
from apptax.utils.config.utilstoml import load_and_validate_toml
from apptax.utils.config.config_schema import TaxhubSchemaConf

migrate = Migrate()

Expand Down Expand Up @@ -43,7 +45,10 @@ def configure_alembic(alembic_config):
def create_app():
app = Flask(__name__, static_folder=os.environ.get("TAXHUB_STATIC_FOLDER", "static"))

app.config.from_pyfile(os.environ.get("TAXHUB_SETTINGS", "config.py"))
DEFAULT_CONFIG_FILE = Path(__file__).absolute().parent.parent / "config/taxhub_config.toml"
CONFIG_FILE = os.environ.get("TAXHUB_CONFIG_FILE", DEFAULT_CONFIG_FILE)
config = load_and_validate_toml(CONFIG_FILE, TaxhubSchemaConf)
app.config.update(config)
app.config.from_prefixed_env(prefix="TAXHUB")

media_path = Path(app.config["MEDIA_FOLDER"], "taxhub").absolute()
Expand All @@ -66,9 +71,6 @@ def create_app():

app.config["DB"] = db

if "CODE_APPLICATION" not in app.config:
app.config["CODE_APPLICATION"] = "TH"

@app.before_request
def load_current_user():
g.current_user = current_user if current_user.is_authenticated else None
Expand All @@ -83,20 +85,26 @@ def favicon():
mimetype="image/vnd.microsoft.icon",
)

# UserHub
from pypnusershub import routes

app.register_blueprint(routes.routes, url_prefix="/api/auth")

# Flask admin
taxhub_admin.init_app(app)
taxhub_admin_addview(app, taxhub_admin)
from apptax.admin.admin import adresses

app.register_blueprint(adresses, url_prefix="/")

# API
from apptax import taxhub_routes
from apptax import taxhub_api_routes

base_api_prefix = app.config["API"].get("API_PREFIX")

for blueprint_path, url_prefix in taxhub_routes:
for blueprint_path, url_prefix in taxhub_api_routes:
module_name, blueprint_name = blueprint_path.split(":")
blueprint = getattr(import_module(module_name), blueprint_name)
app.register_blueprint(blueprint, url_prefix=url_prefix)
app.register_blueprint(blueprint, url_prefix=base_api_prefix + url_prefix)

return app
Empty file added apptax/utils/config/__init__.py
Empty file.
40 changes: 40 additions & 0 deletions apptax/utils/config/config_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""
Description des options de configuration
"""

from marshmallow import Schema, fields, validates_schema, ValidationError, post_load, pre_load
from marshmallow.validate import OneOf, Regexp, Email, Length


class TaxhubApiConf(Schema):
API_PREFIX = fields.String(
load_default="",
validate=Regexp(
r"(^\/(.+)$)|(^\s*$)",
error="API_PREFIX must start with a slash.",
),
)


class TaxhubSchemaConf(Schema):
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",
),
)
SQLALCHEMY_TRACK_MODIFICATIONS = fields.Boolean(load_default=True)
SESSION_TYPE = fields.String(load_default="filesystem")
SECRET_KEY = fields.String(required=True, validate=Length(min=20))
CODE_APPLICATION = fields.String(load_default="TH")
# le cookie expire toute les 7 jours par défaut
COOKIE_EXPIRATION = fields.Integer(load_default=3600 * 24 * 7)
COOKIE_AUTORENEW = fields.Boolean(load_default=True)
TRAP_ALL_EXCEPTIONS = fields.Boolean(load_default=False)
APPLICATION_ROOT = fields.String(load_default="/")
MEDIA_FOLDER = fields.String(load_default="media")
PASS_METHOD = fields.String(load_default="hash")
FLASK_ADMIN_SWATCH = fields.String(load_default="cerulean")
FLASK_ADMIN_FLUID_LAYOUT = fields.Boolean(load_default=True)
API = fields.Nested(TaxhubApiConf, load_default=TaxhubApiConf().load({}))
48 changes: 48 additions & 0 deletions apptax/utils/config/utilstoml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from pathlib import Path

import toml
from marshmallow import EXCLUDE
from marshmallow.exceptions import ValidationError


class ConfigError(Exception):
"""
Configuration error class
Quand un fichier de configuration n'est pas conforme aux attentes
"""

def __init__(self, file, value):
self.value = value
self.file = file

def __str__(self):
msg = "Error in the config file '{}'. Fix the following:\n"
msg = msg.format(self.file)
for key, errors in self.value.items():
msg += "\n\t{}:\n\t\t- {}".format(key, errors)
return msg


def load_and_validate_toml(toml_file, config_schema, partial=None):
"""
Fonction qui charge un fichier toml
et le valide avec un Schema marshmallow
"""
if toml_file:
toml_config = load_toml(toml_file)
else:
toml_config = {}
try:
configs_py = config_schema().load(toml_config, unknown=EXCLUDE, partial=partial)
except ValidationError as e:
raise ConfigError(toml_file, e.messages)
return configs_py


def load_toml(toml_file):
"""
Fonction qui charge un fichier toml
"""
if not Path(toml_file).is_file():
raise Exception("Missing file {}".format(toml_file))
return toml.load(str(toml_file))
14 changes: 14 additions & 0 deletions config/taxhub_config.toml.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

#############################################
# Taxhub backend global configuration file
#############################################

# Database
SQLALCHEMY_DATABASE_URI = "postgresql://monuser:monpassachanger@localhost:5432/mabase"

# Remplacer par une clé alétoire complexe
SECRET_KEY = 'super secret key'

# Configuration liée à l'api de taxhub
[API]
API_PREFIX = "/api"
3 changes: 0 additions & 3 deletions apptax/test_config.py → config/test_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,3 @@

SECRET_KEY = 'a7e0a755dd3f2c382bac5b5cea6c9329802aeedf39e3f10d0462ffb52c3f5e99'

COOKIE_EXPIRATION = 3600

MEDIA_FOLDER = 'medias'
2 changes: 1 addition & 1 deletion docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
- Changement dans les permissions : seuls les profils 2 et 6 sont utilisés. Il faut un profil 2 pour ajouter des attributs / medias et ajouter des taxons à des listes. Il faut un profil 6 pour pouvoir créer des listes / thêmes / type d'attributs.
- Le paramètre `UPLOAD_FOLDER` devient `MEDIA_FOLDER`. Veillez à le remplacer dans le fichier `config.py`. Si vous utilisez TaxHub avec GeoNature, ce paramètre existe déjà et est par défaut à `<GEONATURE_DIR>/backend/medias`.


- La configuration est maintenant gérée dans le fichier `config/taxhub_config.toml` (#517)

1.14.1 (2024-05-23)
===================
Expand Down
3 changes: 2 additions & 1 deletion requirements-common.in
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ psycopg2
python-dotenv
Pillow<10.0.0
urllib3
click>=8.1.3
click>=8.1.3
toml
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ werkzeug==3.0.3
zipp==3.18.2
# via importlib-metadata



Flask-Admin==1.6.0
WTForms==3.0.1
# via flask-admin

toml==0.10.2

0 comments on commit da6f9dd

Please sign in to comment.