Ejemplo n.º 1
0
 def item_edit_copy_uri(self,
         coll_id, type_id, view_id, entity_id, no_entity_msg, 
         continuation_here, continuation_url, action):
     # NOTE: continuation_url is the continuation URL from the current page,
     #       and is used as part of the URL used to redisplay the current 
     #       page with an error message.
     # @@TODO:  pass in viewinfo rather than continuation URLs
     if not entity_id:
         continuation_url_dict = {}
         if continuation_url:
             continuation_url_dict = {'continuation_url': continuation_url}
         return uri_with_params(
             self.get_request_path(), 
             self.error_params(no_entity_msg),
             continuation_url_dict
             )
     redirect_uri = (
         uri_with_params(
             self.view_uri("AnnalistEntityEditView", action=action, 
                 coll_id=coll_id, view_id=view_id, type_id=type_id, entity_id=entity_id
                 ),
             {'continuation_url': continuation_here}
             )
         )
     return redirect_uri
Ejemplo n.º 2
0
    def check_collection_entity(self, entity_id, entity_type, msg):
        """
        Test a supplied entity_id is defined in the current collection,
        returning a URI to display a supplied error message if the test fails.

        NOTE: this function works with the generic base template base_generic.html, which
        is assumed to provide an underlay for the currently viewed page.

        entity_id           entity id that is required to be defined in the current collection.
        entity_type         specified type for entity to delete.
        msg                 message to display if the test fails.

        returns a URI string for use with HttpResponseRedirect to redisplay the 
        current page with the supplied message, or None if entity id is OK.
        """
        # log.info("check_collection_entity: entity_id: %s"%(entity_id))
        # log.info("check_collection_entity: entityparent: %s"%(self.entityparent.get_id()))
        # log.info("check_collection_entity: entityclass: %s"%(self.entityclass))
        redirect_uri = None
        typeinfo = self.entitytypeinfo
        if not typeinfo or typeinfo.get_type_id() != entity_type:
            typeinfo = EntityTypeInfo(self.collection, entity_type)
        if not typeinfo.entityclass.exists(typeinfo.entityparent, entity_id):
            redirect_uri = (uri_with_params(self.view.get_request_path(),
                                            self.view.error_params(msg),
                                            self.get_continuation_url_dict()))
        return redirect_uri
Ejemplo n.º 3
0
    def check_value_supplied(self, val, msg, continuation_url=None, testfn=(lambda v: v)):
        """
        Test if a supplied value is specified (not None) and passes a supplied test,
        returning a URI to display a supplied error message if the test fails.

        NOTE: this function works with the generic base template base_generic.html, which
        is assumed to provide an underlay for the currently viewed page.

        val                 value that is required to be not None and not empty or False
        msg                 message to display if the value evaluated to False
        continuation_url    a continuation URL for the resdiplayed page.
        testfn              is a function to test the value (if not None).  If not specified, 
                            the default test checks that the value does not evaluate as false
                            (e.g. is a non-empty string, list or collection).

        returns a URI string for use with HttpResponseRedirect to redisplay the 
        current page with the supplied message, or None if the value passes the test.
        """
        redirect_uri = None
        continuation_url_dict = {}
        if continuation_url:
            continuation_url_dict = {'continuation_url': continuation_url}
        if (val is None) or not testfn(val):
            redirect_uri = uri_with_params(
                self.get_request_path(), 
                self.error_params(msg),
                continuation_url_dict
                )
        return redirect_uri
Ejemplo n.º 4
0
    def continuation_here(self,
                          request_dict={},
                          default_cont="",
                          base_here=None):
        """
        Returns a URL that returns control to the current page, to be passed as a
        continuation_uri parameter to any subsidiary pages invoked.  Such continuation 
        URIs are cascaded, so that the return URI includes a the `continuation_url` 
        for the current page.

        request_dict    is a request dictionary that is expected to contain the 
                        continuation_url value to use, and other parameters to 
                        be included an any continuation back to the current page.
        default_cont    is a default continuation URI to be used for returning from 
                        the current page if the current POST request does not specify
                        a continuation_url query parameter.
        base_here       if specified, overrides the current request path as the base URI
                        to be used to return to the currently displayed page (e.g. when
                        current request URI is non-idempotent, such as creating a new 
                        entity).
        """
        # Note: use default if request/form parameter is present but blank:
        if not base_here:
            base_here = self.get_request_path()
        continuation_next = self.continuation_next(request_dict, default_cont)
        return uri_with_params(
            base_here,
            continuation_params({"continuation_url": continuation_next},
                                request_dict))
Ejemplo n.º 5
0
    def continuation_here(self, request_dict={}, default_cont="", base_here=None):
        """
        Returns a URL that returns control to the current page, to be passed as a
        continuation_uri parameter to any subsidiary pages invoked.  Such continuation 
        URIs are cascaded, so that the return URI includes a the `continuation_url` 
        for the current page.

        request_dict    is a request dictionary that is expected to contain the 
                        continuation_url value to use, and other parameters to 
                        be included an any continuation back to the current page.
        default_cont    is a default continuation URI to be used for returning from 
                        the current page if the current POST request does not specify
                        a continuation_url query parameter.
        base_here       if specified, overrides the current request path as the base URI
                        to be used to return to the currently displayed page (e.g. when
                        current request URI is non-idempotent, such as creating a new 
                        entity).
        """
        # Note: use default if request/form parameter is present but blank:
        if not base_here:
            base_here = self.get_request_path()
        continuation_next = self.continuation_next(request_dict, default_cont)
        return uri_with_params(base_here, 
            continuation_params({"continuation_url": continuation_next}, request_dict)
            )
Ejemplo n.º 6
0
    def check_value_supplied(self,
                             val,
                             msg,
                             continuation_url={},
                             testfn=(lambda v: v)):
        """
        Test a supplied value is specified (not None) and passes a supplied test,
        returning a URI to display a supplied error message if the test fails.

        NOTE: this function works with the generic base template base_generic.html, which
        is assumed to provide an underlay for the currently viewed page.

        val         value that is required to be not None and not empty or False
        msg         message to display if the value evaluated to False
        testfn      is a function to test the value (if not None).  If not specified, 
                    the default test checks that the value does not evaluate as false
                    (e.g. is a non-empty string, list or collection).

        returns a URI string for use with HttpResponseRedirect to redisplay the 
        current page with the supplied message, or None if the value passes the test.
        """
        redirect_uri = None
        if (val is None) or not testfn(val):
            redirect_uri = uri_with_params(self.get_request_path(),
                                           self.error_params(msg),
                                           continuation_url)
        return redirect_uri
Ejemplo n.º 7
0
    def check_collection_entity(self, entity_id, entity_type, msg):
        """
        Test a supplied entity_id is defined in the current collection,
        returning a URI to display a supplied error message if the test fails.

        NOTE: this function works with the generic base template base_generic.html, which
        is assumed to provide an underlay for the currently viewed page.

        entity_id           entity id that is required to be defined in the current collection.
        entity_type         specified type for entity to delete.
        msg                 message to display if the test fails.

        returns a URI string for use with HttpResponseRedirect to redisplay the 
        current page with the supplied message, or None if entity id is OK.
        """
        # log.info("check_collection_entity: entity_id: %s"%(entity_id))
        # log.info("check_collection_entity: entityparent: %s"%(self.entityparent.get_id()))
        # log.info("check_collection_entity: entityclass: %s"%(self.entityclass))
        redirect_uri = None
        typeinfo     = self.entitytypeinfo
        if not typeinfo or typeinfo.get_type_id() != entity_type:
            typeinfo = EntityTypeInfo(self.collection, entity_type)
        if not typeinfo.entityclass.exists(typeinfo.entityparent, entity_id):
            redirect_uri = (
                uri_with_params(
                    self.view.get_request_path(),
                    self.view.error_params(msg),
                    self.get_continuation_url_dict()
                    )
                )
        return redirect_uri
Ejemplo n.º 8
0
 def item_new_uri(self, coll_id, type_id, view_id, continuation_here):
     redirect_uri = uri_with_params(
         self.view_uri("AnnalistEntityNewView",
                       coll_id=coll_id,
                       view_id=view_id,
                       type_id=type_id,
                       action="new"), continuation_here)
     return redirect_uri
Ejemplo n.º 9
0
    def redirect_info(self, viewuri, view_params={}, info_message=None, info_head=message.ACTION_COMPLETED):
        """
        Redirect to a specified view with an information/confirmation message for display

        (see templates/base_generic.html for display details)
        """
        redirect_uri = uri_with_params(viewuri, view_params, self.info_params(info_message, info_head))
        return HttpResponseRedirect(redirect_uri)
Ejemplo n.º 10
0
 def item_new_uri(self, coll_id, type_id, view_id, continuation_here):
     # @@TODO:  pass in viewinfo rather than continuation URL
     redirect_uri = uri_with_params(
         self.view_uri("AnnalistEntityNewView", 
             coll_id=coll_id, view_id=view_id, type_id=type_id, action="new"
             ),
         {'continuation_url': continuation_here}
         )
     return redirect_uri
Ejemplo n.º 11
0
 def item_new_uri(self, coll_id, type_id, view_id, continuation_here):
     # @@TODO:  pass in viewinfo rather than continuation URL
     redirect_uri = uri_with_params(
         self.view_uri("AnnalistEntityNewView",
                       coll_id=coll_id,
                       view_id=view_id,
                       type_id=type_id,
                       action="new"),
         {'continuation_url': continuation_here})
     return redirect_uri
