Example #1
0
def gen_assets_url(assets: List[str]) -> str:
    """Create an asset bundle and return URL (helper for :func:`ext_assets`)."""
    # TODO: write test for this function
    try:
        names = [split_namespec(a)[0] for a in assets]
    except ValueError:
        abort(400)

    is_js = all(name.endswith('.js') for name in names)
    is_css = all(name.endswith('.css') for name in names)
    output_name = asset_key(assets)
    gendir = os.path.join(current_app.static_folder, 'gen')  # type: ignore[arg-type]
    if not os.path.exists(gendir):
        os.mkdir(gendir)
    # File extensions are for upstream servers to serve the correct content type:
    if is_js:
        # TODO: Move this !jquery.js to somewhere more relevant
        bundle = Bundle(
            assets_repo.require(*(['!jquery.js'] + assets)),
            output='gen/' + output_name + '.js',
            filters='uglipyjs',
        )
    elif is_css:
        bundle = Bundle(
            assets_repo.require(*assets),
            output='gen/' + output_name + '.css',
            filters=['cssrewrite', 'cssmin'],
        )
    else:
        abort(400)

    bundle.env = current_app.assets
    return bundle.urls()[0]
Example #2
0
def gen_assets_url(assets):
    try:
        names = [split_namespec(a)[0] for a in assets]
    except ValueError:
        abort(400)

    is_js = reduce(lambda status, name: status and name.endswith('.js'), names,
                   True)
    is_css = reduce(lambda status, name: status and name.endswith('.css'),
                    names, True)
    output_name = asset_key(assets)
    gendir = os.path.join(current_app.static_folder, 'gen')
    if not os.path.exists(gendir):
        os.mkdir(gendir)
    # The file extensions here are for upstream servers to serve the correct content type:
    if is_js:
        # TODO: Move this !jquery.js to somewhere more relevant
        bundle = Bundle(assets_repo.require(*(['!jquery.js'] + assets)),
                        output='gen/' + output_name + '.js',
                        filters='uglipyjs')
    elif is_css:
        bundle = Bundle(assets_repo.require(*assets),
                        output='gen/' + output_name + '.css',
                        filters=['cssrewrite', 'cssmin'])
    else:
        abort(400)

    bundle.env = current_app.assets
    return bundle.urls()[0]
Example #3
0
def gen_assets_url(assets):
    try:
        names = [split_namespec(a)[0] for a in assets]
    except ValueError:
        abort(400)

    is_js = reduce(lambda status, name: status and name.endswith('.js'), names, True)
    is_css = reduce(lambda status, name: status and name.endswith('.css'), names, True)
    output_name = asset_key(assets)
    gendir = os.path.join(current_app.static_folder, 'gen')
    if not os.path.exists(gendir):
        os.mkdir(gendir)
    # The file extensions here are for upstream servers to serve the correct content type:
    if is_js:
        # TODO: Move this !jquery.js to somewhere more relevant
        bundle = Bundle(assets_repo.require(*(['!jquery.js'] + assets)),
            output='gen/' + output_name + '.js', filters='uglipyjs')
    elif is_css:
        bundle = Bundle(assets_repo.require(*assets),
            output='gen/' + output_name + '.css', filters=['cssrewrite', 'cssmin'])
    else:
        abort(400)

    bundle.env = current_app.assets
    return bundle.urls()[0]
Example #4
0
    def init_app(self, app, requires=[], bundle_js=None, bundle_css=None, assetenv=None,
            static_subdomain=None):
        """
        Initialize an app and load necessary assets.

        :param requires: List of required assets. If an asset has both .js
        and .css components, both will be added to the requirement list.
        Loaded assets will be minified and concatenated into the app's
        ``static/js`` and ``static/css`` folders. If an asset has problems
        with either of these, it should be loaded pre-bundled via the
        ``bundle_js`` and ``bundle_css`` parameters.
        :param bundle_js: Bundle of additional JavaScript.
        :param bundle_css: Bundle of additional CSS.
        :param static_subdomain: Serve static files from this subdomain
        """
        assets_js = []
        assets_css = []
        for item in requires:
            name, spec = split_namespec(item)
            for alist, ext in [(assets_js, '.js'), (assets_css, '.css')]:
                if name + ext in assets:
                    alist.append(name + ext + unicode(spec))
        js_all = Bundle(assets.require('!jquery.js', *assets_js),
            filters='closure_js', output='js/baseframe-packed.js')
        css_all = Bundle(assets.require(*assets_css),
            filters=['cssrewrite', 'cssmin'], output='css/baseframe-packed.css')
        if bundle_js:
            js_all = Bundle(js_all, bundle_js)
        if bundle_css:
            css_all = Bundle(css_all, bundle_css)

        if assetenv is None:
            app.assets = Environment(app)
        else:
            app.assets = assetenv
        app.assets.register('js_jquery', assets.require('jquery.js'))
        app.assets.register('js_all', js_all)
        app.assets.register('css_all', css_all)
        app.register_blueprint(self, static_subdomain=static_subdomain)

        app.config.setdefault('CACHE_KEY_PREFIX', 'flask_cache_' + app.name)
        nwcacheconfig = dict(app.config)
        nwcacheconfig['CACHE_KEY_PREFIX'] = 'networkbar_'
        if 'CACHE_TYPE' not in nwcacheconfig:
            nwcacheconfig['CACHE_TYPE'] = 'simple'

        networkbar_cache.init_app(app, config=nwcacheconfig)
        cache.init_app(app)
        babel.init_app(app)
        FlaskMustache(app)

        if 'NETWORKBAR_DATA' not in app.config:
            app.config['NETWORKBAR_DATA'] = 'https://api.hasgeek.com/1/networkbar/networkbar.json'

        if isinstance(app.config.get('NETWORKBAR_DATA'), (list, tuple)):
            app.config['NETWORKBAR_LINKS'] = app.config['NETWORKBAR_DATA']
Example #5
0
    def init_app(self,
                 app,
                 requires=[],
                 bundle_js=None,
                 bundle_css=None,
                 assetenv=None):
        """
        Initialize an app and load necessary assets.

        :param requires: List of required assets. If an asset has both .js
        and .css components, both will be added to the requirement list.
        Loaded assets will be minified and concatenated into the app's
        ``static/js`` and ``static/css`` folders. If an asset has problems
        with either of these, it should be loaded pre-bundled via the
        ``bundle_js`` and ``bundle_css`` parameters.
        :param bundle_js: Bundle of additional JavaScript.
        :param bundle_css: Bundle of additional CSS.
        """
        assets_js = []
        assets_css = []
        for item in requires:
            name, spec = split_namespec(item)
            for alist, ext in [(assets_js, '.js'), (assets_css, '.css')]:
                if name + ext in assets:
                    alist.append(name + ext + unicode(spec))
        js_all = Bundle(assets.require('!jquery.js', *assets_js),
                        filters='closure_js',
                        output='js/baseframe-packed.js')
        css_all = Bundle(assets.require(*assets_css),
                         filters=['cssrewrite', 'cssmin'],
                         output='css/baseframe-packed.css')
        if bundle_js:
            js_all = Bundle(js_all, bundle_js)
        if bundle_css:
            css_all = Bundle(css_all, bundle_css)

        if assetenv is None:
            app.assets = Environment(app)
        else:
            app.assets = assetenv
        app.assets.register('js_jquery', assets.require('jquery.js'))
        app.assets.register('js_all', js_all)
        app.assets.register('css_all', css_all)
        app.register_blueprint(self)

        app.config.setdefault('CACHE_KEY_PREFIX', 'flask_cache_' + app.name)
        nwcacheconfig = dict(app.config)
        nwcacheconfig['CACHE_KEY_PREFIX'] = 'networkbar_'
        if 'CACHE_TYPE' not in nwcacheconfig:
            nwcacheconfig['CACHE_TYPE'] = 'simple'

        networkbar_cache.init_app(app, config=nwcacheconfig)
        cache.init_app(app)
        babel.init_app(app)
        FlaskMustache(app)

        if 'NETWORKBAR_DATA' not in app.config:
            app.config[
                'NETWORKBAR_DATA'] = 'https://api.hasgeek.com/1/networkbar/networkbar.json'

        if isinstance(app.config.get('NETWORKBAR_DATA'), (list, tuple)):
            app.config['NETWORKBAR_LINKS'] = app.config['NETWORKBAR_DATA']
