Example #1
0
def get_open_url(request, item):
    """Convinience method to the a URL to 'open' the item."""
    from ringo.lib.security import has_permission
    if has_permission("update", item, request):
        return request.route_path(get_action_routename(item, "update"),
                                  id=item.id)
    elif has_permission("read", item, request):
        return request.route_path(get_action_routename(item, "read"),
                                  id=item.id)
    return None
Example #2
0
    def render(self, request):
        """Initialize renderer"""

        # Get the bundles_actions.
        # If bundle_actions is True, display checkboxes and more in the table.
        bundled_actions = []
        for action in get_item_actions(request, self.listing.clazz):
            if action.bundle and security.has_permission(
                    action.name.lower(), request.context, request):
                bundled_actions.append(action)
        table_id = self._get_table_id()
        table_config = self._render_js_config(request, table_id,
                                              bundled_actions)
        values = {
            'items': self.listing.items,
            'clazz': self.listing.clazz,
            'listing': self.listing,
            'request': request,
            '_': request.translate,
            's': security,
            'h': ringo.lib.helpers,
            'bundled_actions': bundled_actions,
            'tableconfig': self.config,
            'tableid': table_id,
            'dtconfig': table_config
        }
        return literal(self.template.render(**values))
Example #3
0
def filter_itemlist_for_user(request, baselist):
    """Returns a filterd baselist. The items are filterd based on
    the permission of the current user in the request. Only items are
    included where the given user has read access. This means:

     1. The user has aproriate role (read access)
     2. Is owner or member of the items group

    :request: Current request
    :baselist: BaseList instance
    :returns: Filtered BaseList instance

    """
    from ringo.lib.security import has_permission
    filtered_items = []
    if request.user and not request.user.has_role("admin"):
        # Iterate over all items and check if the user has generally
        # access to the item.
        for item in baselist.items:
            # Only check ownership if the item provides a uid.
            if has_permission('read', item, request):
                filtered_items.append(item)
        baselist.items = filtered_items
        # Mark this listing to be prefilterd for a user.
        baselist._user = request.user
    return baselist
Example #4
0
    def render(self, request):
        """Initialize renderer"""

        # Get the bundles_actions.
        # If bundle_actions is True, display checkboxes and more in the table.
        bundled_actions = []
        for action in get_item_actions(request, self.listing.clazz):
            if action.bundle and security.has_permission(action.name.lower(),
                                                         request.context,
                                                         request):
                bundled_actions.append(action)
        table_id = self._get_table_id()
        table_config = self._render_js_config(request, table_id)
        values = {'items': self.listing.items,
                  'clazz': self.listing.clazz,
                  'listing': self.listing,
                  'request': request,
                  '_': request.translate,
                  's': security,
                  'h': ringo.lib.helpers,
                  'bundled_actions': bundled_actions,
                  'tableconfig': self.config,
                  'tableid': table_id,
                  'dtconfig': table_config}
        return literal(self.template.render(**values))
Example #5
0
def handle_redirect_on_success(request, backurl=None):
    """Will return a redirect. If there has been a saved "backurl" the
    redirect will on on this url. In all other cases the function will
    try to determine if the item in the request can be opened in edit
    mode or not. If the current user is allowed to open the item in
    edit mode then the update view is called. Else the read view is
    called.

    :request: Current request
    :backurl: Optional. Set backurl manually. This will overwrite
    backurls saved in the session. 
    :returns: Redirect
    """

    item = get_item_from_request(request)
    clazz = request.context.__model__
    backurl = backurl or request.session.get("%s.backurl" % clazz)
    if backurl:
        # Redirect to the configured backurl.
        if request.session.get("%s.backurl" % clazz):
            del request.session["%s.backurl" % clazz]
            request.session.save()
        return HTTPFound(location=backurl)
    else:
        # Handle redirect after success.
        # Check if the user is allowed to call the url after saving
        if has_permission("update", item, request):
            route_name = get_action_routename(item, "update")
            url = request.route_path(route_name, id=item.id)
        else:
            route_name = get_action_routename(item, "read")
            url = request.route_path(route_name, id=item.id)
        return HTTPFound(location=url)
