Ejemplo n.º 1
0
def create_app(conf=config,
               settings_override=None,
               skip_endpoints=False,
               skip_assets=False):
    """Return a :class:`Flask` application instance

    :param conf: Flask config object
    :param settings_override: override the default settings or settings in the configuration file
    """
    if settings_override is None:
        settings_override = {}
    app = Flask(__name__, static_url_path='/app')
    app.config.update(conf)
    app.config.update(settings_override)

    if not app.config.get('ENFORCE_SSL', True):
        try:
            _create_unverified_https_context = ssl._create_unverified_context
        except AttributeError:
            # Legacy Python that doesn't verify HTTPS certificates by default
            pass
        else:
            # Handle target environment that doesn't support HTTPS verification
            ssl._create_default_https_context = _create_unverified_https_context

        # try disabling insecure request warnings (some versions of requests have import errors)
        try:
            from requests.packages.urllib3.exceptions import InsecureRequestWarning
            requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
        except ImportError:
            # Skip if requests does not have InsecureRequestWarning
            pass

    app.logger.debug("Application Configuration: " + str(app.config))

    # setup celery scheduled tasks
    if app.config.get('DEMO_INSTALLATION', False):
        from celery.schedules import crontab

        app.config['CELERYBEAT_SCHEDULE'] = {}
        app.config['CELERYBEAT_SCHEDULE']['reset-demo-data-daily'] = {
            'task': "compair.tasks.demo.reset_demo",
            'schedule': crontab(hour=3, minute=0)
        }

    db.init_app(app)

    celery.conf.update(app.config)

    mail.init_app(app)

    create_persistent_dirs(app.config, app.logger)

    # add include_raw to jinja templates
    app.jinja_env.globals['include_raw'] = lambda filename: Markup(
        app.jinja_loader.get_source(app.jinja_env, filename)[0])
    app.jinja_env.globals['clean_html'] = lambda html_string: clean_html(
        html_string) if html_string else ''
    if not skip_assets and not app.debug and not app.config.get(
            'TESTING', False):
        assets = get_asset_names(app)
        app.config.update(assets)
        prefix = get_asset_prefix(app)
        app.config.update(prefix)

    if not skip_endpoints:
        # Flask-Login initialization
        login_manager.init_app(app)

        # This is how Flask-Login loads the newly logged in user's information
        @login_manager.user_loader
        def load_user(user_id):
            app.logger.debug("User logging in, ID: " + user_id)
            return User.query. \
                options(joinedload("user_courses")). \
                get(int(user_id))

        @login_manager.unauthorized_handler
        def unauthorized():
            if sess.get('THIRD_PARTY_AUTH_ERROR_MSG'):
                msg = sess.pop('THIRD_PARTY_AUTH_ERROR_MSG')
                msg_type = sess.pop('THIRD_PARTY_AUTH_ERROR_TYPE')
                response = jsonify({
                    'message': msg,
                    'status': 403,
                    'type': msg_type
                })
                response.status_code = 403
                return response
            abort(
                401,
                title="User Logged Out",
                message=
                "You must be logged in to see this page. Please log in to continue."
            )

        # Flask-Bouncer initialization
        bouncer.init_app(app)

        # Assigns permissions to the current logged in user
        @bouncer.authorization_method
        def bouncer_define_authorization(user, they):
            original_user = None
            if impersonation.is_impersonating():
                original_user = User.query.get(
                    impersonation.get_impersonation_original_user_id())
            define_authorization(user, they, original_user)

        # Loads the current logged in user. Note that although Flask-Bouncer advertises
        # compatibility with Flask-Login, it looks like it's compatible with an older
        # version than we're using, so we have to override their loader.
        @bouncer.user_loader
        def bouncer_user_loader():
            return current_user

        # setup impersonation
        if app.config.get('IMPERSONATION_ENABLED', False):
            impersonation.init_app(app)

            @impersonation.user_loader
            def load_user(user_id):
                return User.query.get(int(user_id))

            @impersonation.authorize
            def authorize(act_as_user_id):
                try:
                    ensure(impersonation.IMPERSONATE,
                           load_user(act_as_user_id))
                    return True
                except Unauthorized as e:
                    abort(
                        403,
                        title="Impersonation Failed",
                        message=
                        "Sorry, your role in the system does not allow you see a student's view."
                    )

                return False  # normally won't reach here

            @impersonation.process_request
            def process_request(request):
                """
                Callback invoked during impersonation to check incoming requests
                """
                if current_user and current_user.is_authenticated and not current_user.is_anonymous:
                    if not is_allowed_during_impersonation(request):
                        abort(403, title="Action Temporarily Disabled", \
                            message="Sorry, you can't perform that action in the student view. Only the real student can do this.", \
                            disabled_by_impersonation=True)

                # proceed with the request
                return None

        # register regex route converter
        app.url_map.converters['regex'] = RegexConverter

        app = register_api_blueprints(app)

        if app.config.get('MAIL_NOTIFICATION_ENABLED', False):
            capture_notification_events()

        if app.config.get('DEMO_INSTALLATION', False):
            log_demo_events(log)
            app = register_demo_api_blueprints(app)

        if app.config.get('XAPI_ENABLED', False):
            capture_xapi_events()
            app = register_statement_api_blueprints(app)

    return app