Example #6
0
    def init_app(self,
                 app,
                 requires=[],
                 ext_requires=[],
                 bundle_js=None,
                 bundle_css=None,
                 assetenv=None,
                 enable_csrf=False):
        """
        Initialize an app and load necessary assets.

        :param requires: List of required assets. If an asset has both .js
            and .css components, both will be added to the requirement list.
            Loaded assets will be minified and concatenated into the app's
            ``static/js`` and ``static/css`` folders. If an asset has problems
            with either of these, it should be loaded pre-bundled via the
            ``bundle_js`` and ``bundle_css`` parameters.
        :param ext_requires: Same as requires, but will be loaded from
            an external cookiefree server if ``ASSET_SERVER`` is in config,
            before the reqular requires list. Assets are loaded as part of
            ``requires`` if there is no asset server
        :param bundle_js: Bundle of additional JavaScript
        :param bundle_css: Bundle of additional CSS
        """
        app.jinja_env.add_extension('jinja2.ext.do')
        if app.config.get('SERVER_NAME'):
            subdomain = app.config.get('STATIC_SUBDOMAIN', 'static')
            app.add_url_rule('/static/<path:filename>',
                             endpoint='static',
                             view_func=app.send_static_file,
                             subdomain=subdomain)
        else:
            subdomain = None

        ignore_js = ['!jquery.js']
        ignore_css = []
        ext_js = []
        ext_css = []
        if app.config.get('ASSET_SERVER'):
            for itemgroup in ext_requires:
                sub_js = []
                sub_css = []
                if not isinstance(itemgroup, (list, tuple)):
                    itemgroup = [itemgroup]
                for item in itemgroup:
                    name, spec = split_namespec(item)
                    for alist, ilist, ext in [(sub_js, ignore_js, '.js'),
                                              (sub_css, ignore_css, '.css')]:
                        if name + ext in assets:
                            alist.append(name + ext + unicode(spec))
                            ilist.append('!' + name + ext)
                if sub_js:
                    ext_js.append(sub_js)
                if sub_css:
                    ext_css.append(sub_css)
        else:
            requires = [
                item for itemgroup in ext_requires
                for item in (itemgroup if isinstance(itemgroup, (
                    list, tuple)) else [itemgroup])
            ] + requires

        app.config['ext_js'] = ext_js
        app.config['ext_css'] = ext_css

        assets_js = []
        assets_css = []
        for item in requires:
            name, spec = split_namespec(item)
            for alist, ext in [(assets_js, '.js'), (assets_css, '.css')]:
                if name + ext in assets:
                    alist.append(name + ext + unicode(spec))
        js_all = Bundle(assets.require(*(ignore_js + assets_js)),
                        filters='uglipyjs',
                        output='js/baseframe-packed.js')
        css_all = Bundle(assets.require(*(ignore_css + assets_css)),
                         filters=['cssrewrite', 'cssmin'],
                         output='css/baseframe-packed.css')
        if bundle_js:
            js_all = Bundle(js_all, bundle_js)
        if bundle_css:
            css_all = Bundle(css_all, bundle_css)

        if assetenv is None:
            app.assets = Environment(app)
        else:
            app.assets = assetenv
        app.assets.register('js_jquery', assets.require('jquery.js'))
        app.assets.register('js_all', js_all)
        app.assets.register('css_all', css_all)
        app.register_blueprint(self, static_subdomain=subdomain)

        app.config.setdefault('CACHE_KEY_PREFIX',
                              'flask_cache_' + app.name + '/')
        nwcacheconfig = dict(app.config)
        nwcacheconfig['CACHE_KEY_PREFIX'] = 'networkbar_'
        if 'CACHE_TYPE' not in nwcacheconfig:
            nwcacheconfig['CACHE_TYPE'] = 'simple'

        acacheconfig = dict(app.config)
        acacheconfig['CACHE_KEY_PREFIX'] = 'asset_'
        if 'CACHE_TYPE' not in acacheconfig:
            acacheconfig['CACHE_TYPE'] = 'simple'

        networkbar_cache.init_app(app, config=nwcacheconfig)
        asset_cache.init_app(app, config=acacheconfig)
        cache.init_app(app)
        babel.init_app(app)
        if enable_csrf:
            csrf.init_app(app)

        # If this app has a Lastuser extension registered, give it a cache
        lastuser = getattr(app, 'extensions', {}).get('lastuser')
        if lastuser and hasattr(lastuser, 'init_cache'):
            lastuser.init_cache(cache)

        app.config['tz'] = timezone(app.config.get('TIMEZONE', 'UTC'))

        if 'NETWORKBAR_DATA' not in app.config:
            app.config[
                'NETWORKBAR_DATA'] = 'https://api.hasgeek.com/1/networkbar/networkbar.json'

        if isinstance(app.config.get('NETWORKBAR_DATA'), (list, tuple)):
            app.config['NETWORKBAR_LINKS'] = app.config['NETWORKBAR_DATA']