Example #6
0
def get_link_url(item, request, actionname=None, backurl=False):
    """Return a url to the given item. On default the link will be a
    link to the update or read view of the item depending on the
    permission. If the application is configured to open items in read
    mode on default the update action will not be checked. If the user
    does not have enough permissions than None is returned. Optionally
    you can provide the name of a action. In this case the url will be
    build for the given actionname if the user has enough
    permissions."""
    readmode = request.registry.settings.get("app.readmode") in [
        "True", "true"
    ]
    if isinstance(item, BaseItem):
        if actionname:
            from ringo.views.helpers import get_item_modul
            modul = get_item_modul(request, item)
            action = modul.get_action(actionname)
            if action is None:
                # This can happen if the action is not part of the modul
                # but a custum userdefined view. No permission checks
                # are done here yet.
                route_name = get_action_routename(item, actionname)
            else:
                permission = action.permission or action.name.lower()
                if security.has_permission(permission, item, request):
                    route_name = get_action_routename(item,
                                                      action.name.lower())
                else:
                    return None
        elif not readmode and security.has_permission("update", item, request):
            route_name = get_action_routename(item, 'update')
        elif security.has_permission("read", item, request):
            route_name = get_action_routename(item, 'read')
        else:
            return None

        query = {}
        if backurl:
            clazz = request.context.__model__
            query['backurl'] = request.session.get(
                '%s.backurl' % clazz) or request.current_route_path()
        return request.route_path(route_name, id=item.id, _query=query)
    return None
Example #7
0
def get_modules(request, display):
    #  FIXME: Circular import (ti) <2015-05-11 21:52> 
    from ringo.lib.security import has_permission
    user_moduls = []
    # The modules has been load already and are cached. So get them from
    # the cache
    for modul in request.cache_item_modul.all().values():
        # Only show the modul if it matches the desired display location
        # and if the modul has an "list" action which usually is used as
        # entry point into a modul.
        if (modul.display == display and modul.has_action('list')):
            clazz = dynamic_import(modul.clazzpath)
            if has_permission('list', clazz, request):
                user_moduls.append(modul)
    return user_moduls
Example #8
0
    def _get_template_values(self):
        values = FieldRenderer._get_template_values(self)
        comments = []
        for comment in self._field._form._item.comments:
            if security.has_permission('read', comment,
                                       self._field._form._request):
                comments.append(comment)
        if self._field._form.has_errors():
            last_comment = self._field._form.submitted_data.get("comment", "")
        else:
            last_comment = ""

        values['last_comment'] = last_comment
        values['comments'] = comments
        return values
Example #9
0
def get_modules(request, display):
    # FIXME: Circular import (ti) <2015-05-11 21:52>
    from ringo.lib.security import has_permission
    user_moduls = []
    # The modules has been load already and are cached. So get them from
    # the cache
    for modul in request.cache_item_modul.all().values():
        # Only show the modul if it matches the desired display location
        # and if the modul has an "list" action which usually is used as
        # entry point into a modul.
        if (modul.display == display and modul.has_action('list')):
            clazz = dynamic_import(modul.clazzpath)
            if has_permission('list', clazz, request):
                user_moduls.append(modul)
    return user_moduls
Example #10
0
def get_link_url(item, request, actionname=None, backurl=False):
    """Return a url to the given item. On default the link will be a
    link to the update or read view of the item depending on the
    permission. If the user does not have enough permissions than None
    is returned. Optionally you can provide the name of a action. In
    this case the url will be build for the given actionname if the user
    has enough permissions."""
    if isinstance(item, BaseItem):
        if actionname:
            from ringo.views.helpers import get_item_modul
            modul = get_item_modul(request, item)
            action = modul.get_action(actionname)
            if action is None:
                # This can happen if the action is not part of the modul
                # but a custum userdefined view. No permission checks
                # are done here yet.
                route_name = get_action_routename(item, actionname)
            else:
                permission = action.permission or action.name.lower()
                if security.has_permission(permission, item, request):
                    route_name = get_action_routename(item,
                                                      action.name.lower())
                else:
                    return None
        elif security.has_permission("update", item, request):
            route_name = get_action_routename(item, 'update')
        elif security.has_permission("read", item, request):
            route_name = get_action_routename(item, 'read')
        else:
            return None

        query = {}
        if backurl:
            query['backurl'] = request.current_route_path()
        return request.route_path(route_name, id=item.id, _query=query)
    return None