Ejemplo n.º 2
0
def create_app(conf=config, settings_override=None, skip_endpoints=False, skip_assets=False):
    """Return a :class:`Flask` application instance

    :param conf: Flask config object
    :param settings_override: override the default settings or settings in the configuration file
    """
    if settings_override is None:
        settings_override = {}
    app = Flask(__name__, static_url_path='/app')
    app.config.update(conf)
    app.config.update(settings_override)

    if not app.config.get('ENFORCE_SSL', True):
        try:
            _create_unverified_https_context = ssl._create_unverified_context
        except AttributeError:
            # Legacy Python that doesn't verify HTTPS certificates by default
            pass
        else:
            # Handle target environment that doesn't support HTTPS verification
            ssl._create_default_https_context = _create_unverified_https_context

        # try disabling insecure request warnings (some versions of requests have import errors)
        try:
            from requests.packages.urllib3.exceptions import InsecureRequestWarning
            requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
        except ImportError:
            # Skip if requests does not have InsecureRequestWarning
            pass

    app.logger.debug("Application Configuration: " + str(app.config))

    # setup celery scheduled tasks
    if app.config.get('DEMO_INSTALLATION', False):
        #each day at 3am
        app.config.setdefault('CELERYBEAT_SCHEDULE', {})['reset-demo-data-daily'] = {
            'task': "compair.tasks.demo.reset_demo",
            'schedule': crontab(hour=3, minute=0)
        }
    if (app.config.get('XAPI_ENABLED') and app.config.get('LRS_XAPI_STATEMENT_ENDPOINT') != 'local') or \
            (app.config.get('CALIPER_ENABLED') and app.config.get('LRS_CALIPER_HOST') != 'local'):
        # every 6 hours
        app.config.setdefault('CELERYBEAT_SCHEDULE', {})['retry-sending-failed-learning-records'] = {
            'task': "compair.tasks.emit_learning_record.resend_learning_records",
            'schedule': crontab(hour='*/6', minute=0)
        }


    db.init_app(app)

    celery.conf.update(app.config)

    mail.init_app(app)

    create_persistent_dirs(app.config, app.logger)

    # add include_raw to jinja templates
    app.jinja_env.globals['include_raw'] = lambda filename : Markup(app.jinja_loader.get_source(app.jinja_env, filename)[0])
    app.jinja_env.globals['clean_html'] = lambda html_string : clean_html(html_string) if html_string else ''
    if not skip_assets and not app.debug and not app.config.get('TESTING', False):
        assets = get_asset_names(app)
        app.config.update(assets)
        prefix = get_asset_prefix(app)
        app.config.update(prefix)

    if not skip_endpoints:
        # Flask-Login initialization
        login_manager.init_app(app)

        # This is how Flask-Login loads the newly logged in user's information
        @login_manager.user_loader
        def load_user(user_id):
            app.logger.debug("User logging in, ID: " + user_id)
            return User.query. \
                options(joinedload("user_courses")). \
                get(int(user_id))

        @login_manager.unauthorized_handler
        def unauthorized():
            if sess.get('THIRD_PARTY_AUTH_ERROR_MSG'):
                msg = sess.pop('THIRD_PARTY_AUTH_ERROR_MSG')
                msg_type = sess.pop('THIRD_PARTY_AUTH_ERROR_TYPE')
                response = jsonify({'message': msg, 'status': 403, 'type': msg_type})
                response.status_code = 403
                return response
            abort(401, title="User Logged Out", message="You must be logged in to see this page. Please log in to continue.")

        # Flask-Bouncer initialization
        bouncer.init_app(app)

        # Assigns permissions to the current logged in user
        @bouncer.authorization_method
        def bouncer_define_authorization(user, they):
            original_user = None
            if impersonation.is_impersonating():
                original_user = User.query.get(impersonation.get_impersonation_original_user_id())
            define_authorization(user, they, original_user)

        # Loads the current logged in user. Note that although Flask-Bouncer advertises
        # compatibility with Flask-Login, it looks like it's compatible with an older
        # version than we're using, so we have to override their loader.
        @bouncer.user_loader
        def bouncer_user_loader():
            return current_user

        # setup impersonation
        if app.config.get('IMPERSONATION_ENABLED', False):
            impersonation.init_app(app)

            @impersonation.user_loader
            def load_user(user_id):
                return User.query.get(int(user_id))

            @impersonation.authorize
            def authorize(act_as_user_id):
                try:
                    ensure(impersonation.IMPERSONATE, load_user(act_as_user_id))
                    return True
                except Unauthorized as e:
                    abort(403, title="Impersonation Failed", message="Sorry, your role in the system does not allow you see a student's view.")

                return False    # normally won't reach here

            @impersonation.process_request
            def process_request(request):
                """
                Callback invoked during impersonation to check incoming requests
                """
                if current_user and current_user.is_authenticated and not current_user.is_anonymous:
                    if not is_allowed_during_impersonation(request):
                        abort(403, title="Action Temporarily Disabled", \
                            message="Sorry, you can't perform that action in the student view. Only the real student can do this.", \
                            disabled_by_impersonation=True)

                # proceed with the request
                return None

        # register regex route converter
        app.url_map.converters['regex'] = RegexConverter

        app = register_api_blueprints(app)

        if app.config.get('MAIL_NOTIFICATION_ENABLED', False):
            capture_notification_events()

        if app.config.get('DEMO_INSTALLATION', False):
            log_demo_events(log)
            app = register_demo_api_blueprints(app)

        if app.config.get('XAPI_ENABLED', False) or app.config.get('CALIPER_ENABLED', False) :
            capture_events()
            app = register_learning_record_api_blueprints(app)

    return app