Example #7
0
    def init_app(self,
                 app,
                 requires=[],
                 ext_requires=[],
                 bundle_js=None,
                 bundle_css=None,
                 assetenv=None,
                 theme='bootstrap3'):
        """
        Initialize an app and load necessary assets.

        :param requires: List of required assets. If an asset has both .js
            and .css components, both will be added to the requirement list.
            Loaded assets will be minified and concatenated into the app's
            ``static/js`` and ``static/css`` folders. If an asset has problems
            with either of these, it should be loaded pre-bundled via the
            ``bundle_js`` and ``bundle_css`` parameters.
        :param ext_requires: Same as requires, but will be loaded from
            an external cookiefree server if ``ASSET_SERVER`` is in config,
            before the reqular requires list. Assets are loaded as part of
            ``requires`` if there is no asset server
        :param bundle_js: Bundle of additional JavaScript
        :param bundle_css: Bundle of additional CSS
        :param assetenv: Environment for assets (in case your app needs a custom environment)
        """
        # Since Flask 0.11, templates are no longer auto reloaded.
        # Setting the config alone doesn't seem to work, so we explicitly
        # set the jinja environment here.
        if app.config.get('TEMPLATES_AUTO_RELOAD') or (
                app.config.get('TEMPLATES_AUTO_RELOAD') is None
                and app.config.get('DEBUG')):
            app.jinja_env.auto_reload = True
        app.jinja_env.add_extension('jinja2.ext.do')
        app.jinja_env.autoescape = _select_jinja_autoescape
        if app.subdomain_matching:
            # Does this app want a static subdomain? (Default: yes, 'static').
            # Apps can disable this by setting STATIC_SUBDOMAIN = None.
            # Since Werkzeug internally uses '' instead of None, but takes None
            # as the default parameter, we remap '' to None in our config
            subdomain = app.config.get('STATIC_SUBDOMAIN', 'static') or None
            if subdomain:
                for rule in app.url_map.iter_rules('static'):
                    # For safety, seek out and update the static route added by Flask.
                    # Do not touch additional static routes added by the app or other
                    # blueprints
                    if not rule.subdomain:  # Will be '' not None
                        rule.subdomain = subdomain
                        rule.refresh()
                        break
        else:
            subdomain = None

        ignore_js = ['!jquery.js']
        ignore_css = []
        ext_js = []
        ext_css = []
        if app.config.get('ASSET_SERVER'):
            for itemgroup in ext_requires:
                sub_js = []
                sub_css = []
                if not isinstance(itemgroup, (list, tuple)):
                    itemgroup = [itemgroup]
                for item in itemgroup:
                    name, spec = split_namespec(item)
                    for alist, ilist, ext in [(sub_js, ignore_js, '.js'),
                                              (sub_css, ignore_css, '.css')]:
                        if name + ext in assets:
                            alist.append(name + ext + six.text_type(spec))
                            ilist.append('!' + name + ext)
                if sub_js:
                    ext_js.append(sub_js)
                if sub_css:
                    ext_css.append(sub_css)
        else:
            requires = [
                item for itemgroup in ext_requires
                for item in (itemgroup if isinstance(itemgroup, (
                    list, tuple)) else [itemgroup])
            ] + requires

        app.config['ext_js'] = ext_js
        app.config['ext_css'] = ext_css

        assets_js = []
        assets_css = []
        for item in requires:
            name, spec = split_namespec(item)
            for alist, ext in [(assets_js, '.js'), (assets_css, '.css')]:
                if name + ext in assets:
                    alist.append(name + ext + six.text_type(spec))
        js_all = Bundle(assets.require(*(ignore_js + assets_js)),
                        filters='uglipyjs',
                        output='js/baseframe-packed.js')
        css_all = Bundle(assets.require(*(ignore_css + assets_css)),
                         filters=['cssrewrite', 'cssmin'],
                         output='css/baseframe-packed.css')
        if bundle_js:
            js_all = Bundle(js_all, bundle_js)
        if bundle_css:
            css_all = Bundle(css_all, bundle_css)

        if assetenv is None:
            app.assets = Environment(app)
        else:
            app.assets = assetenv
        app.assets.register('js_jquery', assets.require('jquery.js'))
        app.assets.register('js_all', js_all)
        app.assets.register('css_all', css_all)
        app.register_blueprint(self, static_subdomain=subdomain)

        # Optional config for a client app to use a manifest file
        # to load fingerprinted assets
        # If used with webpack, the client app is expected to specify its own webpack.config.js
        # Set `ASSETS_MANIFEST_PATH` in `app.config` to the path for `manifest.json`.
        # Eg: "static/build/manifest.json"
        # Set `ASSET_BASE_PATH` in `app.config` to the path in which the compiled assets are present.
        # Eg: "static/build"
        if app.config.get('ASSET_MANIFEST_PATH'):
            # Load assets into config from a manifest file
            with app.open_resource(app.config['ASSET_MANIFEST_PATH']) as f:
                asset_bundles = json.loads(f.read())
                if app.config.get('assets'):
                    raise ValueError(
                        "Loading assets via a manifest file needs the `ASSETS` config key to be unused"
                    )
                app.config['assets'] = {}
                for asset_key, asset_path in asset_bundles['assets'].items():
                    app.config['assets'][asset_key] = asset_path

        app.config.setdefault('CACHE_KEY_PREFIX',
                              'flask_cache_' + app.name + '/')
        nwcacheconfig = dict(app.config)
        nwcacheconfig['CACHE_KEY_PREFIX'] = 'networkbar_'
        if 'CACHE_TYPE' not in nwcacheconfig:
            nwcacheconfig['CACHE_TYPE'] = 'simple'

        acacheconfig = dict(app.config)
        acacheconfig['CACHE_KEY_PREFIX'] = 'asset_'
        if 'CACHE_TYPE' not in acacheconfig:
            acacheconfig['CACHE_TYPE'] = 'simple'

        networkbar_cache.init_app(app, config=nwcacheconfig)
        asset_cache.init_app(app, config=acacheconfig)
        cache.init_app(app)

        babel.init_app(app)
        if toolbar is not None:
            if 'DEBUG_TB_PANELS' not in app.config:
                app.config['DEBUG_TB_PANELS'] = [
                    'flask_debugtoolbar.panels.versions.VersionDebugPanel',
                    'flask_debugtoolbar.panels.timer.TimerDebugPanel',
                    'flask_debugtoolbar.panels.headers.HeaderDebugPanel',
                    'flask_debugtoolbar.panels.request_vars.RequestVarsDebugPanel',
                    'flask_debugtoolbar.panels.config_vars.ConfigVarsDebugPanel',
                    'flask_debugtoolbar.panels.template.TemplateDebugPanel',
                    'flask_debugtoolbar.panels.sqlalchemy.SQLAlchemyDebugPanel',
                    'flask_debugtoolbar.panels.logger.LoggingPanel',
                    'flask_debugtoolbar.panels.route_list.RouteListDebugPanel',
                    'flask_debugtoolbar.panels.profiler.ProfilerDebugPanel',
                ]
                if line_profile is not None:
                    app.config['DEBUG_TB_PANELS'].append(
                        'flask_debugtoolbar_lineprofilerpanel.panels.LineProfilerPanel'
                    )
            toolbar.init_app(app)

        app.json_encoder = JSONEncoder
        # If this app has a Lastuser extension registered, give it a cache
        lastuser = getattr(app, 'extensions', {}).get('lastuser')
        if lastuser and hasattr(lastuser, 'init_cache'):
            lastuser.init_cache(app=app, cache=cache)

        app.config['tz'] = timezone(app.config.get('TIMEZONE', 'UTC'))

        if theme not in THEME_FILES:
            raise ValueError("Unrecognised theme: %s" % theme)
        app.config['theme'] = theme

        if 'NETWORKBAR_DATA' not in app.config:
            app.config[
                'NETWORKBAR_DATA'] = 'https://api.hasgeek.com/1/networkbar/networkbar.json'

        if isinstance(app.config.get('NETWORKBAR_DATA'), (list, tuple)):
            app.config['NETWORKBAR_LINKS'] = app.config['NETWORKBAR_DATA']