Example #11
0
def setstandin(request, allowed_users=None):
    """Setting members in the default usergroup of the current user.
    Technically this is adding a standin for this user."""

    # Check authentification
    # As this view has now security configured it is
    # generally callable by all users. For this reason we first check if
    # the user is authenticated. If the user is not authenticated the
    # raise an 401 (unauthorized) exception.
    if not request.user:
        raise HTTPUnauthorized

    # Check authorisation
    # For normal users users shall only be allowed to set the standin
    # for their own usergroup. So check this and otherwise raise an exception.
    usergroup = get_item_from_request(request)
    if (usergroup.id != request.user.default_gid
            and not has_permission("update", usergroup, request)):
        raise HTTPForbidden()

    clazz = Usergroup
    request.session['%s.form' % clazz] = "membersonly"
    request.session.save()
    values = {}
    if allowed_users:
        values['_allowedusers'] = [u.login for u in allowed_users]

    # Result may be a HTTPFOUND object.
    result = update(request, values=values)
    if isinstance(result, dict):
        # If the standing is set by an administrational user then the id
        # of the usergroupĀ“s user is stored in the the backurl.
        if request.GET.get('backurl'):
            user_id = urlparse.urlparse(
                request.GET.get('backurl')).path.split('/')[-1]
            user = request.db.query(User).get(user_id)
            if not user:
                raise HTTPBadRequest()
        # Otherwise the user sets the standin of his own group. In this
        # case the user is already in the request.
        else:
            user = request.user
        result['user'] = user

    # Reset form value in session
    handle_caching(request)
    return result
Example #12
0
def setstandin(request, allowed_users=None):
    """Setting members in the default usergroup of the current user.
    Technically this is adding a standin for this user."""

    # Check authentification
    # As this view has now security configured it is
    # generally callable by all users. For this reason we first check if
    # the user is authenticated. If the user is not authenticated the
    # raise an 401 (unauthorized) exception.
    if not request.user:
        raise HTTPUnauthorized

    # Check authorisation
    # For normal users users shall only be allowed to set the standin
    # for their own usergroup. So check this and otherwise raise an exception.
    usergroup = get_item_from_request(request)
    if (usergroup.id != request.user.default_gid
       and not has_permission("update", usergroup, request)):
        raise HTTPForbidden()

    clazz = Usergroup
    request.session['%s.form' % clazz] = "membersonly"
    request.session['%s.backurl' % clazz] = request.current_route_path()
    request.session.save()
    values = {}
    if allowed_users:
        values['_allowedusers'] = [u.login for u in allowed_users]

    # Result may be a HTTPFOUND object.
    result = update(request, values=values)
    if isinstance(result, dict):
        # If the standing is set by an administrational user then the id
        # of the usergroupĀ“s user is stored in the the backurl.
        if request.GET.get('backurl'):
            user_id = urlparse.urlparse(
                request.GET.get('backurl')).path.split('/')[-1]
            user = request.db.query(User).filter(User.id == user_id).one()
        # Otherwise the user sets the standin of his own group. In this
        # case the user is already in the request.
        else:
            user = request.user
        result['user'] = user

    # Reset form value in session
    handle_caching(request)
    return result
