Пример #1
0
def webassets_init():
    global env

    static_path = get_webassets_path()

    public = config.get(u'ckan.base_public_folder')

    public_folder = os.path.abspath(
        os.path.join(os.path.dirname(__file__), u'..', public))

    base_path = os.path.join(public_folder, u'base')

    env = Environment()
    env.directory = static_path
    env.debug = config.get(u'debug', False)
    env.url = u'/webassets/'

    env.append_path(base_path, u'/base/')

    logger.debug(u'Base path {0}'.format(base_path))
    create_library(u'vendor', os.path.join(base_path, u'vendor'))

    create_library(u'base', os.path.join(base_path, u'javascript'))

    create_library(u'datapreview', os.path.join(base_path, u'datapreview'))

    create_library(u'css', os.path.join(base_path, u'css'))
Пример #2
0
def webassets_init():
    global env

    static_path = get_webassets_path()

    public = config.get(u'ckan.base_public_folder')

    public_folder = os.path.abspath(os.path.join(
        os.path.dirname(__file__), u'..', public))

    base_path = os.path.join(public_folder, u'base')

    env = Environment()
    env.directory = static_path
    env.debug = config.get(u'debug', False)
    env.url = u'/webassets/'

    env.append_path(base_path, u'/base/')

    logger.debug(u'Base path {0}'.format(base_path))
    create_library(u'vendor', os.path.join(
        base_path, u'vendor'))

    create_library(u'base', os.path.join(base_path, u'javascript'))

    create_library(u'datapreview', os.path.join(base_path, u'datapreview'))

    create_library(u'css', os.path.join(base_path, u'css'))
Пример #3
0
    def test_append_load_path(self):
        env = Environment()
        assert env.load_path == []

        env.append_path('foo', '/foo')
        assert env.load_path == ['foo']
        assert env.url_mapping == {'foo': '/foo'}

        # Works without path
        env.append_path('bar')
        assert env.load_path == ['foo', 'bar']
        assert env.url_mapping == {'foo': '/foo'}
Пример #4
0
    def test_append_load_path(self):
        env = Environment()
        assert env.load_path == []

        env.append_path('foo', '/foo')
        assert env.load_path == ['foo']
        assert env.url_mapping == {'foo': '/foo'}

        # Works without path
        env.append_path('bar')
        assert env.load_path == ['foo', 'bar']
        assert env.url_mapping == {'foo': '/foo'}
Пример #5
0
    def test_append_load_path(self):
        env = Environment()
        assert env.load_path == []

        env.append_path("foo", "/foo")
        assert env.load_path == ["foo"]
        assert env.url_mapping == {"foo": "/foo"}

        # Works without path
        env.append_path("bar")
        assert env.load_path == ["foo", "bar"]
        assert env.url_mapping == {"foo": "/foo"}
