diff --git a/awx/main/tests/inventory.py b/awx/main/tests/inventory.py index 44f8c48770..455d67de46 100644 --- a/awx/main/tests/inventory.py +++ b/awx/main/tests/inventory.py @@ -478,11 +478,15 @@ class InventoryTest(BaseTest): # just some more groups for kicks inva = Inventory.objects.get(pk=self.inventory_a.pk) - Group.objects.create(name='group-X1', inventory=inva) - Group.objects.create(name='group-X2', inventory=inva) - Group.objects.create(name='group-X3', inventory=inva) - Group.objects.create(name='group-X4', inventory=inva) - Group.objects.create(name='group-X5', inventory=inva) + gx1 = Group.objects.create(name='group-X1', inventory=inva) + gx2 = Group.objects.create(name='group-X2', inventory=inva) + gx2.parents.add(gx1) + gx3 = Group.objects.create(name='group-X3', inventory=inva) + gx3.parents.add(gx2) + gx4 = Group.objects.create(name='group-X4', inventory=inva) + gx4.parents.add(gx3) + gx5 = Group.objects.create(name='group-X5', inventory=inva) + gx5.parents.add(gx4) Permission.objects.create( inventory = inva, @@ -577,6 +581,21 @@ class InventoryTest(BaseTest): removed_group = Group.objects.get(pk=result['id']) self.assertFalse(removed_group.active) + # Removing a group from a hierarchy should migrate its children to the + # parent. The group itself will be deleted (marked inactive), and all + # relationships removed. + url = reverse('main:group_children_list', args=(gx2.pk,)) + data = { + 'id': gx3.pk, + 'disassociate': 1, + } + with self.current_user(self.super_django_user): + response = self.post(url, data, expect=204) + gx3 = Group.objects.get(pk=gx3.pk) + self.assertFalse(gx3.active) + self.assertFalse(gx3 in gx2.children.all()) + self.assertTrue(gx4 in gx2.children.all()) + ######################################################### # FIXME: TAGS diff --git a/awx/main/views.py b/awx/main/views.py index fc40bdb834..4d07ded14e 100644 --- a/awx/main/views.py +++ b/awx/main/views.py @@ -420,13 +420,26 @@ class GroupChildrenList(SubListCreateAPIView): Special case for disassociating a child group from the parent. If the child group has no more parents, then automatically mark it inactive. ''' - response = super(GroupChildrenList, self).unattach(request, *args, **kwargs) - if response.status_code != status.HTTP_204_NO_CONTENT: - return response - sub = self.model.objects.get(pk=request.DATA.get('id', None)) - if sub.parents.filter(active=True).count() == 0: + sub_id = request.DATA.get('id', None) + if not sub_id: + data = dict(msg='"id" is required to disassociate') + return Response(data, status=status.HTTP_400_BAD_REQUEST) + + parent = self.get_parent_object() + parent_key = getattr(self, 'parent_key', None) + relationship = getattr(parent, self.relationship) + sub = get_object_or_400(self.model, pk=sub_id) + + if not request.user.can_access(self.parent_model, 'unattach', parent, + sub, self.relationship): + raise PermissionDenied() + + if sub.parents.filter(active=True).exclude(pk=parent.pk).count() == 0: sub.mark_inactive() - return response + else: + relationship.remove(sub) + + return Response(status=status.HTTP_204_NO_CONTENT) class GroupHostsList(SubListCreateAPIView): ''' the list of hosts directly below a group '''