Example #13
0
def filter_options_on_permissions(request, options):
    """Will filter the given options based on the permissions on the
    current user of the request. After filtering the options will only
    have items where the user is allowed to at least read it.

    :request: current request
    :options: list of tuple of options (item, value, filtered)
    :returns: filtered list of option tuples.

    """
    filtered_options = []
    for option in options:
        visible = False
        if (option[2] and (security.has_permission('read', option[0], request)
           or not hasattr(option[0], 'owner'))):
            visible = True
        filtered_options.append((option[0], option[1], visible))
    return filtered_options
Example #14
0
def handle_redirect_on_success(request, backurl=None):
    """Will return a redirect. If there has been a saved "backurl" the
    redirect will on on this URL. In all other cases the function will
    try to determine if the item in the request can be opened in edit
    mode or not. If the current user is allowed to open the item in
    edit mode then the update view is called. Else the read view is
    called.

    :request: Current request
    :backurl: Optional. Set backurl manually. This will overwrite
    backurl saved in the session.
    :returns: Redirect
    """

    item = get_item_from_request(request)
    clazz = request.context.__model__
    backurl = backurl or request.session.get('%s.backurl' % clazz)

    if request.session.get('%s.backurl' % clazz):
        del request.session['%s.backurl' % clazz]
        request.session.save()

    if backurl and (request.params.get("_submit") not in ["stay", "nextpage"]):
        # Ignore the redirect to the backurl if the user clicks on
        # "Save" and "Save and proceed" Buttons. In this case a special
        # value is part of the form. In case of "Save and return" or
        # the default submittbuttons with no special value we keep the
        # old behavior.
        return HTTPFound(location=backurl)
    elif request.path.find("/create") > -1 or request.path.find(
            "/update") > -1:
        # Handle redirect after success.in case of a create.
        # Check if the user is allowed to call the url after saving
        if has_permission("update", item, request):
            route_name = get_action_routename(item, 'update')
            url = request.route_path(route_name, id=item.id)
        else:
            route_name = get_action_routename(item, 'read')
            url = request.route_path(route_name, id=item.id)
        return HTTPFound(location=url)
    else:
        # Handle all other variants of the redirect and stay on the
        # current url.
        return HTTPFound(location=request.url)
Example #15
0
def get_open_url(request, item):
    """Convinience method to the a URL to 'open' the item."""
    from ringo.lib.security import has_permission

    permissions = ['read']
    # If the application is configured to open items in readmode on
    # default then we will not add the update action to the actions to
    # check.
    if not request.registry.settings.get("app.readmode") in ["True", "true"]:
        permissions.append('update')

    url = None
    for permission in permissions:
        if has_permission(permission, item, request):
            route_name = get_action_routename(item, permission)
            url = request.route_path(route_name, id=item.id)
        else:
            break
    return url
Example #16
0
    def render(self, request):
        """Initialize renderer"""
        # TODO: Enabled sorting of lists. Mind that these lists might be
        # presorted if the user clicked on the header. In this case some
        # get params with sort configurations are in the session. This
        # logic is currently in base/view. (ti) <2014-01-23 23:15>
        # sort_field = self.config.get_default_sort_column()
        # sort_order = self.config.get_default_sort_order()
        # self.listing.sort(sort_field, sort_order)

        if len(self.listing.search_filter) > 0:
            search = self.listing.search_filter[-1][0]
            search_field = self.listing.search_filter[-1][1]
            regexpr = self.listing.search_filter[-1][2]
        else:
            search = ""
            search_field = ""
            regexpr = False
        ssearch = get_saved_searches(request,
                                     self.listing.clazz.__tablename__)

        bundled_actions = []
        for action in get_item_actions(request, self.listing.clazz):
            if action.bundle and security.has_permission(action.name.lower(),
                                                         request.context,
                                                         request):
                bundled_actions.append(action)

        values = {'items': self.listing.items,
                  'clazz': self.listing.clazz,
                  'listing': self.listing,
                  'request': request,
                  '_': request.translate,
                  'h': ringo.lib.helpers,
                  's': security,
                  'bundled_actions': bundled_actions,
                  'search': search,
                  'regexpr': regexpr,
                  'search_field': search_field,
                  'saved_searches': ssearch,
                  'tableconfig': self.config}
        return literal(self.template.render(**values))