Пример #6
0
class IndicoPlugin(Plugin):
    """Base class for an Indico plugin

    All your plugins need to inherit from this class. It extends the
    `Plugin` class from Flask-PluginEngine with useful indico-specific
    functionality that makes it easier to write custom plugins.

    When creating your plugin, the class-level docstring is used to
    generate the friendly name and description of a plugin. Its first
    line becomes the name while everything else goes into the description.

    This class provides methods for some of the more common hooks Indico
    provides. Additional signals are defined in :mod:`~indico.core.signals`
    and can be connected to custom functions using :meth:`connect`.
    """

    #: WTForm for the plugin's settings (requires `configurable=True`).
    #: All fields must return JSON-serializable types.
    settings_form = None
    #: A dictionary which can contain the kwargs for a specific field in the `settings_form`.
    settings_form_field_opts = {}
    #: A dictionary containing default values for settings
    default_settings = {}
    #: A dictionary containing default values for event-specific settings
    default_event_settings = {}
    #: A dictionary containing default values for user-specific settings
    default_user_settings = {}
    #: A set containing the names of settings which store ACLs
    acl_settings = frozenset()
    #: A set containing the names of event-specific settings which store ACLs
    acl_event_settings = frozenset()
    #: A dict containing custom converters for settings
    settings_converters = {}
    #: A dict containing custom converters for event-specific settings
    event_settings_converters = {}
    #: A dict containing custom converters for user-specific settings
    user_settings_converters = {}
    #: If the plugin should link to a details/config page in the admin interface
    configurable = False
    #: The group category that the plugin belongs to
    category = None
    #: If `settings`, `event_settings` and `user_settings` should use strict
    #: mode, i.e. only allow keys in `default_settings`, `default_event_settings`
    #: or `default_user_settings` (or the related `acl_settings` sets)
    strict_settings = False

    def init(self):
        """Called when the plugin is being loaded/initialized.

        If you want to run custom initialization code, this is the
        method to override. Make sure to call the base method or
        the other overridable methods in this class will not be
        called anymore.
        """
        assert self.configurable or not self.settings_form, 'Non-configurable plugin cannot have a settings form'
        self.alembic_versions_path = os.path.join(self.root_path, 'migrations')
        self.connect(signals.plugin.cli, self.add_cli_command)
        self.connect(signals.plugin.get_blueprints, lambda app: self.get_blueprints())
        self.template_hook('vars-js', self.inject_vars_js)
        self._setup_assets()
        self._import_models()

    def _setup_assets(self):
        config = Config.getInstance()
        url_base_path = urlparse(config.getBaseURL()).path
        output_dir = os.path.join(config.getHtdocsDir(), 'static', 'assets', 'plugins', self.name)
        output_url = '{}/static/assets/plugins/{}'.format(url_base_path, self.name)
        static_dir = os.path.join(self.root_path, 'static')
        static_url = '{}/static/plugins/{}'.format(url_base_path, self.name)
        self.assets = Environment(output_dir, output_url, debug=config.getDebug())
        self.assets.append_path(output_dir, output_url)
        self.assets.append_path(static_dir, static_url)
        configure_pyscss(self.assets)
        self.register_assets()

    def _import_models(self):
        old_models = set(db.Model._decl_class_registry.items())
        import_all_models(self.package_name)
        added_models = set(db.Model._decl_class_registry.items()) - old_models
        # Ensure that only plugin schemas have been touched. It would be nice if we could actually
        # restrict a plugin to plugin_PLUGNNAME but since we load all models from the plugin's package
        # which could contain more than one plugin this is not easily possible.
        for name, model in added_models:
            schema = model.__table__.schema
            if not schema.startswith('plugin_'):
                raise Exception("Plugin '{}' added a model which is not in a plugin schema ('{}' in '{}')"
                                .format(self.name, name, schema))

    def connect(self, signal, receiver, **connect_kwargs):
        connect_kwargs['weak'] = False
        func = wrap_in_plugin_context(self, receiver)
        func.indico_plugin = self
        signal.connect(func, **connect_kwargs)

    def get_blueprints(self):
        """Return blueprints to be registered on the application

        A single blueprint can be returned directly, for multiple blueprint you need
        to yield them or return an iterable.
        """
        pass

    def get_vars_js(self):
        """Return a dictionary with variables to be added to vars.js file"""
        return None

    @cached_property
    def translation_path(self):
        """
        Return translation files to be used by the plugin.
        By default, get <root_path>/translations, unless it does not exist
        """
        translations_path = os.path.join(self.root_path, 'translations')
        return translations_path if os.path.exists(translations_path) else None

    @cached_property
    def translation_domain(self):
        """Return the domain for this plugin's translation_path"""
        path = self.translation_path
        return Domain(path) if path else NullDomain()

    def add_cli_command(self, manager):
        """Add custom commands/submanagers to the manager of the `indico` cli tool."""
        pass

    def register_assets(self):
        """Add assets to the plugin's webassets environment.

        In most cases the whole method can consist of calls to
        :meth:`register_js_bundle` and :meth:`register_css_bundle`.
        """
        pass

    def register_js_bundle(self, name, *files):
        """Registers a JS bundle in the plugin's webassets environment"""
        pretty_name = re.sub(r'_js$', '', name)
        bundle = Bundle(*files, filters='rjsmin', output='js/{}_%(version)s.min.js'.format(pretty_name))
        self.assets.register(name, bundle)

    def register_css_bundle(self, name, *files):
        """Registers an SCSS bundle in the plugin's webassets environment"""
        pretty_name = re.sub(r'_css$', '', name)
        bundle = Bundle(*files,
                        filters=('pyscss', 'cssrewrite', 'cssmin'),
                        output='css/{}_%(version)s.min.css'.format(pretty_name),
                        depends=SASS_BASE_MODULES)
        self.assets.register(name, bundle)

    def inject_css(self, name, view_class=None, subclasses=True, condition=None):
        """Injects a CSS bundle into Indico's pages

        :param name: Name of the bundle
        :param view_class: If a WP class is specified, only inject it into pages using that class
        :param subclasses: also inject into subclasses of `view_class`
        :param condition: a callable to determine whether to inject or not. only called, when the
                          view_class criterion matches
        """
        self._inject_asset(signals.plugin.inject_css, name, view_class, subclasses, condition)

    def inject_js(self, name, view_class=None, subclasses=True, condition=None):
        """Injects a JS bundle into Indico's pages

        :param name: Name of the bundle
        :param view_class: If a WP class is specified, only inject it into pages using that class
        :param subclasses: also inject into subclasses of `view_class`
        :param condition: a callable to determine whether to inject or not. only called, when the
                          view_class criterion matches
        """
        self._inject_asset(signals.plugin.inject_js, name, view_class, subclasses, condition)

    def _inject_asset(self, signal, name, view_class=None, subclasses=True, condition=None):
        """Injects an asset bundle into Indico's pages

        :param signal: the signal to use for injection
        :param name: Name of the bundle
        :param view_class: If a WP class is specified, only inject it into pages using that class
        :param subclasses: also inject into subclasses of `view_class`
        :param condition: a callable to determine whether to inject or not. only called, when the
                          view_class criterion matches
        """

        def _do_inject(sender):
            if condition is None or condition():
                return self.assets[name].urls()

        if view_class is None:
            self.connect(signal, _do_inject)
        elif not subclasses:
            self.connect(signal, _do_inject, sender=view_class)
        else:
            def _func(sender):
                if issubclass(sender, view_class):
                    return _do_inject(sender)

            self.connect(signal, _func)

    def inject_vars_js(self):
        """Returns a string that will define variables for the plugin in the vars.js file"""
        vars_js = self.get_vars_js()
        if vars_js:
            return 'var {}Plugin = {};'.format(self.name.title(), json.dumps(vars_js))

    def template_hook(self, name, receiver, priority=50, markup=True):
        """Registers a function to be called when a template hook is invoked.

        For details see :func:~`indico.web.flask.templating.register_template_hook`
        """
        register_template_hook(name, receiver, priority, markup, self)

    @classproperty
    @classmethod
    def logger(cls):
        return Logger.get('plugin.{}'.format(cls.name))

    @cached_classproperty
    @classmethod
    def settings(cls):
        """:class:`SettingsProxy` for the plugin's settings"""
        if cls.name is None:
            raise RuntimeError('Plugin has not been loaded yet')
        instance = cls.instance
        with instance.plugin_context():  # in case the default settings come from a property
            return SettingsProxy('plugin_{}'.format(cls.name), instance.default_settings, cls.strict_settings,
                                 acls=cls.acl_settings, converters=cls.settings_converters)

    @cached_classproperty
    @classmethod
    def event_settings(cls):
        """:class:`EventSettingsProxy` for the plugin's event-specific settings"""
        if cls.name is None:
            raise RuntimeError('Plugin has not been loaded yet')
        instance = cls.instance
        with instance.plugin_context():  # in case the default settings come from a property
            return EventSettingsProxy('plugin_{}'.format(cls.name), instance.default_event_settings,
                                      cls.strict_settings, acls=cls.acl_event_settings,
                                      converters=cls.event_settings_converters)

    @cached_classproperty
    @classmethod
    def user_settings(cls):
        """:class:`UserSettingsProxy` for the plugin's user-specific settings"""
        if cls.name is None:
            raise RuntimeError('Plugin has not been loaded yet')
        instance = cls.instance
        with instance.plugin_context():  # in case the default settings come from a property
            return UserSettingsProxy('plugin_{}'.format(cls.name), instance.default_user_settings,
                                     cls.strict_settings, converters=cls.user_settings_converters)
