canaille-globuzma/canaille/backends/__init__.py

125 lines
3.4 KiB
Python
Raw Normal View History

2023-04-09 21:00:13 +00:00
import importlib
import os
from contextlib import contextmanager
2023-04-09 21:00:13 +00:00
from flask import g
2023-06-05 16:10:37 +00:00
class BaseBackend:
instance = None
def __init__(self, config):
self.config = config
2023-06-05 16:10:37 +00:00
BaseBackend.instance = self
2023-04-09 21:00:13 +00:00
self.register_models()
@classmethod
def get(cls):
return cls.instance
2023-04-08 18:42:38 +00:00
def init_app(self, app):
@app.before_request
2023-04-08 18:42:38 +00:00
def before_request():
return self.setup()
2023-04-08 18:42:38 +00:00
@app.after_request
2023-04-08 18:42:38 +00:00
def after_request(response):
self.teardown()
2023-04-08 18:42:38 +00:00
return response
@contextmanager
def session(self, *args, **kwargs):
yield self.setup(*args, **kwargs)
self.teardown()
@classmethod
2023-12-27 09:57:22 +00:00
def install(self, config):
2023-12-28 17:31:57 +00:00
"""This methods prepares the database to host canaille data."""
raise NotImplementedError()
2023-04-08 18:42:38 +00:00
def setup(self):
2023-12-28 17:31:57 +00:00
"""This method will be called before each http request, it should open
the connection to the backend."""
2023-04-08 18:42:38 +00:00
def teardown(self):
2023-12-28 17:31:57 +00:00
"""This method will be called after each http request, it should close
the connections to the backend."""
2023-04-08 18:42:38 +00:00
@classmethod
def validate(cls, config):
2023-12-28 17:31:57 +00:00
"""This method should validate the config part dedicated to the
backend.
2023-04-08 18:42:38 +00:00
It should raise :class:`~canaille.configuration.ConfigurationError` when
errors are met.
"""
raise NotImplementedError()
2022-11-01 11:25:21 +00:00
def check_user_password(self, user, password: str) -> bool:
"""Checks if the password matches the user password in the database."""
raise NotImplementedError()
def set_user_password(self, user, password: str):
"""Sets a password for the user."""
raise NotImplementedError()
2022-11-01 11:25:21 +00:00
def has_account_lockability(self):
2023-12-28 17:31:57 +00:00
"""Indicates wether the backend supports locking user accounts."""
2022-11-01 11:25:21 +00:00
raise NotImplementedError()
2023-04-09 21:00:13 +00:00
def register_models(self):
from canaille.app import models
module = ".".join(self.__class__.__module__.split(".")[:-1] + ["models"])
try:
backend_models = importlib.import_module(module)
except ModuleNotFoundError:
return
model_names = [
"AuthorizationCode",
"Client",
"Consent",
"Group",
"Token",
"User",
]
for model_name in model_names:
models.register(getattr(backend_models, model_name))
2023-12-25 12:22:43 +00:00
def setup_backend(app, backend=None):
2023-04-09 21:00:13 +00:00
if not backend:
prefix = "CANAILLE_"
available_backends_names = [
f"{prefix}{name}".upper() for name in available_backends()
]
configured_backend_names = [
key[len(prefix) :]
for key in app.config.keys()
if key in available_backends_names
]
backend_name = (
configured_backend_names[0].lower()
if configured_backend_names
else "memory"
)
2023-04-09 21:00:13 +00:00
module = importlib.import_module(f"canaille.backends.{backend_name}.backend")
backend_class = getattr(module, "Backend")
backend = backend_class(app.config)
backend.init_app(app)
with app.app_context():
g.backend = backend
app.backend = backend
2023-12-25 12:22:43 +00:00
return backend
2023-04-09 21:00:13 +00:00
def available_backends():
return {
elt.name
for elt in os.scandir(os.path.dirname(__file__))
if elt.is_dir() and os.path.exists(os.path.join(elt, "backend.py"))
}