def _get_object_path(current_path, current_object, path, default,
                         required):
        if len(path) == 0:
            result = dict(default)
            result.update(current_object)
            for key in required:
                if key not in result:
                    raise ConfigurationError(
                        'Missing configuration value for {}.{}.'.format(
                            '.'.join(current_path), key))
            return result

        k = path[0]
        if k not in current_object:
            raise ConfigurationError(
                'Missing configuration object for {}.{}.'.format(
                    '.'.join(current_path), k))

        current_path.append(k)

        if type(current_object[k]) != dict:
            raise ConfigurationError(
                'The configuration {} is not an object.'.format(
                    '.'.join(current_path)))

        return Config._get_object_path(current_path, current_object[k],
                                       path[1:], default, required)
    def get_logo_config():
        """
        Returns a dictionary of the configured file path's to the logos.

        Returns:
            dict: The configured paths to the logos wrapped in a dictionary.
        """
        assert Config._config is not None

        confederation_key = 'confederation'
        oereb_key = 'oereb'
        canton_key = 'canton'
        msg = 'The definition for "{key}" must be set. Got: {found_config}'
        logo_dict = Config._config.get('logo')
        if not logo_dict.get(confederation_key):
            raise ConfigurationError(
                msg.format(key=confederation_key, found_config=logo_dict))
        if not logo_dict.get(oereb_key):
            raise ConfigurationError(
                msg.format(key=oereb_key, found_config=logo_dict))
        if not logo_dict.get(canton_key):
            raise ConfigurationError(
                msg.format(key=canton_key, found_config=logo_dict))
        file_adapter = FileAdapter()
        confederation_logo = ImageRecord(
            file_adapter.read(logo_dict.get(confederation_key)))
        oereb_logo = ImageRecord(file_adapter.read(logo_dict.get(oereb_key)))
        canton_logo = ImageRecord(file_adapter.read(logo_dict.get(canton_key)))

        return {
            confederation_key: confederation_logo,
            oereb_key: oereb_logo,
            canton_key: canton_logo
        }
    def __init__(self, **kwargs):
        """

        Keyword Args:
            db_connection (str): A rfc1738 conform database connection string in the form of:
                ``<driver_name>://<username>:<password>@<database_host>:<port>/<database_name>``
            model (str): A valid dotted name string which leads to an importable representation of
                sqlalchemy.ext.declarative.DeclarativeMeta or the real class itself.
        """
        from pyramid_oereb import database_adapter

        if database_adapter:
            self._adapter_ = database_adapter
        else:
            raise ConfigurationError(
                'Adapter for database must be defined if you use database sources.'
            )
        if kwargs.get('db_connection'):
            self._key_ = kwargs.get('db_connection')
        else:
            raise ConfigurationError(
                '"db_connection" for source has to be defined in used yaml '
                'configuration file')
        if kwargs.get('model'):
            self._model_ = DottedNameResolver().maybe_resolve(
                kwargs.get('model'))
        else:
            raise ConfigurationError(
                '"model" for source has to be defined in used yaml configuration file'
            )
def parse(cfg_file, cfg_section, c2ctemplate_style=False):
    """
    Parses the defined YAML file and returns the defined section as dictionary.

    Args:
        cfg_file (str): The YAML file to be parsed.
        cfg_section (str): The section to be returned.

    Returns:
        dict: The parsed section as dictionary.
    """
    if cfg_file is None:
        raise ConfigurationError(
            'Missing configuration parameter "pyramid_oereb.cfg.file" or '
            '"pyramid_oereb.cfg.c2ctemplate.file".')
    if cfg_section is None:
        raise ConfigurationError(
            'Missing configuration parameter "pyramid_oereb.cfg.section".')

    try:
        if c2ctemplate_style:
            import c2c.template
            content = c2c.template.get_config(cfg_file)
        else:
            with open(cfg_file) as f:
                content = yaml.safe_load(f.read())
    except IOError as e:
        e.strerror = '{0}{1} \'{2}\', Current working directory is {3}'.format(
            e.strerror, e.args[1], e.filename, os.getcwd())
        raise
    cfg = content.get(cfg_section)
    if cfg is None:
        raise ConfigurationError(
            'YAML file contains no section "{0}"'.format(cfg_section))
    return cfg
Exemple #5
0
    def get_layer_config(theme_code):
        """
        Obtaining the layer configuration of a theme from config.

        Args:
            theme_code (str): The theme code.

        Returns:
            list: Layer index (int) and layer opacity (float).
        """
        assert Config._config is not None
        themes = Config._config.get('plrs')
        if themes and isinstance(themes, list):
            for theme in themes:
                if theme.get('code') == theme_code:
                    view_service = theme.get('view_service')
                    if view_service and isinstance(view_service, dict):
                        layer_index = view_service.get('layer_index')
                        layer_opacity = view_service.get('layer_opacity')
                        if layer_opacity is None:
                            raise ConfigurationError(
                                'For {} the "layer_opacity" was not found!'.format(theme_code)
                            )
                        if layer_index is None:
                            raise ConfigurationError(
                                'For {} the "layer_index" was not found!'.format(theme_code)
                            )
                        return layer_index, layer_opacity
        return None, None
Exemple #6
0
def check_database_config(config):
    from papaye.models import get_manager
    manager = get_manager(config)
    if manager.get_db_version() < manager.get_sw_version():
        raise ConfigurationError('Your database need to be updated! Run '
                                 '"papaye_evolve path_to_your_config_file.ini" command first')
    conn = config.registry._zodb_databases[''].open()
    if user_root_factory(conn) is None or repository_root_factory(conn) is None:
        raise ConfigurationError('Database does not exist! Run "papaye_init '
                                 'path_to_your_config_file.ini command first')
    return True