Ejemplo n.º 12
0
 def item_edit_copy_uri(self, coll_id, type_id, view_id, entity_id,
                        no_entity_msg, continuation_here, continuation_next,
                        action):
     redirect_uri = (self.check_value_supplied(
         entity_id, no_entity_msg, continuation_next) or uri_with_params(
             self.view_uri("AnnalistEntityEditView",
                           action=action,
                           coll_id=coll_id,
                           view_id=view_id,
                           type_id=type_id,
                           entity_id=entity_id), continuation_here))
     return redirect_uri
Ejemplo n.º 13
0
    def redirect_error(self, 
        viewuri, view_params={}, error_message=None, error_head=message.INPUT_ERROR
        ):
        """
        Redirect to a specified view with an error message for display

        (see templates/base_generic.html for display details)
        """
        redirect_uri = uri_with_params(
            viewuri, view_params, self.error_params(error_message, error_head=error_head)
            )
        return HttpResponseRedirect(redirect_uri)
Ejemplo n.º 14
0
    def redirect_info(self,
                      viewuri,
                      view_params={},
                      info_message=None,
                      info_head=message.ACTION_COMPLETED):
        """
        Redirect to a specified view with an information/confirmation message for display

        (see templates/base_generic.html for display details)
        """
        redirect_uri = uri_with_params(
            viewuri, view_params, self.info_params(info_message, info_head))
        return HttpResponseRedirect(redirect_uri)
Ejemplo n.º 15
0
    def redirect_error(self,
                       viewuri,
                       view_params={},
                       error_message=None,
                       error_head=message.INPUT_ERROR):
        """
        Redirect to a specified view with an error message for display

        (see templates/base_generic.html for display details)
        """
        redirect_uri = uri_with_params(
            viewuri, view_params, self.error_params(error_head, error_message))
        return HttpResponseRedirect(redirect_uri)
Ejemplo n.º 16
0
def make_data_ref(request_url, data_ref, resource_type=None):
    """
    Returns a URL reference rel.atiove to the suppliued request_url 
    that can be used as a reference to a data resource based on
    the supplied request URL, data reference and optional type.

    Scope-repated query parameters from the original request_url are 
    preserved, and others are discarded.
    """
    params = scope_params(uri_param_dict(request_url))
    if resource_type:
        params['type'] = resource_type
    return uri_with_params(data_ref, params)
Ejemplo n.º 17
0
def make_data_ref(request_url, data_ref, resource_type=None):
    """
    Returns a URL reference rel.atiove to the suppliued request_url 
    that can be used as a reference to a data resource based on
    the supplied request URL, data reference and optional type.

    Scope-repated query parameters from the original request_url are 
    preserved, and others are discarded.
    """
    params = scope_params(uri_param_dict(request_url))
    if resource_type:
        params['type'] = resource_type
    return uri_with_params(data_ref, params)
Ejemplo n.º 18
0
 def get_continuation_url(self):
     """
     Generate continuation URL for return back to the current request page
     """
     chere = ""
     if self._extras is None:
         log.warning("bound_field.get_continuation_url() - no extra context provided")
     else:
         requrl = self._extras.get("request_url", "")
         if requrl:
             chere  = uri_with_params(requrl, continuation_params(self._extras))
     # log.debug('bound_field.get_continuation_url %s'%(chere,))
     return chere
Ejemplo n.º 19
0
 def item_edit_copy_uri(self, coll_id, type_id, view_id, entity_id,
                        no_entity_msg, continuation_here, continuation_url,
                        action):
     # NOTE: continuation_url is the continuation URL from the current page,
     #       and is used as part of the URL used to redisplay the current
     #       page with an error message.
     # @@TODO:  pass in viewinfo rather than continuation URLs
     if not entity_id:
         continuation_url_dict = {}
         if continuation_url:
             continuation_url_dict = {'continuation_url': continuation_url}
         return uri_with_params(self.get_request_path(),
                                self.error_params(no_entity_msg),
                                continuation_url_dict)
     redirect_uri = (uri_with_params(
         self.view_uri("AnnalistEntityEditView",
                       action=action,
                       coll_id=coll_id,
                       view_id=view_id,
                       type_id=type_id,
                       entity_id=entity_id),
         {'continuation_url': continuation_here}))
     return redirect_uri
Ejemplo n.º 20
0
    def check_delete_type_values(self, listinfo, entity_id, entity_type, msg):
        """
        Checks for attempt to delete type with existing values

        Returns redirect URI to display error, or None if no error
        """
        if entity_type == "_type":
            typeinfo = EntityTypeInfo(listinfo.collection, entity_id)
            if next(typeinfo.enum_entity_ids(), None) is not None:
                return (
                    # Type has values: redisplay form with error message
                    uri_with_params(listinfo.view.get_request_path(),
                                    listinfo.view.error_params(msg),
                                    listinfo.get_continuation_url_dict()))
        return None
Ejemplo n.º 21
0
 def get_continuation_url(self):
     """
     Generate continuation URL for return back to the current request page
     """
     chere = ""
     if self._extras is None:
         log.warning(
             "bound_field.get_continuation_url() - no extra context provided"
         )
     else:
         requrl = self._extras.get("request_url", "")
         if requrl:
             chere = uri_with_params(requrl,
                                     continuation_params(self._extras))
     # log.debug('bound_field.get_continuation_url %s'%(chere,))
     return chere
Ejemplo n.º 22
0
 def item_edit_copy_uri(self, coll_id, type_id, view_id, entity_id,
                        no_entity_msg, continuation_here, continuation_url,
                        action):
     # NOTE: continuation_url is the continuation URL from the current page,
     #       and is used as part of the URL used to redisplay the current
     #       page with an error message.
     # @@TODO:  pass in viewinfo rather than continuation URLs
     redirect_uri = (self.check_value_supplied(
         entity_id, no_entity_msg, continuation_url) or uri_with_params(
             self.view_uri("AnnalistEntityEditView",
                           action=action,
                           coll_id=coll_id,
                           view_id=view_id,
                           type_id=type_id,
                           entity_id=entity_id),
             {'continuation_url': continuation_here}))
     return redirect_uri
Ejemplo n.º 23
0
    def continuation_urls(self, request_dict, default_cont, base_here=None):
        """
        Returns a tuple of two continuation URI dictionary values:

        [0] { 'continuation_url': continuation_next }
        [1] { 'continuation_url': continuation_here }

        where:

        `continuation_next` is the URI to use after the current page has completed
        processing, which is either supplied as a parameter to the current page or 
        set to an indicated default.

        `continuation_here` is a URI that returns control to the current page, to be passed
        as a contionuation_uri parameter to any subsidiary pages invoked.  Such continuation 
        URIs are cascaded, so that the return URI includes a the `continuation_url` for the 
        current page.

        request_dict    is a request dictionary that is expected to contain a 
                        to continuation_url value to use, other parameters to be 
                        included an any continuation back to the current page.
        default_cont    is a default continuation URI to be used for returning from 
                        the current page if the current POST request does not specify
                        a continuation_url query parameter.
        base_here       if specified, overrides the current request path as the base URI
                        to be used to return to the currently displayed page (e.g. when
                        current request URI is non-idempotent, such as creating a new 
                        entity).
        """
        # Note: use default if request/form parameter is present but blank:
        continuation_url = request_dict.get(
            "continuation_url") or default_cont or None
        if not base_here:
            base_here = self.get_request_path()
        if continuation_url:
            continuation_next = {"continuation_url": continuation_url}
        else:
            continuation_next = {}
        continuation_here = uri_with_params(
            base_here,
            continuation_params(continuation_next, request_dict.dict()))
        # continuation_here   = uri_with_continuation_params(
        #     base_here, continuation_next, request_dict.dict()
        #     )
        return (continuation_next, {"continuation_url": continuation_here})
Ejemplo n.º 24
0
    def check_delete_type_values(self, listinfo, entity_id, entity_type, msg):
        """
        Checks for attempt to delete type with existing values

        Returns redirect URI to display error, or None if no error
        """
        if entity_type == "_type":
            typeinfo = EntityTypeInfo(
                listinfo.collection, entity_id
                )
            if next(typeinfo.enum_entity_ids(), None) is not None:
                return (
                    # Type has values: redisplay form with error message
                    uri_with_params(
                        listinfo.view.get_request_path(),
                        listinfo.view.error_params(msg),
                        listinfo.get_continuation_url_dict()
                        )
                    )
        return None
Ejemplo n.º 25
0
 def get_list_url(self, coll_id, list_id, type_id=None, scope=None, search=None, query_params={}):
     """
     Return a URL for accessing the current list display
     """
     list_uri_params = (
         { 'coll_id': coll_id
         , 'list_id': list_id
         })
     if type_id:
         list_uri_params['type_id']  = type_id
     if scope:
         query_params = dict(query_params, scope=scope)
     if search:
         query_params = dict(query_params, search=search)
     list_url = (
         uri_with_params(
             self.view_uri("AnnalistEntityGenericList", **list_uri_params),
             query_params
             )
         )
     return list_url
Ejemplo n.º 26
0
 def get_list_url(self,
                  coll_id,
                  list_id,
                  type_id=None,
                  scope=None,
                  search=None,
                  query_params={}):
     """
     Return a URL for accessing the current list display
     """
     list_uri_params = ({'coll_id': coll_id, 'list_id': list_id})
     if type_id:
         list_uri_params['type_id'] = type_id
     if scope:
         query_params = dict(query_params, scope=scope)
     if search:
         query_params = dict(query_params, search=search)
     list_url = (uri_with_params(
         self.view_uri("AnnalistEntityGenericList", **list_uri_params),
         query_params))
     return list_url