Example #8
0
    def init_app(
            self,
            app: Flask,
            requires: Iterable[str] = (),
            ext_requires: Iterable[Union[str, List[str], Tuple[str,
                                                               ...]]] = (),
            bundle_js=None,
            bundle_css=None,
            assetenv=None,
            theme: str = 'bootstrap3',
            asset_modules=(),
    ):
        """
        Initialize an app with Baseframe and load necessary assets.

        :param requires: List of required assets. If an asset has both .js
            and .css components, both will be added to the requirement list.
            Loaded assets will be minified and concatenated into the app's
            ``static/js`` and ``static/css`` folders. If an asset has problems
            with either of these, it should be loaded pre-bundled via the
            ``bundle_js`` and ``bundle_css`` parameters
        :param ext_requires: Extended requirements, will be loaded first. These used to
            be served from a separate asset server, but that is deprecated
        :param bundle_js: Bundle of additional JavaScript
        :param bundle_css: Bundle of additional CSS
        :param theme: CSS theme, one of 'bootstrap3' (default) or 'mui'
        :param assetenv: Environment for assets (in case your app needs a custom
            environment)
        :param asset_modules: Modules providing additional assets
        """
        # Initialize Sentry logging
        if app.config.get('SENTRY_URL'):
            # With `traces_sample_rate` option set, every transaction created will
            # have that percentage chance of being sent to Sentry. (So, for example,
            # if you set traces_sample_rate to 0.2, approximately 20% of your
            # transactions will get recorded and sent.) We're keeping it 100% by
            # default, but we can change it from app.config if needed.
            sentry_sdk.init(
                dsn=app.config['SENTRY_URL'],
                traces_sample_rate=app.config.get('SENTRY_SAMPLE_RATE', 1.0),
                integrations=[
                    FlaskIntegration(),
                    RqIntegration(),
                    SqlalchemyIntegration(),
                ],
            )

        # Setup secret key rotation
        if app.config['SECRET_KEY']:  # Always present as it's a default
            if not app.config.get('SECRET_KEYS'):
                app.logger.debug("Setting SECRET_KEYS from SECRET_KEY")
                app.config['SECRET_KEYS'] = [app.config['SECRET_KEY']]
        elif app.config.get('SECRET_KEYS'):
            app.logger.debug(
                "Setting SECRET_KEY from first item in SECRET_KEYS")
            app.config['SECRET_KEY'] = app.config['SECRET_KEYS'][0]
        if app.config.get('SECRET_KEY') != app.config.get(
                'SECRET_KEYS', [None])[0]:
            raise ValueError("App has misconfigured secret keys")
        app.session_interface = RotatingKeySecureCookieSessionInterface()

        # Default .js and tracking file for Matomo
        if app.config.get('MATOMO_URL') and app.config.get('MATOMO_ID'):
            app.config.setdefault('MATOMO_JS', 'matomo.js')
            app.config.setdefault('MATOMO_FILE', 'matomo.php')

        statsd.init_app(app)

        # Since Flask 0.11, templates are no longer auto reloaded.
        # Setting the config alone doesn't seem to work, so we explicitly
        # set the jinja environment here.
        if app.config.get('TEMPLATES_AUTO_RELOAD') or (
                app.config.get('TEMPLATES_AUTO_RELOAD') is None
                and app.config.get('DEBUG')):
            app.jinja_env.auto_reload = True
        app.jinja_env.add_extension('jinja2.ext.do')
        app.jinja_env.autoescape = _select_jinja_autoescape
        app.jinja_env.globals['request_is_xhr'] = request_is_xhr
        app.jinja_env.globals['get_locale'] = get_locale
        app.jinja_env.globals['csrf_token'] = generate_csrf
        if app.subdomain_matching:
            # Does this app want a static subdomain? (Default: yes, 'static').
            # Apps can disable this by setting STATIC_SUBDOMAIN = None.
            # Since Werkzeug internally uses '' instead of None, but takes None
            # as the default parameter, we remap '' to None in our config
            subdomain = app.config.get('STATIC_SUBDOMAIN', 'static') or None
            if subdomain:
                for rule in app.url_map.iter_rules('static'):
                    # For safety, seek out and update the static route added by Flask.
                    # Do not touch additional static routes added by the app or other
                    # blueprints
                    if not rule.subdomain:  # Will be '' not None
                        rule.subdomain = subdomain
                        rule.refresh()
                        break
        else:
            subdomain = None

        ignore_js: List[str] = ['!jquery.js']
        ignore_css: List[str] = []
        ext_js: List[List[str]] = []
        ext_css: List[List[str]] = []
        requires = [
            item for itemgroup in ext_requires
            for item in (itemgroup if isinstance(itemgroup, (
                list, tuple)) else [itemgroup])
        ] + list(requires)

        app.config['ext_js'] = ext_js
        app.config['ext_css'] = ext_css

        assets_js: List[str] = []
        assets_css: List[str] = []
        for item in requires:
            name, spec = split_namespec(item)
            for alist, ext in [(assets_js, '.js'), (assets_css, '.css')]:
                if name + ext in assets:
                    alist.append(name + ext + str(spec))
        js_all = Bundle(
            assets.require(*(ignore_js + assets_js)),
            filters='uglipyjs',
            output='js/baseframe-packed.js',
        )
        css_all = Bundle(
            assets.require(*(ignore_css + assets_css)),
            filters=['cssrewrite', 'cssmin'],
            output='css/baseframe-packed.css',
        )
        if bundle_js:
            js_all = Bundle(js_all, bundle_js)
        if bundle_css:
            css_all = Bundle(css_all, bundle_css)

        if assetenv is None:
            app.assets = Environment(app)
        else:
            app.assets = assetenv
        app.assets.register('js_jquery', assets.require('jquery.js'))
        app.assets.register('js_all', js_all)
        app.assets.register('css_all', css_all)
        app.register_blueprint(self, static_subdomain=subdomain)

        for module_name in asset_modules:
            try:
                module = __import__(module_name)
                module.blueprint.init_app(app)
                app.register_blueprint(
                    module.blueprint,
                    url_prefix="/_baseframe",
                    static_subdomain=subdomain,
                )
            except ImportError:
                app.logger.warning("Unable to import asset module: %s",
                                   module_name)

        # Optional config for a client app to use a manifest file
        # to load fingerprinted assets
        # If used with webpack, the client app is expected to specify its own
        # webpack.config.js
        # Set `ASSETS_MANIFEST_PATH` in `app.config` to the path for `manifest.json`.
        # Eg: "static/build/manifest.json"
        # Set `ASSET_BASE_PATH` in `app.config` to the path in which the compiled assets
        # are present.
        # Eg: "static/build"
        if app.config.get('ASSET_MANIFEST_PATH'):
            # Load assets into config from a manifest file
            with app.open_resource(app.config['ASSET_MANIFEST_PATH']) as f:
                asset_bundles = json.loads(f.read())
                if app.config.get('assets'):
                    raise ValueError(
                        "Loading assets via a manifest file needs the `ASSETS` config key to be unused"
                    )
                app.config['assets'] = {}
                for _asset_key, _asset_path in asset_bundles['assets'].items():
                    app.config['assets'][_asset_key] = _asset_path

        app.config.setdefault('CACHE_KEY_PREFIX',
                              'flask_cache_' + app.name + '/')
        nwcacheconfig = dict(app.config)
        nwcacheconfig['CACHE_KEY_PREFIX'] = 'networkbar_'
        if 'CACHE_TYPE' not in nwcacheconfig:
            nwcacheconfig['CACHE_TYPE'] = 'simple'

        acacheconfig = dict(app.config)
        acacheconfig['CACHE_KEY_PREFIX'] = 'asset_'
        if 'CACHE_TYPE' not in acacheconfig:
            acacheconfig['CACHE_TYPE'] = 'simple'

        networkbar_cache.init_app(app, config=nwcacheconfig)
        asset_cache.init_app(app, config=acacheconfig)
        cache.init_app(app)

        babel.init_app(app)
        if toolbar is not None:
            if 'DEBUG_TB_PANELS' not in app.config:
                app.config['DEBUG_TB_PANELS'] = [
                    'flask_debugtoolbar.panels.versions.VersionDebugPanel',
                    'flask_debugtoolbar.panels.timer.TimerDebugPanel',
                    'flask_debugtoolbar.panels.headers.HeaderDebugPanel',
                    'flask_debugtoolbar.panels.request_vars.RequestVarsDebugPanel',
                    'flask_debugtoolbar.panels.config_vars.ConfigVarsDebugPanel',
                    'flask_debugtoolbar.panels.template.TemplateDebugPanel',
                    'flask_debugtoolbar.panels.sqlalchemy.SQLAlchemyDebugPanel',
                    'flask_debugtoolbar.panels.logger.LoggingPanel',
                    'flask_debugtoolbar.panels.route_list.RouteListDebugPanel',
                    'flask_debugtoolbar.panels.profiler.ProfilerDebugPanel',
                ]
            toolbar.init_app(app)

        app.json_encoder = JSONEncoder
        # If this app has a Lastuser extension registered, give it a cache
        lastuser = getattr(app, 'extensions', {}).get('lastuser')
        if lastuser and hasattr(lastuser, 'init_cache'):
            lastuser.init_cache(app=app, cache=cache)

        app.config['tz'] = timezone(app.config.get('TIMEZONE', 'UTC'))

        if theme not in THEME_FILES:
            raise ValueError("Unrecognised theme: %s" % theme)
        app.config['theme'] = theme

        if 'NETWORKBAR_DATA' not in app.config:
            app.config[
                'NETWORKBAR_DATA'] = 'https://api.hasgeek.com/1/networkbar/networkbar.json'

        if isinstance(app.config.get('NETWORKBAR_DATA'), (list, tuple)):
            app.config['NETWORKBAR_LINKS'] = app.config['NETWORKBAR_DATA']

        app.config.setdefault('RECAPTCHA_DATA_ATTRS', {})
        app.config['RECAPTCHA_DATA_ATTRS'].setdefault(
            'callback', 'onInvisibleRecaptchaSubmit')
        app.config['RECAPTCHA_DATA_ATTRS'].setdefault('size', 'invisible')

        if newrelic and os.path.isfile('newrelic.ini'):
            newrelic.agent.initialize('newrelic.ini')
            app.logger.debug("Successfully initiated Newrelic")
        elif not newrelic:
            app.logger.debug("Did not find `newrelic` package, skipping it")
        else:
            app.logger.debug(
                "Did not find New Relic settings file newrelic.ini, skipping it"
            )
