Created
March 10, 2016 13:07
-
-
Save ian-ross/b94f6003484f6b99f4de to your computer and use it in GitHub Desktop.
Possible tutelary bug
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import rest_framework.generics as generic | |
import simplejson as json | |
from rest_framework.test import APIRequestFactory | |
from tutelary.models import Policy | |
from tutelary.mixins import PermissionRequiredMixin | |
from tutelary.decorators import permissioned_model | |
from django.db import models | |
from .factories import UserFactory | |
# Include a dummy Organization model to be able to make Project | |
# objects. | |
@permissioned_model | |
class Organization(models.Model): | |
name = models.CharField(max_length=100) | |
class TutelaryMeta: | |
perm_type = 'organization' | |
path_fields = ('pk',) | |
actions = [ | |
('organization.detail', | |
{'description': 'View organization'}), | |
] | |
# Pretty much as from Oliver. | |
@permissioned_model | |
class Project(models.Model): | |
organization = models.ForeignKey(Organization) | |
class TutelaryMeta: | |
perm_type = 'project' | |
path_fields = ('organization', 'pk',) | |
actions = [ | |
('project.users.list', | |
{'description': 'List users within a project'}), | |
] | |
# You need something to pretend to be a serializer to make view-based | |
# tests go through with DRF. It doesn't need to pretend very well... | |
class DummySerializer: | |
data = 'dummy-data' | |
def __init__(*args, **kwargs): | |
pass | |
def is_valid(self, *args, **kwargs): | |
return True | |
def save(self, *args, **kwargs): | |
pass | |
# This is how I've been faking up views for testing. For DRF, you | |
# need to have either "get_object" (for single object views) or | |
# "get_queryset" (for multi-object views) or both (for multi-action | |
# views, one of which is single object and one of which is | |
# multi-object, like here). The constructor and "object" attribute | |
# here are just to make it so that you can pass an object to as_view. | |
class ProjectUsers(PermissionRequiredMixin, generic.ListCreateAPIView): | |
object = None | |
serializer_class = DummySerializer | |
permission_required = { | |
'GET': 'project.users.list', | |
'POST': 'project.users.add', | |
} | |
def __init__(self, *args, **kwargs): | |
if 'object' in kwargs: | |
self.model = kwargs['object'] | |
self.object = kwargs['object'] | |
def get_object(self): | |
return self.object | |
def get_queryset(self): | |
return [self.object] | |
def test_oliver_bug(db): | |
clause = { | |
"clause": [ | |
{ | |
"effect": "allow", | |
"object": ["organization/*"], | |
"action": ["organization.*"] | |
}, | |
{ | |
"effect": "allow", | |
"object": ["project/*/*"], | |
"action": ["project.*.*"] | |
} | |
] | |
} | |
policy = Policy.objects.create(name='default', body=json.dumps(clause)) | |
user = UserFactory.create(username='testuser') | |
user.assign_policies(policy) | |
# The "successful_authenticator" thing here is more or less | |
# equivalent to calling force_authenticate, I think, but it | |
# requires less "real" DRF stuff. | |
req1 = APIRequestFactory().get('/check') | |
req1.user = user | |
req1.successful_authenticator = True | |
req2 = APIRequestFactory().post('/check') | |
req2.user = user | |
req2.successful_authenticator = True | |
org = Organization(name='TestOrg') | |
proj = Project(organization=org) | |
# This works! | |
rsp1 = ProjectUsers().as_view(object=proj)(req1).render() | |
assert rsp1.status_code == 200 | |
# This works too! | |
rsp2 = ProjectUsers().as_view(object=proj)(req2).render() | |
assert rsp2.status_code == 201 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment