Skip to content

Commit

Permalink
Merge pull request #344 from openprocurement/master
Browse files Browse the repository at this point in the history
add Resource predicates support
  • Loading branch information
leplatrem committed Nov 25, 2016
2 parents 66f1d6a + 15da363 commit 3f6eb1d
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 1 deletion.
20 changes: 19 additions & 1 deletion cornice/pyramidhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,13 @@ def _fallback_view(request):

# In the absence of further information about what went wrong,
# let upstream deal with the mismatch.
raise PredicateMismatch(service.name)

# After "custom predicates" feature has been added there is no need in
# this line. Instead requests will be filtered by "custom predicates"
# feature filter and exception "404 Not found" error will be raised. In
# order to avoid unpredictable cases, we left this line in place and
# excluded it from coverage.
raise PredicateMismatch(service.name) # pragma: no cover
return _fallback_view


Expand Down Expand Up @@ -183,6 +189,11 @@ def register_service_views(config, service):
if hasattr(service, 'traverse'):
route_args['traverse'] = service.traverse

routes = config.get_predlist('route')
for predicate in routes.sorter.names:
if hasattr(service, predicate):
route_args[predicate] = getattr(service, predicate)

config.add_route(route_name, service.path, **route_args)

# 2. register view(s)
Expand Down Expand Up @@ -214,6 +225,13 @@ def register_service_views(config, service):
if attr in args:
args.pop(attr)

# filter predicates defined on Resource
route_predicates = config.get_predlist('route').sorter.names
view_predicates = config.get_predlist('view').sorter.names
for pred in set(route_predicates).difference(view_predicates):
if pred in args:
args.pop(pred)

# pop and compute predicates which get passed through to Pyramid 1:1

predicate_definitions = _pop_complex_predicates(args)
Expand Down
174 changes: 174 additions & 0 deletions tests/test_resource_custom_predicates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
from pyramid import testing
from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
from webtest import TestApp

from cornice.resource import resource
from cornice.resource import view
from .support import TestCase, CatchErrors

EMPLOYEES_DB = {
1: {'name': 'Tony Flash', 'position': 'topmanager', 'salary': 30000},
2: {'name': 'Jimmy Arrow', 'position': 'supervisor', 'salary': 50000}
}


class employeeType(object):
def __init__(self, val, config):
self.val = val

def text(self):
return 'position = %s' % (self.val,)

phash = text

def __call__(self, context, request):
if request.params.get('position') is not None:
position = request.params.get('position')
return position == self.val
return False


@resource(collection_path='/company/employees', path='/company/employees/{id}',
name='Topmanagers', position=u'topmanager')
class EManager(object):

def __init__(self, request, context=None):
self.request = request
self.context = context

@view(renderer='json', accept='application/json')
def collection_get(self):
return ['Topmanagers list get']

@view(renderer='json', accept='application/json')
def get(self):
return {'get': 'Topmanagers'}

@view(renderer='json', accept='application/json')
def collection_post(self):
return ['Topmanagers list post']

@view(renderer='json', accept='application/json')
def patch(self):
return {'patch': 'Topmanagers'}

@view(renderer='json', accept='application/json')
def put(self):
return {'put': 'Topmanagers'}


@resource(collection_path='/company/employees', path='/company/employees/{id}',
name='Supervisors', position=u'supervisor')
class ESupervisor(object):

def __init__(self, request, context=None):
self.request = request
self.context = context

@view(renderer='json', accept='application/json')
def collection_get(self):
return ['Supervisors list get']

@view(renderer='json', accept='application/json')
def get(self):
return {'get': 'Supervisors'}

@view(renderer='json', accept='application/json')
def collection_post(self):
return ['Supervisors list post']

@view(renderer='json', accept='application/json')
def patch(self):
return {'patch': 'Supervisors'}

@view(renderer='json', accept='application/json')
def put(self):
return {'put': 'Supervisors'}


class TestCustomPredicates(TestCase):

def setUp(self):
from pyramid.renderers import JSONP
self.config = testing.setUp()
self.config.add_renderer('jsonp', JSONP(param_name='callback'))
self.config.include("cornice")
self.authz_policy = ACLAuthorizationPolicy()
self.config.set_authorization_policy(self.authz_policy)

self.authn_policy = AuthTktAuthenticationPolicy('$3kr1t')
self.config.set_authentication_policy(self.authn_policy)
self.config.add_route_predicate('position', employeeType)
self.config.scan("tests.test_resource_custom_predicates")
self.app = TestApp(CatchErrors(self.config.make_wsgi_app()))

def tearDown(self):
testing.tearDown()

def test_get_resource_predicates(self):
# Tests for resource with name 'Supervisors'
res = self.app.get('/company/employees?position=supervisor').json
self.assertEqual(res[0], 'Supervisors list get')
res = self.app.get('/company/employees/2?position=supervisor').json
self.assertEqual(res['get'], 'Supervisors')

# Tests for resource with name 'Topmanagers'
res = self.app.get('/company/employees?position=topmanager').json
self.assertEqual(res[0], 'Topmanagers list get')
res = self.app.get('/company/employees/1?position=topmanager').json
self.assertEqual(res['get'], 'Topmanagers')

def test_post_resource_predicates(self):
# Tests for resource with name 'Supervisors'
supervisor_data = {
'name': 'Jimmy Arrow',
'position': 'supervisor',
'salary': 50000
}
res = self.app.post('/company/employees', supervisor_data).json
self.assertEqual(res[0], 'Supervisors list post')

# Tests for resource with name 'Topmanagers'
topmanager_data = {
'name': 'Jimmy Arrow',
'position': 'topmanager',
'salary': 30000
}
res = self.app.post('/company/employees', topmanager_data).json
self.assertEqual(res[0], 'Topmanagers list post')

def test_patch_resource_predicates(self):
# Tests for resource with name 'Supervisors'
res = self.app.patch(
'/company/employees/2?position=supervisor',
{'salary': 1001}
).json
self.assertEqual(res['patch'], 'Supervisors')

# Tests for resource with name 'Topmanagers'
res = self.app.patch(
'/company/employees/1?position=topmanager',
{'salary': 2002}
).json
self.assertEqual(res['patch'], 'Topmanagers')

def test_put_resource_predicates(self):
# Tests for resource with name 'Supervisors'
supervisor_data = {
'position': 'supervisor',
'salary': 53000
}
res = self.app.put('/company/employees/2', supervisor_data).json
self.assertEqual(res['put'], 'Supervisors')

# Tests for resource with name 'Topmanagers'
topmanager_data = {
'position': 'topmanager',
'salary': 33000
}
res = self.app.put('/company/employees/1', topmanager_data).json
self.assertEqual(res['put'], 'Topmanagers')

0 comments on commit 3f6eb1d

Please sign in to comment.