Exemplo n.º 1
0
    def add_static_url(self, url_path, directory, endpoint=None, roles=None):
        """Add a new url rule for static files.

        :param endpoint: flask endpoint name for this url rule.
        :param url: subpath from application static url path. No heading or trailing
                    slash.
        :param directory: directory to serve content from.

        Example::

           app.add_static_url('myplugin',
                              '/path/to/myplugin/resources',
                              endpoint='myplugin_static')

        With default setup it will serve content from directory
        `/path/to/myplugin/resources` from url `http://.../static/myplugin`
        """
        url_path = self.static_url_path + '/' + url_path + '/<path:filename>'
        self.add_url_rule(url_path,
                          endpoint=endpoint,
                          view_func=partial(send_file_from_directory,
                                            directory=directory),
                          roles=roles)
        self.add_access_controller(endpoint,
                                   allow_access_for_roles(Anonymous),
                                   endpoint=True)
Exemplo n.º 2
0
  def add_static_url(self, url_path, directory, endpoint=None,
                     roles=None):
    """
    Adds a new url rule for static files.

    :param endpoint: flask endpoint name for this url rule.
    :param url: subpath from application static url path. No heading or trailing
                slash.
    :param directory: directory to serve content from.

    Example::

       app.add_static_url('myplugin',
                          '/path/to/myplugin/resources',
                          endpoint='myplugin_static')

    With default setup it will serve content from directory
    `/path/to/myplugin/resources` from url `http://.../static/myplugin`
    """
    url_path = self.static_url_path + '/' + url_path + '/<path:filename>'
    self.add_url_rule(url_path,
                      endpoint=endpoint,
                      view_func=partial(send_file_from_directory,
                                        directory=directory),
                      roles=roles)
    self.add_access_controller(endpoint, allow_access_for_roles(Anonymous),
                               endpoint=True)
Exemplo n.º 3
0
    def add_url_rule(self, rule, endpoint=None, view_func=None, roles=None, **options):
        """See :meth:`Flask.add_url_rule`.

        If `roles` parameter is present, it must be a
        :class:`abilian.service.security.models.Role` instance, or a list of
        Role instances.
        """
        super().add_url_rule(rule, endpoint, view_func, **options)

        if roles:
            self.add_access_controller(
                endpoint, allow_access_for_roles(roles), endpoint=True
            )
Exemplo n.º 4
0
  def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
    """
    See :meth:`Flask.add_url_rule`.

    If `roles` parameter is present, it must be a
    :class:`abilian.service.security.models.Role` instance, or a list of
    Role instances.
    """
    roles = options.pop('roles', None)
    super(Application, self).add_url_rule(rule, endpoint, view_func, **options)

    if roles:
      self.add_access_controller(endpoint, allow_access_for_roles(roles),
                                 endpoint=True)
Exemplo n.º 5
0
    def add_url_rule_with_role(
            self,
            rule: str,
            endpoint: str,
            view_func: Callable,
            roles: Collection[Role] = (),
            **options: Any,
    ) -> None:
        """See :meth:`Flask.add_url_rule`.

        If `roles` parameter is present, it must be a
        :class:`abilian.service.security.models.Role` instance, or a list of
        Role instances.
        """
        self.add_url_rule(rule, endpoint, view_func, **options)

        if roles:
            self.add_access_controller(endpoint,
                                       allow_access_for_roles(roles),
                                       endpoint=True)
