def test_project_settings(users, dummy_request): from aarau.views.console.project.action import project_settings user = users['oswald'] project = user.projects[0] query_param = {} submit_body = { 'csrf_token': dummy_request.session.get_csrf_token(), 'name': 'Updated Project Name', 'namespace': project.namespace, 'description': project.description, 'submit': 'Update', } dummy_request.subdomain = 'console' dummy_request.user = user dummy_request.GET = NestedMultiDict(query_param) dummy_request.POST = MultiDict(submit_body) dummy_request.params = NestedMultiDict({**query_param, **submit_body}) dummy_request.matchdict = {'namespace': project.namespace} assert 1 == len(user.projects) res = project_settings(dummy_request) assert ['project.update.success'] == \ dummy_request.session.peek_flash('success') assert isinstance(res, HTTPFound) assert '/projects/{:s}/settings'.format(project.namespace) == res.location user.refresh() assert 1 == len(user.projects) assert 1 == len(list(filter( lambda p: p.namespace == project.namespace, user.projects)))
def test_project_settings_invalid_namespace_in_matchdict(users, dummy_request): from aarau.views.console.project.action import project_settings user = users['oswald'] project = user.projects[0] query_param = {} submit_body = { 'csrf_token': dummy_request.session.get_csrf_token(), 'name': 'Updated Project Name', 'namespace': project.namespace, 'description': project.description, 'submit': 'Update', } dummy_request.subdomain = 'console' dummy_request.user = user dummy_request.GET = NestedMultiDict(query_param) dummy_request.POST = MultiDict(submit_body) dummy_request.params = NestedMultiDict({**query_param, **submit_body}) # other project invalid_project = list( users['weenie'].projects.where(Membership.role == 'primary_owner'))[0] dummy_request.matchdict = {'namespace': invalid_project.namespace} assert 1 == len(user.projects) with pytest.raises(HTTPNotFound): project_settings(dummy_request) assert [] == dummy_request.session.peek_flash('failure') assert [] == dummy_request.session.peek_flash('success')
def test_application_site_new_post_with_validation_error(users, dummy_request): from aarau.views.console.site.form import build_new_application_site_form from aarau.views.console.site.action import site_new user = users['oswald'] project = user.projects[0] query_param = {'type': 'application'} submit_body = { 'submit': 'Create', 'csrf_token': dummy_request.session.get_csrf_token(), # invalid values 'domain': '', 'slug': '', 'application-name': '', 'application-description': '', } dummy_request.subdomain = 'console' dummy_request.user = user dummy_request.GET = NestedMultiDict(query_param) dummy_request.POST = MultiDict(submit_body) dummy_request.params = NestedMultiDict({**query_param, **submit_body}) dummy_request.matchdict = { 'namespace': project.namespace, } res = site_new(dummy_request) form = build_new_application_site_form(dummy_request) assert dummy_request.session.peek_flash('failure') assert isinstance(res, Mapping) assert ('form', 'project', 'site') == tuple(sorted(res.keys())) assert isinstance(res['form'], form.__class__) assert project == res['project'] assert isinstance(res['site'], Site)
def test_project_new(users, dummy_request): from aarau.views.console.project.action import project_new user = users['oswald'] query_param = {} submit_body = { 'csrf_token': dummy_request.session.get_csrf_token(), 'name': 'My New Project', 'namespace': 'my-new-project', 'description': 'This is my new project.', 'submit': 'Create', } dummy_request.subdomain = 'console' dummy_request.user = user dummy_request.GET = NestedMultiDict(query_param) dummy_request.POST = MultiDict(submit_body) dummy_request.params = NestedMultiDict({**query_param, **submit_body}) dummy_request.matchdict = {} assert 1 == len(user.projects) res = project_new(dummy_request) assert ['project.creation.success'] == \ dummy_request.session.peek_flash('success') assert isinstance(res, HTTPFound) assert '/projects/my-new-project' == res.location user.refresh() assert 2 == len(user.projects) assert 1 == len(list(filter( lambda p: p.namespace == 'my-new-project', user.projects)))
def test_it_redirects_to_the_search_page(self, group, pyramid_request): # This should be in the redirect URL. pyramid_request.POST = NestedMultiDict({'q': 'foo bar gar'}) # This should *not* be in the redirect URL. pyramid_request.params = NestedMultiDict({'group_leave': group.pubid}) result = activity.group_leave(pyramid_request) assert isinstance(result, httpexceptions.HTTPSeeOther) assert result.location == 'http://example.com/search?q=foo+bar+gar'
def test_it_returns_404_when_the_group_does_not_exist(self, pyramid_request): pyramid_request.POST = NestedMultiDict({ 'group_leave': 'does_not_exist'}) with pytest.raises(httpexceptions.HTTPNotFound): activity.group_leave(pyramid_request)
def test_project_new_namespace_validation_error_with_invalid_pattern( users, dummy_request): from aarau.views.console.project.form import build_new_project_form from aarau.views.console.project.action import project_new user = users['oswald'] query_param = {} submit_body = { 'csrf_token': dummy_request.session.get_csrf_token(), 'name': '', # invalid namespace 'namespace': '-with-hyphen', 'description': '', 'submit': 'Create', } dummy_request.subdomain = 'console' dummy_request.user = user dummy_request.POST = MultiDict(submit_body) dummy_request.params = NestedMultiDict({**query_param, **submit_body}) dummy_request.matchdict = {} res = project_new(dummy_request) form = build_new_project_form(dummy_request) assert ['project.creation.failure'] == \ dummy_request.session.peek_flash('failure') assert isinstance(res, Mapping) assert ('form',) == tuple(sorted(res.keys())) assert isinstance(res['form'], form.__class__) f = res['form'] assert ['Invalid input.'] == f.namespace.errors
def test_application_site_settings_widgets_missing_site( mocker, users, dummy_request): from aarau.views.console.site.action import site_settings_widgets user = users['oswald'] project = user.projects[0] dummy_request.subdomain = 'console' dummy_request.user = user dummy_request.params = dummy_request.GET = NestedMultiDict({ 'type': 'application', }) dummy_request.matchdict = { 'namespace': project.namespace, 'slug': '', # invalid } dummy_service = DummyService() mocker.spy(dummy_service, 'assign') mocker.spy(dummy_service, 'validate') dummy_request.find_service = (lambda *args, **kwargs: dummy_service) with pytest.raises(HTTPNotFound): site_settings_widgets(dummy_request) # pylint: disable=no-member assert 0 == dummy_service.assign.call_count assert 0 == dummy_service.validate.call_count
def request_params(request): try: params = NestedMultiDict(request.GET, request.POST) except UnicodeDecodeError: response = exception_response(422) response.body = dumps( error_handler( request, response.code, { 'location': 'body', 'name': 'data', 'description': 'Could not decode params' })) response.content_type = 'application/json' raise response except Exception as e: response = exception_response(422) response.body = dumps( error_handler( request, response.code, { 'location': 'body', 'name': str(e.__class__.__name__), 'description': str(e) })) response.content_type = 'application/json' raise response return params
def str_params(self): """ A dictionary-like object containing both the parameters from the query string and request body. """ warn_str_deprecation() return NestedMultiDict(self._str_GET, self._str_POST)
def test_project_settings_namespace_validation_error_with_missing_namespace( users, dummy_request): from aarau.views.console.project.form import build_edit_project_form from aarau.views.console.project.action import project_settings user = users['oswald'] project = user.projects[0] query_param = {} submit_body = { 'csrf_token': dummy_request.session.get_csrf_token(), 'name': project.name, 'namespace': '', # invalid namespace 'description': project.description, 'submit': 'Update', } dummy_request.subdomain = 'console' dummy_request.user = user dummy_request.POST = MultiDict(submit_body) dummy_request.params = NestedMultiDict({**query_param, **submit_body}) dummy_request.matchdict = {'namespace': project.namespace} res = project_settings(dummy_request) form = build_edit_project_form(dummy_request, project) assert ['project.update.failure'] == \ dummy_request.session.peek_flash('failure') assert isinstance(res, Mapping) assert ('form', 'project') == tuple(sorted(res.keys())) assert isinstance(res['form'], form.__class__) f = res['form'] assert ['This field is required.'] == f.namespace.errors
def get_csrf_request(self, post=None): csrf = 'abc' if not u'_csrf' in post.keys(): post.update({'_csrf': csrf}) # We can't use dummyrequest cause the simpleform # needs MultiDict and NestedMultiDict from WebOb request # This is the 'real' request. from webob.multidict import MultiDict, NestedMultiDict multidict = MultiDict() # This is my own invention. Use with caution :) # request = Request.blank('/', method="POST", registry=registry) for key in post.keys(): multidict[key] = post[key] request = testing.DummyRequest(post=multidict, params=NestedMultiDict(multidict)) request.session = Mock() csrf_token = Mock() csrf_token.return_value = csrf request.session.get_csrf_token = csrf_token request.root = self.zodb return request
def test_application_site_new_get(users, dummy_request): from aarau.views.console.site.form import build_new_application_site_form from aarau.views.console.site.action import site_new user = users['oswald'] dummy_request.subdomain = 'console' dummy_request.user = user dummy_request.params = dummy_request.GET = NestedMultiDict({ 'type': 'application', }) dummy_request.POST = NoVars() project = user.projects[0] dummy_request.matchdict = { 'namespace': project.namespace, } res = site_new(dummy_request) form = build_new_application_site_form(dummy_request) assert isinstance(res, Mapping) assert ('form', 'project', 'site') == tuple(sorted(res.keys())) assert isinstance(res['form'], form.__class__) assert project == res['project'] assert isinstance(res['site'], Site)
def test_application_site_insights(users, dummy_request): from aarau.views.console.site.action import site_insights user = users['oswald'] project = user.projects[0] site = project.applications[0] dummy_request.subdomain = 'console' dummy_request.user = user dummy_request.params = dummy_request.GET = NestedMultiDict({ 'type': 'application', }) dummy_request.matchdict = { 'namespace': project.namespace, 'slug': site.slug, } res = site_insights(dummy_request) assert isinstance(res, Mapping) assert ('component_type', 'instance', 'project', 'site') == \ tuple(sorted(res.keys())) assert project == res['project'] assert site == res['site'] assert site.application == res['instance']
def add_child_idea(request): args = request.params if 'context_url' in args: from webob.multidict import NestedMultiDict v = args['context_url'] args = NestedMultiDict(dict(GeneratedIdeaWidgetLink__context_url=v), *args.dicts) return collection_add(request, args)
def test_passes_validation_if_valid_search_after(self, schema, search_after, sort): input_params = NestedMultiDict( MultiDict({"search_after": search_after, "sort": sort}) ) params = validate_query_params(schema, input_params) assert params["search_after"] == search_after
def test_application_site_new_post(mocker, users, dummy_request): from aarau.views.console.site.action import site_new user = users['oswald'] project = user.projects[0] query_param = {'type': 'application'} submit_body = { 'submit': 'Create', 'csrf_token': dummy_request.session.get_csrf_token(), 'domain': 'new.example.org', 'slug': 'new-example-org', 'application-name': 'New Test Application', 'application-description': '...', } dummy_request.subdomain = 'console' dummy_request.user = user dummy_request.GET = NestedMultiDict(query_param) dummy_request.POST = MultiDict(submit_body) dummy_request.params = NestedMultiDict({**query_param, **submit_body}) dummy_request.matchdict = {'namespace': project.namespace} dummy_service = DummyService() mocker.spy(dummy_service, 'assign') mocker.spy(dummy_service, 'sync') dummy_request.find_service = (lambda *args, **kwargs: dummy_service) assert 1 == len(project.applications) res = site_new(dummy_request) assert dummy_request.session.peek_flash('success') assert isinstance(res, HTTPFound) project.refresh() applications = project.applications assert 2 == len(applications) assert 1 == len( list( filter(lambda s: s.application.name == 'New Test Application', applications))) # pylint: disable=no-member assert 1 == dummy_service.assign.call_count assert 1 == dummy_service.sync.call_count
def test_sets_offset_to_0_if_search_after(self, schema): input_params = NestedMultiDict( MultiDict({"search_after": "2009-02-16", "offset": 5}) ) params = validate_query_params(schema, input_params) assert not params["offset"] assert params["search_after"] == "2009-02-16"
def test_it_presents_replies( self, pyramid_request, search_run, presentation_service ): pyramid_request.params = NestedMultiDict(MultiDict({"_separate_replies": "1"})) search_run.return_value = SearchResult(1, ["row-1"], ["reply-1", "reply-2"], {}) views.search(pyramid_request) presentation_service.present_all.assert_called_with(["reply-1", "reply-2"])
def test_url_for(self, pyramid_request, params, expected): pyramid_request.params = NestedMultiDict(*params) pyramid_request.current_route_path = mock.Mock(spec_set=["__call__"]) url_for = paginate(pyramid_request, 600, 10)["url_for"] url = url_for(page=26) # Request the URL for page 26. pyramid_request.current_route_path.assert_called_once_with(_query=expected) assert url == pyramid_request.current_route_path.return_value
def params(self): """ Like ``.str_params``, but decodes values and keys """ params = NestedMultiDict(self._str_GET, self._str_POST) params = UnicodeMultiDict(params, encoding=self.charset, errors=self.unicode_errors, decode_keys=self.decode_param_names) return params
def test_it_handles_duplicate_keys(self, schema): expected_params = MultiDict([("url", "http://foobar"), ("url", "http://foobat")]) input_params = deepcopy(expected_params) input_params.add("unknownparam", "foo") input_params.add("unknownparam", "bar") params = validate_query_params(schema, NestedMultiDict(input_params)) assert params.getall("url") == ["http://foobar", "http://foobat"] assert "unknownparam" not in params
def request_params(request): try: params = NestedMultiDict(request.GET, request.POST) except UnicodeDecodeError: request.errors.add('body', 'data', 'could not decode params') request.errors.status = 422 raise error_handler(request.errors, False) except Exception, e: request.errors.add('body', str(e.__class__.__name__), str(e)) request.errors.status = 422 raise error_handler(request.errors, False)
def POST(self): if self.method not in ('POST', 'PUT', 'PATCH'): return NoVars('Not a form request') # Webob puts uploaded files into the POST dictionary, so here we # combine the Django POST data and uploaded FILES data into a single # dict. return NestedMultiDict( querydict_to_multidict(self._request.POST), querydict_to_multidict(self._request.FILES, wrap=DjangoUploadedFile), )
def test_application_site_new_post_missing_project(users, dummy_request): from aarau.views.console.site.action import site_new user = users['oswald'] query_param = {'type': 'application'} submit_body = { 'submit': 'Create', # rest is omitted } dummy_request.subdomain = 'console' dummy_request.user = user dummy_request.GET = NestedMultiDict(query_param) dummy_request.POST = MultiDict(submit_body) dummy_request.params = NestedMultiDict({**query_param, **submit_body}) dummy_request.matchdict = { 'namespace': '', # invalid } with pytest.raises(HTTPNotFound): site_new(dummy_request)
def test_it_presents_replies(self, pyramid_request, search_run, presentation_service): pyramid_request.params = NestedMultiDict( MultiDict({'_separate_replies': '1'})) search_run.return_value = SearchResult(1, ['row-1'], ['reply-1', 'reply-2'], {}) views.search(pyramid_request) presentation_service.present_all.assert_called_with( ['reply-1', 'reply-2'])
def request_params(request): try: params = NestedMultiDict(request.GET, request.POST) except UnicodeDecodeError: request.errors.add("body", "data", "could not decode params") request.errors.status = 422 raise error_handler(request, False) except Exception as e: request.errors.add("body", str(e.__class__.__name__), str(e)) request.errors.status = 422 raise error_handler(request, False) return params
def create_multidict(*args): """ Create a pylons NestedMultiDict object from tuple lists args = [[('k', '1'), ('k', '2'), ('k', '3')], [('l', 'Z')]] :params args: list of list of tuples :returns: NestedMultiDict object """ multi_dicts = [] for arg in args: multi_dicts.append(MultiDict(arg)) return NestedMultiDict(*multi_dicts)
def test_it_returns_only_known_params(self, schema): expected_params = MultiDict( { "_separate_replies": True, "group": "group1", "quote": "quote me", "references": "3456TA12", "tag": "tagme", "tags": "tagme2", "text": "text me", "uri": "foobar.com", "uri.parts": "bbc", "wildcard_uri": "http://foo.com/*", "url": "https://foobar.com", "any": "foo", "user": "******", "sort": "created", "limit": 10, "order": "asc", "offset": 0, "search_after": "2018-01-01", } ) input_params = NestedMultiDict( MultiDict( { "_separate_replies": "1", "group": "group1", "quote": "quote me", "references": "3456TA12", "tag": "tagme", "tags": "tagme2", "text": "text me", "uri": "foobar.com", "uri.parts": "bbc", "wildcard_uri": "http://foo.com/*", "url": "https://foobar.com", "any": "foo", "user": "******", "sort": "created", "limit": "10", "order": "asc", "offset": "0", "unknown": "no_exist", "no_exist": "unknown", "search_after": "2018-01-01", } ) ) params = validate_query_params(schema, input_params) assert params == expected_params
def test_it_returns_replies( self, pyramid_request, search_run, presentation_service ): pyramid_request.params = NestedMultiDict(MultiDict({"_separate_replies": "1"})) search_run.return_value = SearchResult(1, ["row-1"], ["reply-1", "reply-2"], {}) expected = { "total": 1, "rows": presentation_service.present_all(["row-1"]), "replies": presentation_service.present_all(["reply-1", "reply-2"]), } assert views.search(pyramid_request) == expected
def find_controller(self, state): ''' The main request handler for Pecan applications. ''' # get a sorted list of hooks, by priority (no controller hooks yet) req = state.request pecan_state = req.pecan # store the routing path for the current application to allow hooks to # modify it pecan_state['routing_path'] = path = req.path_info # handle "on_route" hooks self.handle_hooks(self.hooks, 'on_route', state) # lookup the controller, respecting content-type as requested # by the file extension on the URI pecan_state['extension'] = None # attempt to guess the content type based on the file extension if self.guess_content_type_from_ext \ and not pecan_state['content_type'] \ and '.' in path: _, extension = splitext(path.rstrip('/')) # preface with a letter to ensure compat for 2.5 potential_type = guess_type('x' + extension)[0] if extension and potential_type is not None: path = ''.join(path.rsplit(extension, 1)) pecan_state['extension'] = extension pecan_state['content_type'] = potential_type controller, remainder = self.route(req, self.root, path) cfg = _cfg(controller) if cfg.get('generic_handler'): raise exc.HTTPNotFound # handle generic controllers im_self = None if cfg.get('generic'): im_self = six.get_method_self(controller) handlers = cfg['generic_handlers'] controller = handlers.get(req.method, handlers['DEFAULT']) handle_security(controller, im_self) cfg = _cfg(controller) # add the controller to the state so that hooks can use it state.controller = controller # if unsure ask the controller for the default content type content_types = cfg.get('content_types', {}) if not pecan_state['content_type']: # attempt to find a best match based on accept headers (if they # exist) accept = getattr(req.accept, 'header_value', '*/*') if accept == '*/*' or ( accept.startswith('text/html,') and list(content_types.keys()) in self.SIMPLEST_CONTENT_TYPES): pecan_state['content_type'] = cfg.get( 'content_type', 'text/html' ) else: best_default = acceptparse.MIMEAccept( accept ).best_match( content_types.keys() ) if best_default is None: msg = "Controller '%s' defined does not support " + \ "content_type '%s'. Supported type(s): %s" logger.error( msg % ( controller.__name__, pecan_state['content_type'], content_types.keys() ) ) raise exc.HTTPNotAcceptable() pecan_state['content_type'] = best_default elif cfg.get('content_type') is not None and \ pecan_state['content_type'] not in content_types: msg = "Controller '%s' defined does not support content_type " + \ "'%s'. Supported type(s): %s" logger.error( msg % ( controller.__name__, pecan_state['content_type'], content_types.keys() ) ) raise exc.HTTPNotFound # fetch any parameters if req.method == 'GET': params = req.GET elif req.content_type in ('application/json', 'application/javascript'): try: if not isinstance(req.json, dict): raise TypeError('%s is not a dict' % req.json) params = NestedMultiDict(req.GET, req.json) except (TypeError, ValueError): params = req.params else: params = req.params # fetch the arguments for the controller args, varargs, kwargs = self.get_args( state, params.mixed(), remainder, cfg['argspec'], im_self ) state.arguments = Arguments(args, varargs, kwargs) # handle "before" hooks self.handle_hooks(self.determine_hooks(controller), 'before', state) return controller, args + varargs, kwargs
def find_controller(self, state): """ The main request handler for Pecan applications. """ # get a sorted list of hooks, by priority (no controller hooks yet) req = state.request pecan_state = req.pecan # store the routing path for the current application to allow hooks to # modify it pecan_state["routing_path"] = path = req.encget("PATH_INFO") # handle "on_route" hooks self.handle_hooks(self.hooks, "on_route", state) # lookup the controller, respecting content-type as requested # by the file extension on the URI pecan_state["extension"] = None # attempt to guess the content type based on the file extension if self.guess_content_type_from_ext and not pecan_state["content_type"] and "." in path: new_path, extension = splitext(path) # preface with a letter to ensure compat for 2.5 potential_type = guess_type("x" + extension)[0] if potential_type is not None: path = new_path pecan_state["extension"] = extension pecan_state["content_type"] = potential_type controller, remainder = self.route(req, self.root, path) cfg = _cfg(controller) if cfg.get("generic_handler"): raise exc.HTTPNotFound # handle generic controllers im_self = None if cfg.get("generic"): im_self = six.get_method_self(controller) handlers = cfg["generic_handlers"] controller = handlers.get(req.method, handlers["DEFAULT"]) handle_security(controller, im_self) cfg = _cfg(controller) # add the controller to the state so that hooks can use it state.controller = controller # if unsure ask the controller for the default content type content_types = cfg.get("content_types", {}) if not pecan_state["content_type"]: # attempt to find a best match based on accept headers (if they # exist) accept = getattr(req.accept, "header_value", "*/*") if accept == "*/*" or ( accept.startswith("text/html,") and list(content_types.keys()) in self.SIMPLEST_CONTENT_TYPES ): pecan_state["content_type"] = cfg.get("content_type", "text/html") else: best_default = acceptparse.MIMEAccept(accept).best_match(content_types.keys()) if best_default is None: msg = "Controller '%s' defined does not support " + "content_type '%s'. Supported type(s): %s" logger.error(msg % (controller.__name__, pecan_state["content_type"], content_types.keys())) raise exc.HTTPNotAcceptable() pecan_state["content_type"] = best_default elif cfg.get("content_type") is not None and pecan_state["content_type"] not in content_types: msg = "Controller '%s' defined does not support content_type " + "'%s'. Supported type(s): %s" logger.error(msg % (controller.__name__, pecan_state["content_type"], content_types.keys())) raise exc.HTTPNotFound # fetch any parameters if req.method == "GET": params = req.GET elif req.content_type in ("application/json", "application/javascript"): try: if not isinstance(req.json, dict): raise TypeError("%s is not a dict" % req.json) params = NestedMultiDict(req.GET, req.json) except (TypeError, ValueError): params = req.params else: params = req.params # fetch the arguments for the controller args, varargs, kwargs = self.get_args(state, params.mixed(), remainder, cfg["argspec"], im_self) state.arguments = Arguments(args, varargs, kwargs) # handle "before" hooks self.handle_hooks(self.determine_hooks(controller), "before", state) return controller, args + varargs, kwargs