Пример #7
0
from clldutils.path import Path

import clld


def skip(_in, out, **kw):
    """filter to skip content of assets which are fetched from CDN in production."""
    out.write('')  # pragma: no cover


_static_path = Path(clld.__file__).parent.joinpath('web', 'static').as_posix()
environment = Environment(_static_path,
                          '/clld:web/static/',
                          manifest='json:',
                          auto_build=False)
environment.append_path(_static_path, url='/clld:web/static/')

bundles = {
    'js': [
        Bundle('js/jquery.js', 'js/leaflet-src.js', filters=(skip, )),
        'js/bootstrap.min.js',
        'js/jquery.dataTables.min.js',
        'js/oms.min.js',
        Bundle('js/bootstrapx-clickover.js',
               'js/tree.jquery.js',
               'js/leaflet-providers.js',
               'js/leaflet.label.js',
               'js/Control.FullScreen.js',
               'js/leaflet-hash.js',
               'js/clld.js',
               'project.js',
Пример #8
0
class WPBase(OldObservable):
    """
    """
    _title = "Indico"

    # required user-specific "data packages"
    _userData = []

    def __init__( self, rh ):
        config = Config.getInstance()
        db_connected = DBMgr.getInstance().isConnected()

        self._rh = rh
        self._locTZ = ""

        self._asset_env = Environment(os.path.join(config.getHtdocsDir(), "static", "assets"), '/static/assets/')
        self._asset_env.config['PYSCSS_LOAD_PATHS'] = [os.path.join(config.getHtdocsDir(), 'sass', 'lib', 'compass')]
        self._asset_env.append_path(config.getHtdocsDir(), '/')

        if db_connected:
            debug = HelperMaKaCInfo.getMaKaCInfoInstance().isDebugActive()
        else:
            debug = False

        # This is done in order to avoid the problem sending the error report because the DB is not connected.
        if db_connected:
            info = HelperMaKaCInfo.getMaKaCInfoInstance()
            self._asset_env.debug = info.isDebugActive()

        self._dir = config.getTPLDir()
        self._asset_env.debug = debug

        if db_connected:
            css_file = config.getCssStylesheetName()
        else:
            css_file = 'Default.css'

        # register existing assets
        assets.register_all_js(self._asset_env)
        assets.register_all_css(self._asset_env, css_file)

        #store page specific CSS and JS
        self._extraCSS = []
        self._extraJS = []

    def _getBaseURL( self ):
        if self._rh._req.is_https() and Config.getInstance().getBaseSecureURL():
            baseurl = Config.getInstance().getBaseSecureURL()
        else:
            baseurl = Config.getInstance().getBaseURL()
        return baseurl

    def _getTitle( self ):
        return self._title

    def _setTitle( self, newTitle ):
        self._title = newTitle.strip()

    def getCSSFiles(self):
        return self._asset_env['base_css'].urls() + \
            self._asset_env['base_sass'].urls()

    def _getJavaScriptInclude(self, scriptPath):
        return '<script src="'+ scriptPath +'" type="text/javascript"></script>\n'

    def getJSFiles(self):
        return self._asset_env['base_js'].urls()

    def _includeJSPackage(self, pkg_names):
        if not isinstance(pkg_names, list):
            pkg_names = [pkg_names]

        urls = []
        for pkg_name in pkg_names:
            urls += self._asset_env['indico_' + pkg_name.lower()].urls()
        return urls

    def _getJavaScriptUserData(self):
        """
        Returns structured data that should be passed on to the client side
        but depends on user data (can't be in vars.js.tpl)
        """

        user = self._getAW().getUser();

        from MaKaC.webinterface.asyndico import UserDataFactory

        userData = dict((packageName,
                         UserDataFactory(user).build(packageName))
                        for packageName in self._userData)

        return userData

    def _getHeadContent( self ):
        """
        Returns _additional_ content between <head></head> tags.
        Please note that <title>, <meta> and standard CSS are always included.

        Override this method to add your own, page-specific loading of
        JavaScript, CSS and other legal content for HTML <head> tag.
        """
        return ""

    def _getWarningMessage(self):
        return ""

    def _getHTMLHeader( self ):
        from MaKaC.webinterface.pages.conferences import WPConfSignIn
        from MaKaC.webinterface.pages.signIn import WPSignIn
        from MaKaC.webinterface.pages.registrationForm import WPRegistrationFormSignIn
        from MaKaC.webinterface.rh.base import RHModificationBaseProtected
        from MaKaC.webinterface.rh.admins import RHAdminBase

        area=""
        if isinstance(self._rh, RHModificationBaseProtected):
            area=i18nformat(""" - _("Management area")""")
        elif isinstance(self._rh, RHAdminBase):
            area=i18nformat(""" - _("Administrator area")""")

        info = HelperMaKaCInfo().getMaKaCInfoInstance()
        websession = self._getAW().getSession()
        if websession:
            language = websession.getLang()
        else:
            language = info.getLang()

        return wcomponents.WHTMLHeader().getHTML({
            "area": area,
            "baseurl": self._getBaseURL(),
            "conf": Config.getInstance(),
            "page": self,
            "extraCSS": self.getCSSFiles(),
            "extraJSFiles": self.getJSFiles(),
            "extraJS": self._extraJS,
            "language": language,
            "social": info.getSocialAppConfig(),
            "assets": self._asset_env
            })

    def _getHTMLFooter( self ):
        return """
    </body>
</html>
               """

    def _display( self, params ):
        """
        """
        return _("no content")

    def _getAW( self ):
        return self._rh.getAW()

    def display( self, **params ):
        """
        """
        return "%s%s%s"%( self._getHTMLHeader(), \
                            self._display( params ), \
                            self._getHTMLFooter() )


    def addExtraJSFile(self, filename):
        self._extraJSFiles.append(filename)

    def addExtraJS(self, jsCode):
        self._extraJS.append(jsCode)

    # auxiliar functions
    def _escapeChars(self, text):
        # Not doing anything right now - it used to convert % to %% for old-style templates
        return text
Пример #9
0
class IndicoPlugin(Plugin):
    """Base class for an Indico plugin

    All your plugins need to inherit from this class. It extends the
    `Plugin` class from Flask-PluginEngine with useful indico-specific
    functionality that makes it easier to write custom plugins.

    When creating your plugin, the class-level docstring is used to
    generate the friendly name and description of a plugin. Its first
    line becomes the name while everything else goes into the description.

    This class provides methods for some of the more common hooks Indico
    provides. Additional signals are defined in :mod:`~indico.core.signals`
    and can be connected to custom functions using :meth:`connect`.
    """

    #: WTForm for the plugin's settings (requires `configurable=True`).
    #: All fields must return JSON-serializable types.
    settings_form = None
    #: A dictionary which can contain the kwargs for a specific field in the `settings_form`.
    settings_form_field_opts = {}
    #: A dictionary containing default values for settings
    default_settings = {}
    #: A dictionary containing default values for event-specific settings
    default_event_settings = {}
    #: A dictionary containing default values for user-specific settings
    default_user_settings = {}
    #: A set containing the names of settings which store ACLs
    acl_settings = frozenset()
    #: A set containing the names of event-specific settings which store ACLs
    acl_event_settings = frozenset()
    #: If the plugin should link to a details/config page in the admin interface
    configurable = False
    #: The group category that the plugin belongs to
    category = None
    #: If `settings`, `event_settings` and `user_settings` should use strict
    #: mode, i.e. only allow keys in `default_settings`, `default_event_settings`
    #: or `default_user_settings` (or the related `acl_settings` sets)
    strict_settings = False

    def init(self):
        """Called when the plugin is being loaded/initialized.

        If you want to run custom initialization code, this is the
        method to override. Make sure to call the base method or
        the other overridable methods in this class will not be
        called anymore.
        """
        assert self.configurable or not self.settings_form, 'Non-configurable plugin cannot have a settings form'
        self.alembic_versions_path = os.path.join(self.root_path, 'migrations')
        self.connect(signals.plugin.cli, self.add_cli_command)
        self.connect(signals.plugin.get_blueprints,
                     lambda app: self.get_blueprints())
        self.template_hook('vars-js', self.inject_vars_js)
        self._setup_assets()
        self._import_models()

    def _setup_assets(self):
        config = Config.getInstance()
        url_base_path = urlparse(config.getBaseURL()).path
        output_dir = os.path.join(config.getHtdocsDir(), 'static', 'assets',
                                  'plugins', self.name)
        output_url = '{}/static/assets/plugins/{}'.format(
            url_base_path, self.name)
        static_dir = os.path.join(self.root_path, 'static')
        static_url = '{}/static/plugins/{}'.format(url_base_path, self.name)
        self.assets = Environment(output_dir,
                                  output_url,
                                  debug=config.getDebug())
        self.assets.append_path(output_dir, output_url)
        self.assets.append_path(static_dir, static_url)
        configure_pyscss(self.assets)
        self.register_assets()

    def _import_models(self):
        old_models = set(db.Model._decl_class_registry.items())
        import_all_models(self.package_name)
        added_models = set(db.Model._decl_class_registry.items()) - old_models
        # Ensure that only plugin schemas have been touched. It would be nice if we could actually
        # restrict a plugin to plugin_PLUGNNAME but since we load all models from the plugin's package
        # which could contain more than one plugin this is not easily possible.
        for name, model in added_models:
            schema = model.__table__.schema
            if not schema.startswith('plugin_'):
                raise Exception(
                    "Plugin '{}' added a model which is not in a plugin schema ('{}' in '{}')"
                    .format(self.name, name, schema))

    def connect(self, signal, receiver, **connect_kwargs):
        connect_kwargs['weak'] = False
        func = wrap_in_plugin_context(self, receiver)
        func.indico_plugin = self
        signal.connect(func, **connect_kwargs)

    def get_blueprints(self):
        """Return blueprints to be registered on the application

        A single blueprint can be returned directly, for multiple blueprint you need
        to yield them or return an iterable.
        """
        pass

    def get_vars_js(self):
        """Return a dictionary with variables to be added to vars.js file"""
        return None

    @cached_property
    def translation_path(self):
        """
        Return translation files to be used by the plugin.
        By default, get <root_path>/translations, unless it does not exist
        """
        translations_path = os.path.join(self.root_path, 'translations')
        return translations_path if os.path.exists(translations_path) else None

    @cached_property
    def translation_domain(self):
        """Return the domain for this plugin's translation_path"""
        path = self.translation_path
        return Domain(path) if path else NullDomain()

    def add_cli_command(self, manager):
        """Add custom commands/submanagers to the manager of the `indico` cli tool."""
        pass

    def register_assets(self):
        """Add assets to the plugin's webassets environment.

        In most cases the whole method can consist of calls to
        :meth:`register_js_bundle` and :meth:`register_css_bundle`.
        """
        pass

    def register_js_bundle(self, name, *files):
        """Registers a JS bundle in the plugin's webassets environment"""
        pretty_name = re.sub(r'_js$', '', name)
        bundle = Bundle(*files,
                        filters='rjsmin',
                        output='js/{}_%(version)s.min.js'.format(pretty_name))
        self.assets.register(name, bundle)

    def register_css_bundle(self, name, *files):
        """Registers an SCSS bundle in the plugin's webassets environment"""
        pretty_name = re.sub(r'_css$', '', name)
        bundle = Bundle(
            *files,
            filters=('pyscss', 'cssrewrite', 'cssmin'),
            output='css/{}_%(version)s.min.css'.format(pretty_name),
            depends=SASS_BASE_MODULES)
        self.assets.register(name, bundle)

    def inject_css(self,
                   name,
                   view_class=None,
                   subclasses=True,
                   condition=None):
        """Injects a CSS bundle into Indico's pages

        :param name: Name of the bundle
        :param view_class: If a WP class is specified, only inject it into pages using that class
        :param subclasses: also inject into subclasses of `view_class`
        :param condition: a callable to determine whether to inject or not. only called, when the
                          view_class criterion matches
        """
        self._inject_asset(signals.plugin.inject_css, name, view_class,
                           subclasses, condition)

    def inject_js(self,
                  name,
                  view_class=None,
                  subclasses=True,
                  condition=None):
        """Injects a JS bundle into Indico's pages

        :param name: Name of the bundle
        :param view_class: If a WP class is specified, only inject it into pages using that class
        :param subclasses: also inject into subclasses of `view_class`
        :param condition: a callable to determine whether to inject or not. only called, when the
                          view_class criterion matches
        """
        self._inject_asset(signals.plugin.inject_js, name, view_class,
                           subclasses, condition)

    def _inject_asset(self,
                      signal,
                      name,
                      view_class=None,
                      subclasses=True,
                      condition=None):
        """Injects an asset bundle into Indico's pages

        :param signal: the signal to use for injection
        :param name: Name of the bundle
        :param view_class: If a WP class is specified, only inject it into pages using that class
        :param subclasses: also inject into subclasses of `view_class`
        :param condition: a callable to determine whether to inject or not. only called, when the
                          view_class criterion matches
        """
        def _do_inject(sender):
            if condition is None or condition():
                return self.assets[name].urls()

        if view_class is None:
            self.connect(signal, _do_inject)
        elif not subclasses:
            self.connect(signal, _do_inject, sender=view_class)
        else:

            def _func(sender):
                if issubclass(sender, view_class):
                    return _do_inject(sender)

            self.connect(signal, _func)

    def inject_vars_js(self):
        """Returns a string that will define variables for the plugin in the vars.js file"""
        vars_js = self.get_vars_js()
        if vars_js:
            return 'var {}Plugin = {};'.format(self.name.title(),
                                               json.dumps(vars_js))

    def template_hook(self, name, receiver, priority=50, markup=True):
        """Registers a function to be called when a template hook is invoked.

        For details see :func:~`indico.web.flask.templating.register_template_hook`
        """
        register_template_hook(name, receiver, priority, markup, self)

    @classproperty
    @classmethod
    def logger(cls):
        return Logger.get('plugin.{}'.format(cls.name))

    @cached_classproperty
    @classmethod
    def settings(cls):
        """:class:`SettingsProxy` for the plugin's settings"""
        if cls.name is None:
            raise RuntimeError('Plugin has not been loaded yet')
        instance = cls.instance
        with instance.plugin_context(
        ):  # in case the default settings come from a property
            return SettingsProxy('plugin_{}'.format(cls.name),
                                 instance.default_settings,
                                 cls.strict_settings,
                                 acls=cls.acl_settings)

    @cached_classproperty
    @classmethod
    def event_settings(cls):
        """:class:`EventSettingsProxy` for the plugin's event-specific settings"""
        if cls.name is None:
            raise RuntimeError('Plugin has not been loaded yet')
        instance = cls.instance
        with instance.plugin_context(
        ):  # in case the default settings come from a property
            return EventSettingsProxy('plugin_{}'.format(cls.name),
                                      instance.default_event_settings,
                                      cls.strict_settings,
                                      acls=cls.acl_event_settings)

    @cached_classproperty
    @classmethod
    def user_settings(cls):
        """:class:`UserSettingsProxy` for the plugin's user-specific settings"""
        if cls.name is None:
            raise RuntimeError('Plugin has not been loaded yet')
        instance = cls.instance
        with instance.plugin_context(
        ):  # in case the default settings come from a property
            return UserSettingsProxy('plugin_{}'.format(cls.name),
                                     instance.default_user_settings,
                                     cls.strict_settings)
Пример #10
0
from __future__ import unicode_literals, print_function, division, absolute_import

from webassets import Environment, Bundle
from clldutils.path import Path

import clld


def skip(_in, out, **kw):
    """filter to skip content of assets which are fetched from CDN in production."""
    out.write('')  # pragma: no cover

_static_path = Path(clld.__file__).parent.joinpath('web', 'static').as_posix()
environment = Environment(
    _static_path, '/clld:web/static/', manifest='json:', auto_build=False)
environment.append_path(_static_path, url='/clld:web/static/')

bundles = {
    'js': [
        Bundle(
            'js/jquery.js',
            'js/leaflet-src.js',
            filters=(skip,)),
        'js/bootstrap.min.js',
        'js/jquery.dataTables.min.js',
        'js/oms.min.js',
        Bundle(
            'js/bootstrapx-clickover.js',
            'js/tree.jquery.js',
            'js/leaflet-providers.js',
            'js/leaflet.label.js',
class TestCompilation(unittest.TestCase):
    
    def setUp(self):
        res = dirname(__file__)+'/resources/'
        self.env = Environment(dirname(__file__)+"/out", '/media-prefix')
        self.env.cache = False
        self.env.manifest = False
        
        self.env.append_path(res+"assets", "/")
        self.env.append_path(res+"vendor", "/vendors")
        
        self.env.append_path(res, None)
        
        self.env.config["compass_bin"] = "/home/arkus/.gem/ruby/1.9.1/bin/compass"
        self.env.config["vendor_path"] = "vendor"
        
        #logging.basicConfig(level=logging.DEBUG)
        
    def get_bundle_output(self, test_name):
        f = StringIO()
        js = Bundle('scss/%s.scss' % test_name, filters=CompassConnectorFilter, output='%s.css' % test_name)
        self.env.register(test_name, js)
        js.build(output=f)
        
        return f.getvalue()

    def test_simple(self):
        o = self.get_bundle_output("test_simple")
        self.assertIn("color: red;", o)
    
    def test_simple_import(self):
        o = self.get_bundle_output("test_simple_imports")
        self.assertIn("color: red;", o)
        self.assertIn("(style.css)", o)
        self.assertIn("(/style.css)", o)

    def test_fonts(self):
        o = self.get_bundle_output("test_fonts")
        
        self.assertIn("vendor-inline-font: url('data:font/truetype;base64,AAE", o)
        self.assertIn("app-inline-font: url('data:font/truetype;base64,AAE", o)
        
        self.assertIn("url('/this.eot?#iefix')", o)
        self.assertIn("src: url('/fonts/empty.ttf');", o)
        self.assertIn("src: url('/vendors/fonts/vendor_empty.ttf');", o)
    
    def test_images(self):
        o = self.get_bundle_output("test_images")
        
        self.assertIn("vendor-image-url: url('/vendors/images/vendor_1x1.png?", o)
        self.assertIn("app-image-url: url('/images/image.png?", o)
        self.assertIn("width-app: 10px;", o)
        self.assertIn("width-vendor: 10px;", o)
        self.assertIn("image-inline: url('data:image/png;base64,iVB", o)
        self.assertIn("vendor-generated-image-busted: url('/media-prefix/generated-images/1x1.png?", o)
        self.assertIn("vendor-generated-image: url('/media-prefix/generated-images/1x1.png');", o)
        self.assertIn("generated-image-busted: url('/media-prefix/generated-images/1x1.png?", o)
        self.assertIn("generated-image: url('/media-prefix/generated-images/1x1.png');", o)
        
    def test_sprites(self):
        o = self.get_bundle_output("test_sprites")
        
        self.assertIn("background: url('/media-prefix/generated-images/sprites/something-", o)
        self.assertIn("background: url('/media-prefix/generated-images/vendor-something-", o)

    def test_zurb(self):
        self.env.config["compass_plugins"] = {"zurb-foundation":"<99"}
        o = self.get_bundle_output("test_zurb")
        self.assertIn("body", o)
Пример #12
0
import clld


def skip(_in, out, **kw):
    """filter to skip content of assets which are fetched from CDN in production.
    """
    out.write('')  # pragma: no cover

environment = Environment(
    path(clld.__file__).dirname().joinpath('web', 'static'),
    '/clld:web/static/',
    manifest='json:',
    auto_build=False)

environment.append_path(
    path(clld.__file__).dirname().joinpath('web', 'static'), url='/clld:web/static/')

bundles = {
    'js': [
        Bundle(
            'js/jquery-1.8.2.js',
            'js/leaflet-src.js',
            filters=(skip,)),
        'js/bootstrap.min.js',
        'js/jquery.dataTables.min.js',
        'js/oms.min.js',
        Bundle(
            'js/bootstrapx-clickover.js',
            'js/tree.jquery.js',
            'js/leaflet-providers.js',
            'js/leaflet.label.js',
Пример #13
0
    def load_environment(self):
        """Load an :class:`Environment` instance defined in the YAML file.

        Expects the following format:

        .. code-block:: yaml

            directory: ../static
            url: /media
            debug: True
            updater: timestamp
            config:
                compass_bin: /opt/compass
                another_custom_config_value: foo

            bundles:
                # ...

        All values, including ``directory`` and ``url`` are optional. The
        syntax for defining bundles is the same as for
        :meth:`~.YAMLLoader.load_bundles`.

        Sample usage::

            from webassets.loaders import YAMLLoader
            loader = YAMLLoader('asset.yml')
            env = loader.load_environment()

            env['some-bundle'].urls()
        """
        f, filename = self._open()
        try:
            obj = self.yaml.load(f) or {}

            env = Environment()

            # Load environment settings
            for setting in ('debug', 'cache', 'versions', 'url_expire',
                            'auto_build', 'url', 'directory',
                            # TODO: The deprecated values; remove at some point
                            'expire', 'updater'):
                if setting in obj:
                    setattr(env, setting, obj[setting])

            if 'load_path' in obj:
                load_path = obj['load_path']
                if load_path:
                    if isinstance(load_path, list):
                        env.load_path.extend(load_path)
                    else:
                        env.append_path(load_path)

            # Treat the 'directory' option special, make it relative to the
            # path of the YAML file, if we know it.
            if filename and 'directory' in env.config:
                env.directory = path.normpath(
                    path.join(path.dirname(filename),
                              env.config['directory']))

            # Load custom config options
            if 'config' in obj:
                env.config.update(obj['config'])

            # Load bundles
            bundles = self._get_bundles(obj.get('bundles', {}))
            for name, bundle in bundles.iteritems():
                env.register(name, bundle)

            return env
        finally:
            f.close()
Пример #14
0

def skip(_in, out, **kw):
    """filter to skip content of assets which are fetched from CDN in production.
    """
    out.write('')  # pragma: no cover


environment = Environment(path(clld.__file__).dirname().joinpath(
    'web', 'static'),
                          '/clld:web/static/',
                          manifest='json:',
                          auto_build=False)

environment.append_path(path(clld.__file__).dirname().joinpath(
    'web', 'static'),
                        url='/clld:web/static/')

bundles = {
    'js': [
        Bundle('js/jquery-1.8.2.js', 'js/leaflet-src.js', filters=(skip, )),
        'js/bootstrap.min.js',
        'js/jquery.dataTables.min.js',
        'js/oms.min.js',
        Bundle('js/bootstrapx-clickover.js',
               'js/tree.jquery.js',
               'js/leaflet-providers.js',
               'js/leaflet.label.js',
               'js/Control.FullScreen.js',
               'js/leaflet-hash.js',
               'js/clld.js',