Ejemplo n.º 27
0
    def invoke_config_edit_view(self, entityvaluemap, form_data, entity_id,
                                entity_type_id, orig_entity_id,
                                orig_entity_type_id, orig_entity, viewinfo,
                                context_extra_values, messages,
                                config_edit_url, config_edit_perm, url_params,
                                continuation_url):
        """
        Common logic for invoking a configuration resource edit while editing
        some other resource:
          - the entity currently being edited is saved
          - authorization to perform configuration edits is checked
          - a continuaton URL is calculated which is the URL for the current view,
            except that the continuation action is always "edit"
          - a URL for the config edit view is assembled from the supplied base URL
            and parameters, and the calculated continuaton URL
          - an HTTP redirect response to the config edit view is returned.

        If there is a problem with any ofthese steps, an error response is returned
        and displayed in the current view.
        """
        http_response = self.save_entity(entityvaluemap, form_data, entity_id,
                                         entity_type_id, orig_entity_id,
                                         orig_entity_type_id, viewinfo,
                                         context_extra_values, messages)
        if http_response:
            return http_response
        # @@TODO: get permission required mfrom typeinfo of entity to be created
        if viewinfo.check_authorization(config_edit_perm):
            return viewinfo.http_response
        (continuation_next, continuation_here) = self.continuation_urls(
            form_data,
            continuation_url,
            base_here=viewinfo.get_edit_continuation_url(
                entity_type_id, entity_id))
        return HttpResponseRedirect(
            uri_with_params(config_edit_url, url_params, continuation_here))
Ejemplo n.º 28
0
    def post(self, request, coll_id=None, type_id=None, list_id=None):
        """
        Handle response from dynamically generated list display form.
        """
        log.info("views.entitylist.post: coll_id %s, type_id %s, list_id %s" %
                 (coll_id, type_id, list_id))
        log.log(settings.TRACE_FIELD_VALUE, "  %s" % (self.get_request_path()))
        # log.log(settings.TRACE_FIELD_VALUE, "  form data %r"%(request.POST))
        listinfo = self.list_setup(coll_id, type_id, list_id,
                                   request.POST.dict())
        if listinfo.http_response:
            return listinfo.http_response
        if 'close' in request.POST:
            return HttpResponseRedirect(listinfo.get_continuation_url()
                                        or self.collection_view_url)

        # Process requested action
        action = None
        redirect_path = None
        redirect_cont = listinfo.get_continuation_here()
        redirect_params = {}
        entity_ids = request.POST.getlist('entity_select')
        log.debug("entity_ids %r" % (entity_ids))
        if len(entity_ids) > 1:
            listinfo.display_error_response(message.TOO_MANY_ENTITIES_SEL)
        else:
            entity_type = type_id or listinfo.get_list_type_id()
            entity_id = None
            if len(entity_ids) == 1:
                (entity_type,
                 entity_id) = split_type_entity_id(entity_ids[0], entity_type)
            if "new" in request.POST:
                action = "new"
                redirect_path = listinfo.get_new_view_uri(coll_id, entity_type)
            if "copy" in request.POST:
                action = "copy"
                if not entity_id:
                    listinfo.display_error_response(message.NO_ENTITY_FOR_COPY)
                else:
                    redirect_path = listinfo.get_edit_view_uri(
                        coll_id, entity_type, entity_id, action)
            if "edit" in request.POST:
                action = "edit"
                if not entity_id:
                    listinfo.display_error_response(message.NO_ENTITY_FOR_EDIT)
                else:
                    redirect_path = listinfo.get_edit_view_uri(
                        coll_id, entity_type, entity_id, action)
            if "delete" in request.POST:
                action = "delete"
                confirmed_deletion_uri = self.view_uri(
                    "AnnalistEntityDataDeleteView",
                    coll_id=coll_id,
                    type_id=entity_type)
                return listinfo.confirm_delete_entity_response(
                    entity_type, entity_id, confirmed_deletion_uri)
            if "default_view" in request.POST:
                #@@
                # auth_check = self.form_action_auth("config", listinfo.collection, CONFIG_PERMISSIONS)
                #@@
                auth_check = listinfo.check_authorization("config")
                if auth_check:
                    return auth_check
                listinfo.collection.set_default_list(list_id)
                listinfo.add_info_message(message.DEFAULT_LIST_UPDATED % {
                    'coll_id': coll_id,
                    'list_id': list_id
                })
                redirect_path, redirect_params = listinfo.redisplay_path_params(
                )
                redirect_cont = listinfo.get_continuation_next()
            if (("list_type" in request.POST) or ("list_all" in request.POST)):
                action = "list"
                redirect_path = self.get_list_url(
                    coll_id,
                    extract_entity_id(request.POST['list_choice']),
                    type_id=None if "list_all" in request.POST else type_id)
                redirect_params = dict(
                    scope="all" if "list_scope_all" in request.POST else None,
                    search=request.POST['search_for'])
                redirect_cont = listinfo.get_continuation_next()
                # redirect_cont   = None
            if "customize" in request.POST:
                action = "config"
                redirect_path = self.view_uri("AnnalistCollectionEditView",
                                              coll_id=coll_id)
        if redirect_path:
            if redirect_cont:
                redirect_params.update({"continuation_url": redirect_cont})
            listinfo.redirect_response(redirect_path,
                                       redirect_params=redirect_params,
                                       action=action)
            # return (
            #     listinfo.check_authorization(action) or
            #     HttpResponseRedirect(redirect_uri)
            #     )
        if listinfo.http_response:
            return listinfo.http_response

        # Report unexpected form data
        # This shouldn't happen, but just in case...
        # Redirect to continuation with error
        log.error("Unexpected form data posted to %s: %r" %
                  (request.get_full_path(), request.POST))
        err_values = self.error_params(
            message.UNEXPECTED_FORM_DATA % (request.POST),
            message.SYSTEM_ERROR)
        redirect_uri = uri_with_params(listinfo.get_continuation_next(),
                                       err_values)
        return HttpResponseRedirect(redirect_uri)
Ejemplo n.º 29
0
def entitydata_list_url_query(viewname, kwargs, query_params, more_params):
    """
    Helper function for generatinglist URLs
    """
    list_url = reverse(viewname, kwargs=kwargs)
    return uri_with_params(list_url, query_params, more_params)
Ejemplo n.º 30
0
 def __getattr__(self, name):
     """
     Get a bound field description attribute.  If the attribute name is "field_value"
     then the value corresponding to the field description is retrieved from the entity,
     otherwise the named attribute is retrieved from thge field description.
     """
     # log.info("self._key %s, __getattr__ %s"%(self._key, name))
     # log.info("self._key %s"%self._key)
     # log.info("self._entity %r"%self._entity)
     if name in [
             "entity_id", "entity_link", "entity_type_id",
             "entity_type_link"
     ]:
         return self._entityvals.get(name, "")
     elif name == "field_value_key":
         return self._key
     elif name == "context_extra_values":
         return self._extras
     elif name == "field_placeholder":
         return self._field_description.get(
             'field_placeholder', "@@bound_field.field_placeholder@@")
     elif name == "continuation_url":
         if self._extras is None:
             log.warning(
                 "bound_field.continuation_url - no extra context provided")
             return ""
         cont = self._extras.get("request_url", "")
         if cont:
             cont = uri_with_params(cont, continuation_params(self._extras))
         return cont
     elif name == "entity_link_continuation":
         return self.entity_link + self.get_continuation_param()
     elif name == "entity_type_link_continuation":
         return self.entity_type_link + self.get_continuation_param()
     elif name == "field_value":
         field_val = None
         if self._key in self._entityvals:
             field_val = self._entityvals[self._key]
         elif self._extras and self._key in self._extras:
             field_val = self._extras[self._key]
         if field_val is None:
             # Return default value, or empty string.
             # Used to populate form field value when no value supplied, or provide per-field default
             field_val = self._field_description.get(
                 'field_default_value', None)
             if field_val is None:
                 field_val = ""
         return field_val
     elif name == "field_value_link":
         # Used to get link corresponding to a value, if such exists
         return self.get_field_link()
     elif name == "field_value_link_continuation":
         # Used to get link corresponding to a value, if such exists
         return self.get_field_link() + self.get_continuation_param()
     elif name == "field_description":
         # Used to get link corresponding to a value, if such exists
         return self._field_description
     elif name == "options":
         return self.get_field_options()
     else:
         # log.info("bound_field[%s] -> %r"%(name, self._field_description[name]))
         return self._field_description[name]