Example #17
0
    def render(self, request):
        """Initialize renderer"""
        # TODO: Enabled sorting of lists. Mind that these lists might be
        # presorted if the user clicked on the header. In this case some
        # get params with sort configurations are in the session. This
        # logic is currently in base/view. (ti) <2014-01-23 23:15>
        # sort_field = self.config.get_default_sort_column()
        # sort_order = self.config.get_default_sort_order()
        # self.listing.sort(sort_field, sort_order)

        if len(self.listing.search_filter) > 0:
            search = self.listing.search_filter[-1][0]
            search_field = self.listing.search_filter[-1][1]
            regexpr = self.listing.search_filter[-1][2]
        else:
            search = ""
            search_field = ""
            regexpr = False
        ssearch = get_saved_searches(request, self.listing.clazz.__tablename__)

        bundled_actions = []
        for action in get_item_actions(request, self.listing.clazz):
            if action.bundle and security.has_permission(
                    action.name.lower(), request.context, request):
                bundled_actions.append(action)

        values = {
            'items': self.listing.items,
            'clazz': self.listing.clazz,
            'listing': self.listing,
            'request': request,
            '_': request.translate,
            'h': ringo.lib.helpers,
            's': security,
            'bundled_actions': bundled_actions,
            'search': search,
            'regexpr': regexpr,
            'search_field': search_field,
            'saved_searches': ssearch,
            'tableconfig': self.config
        }
        return literal(self.template.render(**values))
Example #18
0
def filter_options_on_permissions(request, options):
    """Will iterate over all options and build a tuple for each option
    with the following information:

    1. The option itself
    2. The value of the option
    3. A flag indicating if the requesting user is allowed to `link` the
       option. This information is later used on rendering.

    :request: current request
    :options: list of tuple of options (item, value, linkable)
    :returns: filtered list of option tuples.

    """
    filtered_options = []
    for option in options:
        linkable = False
        if (option[2] and (security.has_permission('link', option[0], request)
                           or not hasattr(option[0], 'owner'))):
            linkable = True
        filtered_options.append((option[0], option[1], linkable))
    return filtered_options
Example #19
0
def get_read_update_url(request, item, clazz, prefilterd=False):
    """Helper method to get the URL to read or update in item in various
    overviews. If the user of this request is not allowed to see the
    item at all, None will be returned as the url."""

    permissions = ['read']
    # If the application is configured to open items in readmode on
    # default then we will not add the update action to the actions to
    # check.
    if not request.registry.settings.get("app.readmode") in ["True", "true"]:
        permissions.append('update')

    is_admin = request.user.has_role("admin")
    url = None
    for permission in permissions:
        if (permission == 'read' and prefilterd) \
           or is_admin \
           or security.has_permission(permission, item, request):
            url = request.route_path(get_action_routename(clazz, permission),
                                     id=item.id)
        else:
            break
    return url
Example #20
0
File: base.py Project: toirl/ringo
def filter_itemlist_for_user(request, baselist):
    """Returns a filterd baselist. The items are filterd based on
    the permission of the current user in the request. Only items are
    included where the given user has read access. This means:

     1. The user has aproriate role (read access)
     2. Is owner or member of the items group

    :request: Current request
    :baselist: BaseList instance
    :returns: Filtered BaseList instance

    """
    from ringo.lib.security import has_permission
    filtered_items = []
    if request.user and not request.user.has_role("admin"):
        # Iterate over all items and check if the user has generally
        # access to the item.
        for item in baselist.items:
            # Only check ownership if the item provides a uid.
            if has_permission('read', item, request):
                filtered_items.append(item)
        baselist.items = filtered_items
    return baselist
