Skip to content
Snippets Groups Projects
factory.py 4.47 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
from flask import Flask
from whitenoise import WhiteNoise
Benjamin Bertrand's avatar
Benjamin Bertrand committed
from . import settings, models
from .extensions import db, migrate, login_manager, ldap_manager, bootstrap, admin, mail, jwt, toolbar
Benjamin Bertrand's avatar
Benjamin Bertrand committed
from .admin.views import (AdminModelView, ItemAdmin, UserAdmin, GroupAdmin, TokenAdmin,
                          NetworkAdmin)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
from .inventory.views import bp as inventory
from .networks.views import bp as networks
Benjamin Bertrand's avatar
Benjamin Bertrand committed
from .users.views import bp as users
from .api.main import bp as api
Benjamin Bertrand's avatar
Benjamin Bertrand committed
from .defaults import defaults


def register_cli(app):
    @app.cli.command()
    def initdb():
        """Create the database tables and initialize them with default values"""
        db.engine.execute('CREATE EXTENSION IF NOT EXISTS citext')
Benjamin Bertrand's avatar
Benjamin Bertrand committed
        db.create_all()
        for instance in defaults:
            db.session.add(instance)
            try:
                db.session.commit()
            except sa.exc.IntegrityError as e:
                db.session.rollback()
                app.logger.debug(f'{instance} already exists')


def create_app(config=None):
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    app = Flask(__name__)

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

    if not app.debug:
        import logging
        # Send ERROR via mail
        from logging.handlers import SMTPHandler
        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'])
Benjamin Bertrand's avatar
Benjamin Bertrand committed
        mail_handler.setFormatter(logging.Formatter("""
            Message type:       %(levelname)s
            Location:           %(pathname)s:%(lineno)d
            Module:             %(module)s
            Function:           %(funcName)s
            Time:               %(asctime)s

            Message:

            %(message)s
        """))
        mail_handler.setLevel(logging.ERROR)
        app.logger.addHandler(mail_handler)
        # Log to stderr
        handler = logging.StreamHandler()
        handler.setFormatter(logging.Formatter(
            '%(asctime)s %(levelname)s: %(message)s '
            '[in %(pathname)s:%(lineno)d]'
        ))
        # 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)
    app.logger.info('CSEntry created!')
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    app.logger.info('Settings:\n{}'.format(
        '\n'.join(['{}: {}'.format(key, value) for key, value in app.config.items()
                   if key not in ('SECRET_KEY', 'LDAP_BIND_USER_PASSWORD')])))

    bootstrap.init_app(app)
    db.init_app(app)
    migrate.init_app(app)
    login_manager.init_app(app)
    login_manager.login_view = 'users.login'
    ldap_manager.init_app(app)
    mail.init_app(app)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    jwt.init_app(app)
    toolbar.init_app(app)
Benjamin Bertrand's avatar
Benjamin Bertrand committed

    admin.init_app(app)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    admin.add_view(GroupAdmin(models.Group, db.session))
    admin.add_view(UserAdmin(models.User, db.session))
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.NetworkScope, db.session))
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    admin.add_view(NetworkAdmin(models.Network, 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))
Benjamin Bertrand's avatar
Benjamin Bertrand committed

Benjamin Bertrand's avatar
Benjamin Bertrand committed
    app.register_blueprint(inventory)
    app.register_blueprint(networks)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    app.register_blueprint(users)
Benjamin Bertrand's avatar
Benjamin Bertrand committed
    app.register_blueprint(api, url_prefix='/api')
Benjamin Bertrand's avatar
Benjamin Bertrand committed

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

    return app