2021-07-01 09:04:57 +00:00
|
|
|
import datetime
|
2024-03-29 18:31:01 +00:00
|
|
|
import sys
|
2020-08-17 13:49:48 +00:00
|
|
|
|
2021-12-20 22:57:27 +00:00
|
|
|
from flask import Flask
|
|
|
|
from flask import session
|
2023-03-28 18:30:29 +00:00
|
|
|
from flask_wtf.csrf import CSRFProtect
|
2020-09-01 15:11:30 +00:00
|
|
|
|
2023-03-28 18:30:29 +00:00
|
|
|
csrf = CSRFProtect()
|
2020-08-17 13:49:48 +00:00
|
|
|
|
|
|
|
|
2022-11-20 21:34:05 +00:00
|
|
|
def setup_sentry(app): # pragma: no cover
|
2023-12-18 17:06:03 +00:00
|
|
|
if not app.config["CANAILLE"]["SENTRY_DSN"]:
|
2022-01-11 17:02:23 +00:00
|
|
|
return None
|
|
|
|
|
2022-11-20 21:34:05 +00:00
|
|
|
try:
|
2022-01-11 17:02:23 +00:00
|
|
|
import sentry_sdk
|
|
|
|
from sentry_sdk.integrations.flask import FlaskIntegration
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
return None
|
|
|
|
|
2023-12-18 17:06:03 +00:00
|
|
|
sentry_sdk.init(
|
|
|
|
dsn=app.config["CANAILLE"]["SENTRY_DSN"], integrations=[FlaskIntegration()]
|
|
|
|
)
|
2022-01-11 17:02:23 +00:00
|
|
|
return sentry_sdk
|
|
|
|
|
|
|
|
|
2021-12-08 15:10:01 +00:00
|
|
|
def setup_blueprints(app):
|
2023-12-25 23:23:47 +00:00
|
|
|
import canaille.core.endpoints
|
2022-01-05 15:30:46 +00:00
|
|
|
|
2021-12-08 15:10:01 +00:00
|
|
|
app.url_map.strict_slashes = False
|
|
|
|
|
2023-12-25 23:23:47 +00:00
|
|
|
app.register_blueprint(canaille.core.endpoints.bp)
|
2023-09-15 15:24:05 +00:00
|
|
|
|
2024-12-05 11:20:26 +00:00
|
|
|
if app.features.has_oidc:
|
2023-12-25 23:23:47 +00:00
|
|
|
import canaille.oidc.endpoints
|
2023-09-15 15:24:05 +00:00
|
|
|
|
2023-12-25 23:23:47 +00:00
|
|
|
app.register_blueprint(canaille.oidc.endpoints.bp)
|
2020-09-27 15:32:23 +00:00
|
|
|
|
2024-12-22 11:25:47 +00:00
|
|
|
if app.features.has_scim_server:
|
2024-11-25 16:47:31 +00:00
|
|
|
import canaille.scim.endpoints
|
|
|
|
|
|
|
|
app.register_blueprint(canaille.scim.endpoints.bp)
|
|
|
|
|
2020-09-27 15:32:23 +00:00
|
|
|
|
2023-03-28 18:30:29 +00:00
|
|
|
def setup_flask(app):
|
2024-12-22 14:58:45 +00:00
|
|
|
from canaille.app.templating import render_template
|
2024-12-22 10:42:47 +00:00
|
|
|
|
2023-03-28 18:30:29 +00:00
|
|
|
csrf.init_app(app)
|
|
|
|
|
|
|
|
@app.before_request
|
|
|
|
def make_session_permanent():
|
|
|
|
session.permanent = True
|
|
|
|
app.permanent_session_lifetime = datetime.timedelta(days=365)
|
|
|
|
|
2024-12-22 10:42:47 +00:00
|
|
|
@app.errorhandler(400)
|
|
|
|
def bad_request(error):
|
|
|
|
return render_template("error.html", description=error, error_code=400), 400
|
|
|
|
|
|
|
|
@app.errorhandler(403)
|
|
|
|
def unauthorized(error):
|
|
|
|
return render_template("error.html", description=error, error_code=403), 403
|
|
|
|
|
|
|
|
@app.errorhandler(404)
|
|
|
|
def page_not_found(error):
|
|
|
|
from canaille.app.flask import redirect_to_bp_handlers
|
|
|
|
|
|
|
|
return redirect_to_bp_handlers(app, error) or render_template(
|
|
|
|
"error.html", description=error, error_code=404
|
|
|
|
), 404
|
|
|
|
|
|
|
|
@app.errorhandler(500)
|
|
|
|
def server_error(error): # pragma: no cover
|
|
|
|
return render_template("error.html", description=error, error_code=500), 500
|
|
|
|
|
2023-03-28 18:30:29 +00:00
|
|
|
|
2023-06-28 15:56:49 +00:00
|
|
|
def setup_flask_converters(app):
|
|
|
|
from canaille.app import models
|
2024-03-15 18:58:06 +00:00
|
|
|
from canaille.app.flask import model_converter
|
2023-06-28 15:56:49 +00:00
|
|
|
|
2023-04-09 21:00:13 +00:00
|
|
|
for model_name, model_class in models.MODELS.items():
|
|
|
|
app.url_map.converters[model_name.lower()] = model_converter(model_class)
|
2023-06-28 15:56:49 +00:00
|
|
|
|
|
|
|
|
2024-12-12 21:02:46 +00:00
|
|
|
def create_app(
|
|
|
|
config: dict = None,
|
|
|
|
validate: bool = True,
|
|
|
|
backend=None,
|
2025-01-09 17:16:27 +00:00
|
|
|
init_backend=None,
|
2024-12-12 21:02:46 +00:00
|
|
|
env_file: str = None,
|
|
|
|
env_prefix: str = "",
|
|
|
|
):
|
|
|
|
"""Application entry point.
|
|
|
|
|
|
|
|
:param config: A configuration dict. This will take priority over any other configuration method.
|
|
|
|
:param validate: Whether to validate or not the configuration.
|
|
|
|
:param backend: An optional backend to force. If unset backend will be initialized according to the configuration.
|
|
|
|
:param env_file: The path to an environment var file in which configuration can be loaded.
|
|
|
|
:param env_prefix: The prefix to configuration environment vars.
|
|
|
|
"""
|
2023-06-15 16:29:12 +00:00
|
|
|
from .app.configuration import setup_config
|
2024-05-14 20:53:47 +00:00
|
|
|
from .app.features import setup_features
|
2024-03-15 18:58:06 +00:00
|
|
|
from .app.i18n import setup_i18n
|
2024-10-27 12:54:14 +00:00
|
|
|
from .app.logging import setup_logging
|
2024-12-22 14:58:45 +00:00
|
|
|
from .app.templating import setup_jinja
|
|
|
|
from .app.templating import setup_themer
|
2023-04-09 21:00:13 +00:00
|
|
|
from .backends import setup_backend
|
2023-06-15 16:29:12 +00:00
|
|
|
|
2021-12-08 15:10:01 +00:00
|
|
|
app = Flask(__name__)
|
2023-07-10 16:45:54 +00:00
|
|
|
with app.app_context():
|
2024-04-22 16:10:49 +00:00
|
|
|
if not setup_config(
|
|
|
|
app=app,
|
|
|
|
config=config,
|
|
|
|
test_config=validate,
|
|
|
|
env_file=env_file,
|
|
|
|
env_prefix=env_prefix,
|
|
|
|
): # pragma: no cover
|
2024-03-29 18:31:01 +00:00
|
|
|
sys.exit(1)
|
2021-12-08 15:10:01 +00:00
|
|
|
|
2022-01-11 17:02:23 +00:00
|
|
|
sentry_sdk = setup_sentry(app)
|
2021-12-08 15:10:01 +00:00
|
|
|
try:
|
|
|
|
setup_logging(app)
|
2025-01-09 17:16:27 +00:00
|
|
|
backend = setup_backend(app, backend, init_backend)
|
2024-05-14 20:53:47 +00:00
|
|
|
setup_features(app)
|
2023-06-28 15:56:49 +00:00
|
|
|
setup_flask_converters(app)
|
2021-12-08 15:10:01 +00:00
|
|
|
setup_blueprints(app)
|
2021-12-08 17:06:50 +00:00
|
|
|
setup_jinja(app)
|
2022-11-20 21:12:18 +00:00
|
|
|
setup_i18n(app)
|
2021-12-08 15:10:01 +00:00
|
|
|
setup_themer(app)
|
2023-03-28 18:30:29 +00:00
|
|
|
setup_flask(app)
|
2020-09-27 15:32:23 +00:00
|
|
|
|
2024-12-05 11:20:26 +00:00
|
|
|
if app.features.has_oidc:
|
2023-09-15 15:24:05 +00:00
|
|
|
from .oidc.oauth import setup_oauth
|
|
|
|
|
|
|
|
setup_oauth(app)
|
|
|
|
|
2022-11-20 21:34:05 +00:00
|
|
|
except Exception as exc: # pragma: no cover
|
2022-01-11 17:02:23 +00:00
|
|
|
if sentry_sdk:
|
2020-09-29 16:21:41 +00:00
|
|
|
sentry_sdk.capture_exception(exc)
|
|
|
|
raise
|
2021-12-06 20:49:38 +00:00
|
|
|
|
|
|
|
return app
|