Exemplo n.º 6
0
    def __init__(self, name=None, config=None, *args, **kwargs):
        kwargs.setdefault('instance_relative_config', True)
        name = name or __name__

        # used by make_config to determine if we try to load config from instance /
        # environment variable /...
        self._ABILIAN_INIT_TESTING_FLAG = (getattr(config, 'TESTING', False)
                                           if config else False)
        Flask.__init__(self, name, *args, **kwargs)
        del self._ABILIAN_INIT_TESTING_FLAG

        self._setup_script_manager()
        appcontext_pushed.connect(self._install_id_generator)
        ServiceManager.__init__(self)
        PluginManager.__init__(self)
        self.default_view = ViewRegistry()
        self.js_api = dict()

        if config:
            self.config.from_object(config)

        # at this point we have loaded all external config files:
        # SQLALCHEMY_DATABASE_URI is definitively fixed (it cannot be defined in
        # database AFAICT), and LOGGING_FILE cannot be set in DB settings.
        self.setup_logging()

        configured = bool(self.config.get('SQLALCHEMY_DATABASE_URI'))
        self.config['CONFIGURED'] = configured

        if not self.testing:
            self.init_sentry()

        if not configured:
            # set fixed secret_key so that any unconfigured worker will use, so that
            # session can be used during setup even if multiple processes are
            # processing requests.
            self.config['SECRET_KEY'] = 'abilian_setup_key'

        # time to load config bits from database: 'settings'
        # First init required stuff: db to make queries, and settings service
        extensions.db.init_app(self)
        settings_service.init_app(self)

        if configured:
            with self.app_context():
                try:
                    settings = self.services['settings'].namespace(
                        'config').as_dict()
                except sa.exc.DatabaseError as exc:
                    # we may get here if DB is not initialized and "settings" table is
                    # missing. Command "initdb" must be run to initialize db, but first we
                    # must pass app init
                    if not self.testing:
                        # durint tests this message will show up on every test, since db is
                        # always recreated
                        logging.error(exc.message)
                    self.db.session.rollback()
                else:
                    self.config.update(settings)

        if not self.config.get('FAVICO_URL'):
            self.config['FAVICO_URL'] = self.config.get('LOGO_URL')

        languages = self.config.get('BABEL_ACCEPT_LANGUAGES')
        if languages is None:
            languages = abilian.i18n.VALID_LANGUAGES_CODE
        else:
            languages = tuple(lang for lang in languages
                              if lang in abilian.i18n.VALID_LANGUAGES_CODE)
        self.config['BABEL_ACCEPT_LANGUAGES'] = languages

        self._jinja_loaders = list()
        self.register_jinja_loaders(
            jinja2.PackageLoader('abilian.web', 'templates'))

        js_filters = (('closure_js', )
                      if self.config.get('PRODUCTION', False) else None)

        self._assets_bundles = {
            'css': {
                'options':
                dict(filters=('less', 'cssmin'),
                     output='style-%(version)s.min.css')
            },
            'js-top': {
                'options':
                dict(output='top-%(version)s.min.js', filters=js_filters)
            },
            'js': {
                'options':
                dict(output='app-%(version)s.min.js', filters=js_filters)
            },
        }

        # bundles for JS translations
        for lang in languages:
            code = 'js-i18n-' + lang
            filename = 'lang-' + lang + '-%(version)s.min.js'
            self._assets_bundles[code] = {
                'options': dict(output=filename, filters=js_filters),
            }

        for http_error_code in (403, 404, 500):
            self.install_default_handler(http_error_code)

        with self.app_context():
            self.init_extensions()
            self.register_plugins()
            self.add_access_controller('static',
                                       allow_access_for_roles(Anonymous),
                                       endpoint=True)
            # debugtoolbar: this is needed to have it when not authenticated on a
            # private site. We cannot do this in init_debug_toolbar, since auth
            # service is not yet installed
            self.add_access_controller('debugtoolbar',
                                       allow_access_for_roles(Anonymous))
            self.add_access_controller('_debug_toolbar.static',
                                       allow_access_for_roles(Anonymous),
                                       endpoint=True)

        self.maybe_register_setup_wizard()
        self._finalize_assets_setup()
        # At this point all models should have been imported: time to configure
        # mappers. Normally Sqlalchemy does it when needed but mappers may be
        # configured inside sa.orm.class_mapper() which hides a misconfiguration: if
        # a mapper is misconfigured its exception is swallowed by
        # class_mapper(model) results in this laconic (and misleading) message:
        # "model is not mapped"
        sa.orm.configure_mappers()

        signals.components_registered.send(self)
        self.before_first_request(self._set_current_celery_app)
        self.before_first_request(lambda: signals.register_js_api.send(self))

        request_started.connect(self._setup_nav_and_breadcrumbs)

        # Initialize Abilian core services.
        # Must come after all entity classes have been declared.
        # Inherited from ServiceManager. Will need some configuration love later.
        if not self.config.get('TESTING', False):
            with self.app_context():
                self.start_services()