Exemple #7
0
    def __init__(self, **kwargs):
        """

        Keyword Args:
            db_connection (str): A rfc1738 conform database connection string in the form of:
                ``<driver_name>://<username>:<password>@<database_host>:<port>/<database_name>``
            model (str): A valid dotted name string which leads to an importable representation of
                sqlalchemy.ext.declarative.DeclarativeMeta or the real class itself.
        """
        from pyramid_oereb import database_adapter

        if database_adapter:
            self._adapter_ = database_adapter
        else:
            raise ConfigurationError(
                'Adapter for database must be defined if you use database sources.'
            )
        if kwargs.get('db_connection'):
            self._key_ = kwargs.get('db_connection')
        else:
            raise ConfigurationError(
                '"db_connection" for source has to be defined in used yaml '
                'configuration file')
        if kwargs.get('model'):
            self._model_ = DottedNameResolver().maybe_resolve(
                kwargs.get('model'))
        else:
            raise ConfigurationError(
                '"model" for source has to be defined in used yaml configuration file'
            )
        # check if database is available and wait until it might be or raise error
        timeout_target = time.time() + self.TIMEOUT
        db_healthy = False
        current_wait_position = 0
        sleep_period = 1.0
        while time.time() < timeout_target:
            db_healthy = self.health_check()
            if not db_healthy:
                current_wait_position += int(sleep_period)
                # 1.0 sets it to a second
                log.info(
                    'Waiting for the database {} more seconds ({})'.format(
                        self.TIMEOUT - current_wait_position, self._key_))
                time.sleep(sleep_period)
            else:
                break
        if not db_healthy:
            raise ConfigurationError(
                'Database was not reached until timeout of {} seconds ({})'.
                format(self.TIMEOUT, self._key_))
Exemple #8
0
def register_widget_template(template,
                             widget,
                             settings,
                             provides,
                             registry=None):
    """Register new widget template"""
    if not os.path.isfile(template):
        raise ConfigurationError("No such file", template)

    content_type = settings.get('content_type', 'text/html')
    macro = settings.get('macro')
    factory = WidgetTemplateFactory(template, content_type, macro)
    provides = settings.get('provides', provides)
    directlyProvides(factory, provides)

    # check context
    required = (settings.get('context',
                             Interface), settings.get('layer', IFormLayer),
                settings.get('form', None), settings.get('field',
                                                         None), widget)
    # update registry
    if registry is None:
        registry = settings.get('registry')
        if registry is None:
            registry = get_pyramid_registry()
    registry.registerAdapter(factory, required, provides,
                             settings.get('mode', INPUT_MODE))
Exemple #9
0
def get_magpie_url(container=None):
    # type: (Optional[AnySettingsContainer]) -> Str
    if container is None:
        LOGGER.warning(
            "Registry not specified, trying to find Magpie URL from environment"
        )
        url = get_constant("MAGPIE_URL",
                           raise_missing=False,
                           raise_not_set=False,
                           print_missing=False)
        if url:
            return url
        hostname = (
            get_constant("HOSTNAME", raise_not_set=False, raise_missing=False)
            or get_constant(
                "MAGPIE_HOST", raise_not_set=False, raise_missing=False))
        if not hostname:
            raise ConfigurationError(
                "Missing or unset MAGPIE_HOST or HOSTNAME value.")
        magpie_port = get_constant("MAGPIE_PORT", raise_not_set=False)
        magpie_scheme = get_constant("MAGPIE_SCHEME",
                                     raise_not_set=False,
                                     raise_missing=False,
                                     default_value="http")
        return "{}://{}{}".format(
            magpie_scheme, hostname,
            ":{}".format(magpie_port) if magpie_port else "")
    try:
        # add "http" scheme to url if omitted from config since further 'requests' calls fail without it
        # mostly for testing when only "localhost" is specified
        # otherwise config should explicitly define it with 'MAGPIE_URL' env or 'magpie.url' config
        settings = get_settings(container)
        url_parsed = urlparse(
            get_constant("MAGPIE_URL", settings, "magpie.url").strip("/"))
        if url_parsed.scheme in ["http", "https"]:
            return url_parsed.geturl()
        magpie_url = "http://{}".format(url_parsed.geturl())
        print_log(
            "Missing scheme from settings URL, new value: '{}'".format(
                magpie_url), LOGGER, logging.WARNING)
        return magpie_url
    except AttributeError:
        # If magpie.url does not exist, calling strip fct over None will raise this issue
        raise ConfigurationError(
            "MAGPIE_URL or magpie.url config cannot be found")
Exemple #10
0
def validate_config(config, prefix):
    settings = config.get_settings()

    if prefix + 'api_key' not in settings:
        raise ConfigurationError(
            "Megaphone API key must be provided for {}".format(prefix))
    api_key = settings[prefix + 'api_key']

    if prefix + 'url' not in settings:
        raise ConfigurationError(
            "Megaphone URL must be provided for {}".format(prefix))
    url = settings[prefix + 'url']

    if prefix + 'broadcaster_id' not in settings:
        raise ConfigurationError(
            "Megaphone broadcaster_id must be provided for {}".format(prefix))
    broadcaster_id = settings[prefix + 'broadcaster_id']

    return MegaphoneConfig(api_key, url, broadcaster_id)
Exemple #11
0
def register_workflow(config, workflow, type_, content_type=None):
    if content_type is None:
        content_type = IDefaultWorkflow

    reg = config.registry
    if not reg.content.exists(content_type):
        raise ConfigurationError('Workflow %s registered for content_type %s '
                                 'which does not exist.' %
                                 (workflow, content_type))

    reg.workflow.add(workflow, content_type)
Exemple #12
0
def get_phoenix_url(container=None):
    # type: (Optional[AnySettingsContainer]) -> Str
    hostname = (get_constant(
        "PHOENIX_HOST", container, raise_missing=False, raise_not_set=False)
                or get_constant(
                    "HOSTNAME", raise_missing=False, raise_not_set=False))
    if not hostname:
        raise ConfigurationError(
            "Missing or unset PHOENIX_HOST or HOSTNAME value.")
    phoenix_port = get_constant("PHOENIX_PORT", raise_not_set=False)
    return "https://{0}{1}".format(
        hostname, ":{}".format(phoenix_port) if phoenix_port else "")
Exemple #13
0
def includeme(config):
    config.scan(__name__)
    settings = config.registry.settings

    if not 'persona.audiences' in settings:
        raise ConfigurationError(AUDIENCES_MESSAGE)
    # Construct a browserid Verifier using the configured audience.
    # This will pre-compile some regexes to reduce per-request overhead.
    verifier_factory = config.maybe_dotted(settings.get('persona.verifier',
                                                        'browserid.RemoteVerifier'))
    audiences = aslist(settings['persona.audiences'])
    config.registry['persona.verifier'] = verifier_factory(audiences)
Exemple #14
0
def find_megaphone_prefix(registry):
    # FIXME: this assumes only one Megaphone server per config
    listeners = aslist(registry.settings['event_listeners'])
    for listener in listeners:
        prefix = 'event_listeners.{}.'.format(listener)
        listener_modpath = registry.settings['{}use'.format(prefix)]
        # FIXME: maybe be smarter about the current module's path?
        if listener_modpath.startswith('kinto_megaphone.'):
            return prefix

    raise ConfigurationError(
        "No megaphone listeners configured. Listeners are {}".format(
            listeners))
Exemple #15
0
 def callback(context, name, widget):  # pylint: disable=unused-argument
     template = os.path.join(
         os.path.dirname(inspect.getfile(inspect.getmodule(widget))),
         settings.get('template'))
     if not os.path.isfile(template):
         raise ConfigurationError("No such file", template)
     # check registry
     registry = settings.get('registry')
     if registry is None:
         config = context.config.with_package(info.module)  # pylint: disable=no-member
         registry = config.registry
     register_widget_template(template, widget, settings,
                              self.interface, registry)
Exemple #16
0
def override_widget_layout(widget, **settings):
    """Override layout template for a given class

    This function can be used to override a class layout template without using ZCML.
    Settings are the same as for @layout_config decorator.
    """
    template = settings.get('template', '')
    if not template:
        raise ConfigurationError("No template specified")
    if not template.startswith('/'):
        stack = inspect.stack()[1]
        template = os.path.join(
            os.path.dirname(inspect.getfile(inspect.getmodule(stack[0]))),
            template)
    register_widget_template(template, widget, settings, IWidgetLayoutTemplate)
Exemple #17
0
 def __init__(self, **settings):  # pylint: disable=too-many-branches
     if 'name' not in settings:
         raise ConfigurationError(
             "Missing 'name' argument for form definition")
     if 'for_' in settings:
         if settings.get('context') is None:
             settings['context'] = settings.pop('for_')
     if 'layer' in settings:
         settings['request_type'] = settings.pop('layer')
     # get AJAX settings
     settings['ajax'] = ajax_settings = {}
     if 'context' in settings:
         ajax_settings['context'] = settings.get('context')
     if 'ajax_name' in settings:
         ajax_settings['name'] = settings.pop('ajax_name')
     else:
         ajax_settings['name'] = settings['name'].replace('.html', '.json')
     if 'ajax_base' in settings:
         ajax_settings['base'] = settings.pop('ajax_base')
     if 'ajax_implements' in settings:
         ajax_settings['implements'] = settings.pop('ajax_implements')
     if 'ajax_method' in settings:
         method = settings.pop('ajax_method')
         if method is not None:
             ajax_settings['request_method'] = method
     else:
         ajax_settings['request_method'] = 'POST'
     if 'ajax_permission' in settings:
         ajax_settings['permission'] = settings.pop('ajax_permission')
     if 'ajax_renderer' in settings:
         renderer = settings.pop('ajax_renderer')
         if renderer is not None:
             ajax_settings['renderer'] = renderer
     else:
         ajax_settings['renderer'] = 'json'
     if 'ajax_xhr' in settings:
         xhr = settings.pop('ajax_xhr')
         if xhr is not None:
             ajax_settings['xhr'] = xhr
     else:
         ajax_settings['xhr'] = True
     if 'ajax_require_csrf' in settings:
         csrf = settings.pop('ajax_require_csrf')
         if csrf is not None:
             ajax_settings['require_csrf'] = csrf
     self.__dict__.update(settings)
Exemple #18
0
def load_from_config(config, prefix):
    mp_config = validate_config(config, prefix)

    settings = config.get_settings()
    if prefix + "match_kinto_changes" not in settings:
        ERROR_MSG = ("Resources to filter must be provided to kinto_changes "
                     "using match_kinto_changes")
        raise ConfigurationError(ERROR_MSG)
    included_resources = aslist(settings[prefix + "match_kinto_changes"])

    excluded_resources = aslist(settings.get(prefix + "except_kinto_changes", ""))

    client = megaphone.Megaphone(mp_config.url, mp_config.api_key)
    listener = KintoChangesListener(
        client, mp_config.broadcaster_id,
        included_resources, excluded_resources)
    config.add_subscriber(listener._convert_resources, pyramid.events.ApplicationCreated)
    return listener
Exemple #19
0
def add_workflow(config, workflow, content_types=(None,)):
    """Configurator method for adding a workflow.

    If no **content_types** is given, workflow is registered globally.

    :param config: Pyramid configurator
    :param workflow: :class:`Workflow` instance
    :param content_types: Register workflow for given content_types
    :type content_types: iterable

    :raises: :exc:`ConfigurationError` if :meth:`Workflow.check` fails
    :raises: :exc:`ConfigurationError` if **content_type** does not exist
    :raises: :exc:`DoesNotImplement` if **workflow** does not
             implement IWorkflow
    """
    if not IWorkflow.providedBy(workflow):
        raise ValueError('Not a workflow')

    try:
        workflow.check()
    except WorkflowError as why:
        raise ConfigurationError(str(why))

    intr = config.introspectable(
        'pyramid workflows',
        (IWorkflow, content_types, workflow.type),
        content_types,
        'pyramid workflow',
        )
    intr['workflow'] = workflow
    intr['type'] = workflow.type
    intr['content_types'] = content_types

    for content_type in content_types:
        config.action((IWorkflow, content_type, workflow.type),
                      callable=register_workflow,
                      introspectables=(intr,),
                      order=9999,
                      args=(config, workflow, workflow.type, content_type))
