Partial support for permission editablity through REST. More TBA.

This commit is contained in:
Michael DeHaan 2013-04-26 17:32:19 -04:00
parent f18f3a339c
commit b4932ab5a9
5 changed files with 151 additions and 10 deletions

View File

@ -168,15 +168,15 @@ class PrimordialModel(models.Model):
@classmethod
def can_user_administrate(cls, user, obj, data):
# FIXME: do we want a seperate method to override put? This is kind of general purpose
raise exceptions.NotImplementedError()
raise Exception("can_user_administrate needs to be implemented in model subclass")
@classmethod
def can_user_delete(cls, user, obj):
raise exceptions.NotImplementedError()
raise Exception("can_user_delete needs to be implemented in model subclass")
@classmethod
def can_user_read(cls, user, obj):
raise exceptions.NotImplementedError()
raise Exception("can_user_read needs to be implemented in model subclass")
@classmethod
def can_user_add(cls, user, data):
@ -805,6 +805,37 @@ class Permission(CommonModelNameNotUnique):
self.permission_type
))
def get_absolute_url(self):
import lib.urls
return reverse(lib.urls.views_PermissionsDetail, args=(self.pk,))
@classmethod
def can_user_administrate(cls, user, obj, data):
if user.is_superuser:
return True
# a permission can be administrated by a super
# or if a user permission, that an admin of a user's organization
# or if a team permission, an admin of that team's organization
if obj.user and obj.user.organizations.filter(admins__in = [user]).count() > 0:
return True
if obj.team and obj.team.organization.admins.filter(user=user).count() > 0:
return True
return False
@classmethod
def can_user_read(cls, user, obj):
# a permission can be seen by the assigned user or team
# or anyone who can administrate that permission
if obj.user and obj.user == user:
return True
if obj.team and obj.team.users.filter(pk = user.pk).count() > 0:
return True
return cls.can_user_administrate(user, obj, None)
@classmethod
def can_user_delete(cls, user, obj):
return cls.can_user_administrate(user, obj, None)
# TODO: other job types (later)
class JobTemplate(CommonModel):

View File

@ -169,18 +169,42 @@ class TeamSerializer(BaseSerializer):
users = reverse(lib.urls.views_TeamsUsersList, args=(obj.pk,)),
credentials = reverse(lib.urls.views_TeamsCredentialsList, args=(obj.pk,)),
organization = reverse(lib.urls.views_OrganizationsDetail, args=(obj.organization.pk,)),
permissions = reverse(lib.urls.views_TeamsPermissionsList, args=(obj.pk,)),
)
if obj.created_by:
res['created_by'] = reverse(lib.urls.views_UsersDetail, args=(obj.created_by.pk,))
return res
class PermissionSerializer(BaseSerializer):
url = serializers.CharField(source='get_absolute_url', read_only=True)
related = serializers.SerializerMethodField('get_related')
class Meta:
model = Permission
fields = ( 'url', 'id', 'user', 'team', 'name', 'description', 'creation_date',
'project', 'inventory', 'permission_type' )
def get_related(self, obj):
res = dict()
if obj.user:
res['user'] = reverse(lib.urls.views_UsersDetail, args=(obj.user.pk,))
if obj.team:
res['team'] = reverse(lib.urls.views_TeamsDetail, args=(obj.team.pk,))
if self.project:
res['project'] = reverse(lib.urls.views_ProjectsDetail, args=(obj.project.pk,))
if self.inventory:
res['inventory'] = reverse(lib.urls.views_InventoryDetail, args=(obj.inventory.pk,))
if self.created_by:
res['created_by'] = reverse(lib.urls.views_UsersDetail, args=(obj.created_by.pk,))
class CredentialSerializer(BaseSerializer):
# add the URL and related resources
url = serializers.CharField(source='get_absolute_url', read_only=True)
related = serializers.SerializerMethodField('get_related')
# FIXME: may want to make soem of these filtered based on user accessing
# FIXME: may want to make some of these filtered based on user accessing
class Meta:
model = Credential
fields = (
@ -228,6 +252,7 @@ class UserSerializer(BaseSerializer):
admin_of_organizations = reverse(lib.urls.views_UsersAdminOrganizationsList, args=(obj.pk,)),
projects = reverse(lib.urls.views_UsersProjectsList, args=(obj.pk,)),
credentials = reverse(lib.urls.views_UsersCredentialsList, args=(obj.pk,)),
permissions = reverse(lib.urls.views_UsersPermissionsList, args=(obj.pk,)),
)
def get_absolute_url_override(self, obj):