Exemplo n.º 7
0
    def __init__(self, name=None, config=None, *args, **kwargs):
        name = name or __name__

        instance_path = os.environ.get("FLASK_INSTANCE_PATH")
        if instance_path:
            kwargs["instance_path"] = instance_path
        else:
            kwargs.setdefault("instance_relative_config", True)

        # used by make_config to determine if we try to load config from
        # instance / environment variable /...
        self._ABILIAN_INIT_TESTING_FLAG = (getattr(config, "TESTING", False)
                                           if config else False)
        Flask.__init__(self, name, *args, **kwargs)
        del self._ABILIAN_INIT_TESTING_FLAG

        self._setup_script_manager()
        appcontext_pushed.connect(self._install_id_generator)

        ServiceManager.__init__(self)
        PluginManager.__init__(self)
        JinjaManagerMixin.__init__(self)

        self.default_view = ViewRegistry()
        self.js_api = dict()

        self.configure(config)

        # At this point we have loaded all external config files:
        # SQLALCHEMY_DATABASE_URI is definitively fixed (it cannot be defined in
        # database AFAICT), and LOGGING_FILE cannot be set in DB settings.
        self.setup_logging()

        configured = bool(self.config.get("SQLALCHEMY_DATABASE_URI"))
        self.config["CONFIGURED"] = configured

        if not self.testing:
            self.init_sentry()

        if not configured:
            # set fixed secret_key so that any unconfigured worker will use,
            # so that session can be used during setup even if
            # multiple processes are processing requests.
            self.config["SECRET_KEY"] = "abilian_setup_key"

        # time to load config bits from database: 'settings'
        # First init required stuff: db to make queries, and settings service
        extensions.db.init_app(self)
        settings_service.init_app(self)

        if configured:
            with self.app_context():
                try:
                    settings = self.services["settings"]
                    config = settings.namespace("config").as_dict()
                except sa.exc.DatabaseError as exc:
                    # We may get here if DB is not initialized and "settings"
                    # table is missing. Command "initdb" must be run to
                    # initialize db, but first we must pass app init.
                    if not self.testing:
                        # durint tests this message will show up on every test,
                        # since db is always recreated
                        logging.error(exc)
                    db.session.rollback()
                else:
                    self.config.update(config)

        if not self.config.get("FAVICO_URL"):
            self.config["FAVICO_URL"] = self.config.get("LOGO_URL")

        self.register_jinja_loaders(jinja2.PackageLoader("abilian.web"))

        self.init_assets()
        self.install_default_handlers()

        with self.app_context():
            self.init_extensions()
            self.register_plugins()
            self.add_access_controller("static",
                                       allow_access_for_roles(Anonymous),
                                       endpoint=True)
            # debugtoolbar: this is needed to have it when not authenticated
            # on a private site. We cannot do this in init_debug_toolbar,
            # since auth service is not yet installed.
            self.add_access_controller("debugtoolbar",
                                       allow_access_for_roles(Anonymous))
            self.add_access_controller(
                "_debug_toolbar.static",
                allow_access_for_roles(Anonymous),
                endpoint=True,
            )

        self.maybe_register_setup_wizard()
        self._finalize_assets_setup()

        # At this point all models should have been imported: time to configure
        # mappers. Normally Sqlalchemy does it when needed but mappers may be
        # configured inside sa.orm.class_mapper() which hides a
        # misconfiguration: if a mapper is misconfigured its exception is
        # swallowed by class_mapper(model) results in this laconic
        # (and misleading) message: "model is not mapped"
        sa.orm.configure_mappers()

        signals.components_registered.send(self)
        self.before_first_request(self._set_current_celery_app)
        self.before_first_request(lambda: signals.register_js_api.send(self))

        request_started.connect(self._setup_nav_and_breadcrumbs)

        # Initialize Abilian core services.
        # Must come after all entity classes have been declared.
        # Inherited from ServiceManager. Will need some configuration love
        # later.
        if not self.config.get("TESTING", False):
            with self.app_context():
                self.start_services()

        if os.environ.get("FLASK_VALIDATE_HTML"):
            # Workaround circular import
            from abilian.testing.validation import validate_response

            self.after_request(validate_response)