Exemple #20
0
def get_twitcher_protected_service_url(magpie_service_name, hostname=None):
    twitcher_proxy_url = get_constant("TWITCHER_PROTECTED_URL",
                                      raise_not_set=False)
    if not twitcher_proxy_url:
        twitcher_proxy = get_constant("TWITCHER_PROTECTED_PATH",
                                      raise_not_set=False)
        if not twitcher_proxy.endswith("/"):
            twitcher_proxy = twitcher_proxy + "/"
        if not twitcher_proxy.startswith("/"):
            twitcher_proxy = "/" + twitcher_proxy
        if not twitcher_proxy.startswith("/twitcher"):
            twitcher_proxy = "/twitcher" + twitcher_proxy
        hostname = (hostname or get_constant(
            "TWITCHER_HOST", raise_not_set=False, raise_missing=False)
                    or get_constant(
                        "HOSTNAME", raise_not_set=False, raise_missing=False))
        if not hostname:
            raise ConfigurationError(
                "Missing or unset TWITCHER_PROTECTED_URL, TWITCHER_HOST or HOSTNAME value."
            )
        twitcher_proxy_url = "https://{0}{1}".format(hostname, twitcher_proxy)
    twitcher_proxy_url = twitcher_proxy_url.rstrip("/")
    return "{0}/{1}".format(twitcher_proxy_url, magpie_service_name)
def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    # inject the url from the environment
    settings['sqlalchemy.url'] = os.environ.get(
        'DATABASE_URL', 'postgresql://cewing:@localhost:5432/lj2')
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine

    # authn/authz configuration
    auth_secret = os.environ.get('LJ_AUTH_SECRET', 'itsaseekrit')
    authentication_policy = AuthTktAuthenticationPolicy(
        secret=auth_secret,
        hashalg='sha512',
        callback=groupfinder,
    )
    authorization_policy = ACLAuthorizationPolicy()

    config = Configurator(
        settings=settings,
        authentication_policy=authentication_policy,
        authorization_policy=authorization_policy,
        root_factory=DefaultRoot,
    )

    # add a view predicate to validate api keys:
    config.add_view_predicate('valid_api_key', APIKeyPredicate)

    # github authentication configuration:
    config.include('velruse.providers.github')
    github_key = os.environ.get('LJ_GITHUB_KEY', None)
    github_secret = os.environ.get('LJ_GITHUB_SECRET', None)
    if not github_key and not github_secret:
        raise ConfigurationError(
            'Github Login requires LJ_GITHUB_SECRET and LJ_GITHUB_KEY set in the environment'
        )
    config.add_github_login(
        consumer_key=github_key,
        consumer_secret=github_secret,
        scope=settings.get('velruse.providers.github.scope',
                           'user, public_repo'),
    )
    # provide constructing the login url as a request method
    config.add_request_method(lambda req, svc='github': login_url(req, svc),
                              name='login_url')

    # session configuration
    session_secret = os.environ.get('LJ_SESSION_SECRET', 'itsaseekrit')
    session_factory = SignedCookieSessionFactory(session_secret)
    config.set_session_factory(session_factory)

    # templating configuration
    config.include('pyramid_jinja2')

    # view configuration
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('home', '/')
    config.add_route('mine', '/mine')
    config.add_route('about', '/about')
    config.add_route('create', '/entry/create')
    config.add_route('entry',
                     '/entry/{id:\d+}',
                     factory=EntryRoot,
                     traverse='/{id:\d+}')
    config.add_route('edit',
                     '/entry/{id:\d+}/edit',
                     factory=EntryRoot,
                     traverse='/{id:\d+}')
    config.add_route('delete',
                     '/entry/{id:\d+}/delete',
                     factory=EntryRoot,
                     traverse='/{id:\d+}')
    config.add_route('apikey', '/api/key')
    config.add_route('export', '/api/export')
    config.add_route('logout', '/logout')

    # add user to the request
    config.add_request_method(get_user, 'user', reify=True)
    # approved and admin usernames, too
    config.add_request_method(get_approved_users, 'approved', reify=True)
    config.add_request_method(get_admin_users, 'admins', reify=True)
    config.add_request_method(get_active_courses, 'courses', reify=True)

    config.scan()

    return config.make_wsgi_app()
