""" automatically invoked app factory """ import logging import os import pkg_resources import sentry_sdk from sentry_sdk.integrations.flask import FlaskIntegration from flask import Flask from flask_cors import CORS # for debugging # the currently available stubs for flask_migrate are old (they depend on sqlalchemy 1.4 types) from flask_migrate import Migrate, upgrade # type: ignore from flask_login import LoginManager # type: ignore from compendium_v2 import config, environment from compendium_v2.db import db from compendium_v2.auth import setup_oauth from compendium_v2.auth.session_management import setup_login_manager sentry_dsn = os.getenv('SENTRY_DSN') if sentry_dsn: sentry_sdk.init( dsn=sentry_dsn, integrations=[FlaskIntegration()], release=pkg_resources.get_distribution('compendium-v2').version) environment.setup_logging() logger = logging.getLogger(__name__) def _create_app() -> Flask: # used by sphinx to create documentation without config and db migrations app = Flask(__name__) CORS(app) from compendium_v2.routes import default app.register_blueprint(default.routes, url_prefix='/') from compendium_v2.routes import authentication app.register_blueprint(authentication.routes, url_prefix='/') from compendium_v2.routes import api app.register_blueprint(api.routes, url_prefix='/api') return app def _create_app_with_db(app_config) -> Flask: # used by the tests and the publishers app = _create_app() app.config['SECRET_KEY'] = app_config['SECRET_KEY'] app.config['SESSION_COOKIE_SECURE'] = True if 'oidc' not in app_config: app.config['LOGIN_DISABLED'] = True logger.info('No OIDC configuration found, authentication disabled') else: logger.info('OIDC configuration found, authentication will be enabled') app.config['SQLALCHEMY_DATABASE_URI'] = app_config['SQLALCHEMY_DATABASE_URI'] if 'SQLALCHEMY_BINDS' in app_config: # for the publishers app.config['SQLALCHEMY_BINDS'] = app_config['SQLALCHEMY_BINDS'] if 'mail' in app_config: mail_config = app_config['mail'] app.config['MAIL_ENABLE'] = True app.config['MAIL_SERVER'] = mail_config['MAIL_SERVER'] app.config['MAIL_PORT'] = mail_config['MAIL_PORT'] app.config['MAIL_SENDER_EMAIL'] = mail_config['MAIL_SENDER_EMAIL'] # email address to send emails from excluded_admins = mail_config.get('MAIL_EXCLUDED_ADMINS', []) app.config['MAIL_EXCLUDED_ADMINS'] = excluded_admins # list of admin emails not to send emails to else: app.config['MAIL_ENABLE'] = False db.init_app(app) return app def create_app() -> Flask: """ overrides default settings with those found in the file read from env var SETTINGS_FILENAME :return: a new flask app instance """ assert 'SETTINGS_FILENAME' in os.environ, "environment variable 'SETTINGS_FILENAME' is required" with open(os.environ['SETTINGS_FILENAME']) as f: app_config = config.load(f) app = _create_app_with_db(app_config) Migrate(app, db, directory=os.path.join(os.path.dirname(__file__), 'migrations')) logging.info('Flask app initialized') login_manager = LoginManager() login_manager.init_app(app) login_manager.login_view = 'authentication.login' setup_login_manager(login_manager) setup_oauth(app, app_config.get('oidc')) # run migrations on startup with app.app_context(): upgrade() return app