Ejemplo n.º 31
0
    def post(self, request, coll_id=None, type_id=None, list_id=None):
        """
        Handle response from dynamically generated list display form.
        """
        log.info("views.entitylist.post: coll_id %s, type_id %s, list_id %s" %
                 (coll_id, type_id, list_id))
        log.log(settings.TRACE_FIELD_VALUE, "  %s" % (self.get_request_path()))
        log.log(settings.TRACE_FIELD_VALUE, "  form data %r" % (request.POST))
        listinfo = self.list_setup(coll_id, type_id, list_id,
                                   request.POST.dict())
        if listinfo.http_response:
            return listinfo.http_response
        if 'close' in request.POST:
            return HttpResponseRedirect(listinfo.get_continuation_url()
                                        or self.collection_view_url)

        # Process requested action
        redirect_uri = None
        entity_ids = request.POST.getlist('entity_select')
        log.debug("entity_ids %r" % (entity_ids))
        if len(entity_ids) > 1:
            action = ""
            redirect_uri = self.check_value_supplied(
                None,
                message.TOO_MANY_ENTITIES_SEL,
                continuation_url=listinfo.get_continuation_url())
        else:
            entity_type = type_id or listinfo.get_list_type_id()
            entity_id = None
            if len(entity_ids) == 1:
                (entity_type,
                 entity_id) = split_type_entity_id(entity_ids[0], entity_type)
            if "new" in request.POST:
                action = "new"
                redirect_uri = uri_with_params(
                    listinfo.get_new_view_uri(coll_id, entity_type),
                    {'continuation_url': listinfo.get_continuation_here()})
            if "copy" in request.POST:
                action = "copy"
                redirect_uri = (
                    self.check_value_supplied(
                        entity_id,
                        message.NO_ENTITY_FOR_COPY,
                        continuation_url=listinfo.get_continuation_url())
                    or uri_with_params(
                        listinfo.get_edit_view_uri(coll_id, entity_type,
                                                   entity_id, action),
                        {'continuation_url': listinfo.get_continuation_here()
                         }))
            if "edit" in request.POST:
                action = "edit"
                redirect_uri = (
                    self.check_value_supplied(
                        entity_id,
                        message.NO_ENTITY_FOR_EDIT,
                        continuation_url=listinfo.get_continuation_url())
                    or uri_with_params(
                        listinfo.get_edit_view_uri(coll_id, entity_type,
                                                   entity_id, action),
                        {'continuation_url': listinfo.get_continuation_here()
                         }))
            if "delete" in request.POST:
                action = "delete"
                redirect_uri = (self.check_value_supplied(
                    entity_id,
                    message.NO_ENTITY_FOR_DELETE,
                    continuation_url=listinfo.get_continuation_url())
                                or listinfo.check_collection_entity(
                                    entity_id, entity_type,
                                    message.SITE_ENTITY_FOR_DELETE %
                                    {'id': entity_id})
                                or self.check_delete_type_values(
                                    listinfo, entity_id, entity_type,
                                    message.TYPE_VALUES_FOR_DELETE %
                                    {'type_id': entity_id}))
                if not redirect_uri:
                    # Get user to confirm action before actually doing it
                    confirmed_action_uri = self.view_uri(
                        "AnnalistEntityDataDeleteView",
                        coll_id=coll_id,
                        type_id=entity_type)
                    # log.info("coll_id %s, type_id %s, confirmed_action_uri %s"%(coll_id, entity_type, confirmed_action_uri))
                    delete_params = dict_querydict({
                        "entity_delete": ["Delete"],
                        "entity_id": [entity_id],
                        "completion_url": [listinfo.get_continuation_here()],
                        "search_for": [request.POST['search_for']]
                    })
                    curi = listinfo.get_continuation_url()
                    if curi:
                        dict_querydict["continuation_url"] = [curi]
                    message_vals = {
                        'id': entity_id,
                        'type_id': entity_type,
                        'coll_id': coll_id
                    }
                    typeinfo = listinfo.entitytypeinfo
                    if typeinfo is None:
                        typeinfo = EntityTypeInfo(listinfo.collection,
                                                  entity_type)
                    return (self.form_action_auth(
                        "delete", listinfo.collection,
                        typeinfo.permissions_map) or ConfirmView.render_form(
                            request,
                            action_description=message.REMOVE_ENTITY_DATA %
                            message_vals,
                            confirmed_action_uri=confirmed_action_uri,
                            action_params=delete_params,
                            cancel_action_uri=listinfo.get_continuation_here(),
                            title=self.site_data()["title"]))
            if "default_view" in request.POST:
                if listinfo.entitytypeinfo:
                    permissions_map = listinfo.entitytypeinfo.permissions_map
                else:
                    permissions_map = CONFIG_PERMISSIONS
                auth_check = self.form_action_auth("config",
                                                   listinfo.collection,
                                                   permissions_map)
                if auth_check:
                    return auth_check
                listinfo.collection.set_default_list(list_id)
                action = "list"
                msg = message.DEFAULT_LIST_UPDATED % {
                    'coll_id': coll_id,
                    'list_id': list_id
                }
                redirect_uri = (uri_with_params(
                    self.get_request_path(), self.info_params(msg),
                    listinfo.get_continuation_url_dict()))
            if (("list_type" in request.POST) or ("list_all" in request.POST)):
                action = "list"
                redirect_uri = self.get_list_url(
                    coll_id,
                    extract_entity_id(request.POST['list_choice']),
                    type_id=None if "list_all" in request.POST else type_id,
                    scope="all" if "list_scope_all" in request.POST else None,
                    search=request.POST['search_for'],
                    query_params=listinfo.get_continuation_url_dict())
            if "customize" in request.POST:
                action = "config"
                redirect_uri = (uri_with_params(
                    self.view_uri("AnnalistCollectionEditView",
                                  coll_id=coll_id),
                    {'continuation_url': listinfo.get_continuation_here()}))
        if redirect_uri:
            return (listinfo.check_authorization(action)
                    or HttpResponseRedirect(redirect_uri))
        # Report unexpected form data
        # This shouldn't happen, but just in case...
        # Redirect to continuation with error
        log.error("Unexpected form data posted to %s: %r" %
                  (request.get_full_path(), request.POST))
        err_values = self.error_params(
            message.UNEXPECTED_FORM_DATA % (request.POST),
            message.SYSTEM_ERROR)
        redirect_uri = uri_with_params(listinfo.get_continuation_next(),
                                       err_values)
        return HttpResponseRedirect(redirect_uri)