Exemple #22
0
def add_panel(config,
              panel=None,
              name="",
              context=None,
              renderer=None,
              attr=None):
    """ Add a panel configuration to the current
    configuration state.

    Arguments

    panel

      A panel callable or a dotted Python name
      which refers to a panel callable.  This argument is required
      unless a ``renderer`` argument also exists.  If a
      ``renderer`` argument is passed, and a ``panel`` argument is
      not provided, the panel callable defaults to a callable that
      returns an empty dictionary.

    attr

      The panel machinery defaults to using the ``__call__`` method
      of the panel callable (or the function itself, if the
      panel callable is a function) to obtain a response.  The
      ``attr`` value allows you to vary the method attribute used
      to obtain the response.  For example, if your panel was a
      class, and the class has a method named ``index`` and you
      wanted to use this method instead of the class' ``__call__``
      method to return the response, you'd say ``attr="index"`` in the
      panel configuration for the panel.  This is
      most useful when the panel definition is a class.

    renderer

      This is either a single string term (e.g. ``json``) or a
      string implying a path or asset specification
      (e.g. ``templates/panels.pt``) naming a renderer
      implementation.  If the ``renderer`` value does not contain
      a dot ``.``, the specified string will be used to look up a
      renderer implementation, and that renderer implementation
      will be used to construct a response from the panel return
      value.  If the ``renderer`` value contains a dot (``.``),
      the specified term will be treated as a path, and the
      filename extension of the last element in the path will be
      used to look up the renderer implementation, which will be
      passed the full path.  The renderer implementation will be
      used to construct a response from the panel return
      value.

      Note that if the panel itself returns an instance of `basestring` (or just
      `str` in Python 3), the specified renderer implementation is never
      called.

      When the renderer is a path, although a path is usually just
      a simple relative pathname (e.g. ``templates/foo.pt``,
      implying that a template named "foo.pt" is in the
      "templates" directory relative to the directory of the
      current package of the Configurator), a path can be
      absolute, starting with a slash on UNIX or a drive letter
      prefix on Windows.  The path can alternately be an
      asset specification in the form
      ``some.dotted.package_name:relative/path``, making it
      possible to address template assets which live in a
      separate package.

      The ``renderer`` attribute is optional.  If it is not
      defined, the "null" renderer is assumed (no rendering is
      performed and the value is passed back to the upstream
      Pyramid machinery unmodified).

    name

      The optional panel name, which defaults to an empty string.

    context

      An object or a dotted Python name referring to an
      interface or class object that the context must be
      an instance of, *or* the interface that the
      context must provide in order for this panel to be
      found and called.  This predicate is true when the
      context is an instance of the represented class or
      if the context provides the represented interface;
      it is otherwise false.
    """
    panel = config.maybe_dotted(panel)
    context = config.maybe_dotted(context)

    if not panel:
        if renderer:

            def panel(context, request):
                return {}
        else:
            raise ConfigurationError('"panel" was not specified and '
                                     'no "renderer" specified')

    introspectables = []
    discriminator = ['panel', context, name, IPanel, attr]
    discriminator = tuple(discriminator)
    if inspect.isclass(panel) and attr:
        panel_desc = 'method %r of %s' % (attr,
                                          config.object_description(panel))
    else:
        panel_desc = config.object_description(panel)
    panel_intr = config.introspectable('panels', discriminator, panel_desc,
                                       'panel')
    panel_intr.update(
        dict(
            name=name,
            context=context,
            attr=attr,
            callable=panel,
        ))
    introspectables.append(panel_intr)

    def register(renderer=renderer):
        if renderer is None:
            # use default renderer if one exists (reg'd in phase 1)
            if config.registry.queryUtility(IRendererFactory) is not None:
                renderer = renderers.RendererHelper(name=None,
                                                    package=config.package,
                                                    registry=config.registry)

        elif isinstance(renderer, basestring):
            renderer = renderers.RendererHelper(name=renderer,
                                                package=config.package,
                                                registry=config.registry)

        def derive_rendered(wrapped, renderer):
            if renderer is None:
                return wrapped

            def derived(context, request, *args, **kw):
                result = wrapped(context, request, *args, **kw)
                if isinstance(result, basestring):
                    return result
                system = {
                    'panel': panel,
                    'renderer_info': renderer,
                    'context': context,
                    'request': request
                }
                rendered = renderer.render(result, system, request=request)
                return rendered

            return derived

        def derive_unicode(wrapped):
            def derived(context, request, *args, **kw):
                result = wrapped(context, request, *args, **kw)
                if not isinstance(result, unicode):
                    result = unicode(result, 'UTF-8')
                return result

            return derived

        derived_panel = derive_unicode(
            derive_rendered(_PanelMapper(attr)(panel), renderer))

        config.registry.registerAdapter(derived_panel, (context, ), IPanel,
                                        name)

        if renderer is not None and renderer.name and '.' in renderer.name:
            # it's a template
            tmpl_intr = config.introspectable('templates', discriminator,
                                              renderer.name, 'template')
            tmpl_intr.relate('panels', discriminator)
            tmpl_intr['name'] = renderer.name
            tmpl_intr['type'] = renderer.type
            tmpl_intr['renderer'] = renderer
            tmpl_intr.relate('renderer factories', renderer.type)
            introspectables.append(tmpl_intr)

    config.action(('panel', context, name),
                  register,
                  introspectables=introspectables)
Exemple #23
0
def includeme(config):
    """Include persona settings into a pyramid config.

    This function does the following:

        * Setup default authentication and authorization policies, and a default session factory.
          Keep in mind that the sessions are not encrypted, if you need to store secret information in it, please
          override the session factory.
        * Add two request attributes :
            * persona_js, the javascript code to inclue on a page to make persona work.
            * persona_button, the html for a default login/logout button.
        * Set login and logout views for use with persona.
        * Set a forbidden view with a loggin button
    """
    settings = config.get_settings()

    if 'persona.audience' in settings:
        settings['persona.audiences'] = settings['persona.audience']
        warnings.warn('persona.audience has been changed to persona.audiences, and may accept more than one value. '
                      'Please update you config file accordingly.', stacklevel=3)

    if not 'persona.audiences' in settings:
        raise ConfigurationError('Missing persona.audience settings. This is needed for security reasons. '
                                 'See https://developer.mozilla.org/en-US/docs/Persona/Security_Considerations for details.')

    # Default authentication and authorization policies. Those are needed to remember the userid.
    authz_policy = ACLAuthorizationPolicy()
    config.set_authorization_policy(authz_policy)
    secret = settings.get('persona.secret', '')
    authn_policy = AuthTktAuthenticationPolicy(secret, hashalg='sha512')
    config.set_authentication_policy(authn_policy)

    # A default session factory, needed for the csrf check.


    session_factory = SignedCookieSessionFactory(secret)
    config.set_session_factory(session_factory)

    # Either a secret must be provided or the session factory must be overriden.
    def check():
        if config.registry.queryUtility(ISessionFactory) == session_factory and not secret:
            raise ConfigurationError('If you do not override the session factory, you have to provide a persona.secret settings.')
    config.action(None, check, order=PHASE2_CONFIG)


    # Construct a browserid Verifier using the configured audience.
    # This will pre-compile some regexes to reduce per-request overhead.
    verifier_factory = config.maybe_dotted(settings.get('persona.verifier',
                                                        'browserid.RemoteVerifier'))
    audiences = aslist(settings['persona.audiences'])
    config.registry['persona.verifier'] = verifier_factory(audiences)

    # Parameters for the request API call
    request_params = {}
    for option in ('privacyPolicy', 'siteLogo', 'siteName', 'termsOfService', 'backgroundColor'):
        setting_name = 'persona.%s'%option
        if setting_name in settings:
            request_params[option] = settings[setting_name]
    config.registry['persona.request_params'] = json.dumps(request_params)

    # Login and logout views.
    login_route = settings.get('persona.login_route', 'login')
    config.registry['persona.login_route'] = login_route
    login_path = settings.get('persona.login_path', '/login')
    config.add_route(login_route, login_path)
    config.add_view(login, route_name=login_route, check_csrf=True,
                    renderer='json',
                    permission=NO_PERMISSION_REQUIRED)

    logout_route = settings.get('persona.logout_route', 'logout')
    config.registry['persona.logout_route'] = logout_route
    logout_path = settings.get('persona.logout_path', '/logout')
    config.add_route(logout_route, logout_path)
    config.add_view(logout, route_name=logout_route, check_csrf=True,
                    renderer='json',
                    permission=NO_PERMISSION_REQUIRED)

    # A simple 403 view, with a login button.
    config.add_forbidden_view(forbidden)

    # A quick access to the login button
    config.add_request_method(button, 'persona_button', reify=True)

    # The javascript needed by persona
    config.add_request_method(js, 'persona_js', reify=True)

    config.registry['persona.redirect_url_parameter'] = settings.get('persona.redirect_url_parameter', 'came_from')
