From b8ee694d82af71f9de2d89fb284caba194a06430 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Wed, 27 Mar 2013 18:54:30 -0400 Subject: [PATCH] Ability to remove hosts and inventory from groups. --- lib/main/base_views.py | 8 +++++- lib/main/models/__init__.py | 9 ++++--- lib/main/tests/inventory.py | 45 +++++++++++++++++++++------------ lib/main/tests/organizations.py | 2 ++ lib/main/views.py | 15 ++++++++--- 5 files changed, 55 insertions(+), 24 deletions(-) diff --git a/lib/main/base_views.py b/lib/main/base_views.py index a7a50893d5..2c672a903f 100644 --- a/lib/main/base_views.py +++ b/lib/main/base_views.py @@ -86,6 +86,7 @@ class BaseSubList(BaseList): parent_id = kwargs['pk'] sub_id = request.DATA.get('id', None) main = self.__class__.parent_model.objects.get(pk=parent_id) + severable = getattr(self.__class__, 'severable', True) subs = None @@ -150,7 +151,12 @@ class BaseSubList(BaseList): else: if not request.user.is_superuser and not self.__class__.parent_model.can_user_unattach(request.user, main, sub, self.__class__.relationship): raise PermissionDenied() - relationship.remove(sub) + if severable: + relationship.remove(sub) + else: + # resource is just a ForeignKey, can't remove it from the set, just set it inactive + sub.active = False + sub.save() return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/lib/main/models/__init__.py b/lib/main/models/__init__.py index 4e670995da..8df6f715ce 100644 --- a/lib/main/models/__init__.py +++ b/lib/main/models/__init__.py @@ -352,9 +352,12 @@ class Inventory(CommonModel): @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 + 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_unattach(cls, user, obj, sub_obj, relationship): return cls._has_permission_types(user, obj, PERMISSION_TYPES_ALLOWING_INVENTORY_WRITE) @classmethod diff --git a/lib/main/tests/inventory.py b/lib/main/tests/inventory.py index c96f9a1292..e105d3112f 100644 --- a/lib/main/tests/inventory.py +++ b/lib/main/tests/inventory.py @@ -204,6 +204,14 @@ class InventoryTest(BaseTest): # a normal user with edit permission on the inventory can associate hosts with inventories url5 = '/api/v1/inventories/5/hosts/' added_by_collection_d = self.post(url5, data=new_host_d, expect=201, auth=self.get_other_credentials()) + got = self.get(url5, expect=200, auth=self.get_other_credentials()) + self.assertEquals(got['count'], 4) + + # now remove the host from inventory (still keeps the record) + added_by_collection_d['disassociate'] = 1 + self.post(url5, data=added_by_collection_d, expect=204, auth=self.get_other_credentials()) + got = self.get(url5, expect=200, auth=self.get_other_credentials()) + self.assertEquals(got['count'], 3) ################################################## # GROUPS->inventories POST via subcollection @@ -228,7 +236,15 @@ class InventoryTest(BaseTest): 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()) + self.post(url5, data=new_group_d, expect=400, auth=self.get_other_credentials()) + got = self.get(url5, expect=200, auth=self.get_other_credentials()) + self.assertEquals(got['count'], 4) + + remove_me = added_by_collection + remove_me['disassociate'] = 1 + self.post(url5, data=remove_me, expect=204, auth=self.get_other_credentials()) + got = self.get(url5, expect=200, auth=self.get_other_credentials()) + self.assertEquals(got['count'], 3) ################################################### # VARIABLES @@ -341,35 +357,32 @@ class InventoryTest(BaseTest): checked = self.get(subgroups_url3, expect=200, auth=self.get_normal_credentials()) self.assertEqual(checked['count'], 1) + # now post it back to remove it, by adding the disassociate bit + result = checked['results'][0] + result['disassociate'] = 1 + self.post(subgroups_url3, data=result, expect=204, auth=self.get_other_credentials()) + checked = self.get(subgroups_url3, expect=200, auth=self.get_normal_credentials()) + self.assertEqual(checked['count'], 0) + # try to double disassociate to see what happens (should no-op) + self.post(subgroups_url3, data=result, expect=204, auth=self.get_other_credentials()) + ######################################################### - # DISASSOCIATION TESTS - # hosts from inventory - # groups from inventory - # children from groups - # others? - - ######################################################### - # TAGS + # FIXME: TAGS # the following objects can be tagged and the tags can be read - # inventory - # host records - # group records - # variable records + # this may just be in a seperate test file called 'tags' ######################################################### - # RELATED FIELDS + # FIXME: RELATED FIELDS # on an inventory resource, I can see related resources for hosts and groups and permissions # and these work - # on a host resource, I can see related resources variables and inventories # and these work - # on a group resource, I can see related resources for variables, inventories, and children # and these work diff --git a/lib/main/tests/organizations.py b/lib/main/tests/organizations.py index 1bc2c10108..4608b9a61e 100644 --- a/lib/main/tests/organizations.py +++ b/lib/main/tests/organizations.py @@ -230,6 +230,8 @@ class OrganizationsTest(BaseTest): self.post(projects1_url, dict(asdf=1234), expect=400, auth=self.get_super_credentials()) # test that by posting a pk + disassociate: True we can remove a relationship + projects1 = self.get(projects1_url, expect=200, auth=self.get_super_credentials()) + self.assertEquals(projects1['count'], 6) a_project['disassociate'] = True self.post(projects1_url, a_project, expect=204, auth=self.get_super_credentials()) projects1 = self.get(projects1_url, expect=200, auth=self.get_super_credentials()) diff --git a/lib/main/views.py b/lib/main/views.py index eaa825e6f4..9020f573cd 100644 --- a/lib/main/views.py +++ b/lib/main/views.py @@ -334,10 +334,13 @@ class InventoryHostsList(BaseSubList): postable = True # FIXME: go back and add these to other SubLists inject_primary_key_on_post_as = 'inventory' + severable = False def _get_queryset(self): - # FIXME: more DRY methods like this - return Inventory._filter_queryset(Inventory.objects.get(pk=self.kwargs['pk']).hosts) + inventory = Inventory.objects.get(pk=self.kwargs['pk']) + base = inventory.hosts + # FIXME: verify that you can can_read permission on the inventory is required + return base.all() class GroupsList(BaseList): @@ -416,10 +419,14 @@ class InventoryGroupsList(BaseSubList): postable = True # FIXME: go back and add these to other SubLists inject_primary_key_on_post_as = 'inventory' + severable = False def _get_queryset(self): - # FIXME: more DRY methods like this - return Inventory._filter_queryset(Inventory.objects.get(pk=self.kwargs['pk']).groups) + # FIXME: share code with inventory filter queryset methods (make that a classmethod) + inventory = Inventory.objects.get(pk=self.kwargs['pk']) + base = inventory.groups + # FIXME: verify that you can can_read permission on the inventory is required + return base class GroupsVariableDetail(VariableBaseDetail):