Ejemplo n.º 32
0
    def post(self, request):
        """
        Process options to add or remove a collection in an Annalist site
        """
        log.debug("site.post: %r" % (request.POST.lists()))

        collections = request.POST.getlist("select", [])
        coll_id = collections[0] if collections else "_"
        coll_ids = {'ids': ", ".join(collections)}
        perm_req = None
        perm_scope = None
        none_msg = None
        many_msg = None
        redirect_uri = None
        http_response = None
        # Process POST option
        if "view" in request.POST:
            # Collection data is considered part of configuration, hence CONFIG_PERMISSIONS:
            perm_req = CONFIG_PERMISSIONS["view"]
            # Use Collection or Site permissions:
            perm_scope = "all"
            none_msg = message.NO_COLLECTION_VIEW
            many_msg = message.MANY_COLLECTIONS_VIEW
            target_uri = self.view_uri("AnnalistEntityEditView",
                                       coll_id=layout.SITEDATA_ID,
                                       view_id="Collection_view",
                                       type_id="_coll",
                                       entity_id=coll_id,
                                       action="view")
            redirect_uri = uri_with_params(
                target_uri, {'continuation_url': self.continuation_here()})
        elif "edit" in request.POST:
            perm_req = CONFIG_PERMISSIONS["edit"]
            perm_scope = "all"
            none_msg = message.NO_COLLECTION_EDIT
            many_msg = message.MANY_COLLECTIONS_EDIT
            target_uri = self.view_uri("AnnalistEntityEditView",
                                       coll_id=layout.SITEDATA_ID,
                                       view_id="Collection_view",
                                       type_id="_coll",
                                       entity_id=coll_id,
                                       action="edit")
            redirect_uri = uri_with_params(
                target_uri, {'continuation_url': self.continuation_here()})
        elif "remove" in request.POST:
            perm_req = "DELETE_COLLECTION"
            perm_scope = "all"  # Collection or site permissions
            none_msg = message.NO_COLLECTIONS_REMOVE
        elif "new" in request.POST:
            perm_req = "CREATE_COLLECTION"
            perm_scope = "site"  # Site permission required
            new_id = request.POST["new_id"]
            new_label = request.POST["new_label"]
        # Common checks
        if none_msg and not collections:
            http_response = self.redirect_info(
                self.view_uri("AnnalistSiteView"),
                info_message=none_msg,
                info_head=message.NO_ACTION_PERFORMED)
        elif many_msg and len(collections) > 1:
            http_response = self.redirect_info(
                self.view_uri("AnnalistSiteView"),
                info_message=many_msg % coll_ids,
                info_head=message.NO_ACTION_PERFORMED)
        elif perm_req:
            if perm_scope == "all":
                # Check collections for permissions
                for cid in collections:
                    if http_response is None:
                        site = self.site(host=self.get_request_host())
                        sitedata = self.site_data()
                        coll = Collection.load(site, cid, altscope="site")
                        http_response = (
                            self.authorize("ADMIN", coll)
                            and  # Either of these...
                            self.authorize(perm_req, coll))
                        coll = None
            else:
                # Check site only for permissions
                http_response = (self.authorize("ADMIN", None)
                                 and self.authorize(perm_req, None))
        if http_response is not None:
            return http_response
        # Perform selected option
        if redirect_uri:
            log.info("Redirect to %s" % redirect_uri)
            return HttpResponseRedirect(redirect_uri)
        if "remove" in request.POST:
            if layout.SITEDATA_ID in collections:
                log.warning("Attempt to delete site data collection %(ids)s" %
                            (coll_ids))
                http_response = self.error(
                    self.error403values(scope="DELETE_SITE"))
            else:
                http_response = ConfirmView.render_form(
                    request,
                    action_description=message.REMOVE_COLLECTIONS % coll_ids,
                    action_params=request.POST,
                    confirmed_action_uri=self.view_uri(
                        'AnnalistSiteActionView'),
                    cancel_action_uri=self.view_uri('AnnalistSiteView'),
                    title=self.site_data()["title"])
            return http_response
        if "new" in request.POST:
            log.info("New collection %s: %s" % (new_id, new_label))
            error_message = None
            if not new_id:
                error_message = message.MISSING_COLLECTION_ID
            elif not util.valid_id(new_id):
                error_message = message.INVALID_COLLECTION_ID % {
                    'coll_id': new_id
                }
            if error_message:
                return self.redirect_error(self.view_uri("AnnalistSiteView"),
                                           error_message=error_message)
            coll_meta = ({RDFS.CURIE.label: new_label, RDFS.CURIE.comment: ""})
            # Add collection
            coll = self.site().add_collection(new_id, coll_meta)
            coll.generate_coll_jsonld_context()
            user = self.request.user
            user_id = user.username
            user_uri = "mailto:" + user.email
            user_name = "%s %s" % (user.first_name, user.last_name)
            user_description = "User %s: permissions for %s in collection %s" % (
                user_id, user_name, new_id)
            coll.create_user_permissions(user_id,
                                         user_uri,
                                         user_name,
                                         user_description,
                                         user_permissions=[
                                             "VIEW", "CREATE", "UPDATE",
                                             "DELETE", "CONFIG", "ADMIN"
                                         ])
            return self.redirect_info(
                self.view_uri("AnnalistSiteView"),
                info_message=message.CREATED_COLLECTION_ID %
                {'coll_id': new_id})

        # elif "remove" in request.POST:
        #     collections = request.POST.getlist("select", [])
        #     if collections:
        #         # Check authorization
        #         if layout.SITEDATA_ID in collections:
        #             log.warning("Attempt to delete site data collection %r"%(collections))
        #             auth_required = self.error(self.error403values(scope="DELETE_SITE"))
        #         else:
        #             auth_required = (
        #                 self.authorize("ADMIN", None) and           # either of these..
        #                 self.authorize("DELETE_COLLECTION", None)
        #                 )
        #         return (
        #             # Get user to confirm action before actually doing it
        #             auth_required or
        #             ConfirmView.render_form(request,
        #                 action_description=     message.REMOVE_COLLECTIONS%{'ids': ", ".join(collections)},
        #                 action_params=          request.POST,
        #                 confirmed_action_uri=   self.view_uri('AnnalistSiteActionView'),
        #                 cancel_action_uri=      self.view_uri('AnnalistSiteView'),
        #                 title=                  self.site_data()["title"]
        #                 )
        #             )
        #     else:
        #         return self.redirect_info(
        #             self.view_uri("AnnalistSiteView"),
        #             info_message=message.NO_COLLECTIONS_REMOVE, info_head=message.NO_ACTION_PERFORMED
        #             )
        # if "new" in request.POST:
        #     # Create new collection with name and label supplied
        #     new_id    = request.POST["new_id"]
        #     new_label = request.POST["new_label"]
        #     log.debug("New collection %s: %s"%(new_id, new_label))
        #     if not new_id:
        #         return self.redirect_error(
        #             self.view_uri("AnnalistSiteView"),
        #             error_message=message.MISSING_COLLECTION_ID
        #             )
        #     if not util.valid_id(new_id):
        #         return self.redirect_error(
        #             self.view_uri("AnnalistSiteView"),
        #             error_message=message.INVALID_COLLECTION_ID%{'coll_id': new_id}
        #             )
        #     # Create new collection with name and label supplied
        #     auth_required = (
        #         self.authorize("ADMIN", None) and           # either of these..
        #         self.authorize("CREATE_COLLECTION", None)
        #         )
        #     if auth_required:
        #         return auth_required
        #     coll_meta = (
        #         { RDFS.CURIE.label:    new_label
        #         , RDFS.CURIE.comment:  ""
        #         })
        #     coll = self.site().add_collection(new_id, coll_meta)
        #     # Generate initial context
        #     coll.generate_coll_jsonld_context()
        #     # Create full permissions in new collection for creating user
        #     user = self.request.user
        #     user_id = user.username
        #     user_uri = "mailto:"+user.email
        #     user_name = "%s %s"%(user.first_name, user.last_name)
        #     user_description = "User %s: permissions for %s in collection %s"%(user_id, user_name, new_id)
        #     coll.create_user_permissions(
        #         user_id, user_uri,
        #         user_name, user_description,
        #         user_permissions=["VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG", "ADMIN"]
        #         )
        #     return self.redirect_info(
        #         self.view_uri("AnnalistSiteView"),
        #         info_message=message.CREATED_COLLECTION_ID%{'coll_id': new_id}
        #         )
        log.warning("Invalid POST request: %r" % (request.POST.lists()))
        return self.error(self.error400values())
Ejemplo n.º 33
0
    def post(self, request):
        """
        Process options to add or remove a collection in an Annalist site
        """
        log.debug("site.post: %r"%(request.POST.lists()))

        collections   = request.POST.getlist("select", [])
        coll_id       = collections[0] if collections else "_"
        coll_ids      = {'ids': ", ".join(collections)}
        perm_req      = None
        perm_scope    = None
        none_msg      = None
        many_msg      = None
        redirect_uri  = None
        http_response = None
        # Process POST option
        if   "view" in request.POST:
            # Collection data is considered part of configuration, hence CONFIG_PERMISSIONS:
            perm_req     = CONFIG_PERMISSIONS["view"]
            # Use Collection or Site permissions:
            perm_scope   = "all"
            none_msg     = message.NO_COLLECTION_VIEW
            many_msg     = message.MANY_COLLECTIONS_VIEW
            target_uri   = self.view_uri("AnnalistEntityEditView",
                coll_id=layout.SITEDATA_ID,
                view_id="Collection_view",
                type_id="_coll",
                entity_id=coll_id,
                action="view"
                )
            redirect_uri = uri_with_params(
                    target_uri, 
                    {'continuation_url': self.continuation_here()}
                    )
        elif "edit" in  request.POST:
            perm_req    = CONFIG_PERMISSIONS["edit"]
            perm_scope  = "all"
            none_msg    = message.NO_COLLECTION_EDIT
            many_msg    = message.MANY_COLLECTIONS_EDIT
            target_uri  = self.view_uri("AnnalistEntityEditView",
                coll_id=layout.SITEDATA_ID,
                view_id="Collection_view",
                type_id="_coll",
                entity_id=coll_id,
                action="edit"
                )
            redirect_uri = uri_with_params(
                    target_uri, 
                    {'continuation_url': self.continuation_here()}
                    )
        elif "remove" in request.POST:
            perm_req    = "DELETE_COLLECTION"
            perm_scope  = "all"    # Collection or site permissions
            none_msg    = message.NO_COLLECTIONS_REMOVE
        elif "new" in request.POST:
            perm_req    = "CREATE_COLLECTION"
            perm_scope  = "site"    # Site permission required
            new_id      = request.POST["new_id"]
            new_label   = request.POST["new_label"]
        # Common checks
        if none_msg and not collections:
            http_response = self.redirect_info(
                self.view_uri("AnnalistSiteView"), 
                info_message=none_msg, info_head=message.NO_ACTION_PERFORMED
                )
        elif many_msg and len(collections) > 1:
            http_response = self.redirect_info(
                self.view_uri("AnnalistSiteView"), 
                info_message=many_msg%coll_ids, 
                info_head=message.NO_ACTION_PERFORMED
                )
        elif perm_req:
            if perm_scope == "all":
                # Check collections for permissions
                for cid in collections:
                    if http_response is None:
                        site     = self.site(host=self.get_request_host())
                        sitedata = self.site_data()
                        coll     = Collection.load(site, cid, altscope="site")
                        http_response = (
                            self.authorize("ADMIN", coll) and   # Either of these...
                            self.authorize(perm_req, coll)
                            )
                        coll = None
            else:
                # Check site only for permissions
                http_response = (
                    self.authorize("ADMIN", None) and 
                    self.authorize(perm_req, None)
                    )
        if http_response is not None:
            return http_response            
        # Perform selected option
        if redirect_uri:
            log.info("Redirect to %s"%redirect_uri)
            return HttpResponseRedirect(redirect_uri)
        if "remove" in request.POST:
            if layout.SITEDATA_ID in collections:
                log.warning("Attempt to delete site data collection %(ids)s"%(coll_ids))
                http_response = self.error(self.error403values(scope="DELETE_SITE"))
            else:
                http_response = ConfirmView.render_form(request,
                    action_description=     message.REMOVE_COLLECTIONS%coll_ids,
                    action_params=          request.POST,
                    confirmed_action_uri=   self.view_uri('AnnalistSiteActionView'),
                    cancel_action_uri=      self.view_uri('AnnalistSiteView'),
                    title=                  self.site_data()["title"]
                    )
            return http_response
        if "new" in request.POST:
            log.info("New collection %s: %s"%(new_id, new_label))
            error_message = None
            if not new_id:
                error_message = message.MISSING_COLLECTION_ID
            elif not util.valid_id(new_id):
                error_message = message.INVALID_COLLECTION_ID%{'coll_id': new_id}
            if error_message:
                return self.redirect_error(
                    self.view_uri("AnnalistSiteView"), 
                    error_message=error_message
                    )
            coll_meta = (
                { RDFS.CURIE.label:    new_label
                , RDFS.CURIE.comment:  ""
                })
            # Add collection
            coll = self.site().add_collection(new_id, coll_meta)
            coll.generate_coll_jsonld_context()
            user             = self.request.user
            user_id          = user.username
            user_uri         = "mailto:"+user.email
            user_name        = "%s %s"%(user.first_name, user.last_name)
            user_description = "User %s: permissions for %s in collection %s"%(user_id, user_name, new_id)
            coll.create_user_permissions(
                user_id, user_uri, 
                user_name, user_description,
                user_permissions=["VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG", "ADMIN"]
                )
            return self.redirect_info(
                self.view_uri("AnnalistSiteView"), 
                info_message=message.CREATED_COLLECTION_ID%{'coll_id': new_id}
                )

        # elif "remove" in request.POST:
        #     collections = request.POST.getlist("select", [])
        #     if collections:
        #         # Check authorization
        #         if layout.SITEDATA_ID in collections:
        #             log.warning("Attempt to delete site data collection %r"%(collections))
        #             auth_required = self.error(self.error403values(scope="DELETE_SITE"))
        #         else:
        #             auth_required = (
        #                 self.authorize("ADMIN", None) and           # either of these..
        #                 self.authorize("DELETE_COLLECTION", None)
        #                 )
        #         return (
        #             # Get user to confirm action before actually doing it
        #             auth_required or
        #             ConfirmView.render_form(request,
        #                 action_description=     message.REMOVE_COLLECTIONS%{'ids': ", ".join(collections)},
        #                 action_params=          request.POST,
        #                 confirmed_action_uri=   self.view_uri('AnnalistSiteActionView'),
        #                 cancel_action_uri=      self.view_uri('AnnalistSiteView'),
        #                 title=                  self.site_data()["title"]
        #                 )
        #             )
        #     else:
        #         return self.redirect_info(
        #             self.view_uri("AnnalistSiteView"), 
        #             info_message=message.NO_COLLECTIONS_REMOVE, info_head=message.NO_ACTION_PERFORMED
        #             )
        # if "new" in request.POST:
        #     # Create new collection with name and label supplied
        #     new_id    = request.POST["new_id"]
        #     new_label = request.POST["new_label"]
        #     log.debug("New collection %s: %s"%(new_id, new_label))
        #     if not new_id:
        #         return self.redirect_error(
        #             self.view_uri("AnnalistSiteView"), 
        #             error_message=message.MISSING_COLLECTION_ID
        #             )
        #     if not util.valid_id(new_id):
        #         return self.redirect_error(
        #             self.view_uri("AnnalistSiteView"), 
        #             error_message=message.INVALID_COLLECTION_ID%{'coll_id': new_id}
        #             )
        #     # Create new collection with name and label supplied
        #     auth_required = (
        #         self.authorize("ADMIN", None) and           # either of these..
        #         self.authorize("CREATE_COLLECTION", None)
        #         )
        #     if auth_required:
        #         return auth_required
        #     coll_meta = (
        #         { RDFS.CURIE.label:    new_label
        #         , RDFS.CURIE.comment:  ""
        #         })
        #     coll = self.site().add_collection(new_id, coll_meta)
        #     # Generate initial context
        #     coll.generate_coll_jsonld_context()
        #     # Create full permissions in new collection for creating user
        #     user = self.request.user
        #     user_id = user.username
        #     user_uri = "mailto:"+user.email
        #     user_name = "%s %s"%(user.first_name, user.last_name)
        #     user_description = "User %s: permissions for %s in collection %s"%(user_id, user_name, new_id)
        #     coll.create_user_permissions(
        #         user_id, user_uri, 
        #         user_name, user_description,
        #         user_permissions=["VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG", "ADMIN"]
        #         )
        #     return self.redirect_info(
        #         self.view_uri("AnnalistSiteView"), 
        #         info_message=message.CREATED_COLLECTION_ID%{'coll_id': new_id}
        #         )
        log.warning("Invalid POST request: %r"%(request.POST.lists()))
        return self.error(self.error400values())