Exemplo n.º 8
0
  def __init__(self, name=None, config=None, *args, **kwargs):
    kwargs.setdefault('instance_relative_config', True)
    name = name or __name__

    # used by make_config to determine if we try to load config from instance /
    # environment variable /...
    self._ABILIAN_INIT_TESTING_FLAG = (getattr(config, 'TESTING', False)
                                       if config else False)
    Flask.__init__(self, name, *args, **kwargs)
    del self._ABILIAN_INIT_TESTING_FLAG

    self._setup_script_manager()
    appcontext_pushed.connect(self._install_id_generator)
    ServiceManager.__init__(self)
    PluginManager.__init__(self)
    self.default_view = ViewRegistry()
    self.js_api = dict()

    if config:
      self.config.from_object(config)

    # at this point we have loaded all external config files:
    # SQLALCHEMY_DATABASE_URI is definitively fixed (it cannot be defined in
    # database AFAICT), and LOGGING_FILE cannot be set in DB settings.
    self.setup_logging()

    configured = bool(self.config.get('SQLALCHEMY_DATABASE_URI'))
    self.config['CONFIGURED'] = configured

    if not self.testing:
      self.init_sentry()

    if not configured:
      # set fixed secret_key so that any unconfigured worker will use, so that
      # session can be used during setup even if multiple processes are
      # processing requests.
      self.config['SECRET_KEY'] = 'abilian_setup_key'

    # time to load config bits from database: 'settings'
    # First init required stuff: db to make queries, and settings service
    extensions.db.init_app(self)
    settings_service.init_app(self)

    if configured:
      with self.app_context():
        try:
          settings = self.services['settings'].namespace('config').as_dict()
        except sa.exc.DatabaseError as exc:
          # we may get here if DB is not initialized and "settings" table is
          # missing. Command "initdb" must be run to initialize db, but first we
          # must pass app init
          if not self.testing:
            # durint tests this message will show up on every test, since db is
            # always recreated
            logging.error(exc.message)
          self.db.session.rollback()
        else:
          self.config.update(settings)

    if not self.config.get('FAVICO_URL'):
      self.config['FAVICO_URL'] = self.config.get('LOGO_URL')

    languages = self.config.get('BABEL_ACCEPT_LANGUAGES')
    if languages is None:
      languages = abilian.i18n.VALID_LANGUAGES_CODE
    else:
      languages = tuple(lang for lang in languages
                        if lang in abilian.i18n.VALID_LANGUAGES_CODE)
    self.config['BABEL_ACCEPT_LANGUAGES'] = languages

    self._jinja_loaders = list()
    self.register_jinja_loaders(
      jinja2.PackageLoader('abilian.web', 'templates'))

    js_filters = (('closure_js',)
                  if self.config.get('PRODUCTION', False)
                  else None)

    self._assets_bundles = {
        'css': {'options': dict(filters=('less', 'cssmin'),
                                output='style-%(version)s.min.css',)},
        'js-top': {'options': dict(output='top-%(version)s.min.js',
                                   filters=js_filters,)},
        'js': {'options': dict(output='app-%(version)s.min.js',
                               filters=js_filters)},
    }

    # bundles for JS translations
    for lang in languages:
      code = 'js-i18n-' + lang
      filename = 'lang-' + lang + '-%(version)s.min.js'
      self._assets_bundles[code] = {
          'options': dict(output=filename, filters=js_filters),
      }

    for http_error_code in (403, 404, 500):
      self.install_default_handler(http_error_code)

    with self.app_context():
      self.init_extensions()
      self.register_plugins()
      self.add_access_controller('static', allow_access_for_roles(Anonymous),
                                 endpoint=True)
      # debugtoolbar: this is needed to have it when not authenticated on a
      # private site. We cannot do this in init_debug_toolbar, since auth
      # service is not yet installed
      self.add_access_controller('debugtoolbar',
                                 allow_access_for_roles(Anonymous),)
      self.add_access_controller('_debug_toolbar.static',
                                 allow_access_for_roles(Anonymous),
                                 endpoint=True)

    self.maybe_register_setup_wizard()
    self._finalize_assets_setup()
    # At this point all models should have been imported: time to configure
    # mappers. Normally Sqlalchemy does it when needed but mappers may be
    # configured inside sa.orm.class_mapper() which hides a misconfiguration: if
    # a mapper is misconfigured its exception is swallowed by
    # class_mapper(model) results in this laconic (and misleading) message:
    # "model is not mapped"
    sa.orm.configure_mappers()

    signals.components_registered.send(self)
    self.before_first_request(self._set_current_celery_app)
    self.before_first_request(
        lambda: signals.register_js_api.send(self)
    )

    request_started.connect(self._setup_nav_and_breadcrumbs)

    # Initialize Abilian core services.
    # Must come after all entity classes have been declared.
    # Inherited from ServiceManager. Will need some configuration love later.
    if not self.config.get('TESTING', False):
      with self.app_context():
        self.start_services()
