Skip to content
Snippets Groups Projects
factory.py 5.67 KiB
Newer Older
Benjamin Bertrand's avatar
Benjamin Bertrand committed
# -*- coding: utf-8 -*-
"""
app.factory
~~~~~~~~~~~

Create the WSGI application.

:copyright: (c) 2017 European Spallation Source ERIC
:license: BSD 2-Clause, see LICENSE for more details.

"""
import sqlalchemy as sa
import rq_dashboard
Benjamin Bertrand's avatar
Benjamin Bertrand committed
from flask import Flask
from whitenoise import WhiteNoise
Benjamin Bertrand's avatar
Benjamin Bertrand committed
from . import settings, models
Benjamin Bertrand's avatar
Benjamin Bertrand committed
from .extensions import (
    db,
    migrate,
    login_manager,
    ldap_manager,
    bootstrap,
    admin,
    mail,
    jwt,
    toolbar,
    session_redis_store,
    fsession,
    cache,
)
from .admin.views import (
    AdminModelView,
    ItemAdmin,
    UserAdmin,
    TokenAdmin,
    NetworkAdmin,
    TaskAdmin,
)
from .main.views import bp as main
Benjamin Bertrand's avatar
Benjamin Bertrand committed
from .inventory.views import bp as inventory
from .network.views import bp as network
Benjamin Bertrand's avatar
Benjamin Bertrand committed
from .task.views import bp as task
from .user.views import bp as user
from .api.user import bp as user_api
Benjamin Bertrand's avatar
Benjamin Bertrand committed
from .api.inventory import bp as inventory_api
from .api.network import bp as network_api
from .commands import register_cli
from . import utils
def create_app(config=None):
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    app = Flask(__name__)

    app.config.from_object(rq_dashboard.default_settings)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    app.config.from_object(settings)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    app.config.from_envvar("LOCAL_SETTINGS", silent=True)
    app.config.update(config or {})
Benjamin Bertrand's avatar
Benjamin Bertrand committed

Benjamin Bertrand's avatar
Benjamin Bertrand committed
    app.jinja_env.filters["datetimeformat"] = utils.format_datetime
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    if not app.debug:
        import logging
Benjamin Bertrand's avatar
Benjamin Bertrand committed
        # Send ERROR via mail
        from logging.handlers import SMTPHandler
Benjamin Bertrand's avatar
Benjamin Bertrand committed

        mail_handler = SMTPHandler(
            app.config["MAIL_SERVER"],
            fromaddr=app.config["EMAIL_SENDER"],
            toaddrs=app.config["ADMIN_EMAILS"],
            subject="CSEntry: ERROR raised",
            credentials=app.config["MAIL_CREDENTIALS"],
        )
        mail_handler.setFormatter(
            logging.Formatter(
                """
Benjamin Bertrand's avatar
Benjamin Bertrand committed
            Message type:       %(levelname)s
            Location:           %(pathname)s:%(lineno)d
            Module:             %(module)s
            Function:           %(funcName)s
            Time:               %(asctime)s

            Message:

            %(message)s
Benjamin Bertrand's avatar
Benjamin Bertrand committed
        mail_handler.setLevel(logging.ERROR)
        app.logger.addHandler(mail_handler)
        # Log to stderr
        handler = logging.StreamHandler()
Benjamin Bertrand's avatar
Benjamin Bertrand committed
        handler.setFormatter(
            logging.Formatter(
                "%(asctime)s %(levelname)s: %(message)s " "[in %(pathname)s:%(lineno)d]"
            )
        )
Benjamin Bertrand's avatar
Benjamin Bertrand committed
        # Set app logger level to DEBUG
        # otherwise only WARNING and above are propagated
        app.logger.setLevel(logging.DEBUG)
        handler.setLevel(logging.DEBUG)
        app.logger.addHandler(handler)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    app.logger.info("CSEntry created!")
    # Remove variables that contain a password
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    settings_to_display = [
        f"{key}: {value}"
        for key, value in app.config.items()
        if key
        not in (
            "SECRET_KEY",
            "LDAP_BIND_USER_PASSWORD",
            "MAIL_CREDENTIALS",
            "SQLALCHEMY_DATABASE_URI",
        )
    ]
    # The repr() of make_url hides the password
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    settings_to_display.append(
        f'SQLALCHEMY_DATABASE_URI: {sa.engine.url.make_url(app.config["SQLALCHEMY_DATABASE_URI"])!r}'
    )
    settings_string = "\n".join(settings_to_display)
    app.logger.info(f"Settings:\n{settings_string}")
Benjamin Bertrand's avatar
Benjamin Bertrand committed

    bootstrap.init_app(app)
    db.init_app(app)
    migrate.init_app(app)
    login_manager.init_app(app)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    login_manager.login_view = "user.login"
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    ldap_manager.init_app(app)
    mail.init_app(app)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    jwt.init_app(app)
    toolbar.init_app(app)
    session_redis_store.init_app(app)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    app.config["SESSION_REDIS"] = session_redis_store
    fsession.init_app(app)
    cache.init_app(app)
Benjamin Bertrand's avatar
Benjamin Bertrand committed

    admin.init_app(app)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    admin.add_view(UserAdmin(models.User, db.session, endpoint="users"))
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    admin.add_view(TokenAdmin(models.Token, db.session))
    admin.add_view(AdminModelView(models.Action, db.session))
    admin.add_view(AdminModelView(models.Manufacturer, db.session))
    admin.add_view(AdminModelView(models.Model, db.session))
    admin.add_view(AdminModelView(models.Location, db.session))
    admin.add_view(AdminModelView(models.Status, db.session))
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    admin.add_view(ItemAdmin(models.Item, db.session))
    admin.add_view(AdminModelView(models.ItemComment, db.session))
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    admin.add_view(AdminModelView(models.Domain, db.session))
    admin.add_view(AdminModelView(models.NetworkScope, db.session))
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    admin.add_view(NetworkAdmin(models.Network, db.session, endpoint="networks"))
    admin.add_view(AdminModelView(models.DeviceType, db.session))
    admin.add_view(AdminModelView(models.Host, db.session))
    admin.add_view(AdminModelView(models.Interface, db.session))
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    admin.add_view(AdminModelView(models.Mac, db.session))
    admin.add_view(AdminModelView(models.Cname, db.session))
    admin.add_view(AdminModelView(models.Tag, db.session))
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    admin.add_view(TaskAdmin(models.Task, db.session, endpoint="tasks"))
Benjamin Bertrand's avatar
Benjamin Bertrand committed

    app.register_blueprint(main)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    app.register_blueprint(inventory, url_prefix="/inventory")
    app.register_blueprint(network, url_prefix="/network")
    app.register_blueprint(task, url_prefix="/task")
    app.register_blueprint(user, url_prefix="/user")
    app.register_blueprint(user_api, url_prefix="/api/v1/user")
    app.register_blueprint(inventory_api, url_prefix="/api/v1/inventory")
    app.register_blueprint(network_api, url_prefix="/api/v1/network")
    app.register_blueprint(rq_dashboard.blueprint, url_prefix="/rq")

    app.wsgi_app = WhiteNoise(app.wsgi_app, root="static/")
    app.wsgi_app.add_files(
Benjamin Bertrand's avatar
Benjamin Bertrand committed
        root="/opt/conda/envs/csentry/lib/python3.6/site-packages/flask_bootstrap/static/",
        prefix="bootstrap/",
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    register_cli(app)

    return app