Ejemplo n.º 34
0
    def form_response(self, viewinfo, entity_id, orig_entity_id,
                      entity_type_id, orig_entity_type_id, messages,
                      context_extra_values):
        """
        Handle POST response from entity edit form.
        """
        log.info(
            "form_response entity_id %s, orig_entity_id %s, entity_type_id %s, orig_entity_type_id %s"
            % (entity_id, orig_entity_id, entity_type_id, orig_entity_type_id))
        form_data = self.request.POST
        continuation_url = context_extra_values['continuation_url']
        if 'cancel' in form_data:
            return HttpResponseRedirect(continuation_url)

        typeinfo = viewinfo.entitytypeinfo
        orig_entity = self.get_entity(orig_entity_id, typeinfo,
                                      viewinfo.action)
        # log.info("orig_entity %r"%(orig_entity.get_values(),))
        entityvaluemap = self.get_view_entityvaluemap(viewinfo, orig_entity)

        # Check response has valid id and type
        if not util.valid_id(entity_id):
            log.debug("form_response: entity_id not util.valid_id('%s')" %
                      entity_id)
            return self.form_re_render(
                viewinfo,
                entityvaluemap,
                form_data,
                context_extra_values,
                error_head=messages['entity_heading'],
                error_message=messages['entity_invalid_id'])
        if not util.valid_id(entity_type_id):
            log.debug("form_response: entity_type_id not util.valid_id('%s')" %
                      entity_type_id)
            return self.form_re_render(
                viewinfo,
                entityvaluemap,
                form_data,
                context_extra_values,
                error_head=messages['entity_type_heading'],
                error_message=messages['entity_type_invalid'])

        # Save updated details
        if 'save' in form_data:
            # log.info(
            #     "save: entity_id %s, orig_entity_id %s, type_id %s, orig_type_id %s"%
            #     (entity_id, orig_entity_id, entity_type_id, orig_entity_type_id)
            #     )
            http_response = self.save_entity(entityvaluemap, form_data,
                                             entity_id, entity_type_id,
                                             orig_entity_id,
                                             orig_entity_type_id, viewinfo,
                                             context_extra_values, messages)
            return http_response or HttpResponseRedirect(continuation_url)

        # Add field from entity view (as opposed to view description view)
        # See below call of 'find_add_field' for adding field in view description
        if 'add_view_field' in form_data:
            view_edit_uri_base = self.view_uri("AnnalistEntityEditView",
                                               coll_id=viewinfo.coll_id,
                                               view_id="View_view",
                                               type_id="_view",
                                               entity_id=viewinfo.view_id,
                                               action="edit")
            return self.invoke_config_edit_view(
                entityvaluemap, form_data, entity_id, entity_type_id,
                orig_entity_id, orig_entity_type_id, orig_entity, viewinfo,
                context_extra_values, messages, view_edit_uri_base, "config",
                {"add_field": "View_fields"}, continuation_url)

        # Update or define new view or type (invoked from generic entity editing view)
        # Save current entity and redirect to view edit with new field added, and
        # current page as continuation.
        if 'use_view' in form_data:
            # Save entity, then redirect to selected view
            http_response = self.save_entity(entityvaluemap, form_data,
                                             entity_id, entity_type_id,
                                             orig_entity_id,
                                             orig_entity_type_id, viewinfo,
                                             context_extra_values, messages)
            if http_response:
                return http_response
            view_uri_params = ({
                'coll_id': viewinfo.coll_id,
                'type_id': entity_type_id,
                'view_id': form_data['view_choice'],
                'entity_id': entity_id,
                'action': "edit"
            })
            redirect_uri = (uri_with_params(
                self.view_uri("AnnalistEntityEditView", **view_uri_params),
                {'continuation_url': continuation_url}))
            return HttpResponseRedirect(redirect_uri)

        # New entity buttons
        #
        # These may use explicit button ids per the table below, or may be part of
        # an enumered-value field used to create a new enumerated value instance.
        #
        # In all cases, the current entity is saved and the browser is redirected
        # to a new page to enter details of a new entity of the appropriate type.
        #
        new_button_map = ({
            'new_type': {
                'type_id': "_type",
                'view_id': "Type_view"
            },
            'new_view': {
                'type_id': "_view",
                'view_id': "View_view"
            },
            'new_field': {
                'type_id': "_field",
                'view_id': "Field_view"
            },
            'new_group': {
                'type_id': "_group",
                'view_id': "Field_group_view"
            }
        })
        new_type_id = None
        for button_id in new_button_map.keys():
            if button_id in form_data:
                new_type_id = new_button_map[button_id]['type_id']
                new_view_id = new_button_map[button_id]['view_id']
                break

        new_enum = self.find_new_enum(entityvaluemap, form_data)
        if new_enum:
            new_type_id = new_enum['field_options_typeref']
            new_typeinfo = EntityTypeInfo(viewinfo.site, viewinfo.collection,
                                          new_type_id)
            new_view_id = new_typeinfo.get_default_view_id()

        if new_type_id is not None:
            new_edit_uri_base = self.view_uri("AnnalistEntityNewView",
                                              coll_id=viewinfo.coll_id,
                                              view_id=new_view_id,
                                              type_id=new_type_id,
                                              action="new")
            return self.invoke_config_edit_view(
                entityvaluemap, form_data, entity_id, entity_type_id,
                orig_entity_id, orig_entity_type_id, orig_entity, viewinfo,
                context_extra_values, messages, new_edit_uri_base, "new", {},
                continuation_url)

        # Add new instance of repeating field, and redisplay
        add_field = self.find_add_field(entityvaluemap, form_data)
        # log.info("*** Add field: "+repr(add_field))
        if add_field:
            entityvals = entityvaluemap.map_form_data_to_values(form_data)
            return self.update_view_fields(viewinfo, add_field, entityvals,
                                           entityvaluemap,
                                           **context_extra_values)

        # Remove Field(s), and redisplay
        remove_field = self.find_remove_field(entityvaluemap, form_data)
        if remove_field:
            if not remove_field['remove_fields']:
                log.debug(
                    "form_response: No field(s) selected for remove_field")
                return self.form_re_render(
                    viewinfo,
                    entityvaluemap,
                    form_data,
                    context_extra_values,
                    error_head=messages['remove_field_error'],
                    error_message=messages['no_field_selected'])
            entityvals = entityvaluemap.map_form_data_to_values(form_data)
            return self.update_view_fields(viewinfo, remove_field, entityvals,
                                           entityvaluemap,
                                           **context_extra_values)

        # Report unexpected form data
        # This shouldn't happen, but just in case...
        # Redirect to continuation with error
        err_values = self.error_params(
            message.UNEXPECTED_FORM_DATA % (form_data), message.SYSTEM_ERROR)
        log.warning("Unexpected form data %s" % (err_values))
        log.warning("Continue to %s" % (continuation_url))
        for k, v in form_data.items():
            log.info("  form[%s] = %r" % (k, v))
        redirect_uri = uri_with_params(continuation_url, err_values)
        return HttpResponseRedirect(redirect_uri)