Example #21
0
def bundle_(request):
    clazz = request.context.__model__
    module = get_item_modul(request, clazz)
    handle_history(request)
    handle_params(request)
    _ = request.translate

    # Handle bundle params. If the request has the bundle_action param
    # the request is the intial request for a bundled action. In this
    # case we can delete all previous selected and stored item ids in
    # the session.
    params = request.params.mixed()
    if params.get('bundle_action'):
        request.session['%s.bundle.action' % clazz] = params.get('bundle_action')
        try:
            del request.session['%s.bundle.items' % clazz]
        except KeyError:
            pass
        request.session['%s.bundle.items' % clazz] = params.get('id', [])
    bundle_action = request.session.get('%s.bundle.action' % clazz)
    ids = request.session.get('%s.bundle.items' % clazz)

    # Check if the user selected at least one item. If not show an
    # dialog informing that the selection is empty.
    if not ids:
        title =  _("Empty selection")
        body =  _("You have not selected any item in the list. "
                  "Click 'OK' to return to the overview.")
        renderer = WarningDialogRenderer(request, title, body)
        rvalue = {}
        rvalue['dialog'] = literal(renderer.render(url=request.referrer))
        return rvalue

    # If the user only selects one single item it is not a list. So
    # convert it to a list with one item.
    if not isinstance(ids, list):
        ids = [ids]

    factory = clazz.get_item_factory()
    items = []
    ignored_items = []
    for id in ids:
        # Check if the user is allowed to call the requested action on
        # the loaded item. If so append it the the bundle, if not ignore
        # it.
        item = factory.load(id)
        if has_permission(bundle_action.lower(), item, request):
            items.append(item)
        else:
            ignored_items.append(item)

    # After checking the permissions the list of items might be empty.
    # If so show a warning to the user to inform him that the selected
    # action is not applicable.
    if not items:
        title = _("${action} not applicable",
                  mapping={"action": bundle_action})
        body = _("After checking the permissions no items remain "
                 "for which an '${action}' can be performed. "
                 "(${num} items were filtered out.)",
                 mapping={"action": bundle_action,
                          "num": len(ignored_items)})
        renderer = WarningDialogRenderer(request, title, body)
        rvalue = {}
        rvalue['dialog'] = literal(renderer.render(url=request.referrer))
        return rvalue

    handler = get_bundle_action_handler(_bundle_request_handlers,
                                        bundle_action.lower(),
                                        module.name)
    return handler(request, items, None)
Example #22
0
    def set_values(self, values, use_strict=False, request=None):
        """Will set the values of the item. The values to be set are
        provided by a dictionary with key value pairs given with the
        `values` option. Keys in the dictionary beginning with "_" are
        considered private and are ignored.

        This function does not explicit handle saving the changed data!
        Saving data (E.g making a new instance of an item persistent in
        the DB) is handled by the :func:`.BaseItkkem.save` method.

        .. note::
            Setting the values for foreign key attributes might not work
            as expected. This is especially true for foreign keys to
            already existing items. You are not able to change a
            existing relation in the items by changing the foreign key
            value (You must do this by setting the related item). In
            this case the value for the foreign key seems to be ignored
            and replaced by the one of the actual related item.  In
            contrast you can set a new relation by setting the foreign
            key if this is a new relation.

        :values: Dictionary with values to be set
        :use_strict: boolean, if true raise a exception if an attribute is
                     missing (default: False).
        """
        for key, value in values.iteritems():
            # Ignore private form fields
            if key.startswith('_'):
                continue
            try:
                oldvalue = getattr(self, key)
                # If oldvalue is equal to the new value we need no
                # change at all in the model so continue
                if oldvalue == value:
                    continue
                log.debug(u"Setting value '%s' in %s" % (repr(value), key))
                if isinstance(value, list) and isinstance(oldvalue, list):
                    # Special handling for relations in NM relations.
                    # See ticket #19 in Ringo issue tracker for more
                    # details. Simply exchaning the relations in this
                    # case seems not to work. I case of the error in
                    # triggering the deleting of items in the
                    # nm-relation from both sides. In this case the
                    # second deletion will fail.
                    #
                    # Regarding to
                    # http://docs.sqlalchemy.org/en/latest/orm/basic_relationships.html#deleting-rows-from-the-many-to-many-table
                    # relations should be removed by using remove(item).
                    # Howver poping the items before adding the new
                    # items seems to work too. I excpet that poping the
                    # items will somehow tweak SQLAlchemy in the way
                    # that it handles deleting items correct now.

                    # Ensure correct relations.
                    # Commit 2b8ccb9 introduces a change for the
                    # Listingfieldrenderer which affects handling
                    # relations. The submitted values does no longer contain
                    # all linked elements. Now the submitted values will
                    # only contain linked elements which can be
                    # read/linked by the user. Because this is often only a
                    # subset of actually linked items, the code now must
                    # ensure that relations to items which where not
                    # included in the submitted values does not get lost.
                    if request:
                        from ringo.lib.security import has_permission
                        # Oldvalue contains all actually linked items.
                        for ov in oldvalue:
                            if not has_permission("link", ov, request):
                                # It the item was linked by the user is
                                # not allowed to link it (is not part of
                                # the submitted values), we must keep
                                # the relation.
                                value.append(ov)
                        # Now value contains all previous linked items
                        # the user is not allowed to change, plus the
                        # current selection of the user.
                    while oldvalue:
                        oldvalue.pop(0)
                    for nvalue in value:
                        oldvalue.append(nvalue)
                else:
                    setattr(self, key, value)
            except AttributeError:
                log.warning(('Not saving "%s". Attribute/Property not'
                             ' found') % key)
                if use_strict:
                    raise AttributeError(('Not setting "%s".'
                                          ' Attribute not found.') % key)
