__init__.py 3.63 KB
#! ../venv/bin/python
import os

from dotenv import load_dotenv, find_dotenv, dotenv_values
from markdown import markdown

# Load config from .env ; do this before importing local libs (and flask)
# 1. Write into OS environment -- if this fails you forgot to create .env file
load_dotenv(find_dotenv(raise_error_if_not_found=True), override=True)
# 2. Load it as well to inject it later into app.config
local_env = dotenv_values(find_dotenv())
# 3. Cast integers to integers
for key in local_env.keys():
    try:
        local_env[key] = int(local_env[key])
    except ValueError:
        pass


from flask import Flask, url_for
from flask.cli import ScriptInfo
from webassets.loaders import PythonLoader as PythonAssetsLoader


from flaskr import assets
from flaskr.models import db, Estimation, EstimationView
from flaskr.controllers.main_controller import main
from flaskr.extensions import (
    admin,
    assets_env,
    basic_auth,
    cache,
    debug_toolbar,
    login_manager,
    mail,
    session,
    captcha,
    icon2html,
)
from flaskr.content import content
from flaskr.core import increment_hit_counter, get_hit_counter


def create_app(object_name):
    """
    A flask application factory, as explained here:
    http://flask.pocoo.org/docs/patterns/appfactories/

    Arguments:
        object_name: the python path of the config object,
                     e.g. flaskr.settings.ProductionConfig
    """

    app = Flask(__name__)

    # We bypass object_name (for dev with flask run)
    if type(object_name) == ScriptInfo:
        object_name = 'flaskr.settings.DevelopmentConfig'

    # Load the configuration
    app.config.from_object(object_name)
    app.config.update(**local_env)

    app.config['BASIC_AUTH_USERNAME'] = os.getenv('ADMIN_USERNAME')
    app.config['BASIC_AUTH_PASSWORD'] = os.getenv('ADMIN_PASSWORD')

    app.config['CAPTCHA_ENABLE'] = False
    app.config['CAPTCHA_LENGTH'] = 5
    app.config['CAPTCHA_WIDTH'] = 256
    app.config['CAPTCHA_HEIGHT'] = 158
    app.config['SESSION_TYPE'] = 'sqlalchemy'

    # Initialize
    cache.init_app(app)
    session.init_app(app)
    captcha.init_app(app)
    mail.init_app(app)
    debug_toolbar.init_app(app)
    db.init_app(app)
    login_manager.init_app(app)
    admin.init_app(app)
    admin.add_view(EstimationView(Estimation, db.session))
    basic_auth.init_app(app)

    # For session storage
    app.session_interface.db.create_all()

    # Import and register the different asset bundles
    assets_env.init_app(app)
    assets_loader = PythonAssetsLoader(assets)
    for name, bundle in assets_loader.load_bundles().items():
        assets_env.register(name, bundle)

    # Register our blueprints
    app.register_blueprint(main)

    # VERSION (move to version.py ?)
    version = "0.0.0"
    with open('VERSION', 'r') as version_file:
        version = version_file.read().strip()

    # Inject it as global template var
    @app.context_processor
    def inject_template_global_variables():
        return dict(
            content=content,
            version=version,
            visits=get_hit_counter(),
        )

    # Markdown jinja2 filter
    @app.template_filter('markdown')
    def markdown_filter(text):
        text = icon2html(text)
        return markdown(text, extensions=['extra'])

    # Authentication Gate for the Admin
    @app.before_first_request
    def restrict_admin_url():
        endpoint = 'admin.index'
        url = url_for(endpoint)
        admin_index = app.view_functions.pop(endpoint)

        @app.route(url, endpoint=endpoint)
        @basic_auth.required
        # @roles_required('admin')
        def secure_admin_index():
            return admin_index()

    return app