Ejemplo n.º 35
0
    def post(self, request, coll_id=None, type_id=None, list_id=None):
        """
        Handle response from dynamically generated list display form.
        """
        log.info("views.entitylist.post: coll_id %s, type_id %s, list_id %s"%(coll_id, type_id, list_id))
        log.log(settings.TRACE_FIELD_VALUE, "  %s"%(self.get_request_path()))
        log.log(settings.TRACE_FIELD_VALUE, "  form data %r"%(request.POST))
        listinfo = self.list_setup(coll_id, type_id, list_id, request.POST.dict())
        if listinfo.http_response:
            return listinfo.http_response
        if 'close' in request.POST:
            return HttpResponseRedirect(listinfo.get_continuation_url() or self.collection_view_url)

        # Process requested action
        redirect_uri = None
        entity_ids   = request.POST.getlist('entity_select')
        log.debug("entity_ids %r"%(entity_ids))
        if len(entity_ids) > 1:
            action = ""
            redirect_uri = self.check_value_supplied(
                None, message.TOO_MANY_ENTITIES_SEL,
                continuation_url=listinfo.get_continuation_url()
                )
        else:
            entity_type = type_id or listinfo.get_list_type_id()
            entity_id   = None
            if len(entity_ids) == 1:
                (entity_type, entity_id) = split_type_entity_id(entity_ids[0], entity_type)
            if "new" in request.POST:
                action = "new"
                redirect_uri = uri_with_params(
                    listinfo.get_new_view_uri(coll_id, entity_type), 
                    {'continuation_url': listinfo.get_continuation_here()}
                    )
            if "copy" in request.POST:
                action = "copy"
                redirect_uri = (
                    self.check_value_supplied(entity_id, 
                        message.NO_ENTITY_FOR_COPY, 
                        continuation_url=listinfo.get_continuation_url()
                        )
                    or
                    uri_with_params(
                        listinfo.get_edit_view_uri(
                            coll_id, entity_type, entity_id, action
                            ),
                        {'continuation_url': listinfo.get_continuation_here()}
                        )
                    )
            if "edit" in request.POST:
                action = "edit"
                redirect_uri = (
                    self.check_value_supplied(entity_id, 
                        message.NO_ENTITY_FOR_EDIT,
                        continuation_url=listinfo.get_continuation_url()
                        )
                    or
                    uri_with_params(
                        listinfo.get_edit_view_uri(
                            coll_id, entity_type, entity_id, action
                            ),
                        {'continuation_url': listinfo.get_continuation_here()}
                        )
                    )
            if "delete" in request.POST:
                action = "delete"
                redirect_uri = (
                    self.check_value_supplied(entity_id, 
                        message.NO_ENTITY_FOR_DELETE,
                        continuation_url=listinfo.get_continuation_url()
                        )
                    or
                    listinfo.check_collection_entity(entity_id, entity_type,
                        message.SITE_ENTITY_FOR_DELETE%{'id': entity_id}
                        )
                    or
                    self.check_delete_type_values(listinfo,
                        entity_id, entity_type,
                        message.TYPE_VALUES_FOR_DELETE%{'type_id': entity_id}
                        )
                    )
                if not redirect_uri:
                    # Get user to confirm action before actually doing it
                    confirmed_action_uri = self.view_uri(
                        "AnnalistEntityDataDeleteView", 
                        coll_id=coll_id, type_id=entity_type
                        )
                    # log.info("coll_id %s, type_id %s, confirmed_action_uri %s"%(coll_id, entity_type, confirmed_action_uri))
                    delete_params = dict_querydict(
                        { "entity_delete":      ["Delete"]
                        , "entity_id":          [entity_id]
                        , "completion_url":     [listinfo.get_continuation_here()]
                        , "search_for":         [request.POST['search_for']]
                        })
                    curi = listinfo.get_continuation_url()
                    if curi:
                        dict_querydict["continuation_url"] = [curi]
                    message_vals = {'id': entity_id, 'type_id': entity_type, 'coll_id': coll_id}
                    typeinfo = listinfo.entitytypeinfo
                    if typeinfo is None:
                        typeinfo = EntityTypeInfo(listinfo.collection, entity_type)
                    return (
                        self.form_action_auth(
                            "delete", listinfo.collection, typeinfo.permissions_map
                            ) or
                        ConfirmView.render_form(request,
                            action_description=     message.REMOVE_ENTITY_DATA%message_vals,
                            confirmed_action_uri=   confirmed_action_uri,
                            action_params=          delete_params,
                            cancel_action_uri=      listinfo.get_continuation_here(),
                            title=                  self.site_data()["title"]
                            )
                        )
            if "default_view" in request.POST:
                if listinfo.entitytypeinfo:
                    permissions_map = listinfo.entitytypeinfo.permissions_map
                else:
                    permissions_map = CONFIG_PERMISSIONS
                auth_check = self.form_action_auth("config", listinfo.collection, permissions_map)
                if auth_check:
                    return auth_check
                listinfo.collection.set_default_list(list_id)
                action = "list"
                msg    = message.DEFAULT_LIST_UPDATED%{'coll_id': coll_id, 'list_id': list_id}         
                redirect_uri = (
                    uri_with_params(
                        self.get_request_path(), 
                        self.info_params(msg),
                        listinfo.get_continuation_url_dict()
                        )
                    )
            if ( ("list_type" in request.POST) or ("list_all"  in request.POST) ):
                action       = "list"
                redirect_uri = self.get_list_url(
                    coll_id, extract_entity_id(request.POST['list_choice']),
                    type_id=None if "list_all" in request.POST else type_id,
                    scope="all" if "list_scope_all" in request.POST else None,
                    search=request.POST['search_for'],
                    query_params=listinfo.get_continuation_url_dict()
                    )
            if "customize" in request.POST:
                action       = "config"
                redirect_uri = (
                    uri_with_params(
                        self.view_uri(
                            "AnnalistCollectionEditView", 
                            coll_id=coll_id
                            ),
                        {'continuation_url': listinfo.get_continuation_here()}
                        )
                    )
        if redirect_uri:
            return (
                listinfo.check_authorization(action) or
                HttpResponseRedirect(redirect_uri)
                )
        # Report unexpected form data
        # This shouldn't happen, but just in case...
        # Redirect to continuation with error
        log.error("Unexpected form data posted to %s: %r"%(request.get_full_path(), request.POST))
        err_values = self.error_params(
            message.UNEXPECTED_FORM_DATA%(request.POST), 
            message.SYSTEM_ERROR
            )
        redirect_uri = uri_with_params(listinfo.get_continuation_next(), err_values)
        return HttpResponseRedirect(redirect_uri)