Exemple #24
0
 def check():
     if config.registry.queryUtility(ISessionFactory) == session_factory and not secret:
         raise ConfigurationError('If you do not override the session factory, you have to provide a persona.secret settings.')
Exemple #25
0
def _create_theme_tables(configuration_yaml_path,
                         theme,
                         section='pyramid_oereb',
                         tables_only=False):
    """
    Create all tables defined in the specified module.

    Args:
        configuration_yaml_path (str): Path to the configuration file.
        theme (str): Code of the theme to create the tables for.
        section (str): Section within the specified configuration file used for pyramid_oereb. Default is
            'pyramid_oereb'.
        tables_only (bool): True to skip creation of schema. Default is False.
    """

    # Parse themes from configuration
    config = parse(configuration_yaml_path, section)
    themes = config.get('plrs')
    if not isinstance(themes, list):
        raise ConfigurationError('No list of themes found.')

    # Find the specified theme
    found = False
    for t in themes:
        if t.get('code') == theme:

            # Check required configuration parameters
            params = t.get('source').get('params')
            if not isinstance(params, dict):
                raise ConfigurationError(
                    'Missing params property in source definition.')
            if not ('db_connection' in params and 'models' in params):
                raise ConfigurationError(
                    'Params has to contain "db_connection" and "models" properties.'
                )

            # Create sqlalchemy engine for configured connection and load module containing models
            engine = create_engine(params.get('db_connection'), echo=True)
            models = DottedNameResolver().resolve(params.get('models'))

            if not tables_only:
                # Iterate over contained classes to collect needed schemas
                classes = inspect.getmembers(models, inspect.isclass)
                schemas = []
                create_schema_sql = 'CREATE SCHEMA IF NOT EXISTS {schema};'
                for c in classes:
                    class_ = c[1]
                    if hasattr(class_, '__table__'
                               ) and class_.__table__.schema not in schemas:
                        schemas.append(class_.__table__.schema)

                # Try to create missing schemas
                connection = engine.connect()
                try:
                    for schema in schemas:
                        connection.execute(
                            create_schema_sql.format(schema=schema))
                finally:
                    connection.close()

            # Create tables
            models.Base.metadata.create_all(engine)
            found = True
            break

    if not found:
        raise ValueError(
            'Specified theme "{theme}" not found in configuration.'.format(
                theme=theme))
    def get_bbox(geometry):
        """
        Return a bbox adapted for the map size specified in the print configuration
         and based on the geometry and a buffer (margin to add between the geometry
         and the border of the map).

        Args:
            geometry (list): The geometry (bbox) of the feature to center the map on.

        Returns:
            list: The bbox (meters) for the print.
        """
        print_conf = Config.get_object_path(
            'print', required=['basic_map_size', 'buffer'])
        print_buffer = print_conf['buffer']
        map_size = print_conf['basic_map_size']
        map_width = float(map_size[0])
        map_height = float(map_size[1])

        if print_buffer * 2 >= min(map_width, map_height):
            error_msg_txt = 'Your print buffer ({}px)'.format(print_buffer)
            error_msg_txt += ' applied on each side of the feature exceed the smaller'
            error_msg_txt += ' side of your map {}px.'.format(
                min(map_width, map_height))
            raise ConfigurationError(error_msg_txt)

        geom_bounds = geometry.bounds
        geom_width = float(geom_bounds[2] - geom_bounds[0])
        geom_height = float(geom_bounds[3] - geom_bounds[1])

        geom_ration = geom_width / geom_height
        map_ration = map_width / map_height

        # If the format of the map is naturally adapted to the format of the geometry
        is_format_adapted = geom_ration > map_ration

        if is_format_adapted:
            # Part (percent) of the margin compared to the map width.
            margin_in_percent = 2 * print_buffer / map_width
            # Size of the margin in geom units.
            geom_margin = geom_width * margin_in_percent
            # Geom width with the margins (right and left).
            adapted_geom_width = geom_width + (2 * geom_margin)
            # Adapted geom height to the map height
            adapted_geom_height = (adapted_geom_width / map_width) * map_height
        else:
            # Part (percent) of the margin compared to the map height.
            margin_in_percent = 2 * print_buffer / map_height
            # Size of the margin in geom units.
            geom_margin = geom_height * margin_in_percent
            # Geom height with the buffer (top and bottom).
            adapted_geom_height = geom_height + (2 * geom_margin)
            # Adapted geom width to the map width
            adapted_geom_width = (adapted_geom_height / map_height) * map_width

        height_to_add = (adapted_geom_height - geom_height) / 2
        width_to_add = (adapted_geom_width - geom_width) / 2

        return [
            geom_bounds[0] - width_to_add,
            geom_bounds[1] - height_to_add,
            geom_bounds[2] + width_to_add,
            geom_bounds[3] + height_to_add,
        ]