Exemplo n.º 9
0
    def setup(self, config):
        self.configure(config)

        # At this point we have loaded all external config files:
        # SQLALCHEMY_DATABASE_URI is definitively fixed (it cannot be defined in
        # database AFAICT), and LOGGING_FILE cannot be set in DB settings.
        self.setup_logging()

        appcontext_pushed.connect(self.install_id_generator)

        if not self.testing:
            self.init_sentry()

        # time to load config bits from database: 'settings'
        # First init required stuff: db to make queries, and settings service
        extensions.db.init_app(self)
        settings_service.init_app(self)

        self.register_jinja_loaders(jinja2.PackageLoader("abilian.web"))
        self.init_assets()
        self.install_default_handlers()

        with self.app_context():
            self.init_extensions()
            self.register_plugins()
            self.add_access_controller(
                "static", allow_access_for_roles(Anonymous), endpoint=True
            )
            # debugtoolbar: this is needed to have it when not authenticated
            # on a private site. We cannot do this in init_debug_toolbar,
            # since auth service is not yet installed.
            self.add_access_controller(
                "debugtoolbar", allow_access_for_roles(Anonymous)
            )
            self.add_access_controller(
                "_debug_toolbar.static",
                allow_access_for_roles(Anonymous),
                endpoint=True,
            )

        # TODO: maybe reenable later
        # self.maybe_register_setup_wizard()

        self._finalize_assets_setup()

        # At this point all models should have been imported: time to configure
        # mappers. Normally Sqlalchemy does it when needed but mappers may be
        # configured inside sa.orm.class_mapper() which hides a
        # misconfiguration: if a mapper is misconfigured its exception is
        # swallowed by class_mapper(model) results in this laconic
        # (and misleading) message: "model is not mapped"
        sa.orm.configure_mappers()

        signals.components_registered.send(self)

        request_started.connect(self.setup_nav_and_breadcrumbs)
        init_hooks(self)

        # Initialize Abilian core services.
        # Must come after all entity classes have been declared.
        # Inherited from ServiceManager. Will need some configuration love
        # later.
        if not self.testing:
            with self.app_context():
                self.start_services()

        setup(self)
Exemplo n.º 10
0
    def setup(self, config: Optional[type]) -> None:
        self.configure(config)

        # At this point we have loaded all external config files:
        # SQLALCHEMY_DATABASE_URI is definitively fixed (it cannot be defined in
        # database AFAICT), and LOGGING_FILE cannot be set in DB settings.
        self.setup_logging()

        appcontext_pushed.connect(self.install_id_generator)

        if not self.testing:
            self.init_sentry()

        # time to load config bits from database: 'settings'
        # First init required stuff: db to make queries, and settings service
        extensions.db.init_app(self)
        settings_service.init_app(self)

        self.register_jinja_loaders(jinja2.PackageLoader("abilian.web"))
        self.init_assets()
        self.install_default_handlers()

        with self.app_context():
            self.init_extensions()
            self.register_plugins()
            self.add_access_controller("static",
                                       allow_access_for_roles(Anonymous),
                                       endpoint=True)
            # debugtoolbar: this is needed to have it when not authenticated
            # on a private site. We cannot do this in init_debug_toolbar,
            # since auth service is not yet installed.
            self.add_access_controller("debugtoolbar",
                                       allow_access_for_roles(Anonymous))
            self.add_access_controller(
                "_debug_toolbar.static",
                allow_access_for_roles(Anonymous),
                endpoint=True,
            )

        # TODO: maybe reenable later
        # self.maybe_register_setup_wizard()

        self._finalize_assets_setup()

        # At this point all models should have been imported: time to configure
        # mappers. Normally Sqlalchemy does it when needed but mappers may be
        # configured inside sa.orm.class_mapper() which hides a
        # misconfiguration: if a mapper is misconfigured its exception is
        # swallowed by class_mapper(model) results in this laconic
        # (and misleading) message: "model is not mapped"
        sa.orm.configure_mappers()

        signals.components_registered.send(self)

        request_started.connect(self.setup_nav_and_breadcrumbs)
        init_hooks(self)

        # Initialize Abilian core services.
        # Must come after all entity classes have been declared.
        # Inherited from ServiceManager. Will need some configuration love
        # later.
        if not self.testing:
            with self.app_context():
                self.start_services()

        setup(self)