Example #9
0
    def init_app(self, app, requires=[], ext_requires=[], bundle_js=None, bundle_css=None, assetenv=None,
            enable_csrf=False):
        """
        Initialize an app and load necessary assets.

        :param requires: List of required assets. If an asset has both .js
            and .css components, both will be added to the requirement list.
            Loaded assets will be minified and concatenated into the app's
            ``static/js`` and ``static/css`` folders. If an asset has problems
            with either of these, it should be loaded pre-bundled via the
            ``bundle_js`` and ``bundle_css`` parameters.
        :param ext_requires: Same as requires, but will be loaded from
            an external cookiefree server if ``ASSET_SERVER`` is in config,
            before the reqular requires list. Assets are loaded as part of
            ``requires`` if there is no asset server
        :param bundle_js: Bundle of additional JavaScript
        :param bundle_css: Bundle of additional CSS
        """
        app.jinja_env.add_extension('jinja2.ext.do')
        if app.config.get('SERVER_NAME'):
            subdomain = app.config.get('STATIC_SUBDOMAIN', 'static')
            app.add_url_rule('/static/<path:filename>', endpoint='static',
                view_func=app.send_static_file, subdomain=subdomain)
        else:
            subdomain = None

        ignore_js = ['!jquery.js']
        ignore_css = []
        ext_js = []
        ext_css = []
        if app.config.get('ASSET_SERVER'):
            for itemgroup in ext_requires:
                sub_js = []
                sub_css = []
                if not isinstance(itemgroup, (list, tuple)):
                    itemgroup = [itemgroup]
                for item in itemgroup:
                    name, spec = split_namespec(item)
                    for alist, ilist, ext in [(sub_js, ignore_js, '.js'), (sub_css, ignore_css, '.css')]:
                        if name + ext in assets:
                            alist.append(name + ext + unicode(spec))
                            ilist.append('!' + name + ext)
                if sub_js:
                    ext_js.append(sub_js)
                if sub_css:
                    ext_css.append(sub_css)
        else:
            requires = [item for itemgroup in ext_requires
                for item in (itemgroup if isinstance(itemgroup, (list, tuple)) else [itemgroup])] + requires

        app.config['ext_js'] = ext_js
        app.config['ext_css'] = ext_css

        assets_js = []
        assets_css = []
        for item in requires:
            name, spec = split_namespec(item)
            for alist, ext in [(assets_js, '.js'), (assets_css, '.css')]:
                if name + ext in assets:
                    alist.append(name + ext + unicode(spec))
        js_all = Bundle(assets.require(*(ignore_js + assets_js)),
            filters='uglipyjs', output='js/baseframe-packed.js')
        css_all = Bundle(assets.require(*(ignore_css + assets_css)),
            filters=['cssrewrite', 'cssmin'], output='css/baseframe-packed.css')
        if bundle_js:
            js_all = Bundle(js_all, bundle_js)
        if bundle_css:
            css_all = Bundle(css_all, bundle_css)

        if assetenv is None:
            app.assets = Environment(app)
        else:
            app.assets = assetenv
        app.assets.register('js_jquery', assets.require('jquery.js'))
        app.assets.register('js_all', js_all)
        app.assets.register('css_all', css_all)
        app.register_blueprint(self, static_subdomain=subdomain)

        app.config.setdefault('CACHE_KEY_PREFIX', 'flask_cache_' + app.name + '/')
        nwcacheconfig = dict(app.config)
        nwcacheconfig['CACHE_KEY_PREFIX'] = 'networkbar_'
        if 'CACHE_TYPE' not in nwcacheconfig:
            nwcacheconfig['CACHE_TYPE'] = 'simple'

        acacheconfig = dict(app.config)
        acacheconfig['CACHE_KEY_PREFIX'] = 'asset_'
        if 'CACHE_TYPE' not in acacheconfig:
            acacheconfig['CACHE_TYPE'] = 'simple'

        networkbar_cache.init_app(app, config=nwcacheconfig)
        asset_cache.init_app(app, config=acacheconfig)
        cache.init_app(app)
        babel.init_app(app)
        if enable_csrf:
            csrf.init_app(app)

        # If this app has a Lastuser extension registered, give it a cache
        lastuser = getattr(app, 'extensions', {}).get('lastuser')
        if lastuser and hasattr(lastuser, 'init_cache'):
            lastuser.init_cache(cache)

        app.config['tz'] = timezone(app.config.get('TIMEZONE', 'UTC'))

        if 'NETWORKBAR_DATA' not in app.config:
            app.config['NETWORKBAR_DATA'] = 'https://api.hasgeek.com/1/networkbar/networkbar.json'

        if isinstance(app.config.get('NETWORKBAR_DATA'), (list, tuple)):
            app.config['NETWORKBAR_LINKS'] = app.config['NETWORKBAR_DATA']