From c2bffe47d49ddc45851be62b5157a0c2cf7097ae Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Tue, 26 Mar 2013 19:21:18 -0400 Subject: [PATCH] Fixup attach logic for inventory hosts/groups on subcollections. Pass serializer errors through on conflict scenarios. --- lib/main/base_views.py | 4 +- lib/main/models/__init__.py | 12 ++- lib/main/tests/inventory.py | 144 ++++++------------------------------ lib/main/views.py | 17 +++++ lib/urls.py | 2 + 5 files changed, 54 insertions(+), 125 deletions(-) diff --git a/lib/main/base_views.py b/lib/main/base_views.py index f8f71965ed..c217837449 100644 --- a/lib/main/base_views.py +++ b/lib/main/base_views.py @@ -111,7 +111,7 @@ class BaseSubList(BaseList): # attempt to deserialize the object ser = self.__class__.serializer_class(data=request.DATA) if not ser.is_valid(): - return Response(status=status.HTTP_400_BAD_REQUEST, data=python_json.dumps(dict(msg='invalid post data'))) + return Response(status=status.HTTP_400_BAD_REQUEST, data=ser.errors) # ask the usual access control settings if not self.__class__.model.can_user_add(request.user, ser.init_data): @@ -126,7 +126,7 @@ class BaseSubList(BaseList): if not self.__class__.parent_model.can_user_attach(request.user, main, obj, self.__class__.relationship): raise PermissionDenied() - return Response(status=status.HTTP_201_CREATED, data=python_json.dumps(ser.data)) + return Response(status=status.HTTP_201_CREATED, data=ser.data) else: diff --git a/lib/main/models/__init__.py b/lib/main/models/__init__.py index b7c3805599..8d07973110 100644 --- a/lib/main/models/__init__.py +++ b/lib/main/models/__init__.py @@ -349,6 +349,14 @@ class Inventory(CommonModel): def can_user_administrate(cls, user, obj): return cls._has_permission_types(user, obj, PERMISSION_TYPES_ALLOWING_INVENTORY_ADMIN) + @classmethod + def can_user_attach(cls, user, obj, sub_obj, relationship_type): + ''' whether you can add sub_obj to obj using the relationship type in a subobject view ''' + if type(sub_obj) != User: + if not sub_obj.can_user_read(user, sub_obj): + return False + return cls._has_permission_types(user, obj, PERMISSION_TYPES_ALLOWING_INVENTORY_WRITE) + @classmethod def can_user_read(cls, user, obj): return cls._has_permission_types(user, obj, PERMISSION_TYPES_ALLOWING_INVENTORY_READ) @@ -381,7 +389,9 @@ class Host(CommonModelNameNotUnique): if not 'inventory' in data: return False inventory = Inventory.objects.get(pk=data['inventory']) - return Inventory._has_permission_types(user, inventory, PERMISSION_TYPES_ALLOWING_INVENTORY_WRITE) + rc = Inventory._has_permission_types(user, inventory, PERMISSION_TYPES_ALLOWING_INVENTORY_WRITE) + return rc + def get_absolute_url(self): import lib.urls diff --git a/lib/main/tests/inventory.py b/lib/main/tests/inventory.py index af924121d9..aaea225c1e 100644 --- a/lib/main/tests/inventory.py +++ b/lib/main/tests/inventory.py @@ -184,7 +184,6 @@ class InventoryTest(BaseTest): # HOSTS->inventories POST via subcollection url = '/api/v1/inventories/1/hosts/' - new_host_a = dict(name='web100.example.com') new_host_b = dict(name='web101.example.com') new_host_c = dict(name='web102.example.com') @@ -201,25 +200,38 @@ class InventoryTest(BaseTest): added_by_collection = self.post(url, data=new_host_c, expect=403, auth=self.get_nobody_credentials()) # a normal user with edit permission on the inventory can associate hosts with inventories - added_by_collection = self.post(url, data=new_host_d, expect=403, auth=self.get_other_credentials()) + url5 = '/api/v1/inventories/5/hosts/' + added_by_collection = self.post(url5, data=new_host_d, expect=201, auth=self.get_other_credentials()) ################################################## # GROUPS->inventories POST via subcollection + + url = '/api/v1/inventories/1/groups/' + new_group_a = dict(name='web100') + new_group_b = dict(name='web101') + new_group_c = dict(name='web102') + new_group_d = dict(name='web103') + new_group_e = dict(name='web104') # a super user can associate groups with inventories + added_by_collection = self.post(url, data=new_group_a, expect=201, auth=self.get_super_credentials()) # an org admin can associate groups with inventories + added_by_collection = self.post(url, data=new_group_b, expect=201, auth=self.get_normal_credentials()) # a normal user cannot associate groups with inventories + added_by_collection = self.post(url, data=new_group_c, expect=403, auth=self.get_nobody_credentials()) # a normal user with edit permissions on the inventory can associate groups with inventories + url5 = '/api/v1/inventories/5/groups/' + added_by_collection = self.post(url5, data=new_group_d, expect=201, auth=self.get_other_credentials()) + # make sure duplicates give 400s + added_by_collection2 = self.post(url5, data=new_group_d, expect=400, auth=self.get_other_credentials()) ################################################### # VARIABLES - # a super user can create variable objects - - # an org admin can create variable objects + # an org admin can create variable objects (defers to inventory permissions) # a normal user cannot create variable objects @@ -258,50 +270,8 @@ class InventoryTest(BaseTest): # a normal user with inventory edit permissions can associate subgroups - ###################################################### - # GROUP ACCESS - - # a super user can get a group record - - # an org admin can get a group record - - # a user who is on a team who has read permissions on an inventory can get a group record + # FIXME: go back and put in GET requests after all the post stuff - # a regular user cannot read any group records - - ######################################################## - # HOST ACCESS - - # a super user can get a host record - - # an org admin can get a host record - - # a user who is on a team who has read permissions on an inventory can get a host record - - # a regular user cannot get a host record - - ######################################################### - # GROUP VARIABLE ACCESS - - # a super user can see the variables attached to a group - - # a org admin can see the variables attached to a group - - # a user who is on a team who has read permissions on an inventory can see the variables attached to a group - - # a regular user cannot get a group variable record - - ######################################################### - # HOST VARIABLE ACCESS - - # a super user can see the variables attached to a host - - # a org admin can see the variables attached to a host - - # a user who is on a team who has read permissions on an inventory can see the variables attached to a host - - # a regular user cannot see variables attached to a host - ######################################################### # GROUP CHILDREN ACCESS @@ -314,86 +284,16 @@ class InventoryTest(BaseTest): # a regular user cannot see children attached to a group ######################################################### - # VARIABLE RESOURCE ACCESS - - # a super user can see a variable record - - # an org admin can see a variable record - - # a user who is on a team who has read permissions on an inventory can see the variable record - - # a regular user cannot see a variable record - - ######################################################### - # SUPER USER DISASSOCIATION - - # a super user can disassociate... - + # DISASSOCIATION TESTS # hosts from inventory - # groups from inventory - # subgroups from groups - - # the inventory task code returns valid inventory JSON. - - ######################################################### - # ORG ADMIN DISASSOCIATION - - # an org admin user can disassociate... - - # hosts from inventory - - # groups from inventory - - # subgroups from groups - - ######################################################### - # USER DISASSOCIATION - - # a user with inventory edit permission disassociate... - - # hosts from inventory - - # groups from inventory - - # subgroups from groups - - ######################################################### - # USER DISASSOCIATION (2) - - # a regular user cannot disassociate.... - - # hosts from inventory - - # groups from inventory - - # subgroups from inventory - + # others? + ######################################################### # TAGS - # the following objects can be tagged - - # inventory - - # host records - - # group records - - # variable records - - # the following objects can have their tags listed - - # inventory - - # host records - - # group records - - # variable records - - # the following tags can be removed + # the following objects can be tagged and the tags can be read # inventory diff --git a/lib/main/views.py b/lib/main/views.py index 4d73ef208c..05be6c38c0 100644 --- a/lib/main/views.py +++ b/lib/main/views.py @@ -372,4 +372,21 @@ class GroupsDetail(BaseDetail): serializer_class = GroupSerializer permission_classes = (CustomRbac,) +class InventoryGroupsList(BaseSubList): + + model = Group + serializer_class = GroupSerializer + permission_classes = (CustomRbac,) + # to allow the sub-aspect listing + parent_model = Inventory + relationship = 'groups' + # to allow posting to this resource to create resources + postable = True + # FIXME: go back and add these to other SubLists + inject_primary_key_on_post_as = 'inventory' + + def _get_queryset(self): + # FIXME: more DRY methods like this + return Inventory._filter_queryset(Inventory.objects.get(pk=self.kwargs['pk']).groups) + diff --git a/lib/urls.py b/lib/urls.py index 12761b70a9..23cc1c4769 100644 --- a/lib/urls.py +++ b/lib/urls.py @@ -47,6 +47,7 @@ views_ProjectsDetail = views.OrganizationsDetail.as_view() views_InventoryList = views.InventoryList.as_view() views_InventoryDetail = views.InventoryDetail.as_view() views_InventoryHostsList = views.InventoryHostsList.as_view() +views_InventoryGroupsList = views.InventoryGroupsList.as_view() # group service views_GroupsList = views.GroupsList.as_view() @@ -97,6 +98,7 @@ urlpatterns = patterns('', url(r'^api/v1/inventories/$', views_InventoryList), url(r'^api/v1/inventories/(?P[0-9]+)/$', views_InventoryDetail), url(r'^api/v1/inventories/(?P[0-9]+)/hosts/$', views_InventoryHostsList), + url(r'^api/v1/inventories/(?P[0-9]+)/groups/$', views_InventoryGroupsList), # host service url(r'^api/v1/hosts/$', views_HostsList),