import logging import os from logging.config import dictConfig from flask_api import FlaskAPI from flask_cors import CORS from flask_marshmallow import Marshmallow from flask_migrate import Migrate from flask_security import Security from sqlalchemy import create_engine from sqlalchemy_utils import create_database from sqlalchemy_utils import database_exists from . import access from . import command_execution from . import database from . import error from . import models from .container import get_initialize_container from .endpoints import admin from .endpoints import command from .endpoints import login from .endpoints import logout __title__ = "monsun_backend" __author__ = "Andreas Berthoud, Fabian Klein" __version__ = "0.0.0" __email__ = "andreasberthoud@gmail.com" __copyright__ = f"2021 {__author__}" os.environ.update( { "DATABASE_URI": "postgresql+psycopg2://" "{dbuser}:{dbpass}@{dbhost}/{dbname}{sslmode}".format( dbuser=os.getenv("POSTGRES_USER", "usr"), dbpass=os.getenv("POSTGRES_PASSWORD", "pass"), dbhost=os.getenv("POSTGRES_HOST", "localhost"), dbname=os.getenv("POSTGRES_DB_NAME", "monsun_backend"), sslmode="?sslmode=require" if os.getenv("ENABLE_SSL") is not None else "", ), }, ) migrate = Migrate() def create_app() -> FlaskAPI: app = FlaskAPI(__name__) container_ = get_initialize_container() app.register_blueprint(command.bp) app.register_blueprint(login.bp) app.register_blueprint(logout.bp) app.register_blueprint(admin.bp) # somehow the 'flask db upgrade' does not create the DB as promised... # so let's do it here instead engine = create_engine(os.getenv("DATABASE_URI")) if not database_exists(engine.url): create_database(engine.url) dictConfig( { "version": 1, "disable_existing_loggers": False, "formatters": { "default": { "format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s", }, }, "handlers": { "console": { "class": "logging.StreamHandler", "formatter": "default", "stream": "ext://sys.stdout", }, }, "root": {"level": "NOTSET", "handlers": ["console"]}, "logger": { "monsun_backend": { "level": "DEBUG", "propagate": "no", }, }, }, ) logger = logging.getLogger("monsun_backend.init") _exception_logger = logging.getLogger("monsun_backend.exception") if os.getenv("MONSUN_DEBUG"): logger.debug("=== MONSUN DEBUG MODE ===") CORS( app, origins=["http://localhost:4200"], supports_credentials=True, ) app.config.update( SECRET_KEY=os.getenv("SECRET"), SQLALCHEMY_TRACK_MODIFICATIONS=False, SQLALCHEMY_DATABASE_URI=os.getenv("DATABASE_URI"), SESSION_COOKIE_SECURE=container_.config.session_cookie_secure(required=True), SESSION_COOKIE_HTTPONLY=container_.config.session_cookie_httponly( required=True, ), SESSION_COOKIE_SAMESITE=container_.config.session_cookie_samesite( required=True, ), ) logger.info(f"DATABASE_URI: {os.getenv('DATABASE_URI')}") database.db.init_app(app) migrate.init_app(app, database.db) Marshmallow(app) Security(app=app, datastore=models.user_datastore) access.init_app(app) # register error handler @app.errorhandler(error.MonsunError) def monsun_error_handler(e: error.MonsunError): if 500 > e.status_code >= 400: _exception_logger.info(f"Exception raised ({e.status_code}): {e.data}") if e.status_code >= 500: _exception_logger.error(f"Exception raised ({e.status_code}): {e.data}") return e.response if os.environ.get("WERKZEUG_RUN_MAIN") != "true": # prevent from be called twice in debug mode command_execution.start_backgroup_process() return app