Example #23
0
def bundle_(request):
    clazz = request.context.__model__
    module = get_item_modul(request, clazz)
    _ = request.translate

    # Handle bundle params. If the request has the bundle_action param
    # the request is the intial request for a bundled action. In this
    # case we can delete all previous selected and stored item ids in
    # the session.
    params = request.params.mixed()
    if params.get('bundle_action'):
        request.session['%s.bundle.action' %
                        clazz] = params.get('bundle_action')
        try:
            del request.session['%s.bundle.items' % clazz]
        except KeyError:
            pass
        request.session['%s.bundle.items' % clazz] = params.get('id', [])
    bundle_action = request.session.get('%s.bundle.action' % clazz)
    ids = request.session.get('%s.bundle.items' % clazz)

    # Check if the user selected at least one item. If not show an
    # dialog informing that the selection is empty.
    if not ids:
        title = _("Empty selection")
        body = _("You have not selected any item in the list. "
                 "Click 'OK' to return to the overview.")
        renderer = WarningDialogRenderer(request, title, body)
        rvalue = {}
        rvalue['dialog'] = literal(renderer.render(url=request.referrer))
        return rvalue

    # If the user only selects one single item it is not a list. So
    # convert it to a list with one item.
    if not isinstance(ids, list):
        ids = [ids]

    factory = clazz.get_item_factory()
    items = []
    ignored_items = []
    for id in ids:
        # Check if the user is allowed to call the requested action on
        # the loaded item. If so append it the the bundle, if not ignore
        # it.
        item = factory.load(id)
        if has_permission(bundle_action.lower(), item, request):
            items.append(item)
        else:
            ignored_items.append(item)

    # After checking the permissions the list of items might be empty.
    # If so show a warning to the user to inform him that the selected
    # action is not applicable.
    if not items:
        title = _("${action} not applicable",
                  mapping={"action": bundle_action})
        body = _(
            "After checking the permissions no items remain "
            "for which an '${action}' can be performed. "
            "(${num} items were filtered out.)",
            mapping={
                "action": bundle_action,
                "num": len(ignored_items)
            })
        renderer = WarningDialogRenderer(request, title, body)
        rvalue = {}
        rvalue['dialog'] = literal(renderer.render(url=request.referrer))
        return rvalue

    handler = get_bundle_action_handler(_bundle_request_handlers,
                                        bundle_action.lower(), module.name)
    return handler(request, items, None)