Ejemplo n.º 36
0
    def post(self,
             request,
             coll_id=None,
             type_id=None,
             list_id=None,
             scope=None):
        """
        Handle response from dynamically generated list display form.
        """
        log.info("views.entitylist.post: coll_id %s, type_id %s, list_id %s" %
                 (coll_id, type_id, list_id))
        # log.info("  %s"%(self.get_request_path()))
        # log.info("  form data %r"%(request.POST))
        continuation_next, continuation_here = self.continuation_urls(
            request.POST, None
            # self.view_uri("AnnalistSiteView")
            # self.view_uri("AnnalistCollectionEditView", coll_id=coll_id)
        )
        if 'close' in request.POST:
            return HttpResponseRedirect(
                continuation_next.get('continuation_url',
                                      self.view_uri("AnnalistSiteView")))

        # Not "Close": set up list parameters
        listinfo = self.list_setup(coll_id, type_id, list_id)
        if listinfo.http_response:
            return listinfo.http_response

        # Process requested action
        redirect_uri = None
        entity_ids = request.POST.getlist('entity_select')
        log.debug("entity_ids %r" % (entity_ids))
        if len(entity_ids) > 1:
            action = ""
            redirect_uri = self.check_value_supplied(
                None, message.TOO_MANY_ENTITIES_SEL)
        else:
            (entity_type, entity_id) = (entity_ids[0].split("/") if
                                        len(entity_ids) == 1 else (None, None))
            entity_type = entity_type or type_id or listinfo.get_list_type_id()
            if "new" in request.POST:
                action = "new"
                redirect_uri = uri_with_params(
                    listinfo.get_new_view_uri(coll_id, entity_type),
                    continuation_here)
            if "copy" in request.POST:
                action = "copy"
                redirect_uri = (self.check_value_supplied(
                    entity_id,
                    message.NO_ENTITY_FOR_COPY,
                    continuation_url=continuation_next) or uri_with_params(
                        listinfo.get_edit_view_uri(coll_id, entity_type,
                                                   entity_id, action),
                        continuation_here))
            if "edit" in request.POST:
                action = "edit"
                redirect_uri = (self.check_value_supplied(
                    entity_id,
                    message.NO_ENTITY_FOR_EDIT,
                    continuation_url=continuation_next) or uri_with_params(
                        listinfo.get_edit_view_uri(coll_id, entity_type,
                                                   entity_id, action),
                        continuation_here))
            if "delete" in request.POST:
                action = "delete"
                redirect_uri = (self.check_value_supplied(
                    entity_id,
                    message.NO_ENTITY_FOR_DELETE,
                    continuation_url=continuation_next)
                                or listinfo.check_collection_entity(
                                    entity_id,
                                    entity_type,
                                    message.SITE_ENTITY_FOR_DELETE %
                                    {'id': entity_id},
                                    continuation_url=continuation_next)
                                or self.check_delete_type_values(
                                    listinfo,
                                    entity_id,
                                    entity_type,
                                    message.TYPE_VALUES_FOR_DELETE %
                                    {'type_id': entity_id},
                                    continuation_url=continuation_next))
                if not redirect_uri:
                    # Get user to confirm action before actually doing it
                    confirmed_action_uri = self.view_uri(
                        "AnnalistEntityDataDeleteView",
                        coll_id=coll_id,
                        type_id=entity_type)
                    # log.info("coll_id %s, type_id %s, confirmed_action_uri %s"%(coll_id, entity_type, confirmed_action_uri))
                    delete_params = dict_querydict({
                        "entity_delete": ["Delete"],
                        "entity_id": [entity_id],
                        "completion_url":
                        [continuation_here['continuation_url']],
                        "continuation_url":
                        [continuation_next.get('continuation_url')],
                        "search_for": [request.POST['search_for']]
                    })
                    message_vals = {
                        'id': entity_id,
                        'type_id': entity_type,
                        'coll_id': coll_id
                    }
                    typeinfo = listinfo.entitytypeinfo
                    if typeinfo is None:
                        typeinfo = EntityTypeInfo(listinfo.site,
                                                  listinfo.collection,
                                                  entity_type)
                    return (self.form_action_auth(
                        "delete", listinfo.collection,
                        typeinfo.permissions_map) or ConfirmView.render_form(
                            request,
                            action_description=message.REMOVE_ENTITY_DATA %
                            message_vals,
                            confirmed_action_uri=confirmed_action_uri,
                            action_params=delete_params,
                            cancel_action_uri=self.get_request_path(),
                            title=self.site_data()["title"]))
            if "default_view" in request.POST:
                if listinfo.entitytypeinfo:
                    permissions_map = listinfo.entitytypeinfo.permissions_map
                else:
                    permissions_map = CONFIG_PERMISSIONS
                auth_check = self.form_action_auth("config",
                                                   listinfo.collection,
                                                   permissions_map)
                if auth_check:
                    return auth_check
                listinfo.collection.set_default_list(list_id)
                action = "list"
                msg = message.DEFAULT_VIEW_UPDATED % {
                    'coll_id': coll_id,
                    'list_id': list_id
                }
                redirect_uri = (uri_with_params(self.get_request_path(),
                                                self.info_params(msg),
                                                continuation_next))
            if ("view" in request.POST) or ("view_all" in request.POST):
                action = "list"
                search = request.POST['search_for']
                params = continuation_next
                if search:
                    params = dict(params, search=search)
                list_uri_params = ({
                    'coll_id': coll_id,
                    'list_id': request.POST['list_choice']
                })
                if "view_all" in request.POST:
                    list_uri_params['scope'] = "all"
                #@@
                # if type_id:
                #     list_uri_params.update({'type_id': type_id})
                #@@
                redirect_uri = (uri_with_params(
                    self.view_uri("AnnalistEntityGenericList",
                                  **list_uri_params), params))
            if "customize" in request.POST:
                action = "config"
                redirect_uri = (uri_with_params(
                    self.view_uri("AnnalistCollectionEditView",
                                  coll_id=coll_id), continuation_here))
        if redirect_uri:
            return (listinfo.check_authorization(action)
                    or HttpResponseRedirect(redirect_uri))
        # Report unexpected form data
        # This shouldn't happen, but just in case...
        # Redirect to continuation with error
        log.error("Unexpected form data posted to %s: %r" %
                  (request.get_full_path(), request.POST))
        err_values = self.error_params(
            message.UNEXPECTED_FORM_DATA % (request.POST),
            message.SYSTEM_ERROR)
        redirect_uri = uri_with_params(continuation_next['continuation_url'],
                                       err_values)
        return HttpResponseRedirect(redirect_uri)
Ejemplo n.º 37
0
    def post(self, request, coll_id=None, type_id=None, list_id=None):
        """
        Handle response from dynamically generated list display form.
        """
        log.info("views.entitylist.post: coll_id %s, type_id %s, list_id %s"%(coll_id, type_id, list_id))
        log.log(settings.TRACE_FIELD_VALUE, "  %s"%(self.get_request_path()))
        # log.log(settings.TRACE_FIELD_VALUE, "  form data %r"%(request.POST))
        listinfo = self.list_setup(coll_id, type_id, list_id, request.POST.dict())
        if listinfo.http_response:
            return listinfo.http_response
        if 'close' in request.POST:
            return HttpResponseRedirect(listinfo.get_continuation_url() or self.collection_view_url)

        # Process requested action
        action          = None
        redirect_path   = None
        redirect_cont   = listinfo.get_continuation_here()
        redirect_params = {}
        entity_ids      = request.POST.getlist('entity_select')
        log.debug("entity_ids %r"%(entity_ids))
        if len(entity_ids) > 1:
            listinfo.display_error_response(message.TOO_MANY_ENTITIES_SEL)
        else:
            entity_type = type_id or listinfo.get_list_type_id()
            entity_id   = None
            if len(entity_ids) == 1:
                (entity_type, entity_id) = split_type_entity_id(entity_ids[0], entity_type)
                log.info("EntityList.post entity_ids: entity_type %s, entity_id %s"%(entity_type, entity_id))
            if "new" in request.POST:
                action        = "new"
                redirect_path = listinfo.get_new_view_uri(coll_id, entity_type)
            if "copy" in request.POST:
                action = "copy"
                if not entity_id:
                    listinfo.display_error_response(message.NO_ENTITY_FOR_COPY)
                else:
                    redirect_path = listinfo.get_edit_view_uri(
                        coll_id, entity_type, entity_id, action
                        )
            if "edit" in request.POST:
                action = "edit"
                if not entity_id:
                    listinfo.display_error_response(message.NO_ENTITY_FOR_EDIT)
                else:
                    redirect_path = listinfo.get_edit_view_uri(
                        coll_id, entity_type, entity_id, action
                        )
            if "delete" in request.POST:
                action = "delete"
                confirmed_deletion_uri = self.view_uri(
                    "AnnalistEntityDataDeleteView", 
                    coll_id=coll_id, type_id=entity_type
                    )
                return listinfo.confirm_delete_entity_response(
                    entity_type, entity_id, 
                    confirmed_deletion_uri
                    )
            if "default_view" in request.POST:
                #@@
                # auth_check = self.form_action_auth("config", listinfo.collection, CONFIG_PERMISSIONS)
                #@@
                auth_check = listinfo.check_authorization("config")
                if auth_check:
                    return auth_check
                listinfo.collection.set_default_list(list_id)
                listinfo.add_info_message(
                    message.DEFAULT_LIST_UPDATED%{'coll_id': coll_id, 'list_id': list_id}         
                    )
                redirect_path, redirect_params = listinfo.redisplay_path_params()
                redirect_cont   = listinfo.get_continuation_next()
            if ( ("list_type" in request.POST) or ("list_all"  in request.POST) ):
                action          = "list"
                redirect_path   = self.get_list_url(
                    coll_id, extract_entity_id(request.POST['list_choice']),
                    type_id=None if "list_all" in request.POST else type_id
                    )
                redirect_params = dict(
                    scope="all" if "list_scope_all" in request.POST else None,
                    search=request.POST['search_for']
                    )
                redirect_cont   = listinfo.get_continuation_next()
                # redirect_cont   = None
            if "customize" in request.POST:
                action        = "config"
                redirect_path = self.view_uri(
                            "AnnalistCollectionEditView", 
                            coll_id=coll_id
                            )
        if redirect_path:
            if redirect_cont:
                redirect_params.update(
                    { "continuation_url": redirect_cont }
                    )
            listinfo.redirect_response(
                redirect_path, redirect_params=redirect_params, action=action
                )
            # return (
            #     listinfo.check_authorization(action) or
            #     HttpResponseRedirect(redirect_uri)
            #     )
        if listinfo.http_response:
            return listinfo.http_response


        # Report unexpected form data
        # This shouldn't happen, but just in case...
        # Redirect to continuation with error
        log.error("Unexpected form data posted to %s: %r"%(request.get_full_path(), request.POST))
        err_values = self.error_params(
            message.UNEXPECTED_FORM_DATA%(request.POST), 
            message.SYSTEM_ERROR
            )
        redirect_uri = uri_with_params(listinfo.get_continuation_next(), err_values)
        return HttpResponseRedirect(redirect_uri)