Exemple #27
0
def add_layout(config,
               layout=None,
               template=None,
               name='',
               context=None,
               containment=None):
    """
    Add a layout configuration to the current configuration state.

    Arguments

    layout

        A layout class or dotted Python name which refers to a layout class.
        This argument is not required.  If the layout argument is not provided,
        a default layout class is used which merely has ``context`` and
        ``request`` as instance attributes.

    template

        A string implying a path or an asset specification for a template file.
        The file referred to by this argument must have a suffix that maps to a
        known renderer. This template will be available to other templates as
        the renderer global ``main_template``.  This argument is required.

    name

        The layout name.

    context

        An object or a dotted Python name referring to an
        interface or class object that the context must be
        an instance of, *or* the interface that the
        context must provide in order for this layout to be
        found and used.  This predicate is true when the
        context is an instance of the represented class or
        if the context provides the represented interface;
        it is otherwise false.

    containment

        This value should be a Python class or interface (or a
        dotted Python name) that an object in the
        lineage of the context must provide in order for this view
        to be found and called.  The nodes in your object graph must be
        "location-aware" to use this feature.
    """
    layout = config.maybe_dotted(layout)
    context = config.maybe_dotted(context)
    containment = config.maybe_dotted(containment)

    if layout is None:

        class layout(object):
            def __init__(self, context, request):
                self.context = context
                self.request = request

    if template is None:
        raise ConfigurationError('"template" is required')

    introspectables = []
    discriminator = ['layout', context, name, ILayout]
    discriminator = tuple(discriminator)
    layout_desc = 'Layout %s' % (config.object_description(layout))
    layout_intr = config.introspectable('layouts', discriminator, layout_desc,
                                        'layout')

    def register(template=template):
        if isinstance(template, basestring):
            template = renderers.RendererHelper(name=template,
                                                package=config.package,
                                                registry=config.registry)

        layout_intr.update(
            dict(
                name=name,
                filename=template.name,
                context=context,
                callable=layout,
            ))
        introspectables.append(layout_intr)

        def derived_layout(context, request):
            wrapped = layout(context, request)
            wrapped.__layout__ = name
            wrapped.__template__ = template
            wrapped.__config_package__ = config.package
            return wrapped

        r_context = context
        if r_context is None:
            r_context = Interface
        if not IInterface.providedBy(r_context):
            r_context = implementedBy(r_context)

        reg_layout = config.registry.adapters.lookup((r_context, ),
                                                     ILayout,
                                                     name=name)
        if isinstance(reg_layout, _MultiLayout):
            reg_layout[containment] = derived_layout
            return
        elif containment:
            reg_layout = _MultiLayout(reg_layout)
            reg_layout[containment] = derived_layout
        else:
            reg_layout = derived_layout

        config.registry.registerAdapter(reg_layout, (context, ),
                                        ILayout,
                                        name=name)

    config.action(('layout', context, name, containment),
                  register,
                  introspectables=introspectables)
def add_resource(self, handler, member_name, collection_name, **kwargs):
    """ Add some RESTful routes for a resource handler.
    
    This function should never be called directly; instead the
    ``pyramid_routehelper.includeme`` function should be used to include this
    function into an application; the function will thereafter be available
    as a method of the resulting configurator.

    The concept of a web resource maps somewhat directly to 'CRUD' 
    operations. The overlying things to keep in mind is that
    adding a resource handler is about handling creating, viewing, and
    editing that resource.
    
    ``handler`` is a dotted name of (or direct reference to) a
    Python handler class,
    e.g. ``'my.package.handlers.MyHandler'``.
    
    ``member_name`` should be the appropriate singular version of the resource
    given your locale and used with members of the collection.
    
    ``collection_name`` will be used to refer to the resource collection methods
    and should be a plural version of the member_name argument.
    
    All keyword arguments are optional.
    
    ``collection``
        Additional action mappings used to manipulate/view the
        entire set of resources provided by the handler.
        
        Example::
            
            config.add_resource('myproject.handlers:MessageHandler', 'message', 'messages', collection={'rss':'GET'})
            # GET /messages/rss (maps to the rss action)
            # also adds named route "rss_message"
    
    ``member``
        Additional action mappings used to access an individual
        'member' of this handler's resources.
        
        Example::
            
            config.add_resource('myproject.handlers:MessageHandler', 'message', 'messages', member={'mark':'POST'})
            # POST /messages/1/mark (maps to the mark action)
            # also adds named route "mark_message"
    
    ``new``
        Action mappings that involve dealing with a new member in
        the controller resources.
        
        Example::
            
            config.add_resource('myproject.handlers:MessageHandler', 'message', 'messages',  new={'preview':'POST'})
            # POST /messages/new/preview (maps to the preview action)
            # also adds a url named "preview_new_message"
    
    ``path_prefix``
        Prepends the URL path for the Route with the path_prefix
        given. This is most useful for cases where you want to mix
        resources or relations between resources.
    
    ``name_prefix``
        Perpends the route names that are generated with the
        name_prefix given. Combined with the path_prefix option,
        it's easy to generate route names and paths that represent
        resources that are in relations.
        
        Example::
            
            config.add_resource('myproject.handlers:CategoryHandler', 'message', 'messages',
                path_prefix='/category/:category_id', 
                name_prefix="category_")
            # GET /category/7/messages/1
            # has named route "category_message"
            
    ``parent_resource`` 
        A ``dict`` containing information about the parent
        resource, for creating a nested resource. It should contain
        the ``member_name`` and ``collection_name`` of the parent
        resource.

        If ``parent_resource`` is supplied and ``path_prefix``
        isn't, ``path_prefix`` will be generated from
        ``parent_resource`` as
        "<parent collection name>/:<parent member name>_id". 

        If ``parent_resource`` is supplied and ``name_prefix``
        isn't, ``name_prefix`` will be generated from
        ``parent_resource`` as  "<parent member name>_". 

        Example:: 

            >>> from pyramid.url import route_path
            >>> config.add_resource('myproject.handlers:LocationHandler', 'location', 'locations', 
            ...            parent_resource=dict(member_name='region', 
            ...                                 collection_name='regions'))
            >>> # path_prefix is "regions/:region_id" 
            >>> # name prefix is "region_"  
            >>> route_path('region_locations', region_id=13) 
            '/regions/13/locations'
            >>> route_path('region_new_location', region_id=13) 
            '/regions/13/locations/new'
            >>> route_path('region_location', region_id=13, id=60) 
            '/regions/13/locations/60'
            >>> route_path('region_edit_location', region_id=13, id=60) 
            '/regions/13/locations/60/edit'

        Overriding generated ``path_prefix``::

            >>> config.add_resource('myproject.handlers:LocationHandler', 'location', 'locations', 
            ...            parent_resource=dict(member_name='region',
            ...                                 collection_name='regions'),
            ...            path_prefix='areas/:area_id')
            >>> # name prefix is "region_"
            >>> route_path('region_locations', area_id=51)
            '/areas/51/locations'

        Overriding generated ``name_prefix``::

            >>> config.add_resource('myproject.handlers:LocationHandler', 'location', 'locations', 
            ...            parent_resource=dict(member_name='region',
            ...                                 collection_name='regions'),
            ...            name_prefix='')
            >>> # path_prefix is "regions/:region_id" 
            >>> route_path('locations', region_id=51)
            '/regions/51/locations'
    """
    handler = self.maybe_dotted(handler)
    
    action_kwargs = {}
    for name,meth in inspect.getmembers(handler, inspect.ismethod):
        if hasattr(meth, '__exposed__'):
            for settings in meth.__exposed__:
                config_settings = settings.copy()
                action_name = config_settings.pop('alt_for', name)

                # If format is not set, use the route that doesn't specify a format
                if 'format' not in config_settings:
                    if 'default' in action_kwargs.get(action_name,{}):
                        raise ConfigurationError("Two methods have been decorated without specifying a format.")
                    else:
                        action_kwargs.setdefault(action_name, {})['default'] = config_settings
                # Otherwise, append to the list of view config settings for formatted views
                else:
                    config_settings['attr'] = name
                    action_kwargs.setdefault(action_name, {}).setdefault('formatted',[]).append(config_settings)
                
    collection = kwargs.pop('collection', {})
    member = kwargs.pop('member', {})
    new = kwargs.pop('new', {})
    path_prefix = kwargs.pop('path_prefix', None)
    name_prefix = kwargs.pop('name_prefix', None)
    parent_resource = kwargs.pop('parent_resource', None)
    
    if parent_resource is not None:
        if path_prefix is None:
            path_prefix = '%s/:%s_id' % (parent_resource['collection_name'], parent_resource['member_name'])
        if name_prefix is None:
            name_prefix = '%s_' % parent_resource['member_name']
    else:
        if path_prefix is None: path_prefix = ''
        if name_prefix is None: name_prefix = ''
    
    member['edit'] = 'GET'
    new['new'] = 'GET'
    
    def swap(dct, newdct):
        map(lambda (key,value): newdct.setdefault(value.upper(), []).append(key), dct.items())
        return newdct
    
    collection_methods = swap(collection, {})
    member_methods = swap(member, {})
    new_methods = swap(new, {})
    
    collection_methods.setdefault('POST', []).insert(0, 'create')
    member_methods.setdefault('PUT', []).insert(0, 'update')
    member_methods.setdefault('DELETE', []).insert(0, 'delete')
    
    # Continue porting code
    controller = strip_slashes(collection_name)
    path_prefix = strip_slashes(path_prefix)
    path_prefix = '/' + path_prefix
    if path_prefix and path_prefix != '/':
        path = path_prefix + '/' + controller
    else:
        path = '/' + controller
    collection_path = path
    new_path = path + '/new'
    member_path = path + '/:id'
    
    added_route_names = {}
    
    def add_route_if_new(self, route_name, path, **kwargs):
        if route_name not in added_route_names:
            self.add_route(route_name, path, **kwargs)
            added_route_names[route_name] = path

    def add_route_and_view(self, action, route_name, path, request_method='any'):
        if request_method != 'any':
            request_method = request_method.upper()
        else:
            request_method = None
        
        add_route_if_new(self, route_name, path, **kwargs)
        self.add_view(view=handler, attr=action, route_name=route_name, request_method=request_method, **action_kwargs.get(action, {}).get('default', {}))
        
        for format_kwargs in action_kwargs.get(action, {}).get('formatted', []):
            format = format_kwargs.pop('format')
            formatted_route_name = "%s_formatted_%s" % (format, route_name)
            
            add_route_if_new(self, formatted_route_name, "%s.%s" % (path, format), **kwargs)
            self.add_view(view=handler, attr=format_kwargs.pop('attr'), request_method=request_method,
                          route_name = "%s_formatted_%s" % (format, route_name), **format_kwargs)
    
    for method, lst in collection_methods.iteritems():
        primary = (method != 'GET' and lst.pop(0)) or None
        for action in lst:
            add_route_and_view(self, action, "%s%s_%s" % (name_prefix, action, collection_name), "%s/%s" % (collection_path,action))
        
        if primary:
            add_route_and_view(self, primary, name_prefix + collection_name, collection_path, method)
    
    # Add route and view for collection
    add_route_and_view(self, 'index', name_prefix + collection_name, collection_path, 'GET')
    
    for method, lst in new_methods.iteritems():
        for action in lst:
            path = (action == 'new' and new_path) or "%s/%s" % (new_path, action)
            name = "new_" + member_name
            if action != 'new':
                name = action + "_" + name
            formatted_path = (action == 'new' and new_path + '.:format') or "%s/%s.:format" % (new_path, action)
            add_route_and_view(self, action, name_prefix + name, path, method)
    
    for method, lst in member_methods.iteritems():
        if method not in ['POST', 'GET', 'any']:
            primary = lst.pop(0)
        else:
            primary = None
        for action in lst:
            add_route_and_view(self, action, '%s%s_%s' % (name_prefix, action, member_name), '%s/%s' % (member_path, action))
        
        if primary:
            add_route_and_view(self, primary, name_prefix + member_name, member_path, method)
    
    add_route_and_view(self, 'show', name_prefix + member_name, member_path, method)

# Submapper support


# Sub_domain option


# Converters??