View File

@ -386,15 +386,56 @@ class ProjectsTest(BaseTest):
# =====================================================================
# PERMISSIONS
user = self.other_django_user
team = Team.objects.get(pk=1)
organization = Organization.objects.get(pk=1)
inventory = Inventory.objects.create(
name = 'test inventory',
organization = organization,
created_by = self.super_django_user
)
project = Project.objects.get(pk=1)
# can add permissions to a user
user_permission = dict(
name='user can deploy a certain project to a certain inventory',
# user=user.pk, # no need to specify, this will be automatically filled in
inventory=inventory.pk,
project=project.pk,
permission_type=PERM_INVENTORY_DEPLOY
)
team_permission = dict(
name='team can deploy a certain project to a certain inventory',
# team=team.pk, # no need to specify, this will be automatically filled in
inventory=inventory.pk,
project=project.pk,
permission_type=PERM_INVENTORY_DEPLOY
)
url = '/api/v1/users/%s/permissions/' % user.pk
self.post(url, user_permission, expect=201, auth=self.get_super_credentials())
# can add permissions on a team
url = '/api/v1/teams/%s/permissions/' % team.pk
self.post(url, team_permission, expect=201, auth=self.get_super_credentials())
# can list permissions on a user
url = '/api/v1/users/%s/permissions/' % user.pk
# can list permissions on a team
url = '/api/v1/teams/%s/permissions/' % team.pk
# can edit a permission
# can remove credentials from a user
# can remove credentials from a team
# can remove permissions from a user
# do need to disassociate, just delete it
# can remove permissions from a team
# do need to disassociate, just delete it

View File

@ -266,6 +266,23 @@ class TeamsUsersList(BaseSubList):
return base
raise PermissionDenied()
class TeamsPermissionsList(BaseSubList):
model = Permission
serializer_class = PermissionSerializer
permission_classes = (CustomRbac,)
parent_model = Team
relationship = 'permissions'
postable = True
filter_fields = ('name',)
inject_primary_key_on_post_as = 'team'
def _get_queryset(self):
team = Team.objects.get(pk=self.kwargs['pk'])
if not Team.can_user_administrate(self.request.user, team, None):
raise PermissionDenied()
return Permission.objects.filter(team = team)
class TeamsProjectsList(BaseSubList):
@ -423,6 +440,23 @@ class UsersTeamsList(BaseSubList):
raise PermissionDenied()
return Team.objects.filter(users__in = [ user ])
class UsersPermissionsList(BaseSubList):
model = Permission
serializer_class = PermissionSerializer
permission_classes = (CustomRbac,)
parent_model = User
relationship = 'permissions'
postable = True
filter_fields = ('name',)
inject_primary_key_on_post_as = 'user'
def _get_queryset(self):
user = User.objects.get(pk=self.kwargs['pk'])
if not UserHelper.can_user_administrate(self.request.user, user, None):
raise PermissionDenied()
return Permission.objects.filter(user=user)
class UsersProjectsList(BaseSubList):
model = Project
@ -514,6 +548,11 @@ class CredentialsDetail(BaseDetail):
serializer_class = CredentialSerializer
permission_classes = (CustomRbac,)
class PermissionsDetail(BaseDetail):
model = Permission
serializer_class = PermissionSerializer
permission_classes = (CustomRbac,)
class InventoryList(BaseList):

View File

@ -102,6 +102,10 @@ views_TagsDetail = views.TagsDetail.as_view()
# credentials service
views_CredentialsDetail = views.CredentialsDetail.as_view()
# permissions
views_UsersPermissionsList = views.UsersPermissionsList.as_view()
views_TeamsPermissionsList = views.TeamsPermissionsList.as_view()
views_PermissionsDetail = views.PermissionsDetail.as_view()
urlpatterns = patterns('',
@ -199,8 +203,9 @@ urlpatterns = patterns('',
url(r'^api/v1/credentials/(?P<pk>[0-9]+)/$', views_CredentialsDetail),
# permissions services
# ... users
# ... teams
url(r'^api/v1/users/(?P<pk>[0-9]+)/permissions/$', views_UsersPermissionsList),
url(r'^api/v1/teams/(?P<pk>[0-9]+)/permissions/$', views_TeamsPermissionsList),
url(r'^api/v1/permissions/(?P<pk>[0-9]+)/$', views_PermissionsDetail),
)