Ability to add child groups to groups.

This commit is contained in:
Michael DeHaan 2013-03-27 18:17:21 -04:00
parent 4a2673482b
commit 6e15d7a913
5 changed files with 101 additions and 17 deletions

View File

@ -421,6 +421,16 @@ class Group(CommonModelNameNotUnique):
inventory = Inventory.objects.get(pk=data['inventory'])
return Inventory._has_permission_types(user, inventory, PERMISSION_TYPES_ALLOWING_INVENTORY_WRITE)
@classmethod
def can_user_administrate(cls, user, obj):
# here this controls whether the user can attach subgroups
return Inventory._has_permission_types(user, obj.inventory, PERMISSION_TYPES_ALLOWING_INVENTORY_WRITE)
@classmethod
def can_user_read(cls, user, obj):
return Inventory.can_user_read(user, obj.inventory)
def get_absolute_url(self):
import lib.urls
return reverse(lib.urls.views_GroupsDetail, args=(self.pk,))

View File

@ -114,7 +114,7 @@ class GroupSerializer(BaseSerializer):
related = serializers.SerializerMethodField('get_related')
class Meta:
model = Host
model = Group
fields = ('url', 'id', 'name', 'description', 'creation_date', 'inventory')
def get_related(self, obj):

View File

@ -159,6 +159,8 @@ class InventoryTest(BaseTest):
new_group_c = dict(name='web4', inventory=inv.pk)
new_group_d = dict(name='web5', inventory=inv.pk)
new_group_e = dict(name='web6', inventory=inv.pk)
groups = '/api/v1/groups/'
data0 = self.post(groups, data=invalid, expect=400, auth=self.get_super_credentials())
data0 = self.post(groups, data=new_group_a, expect=201, auth=self.get_super_credentials())
@ -176,7 +178,7 @@ class InventoryTest(BaseTest):
# permission_type = PERM_INVENTORY_WRITE
#)
group_data3 = self.post(groups, data=new_group_c, expect=201, auth=self.get_other_credentials())
# hostnames must be unique inside an organization
group_data4 = self.post(groups, data=new_group_c, expect=400, auth=self.get_other_credentials())
@ -268,44 +270,82 @@ class InventoryTest(BaseTest):
###################################################
# VARIABLES -> GROUPS
vars_a = dict(asdf=7777, dog='droopy', cat='battlecat', unstructured=dict(a=[1,1,1],b=dict(x=1,y=2)))
vars_b = dict(asdf=8888, dog='snoopy', cat='cheshire', unstructured=dict(a=[2,2,2],b=dict(x=3,y=4)))
vars_c = dict(asdf=9999, dog='pluto', cat='five', unstructured=dict(a=[3,3,3],b=dict(z=5)))
groups = Group.objects.all()
vdata1_url = "/api/v1/groups/%s/variable_data/" % (groups[0].pk)
vdata2_url = "/api/v1/groups/%s/variable_data/" % (groups[1].pk)
# a super user can associate variable objects with groups
got = self.get(vdata1_url, expect=200, auth=self.get_super_credentials())
self.assertEquals(got, {})
put = self.put(vdata1_url, data=vars_a, expect=200, auth=self.get_super_credentials())
self.assertEquals(put, vars_a)
# an org admin can associate variable objects with groups
put = self.put(vdata1_url, data=vars_b, expect=200, auth=self.get_normal_credentials())
# a normal user cannot associate variable objects with groups
put = self.put(vdata1_url, data=vars_b, expect=403, auth=self.get_nobody_credentials())
# a normal user with inventory edit permissions can associate variable objects with groups
put = self.put(vdata1_url, data=vars_c, expect=200, auth=self.get_normal_credentials())
self.assertEquals(put, vars_c)
####################################################
# SUBGROUPS
groups = Group.objects.all()
# just some more groups for kicks
inv = Inventory.objects.get(pk=1)
Group.objects.create(name='group-X1', inventory=inv)
Group.objects.create(name='group-X2', inventory=inv)
Group.objects.create(name='group-X3', inventory=inv)
Group.objects.create(name='group-X4', inventory=inv)
Group.objects.create(name='group-X5', inventory=inv)
Permission.objects.create(
inventory = inv,
user = self.other_django_user,
permission_type = PERM_INVENTORY_WRITE
)
# a super user can set subgroups
subgroups_url = '/api/v1/groups/1/children/'
child_url = '/api/v1/groups/2/'
subgroups_url2 = '/api/v1/groups/3/children/'
subgroups_url3 = '/api/v1/groups/4/children/'
subgroups_url4 = '/api/v1/groups/5/children/'
got = self.get(child_url, expect=200, auth=self.get_super_credentials())
self.post(subgroups_url, data=got, expect=204, auth=self.get_super_credentials())
kids = Group.objects.get(pk=1).children.all()
self.assertEqual(len(kids), 1)
checked = self.get(subgroups_url, expect=200, auth=self.get_super_credentials())
self.assertEquals(checked['count'], 1)
# an org admin can set subgroups
self.post(subgroups_url2, data=got, expect=204, auth=self.get_normal_credentials())
# double post causes conflict error
self.post(subgroups_url2, data=got, expect=409, auth=self.get_normal_credentials())
checked = self.get(subgroups_url2, expect=200, auth=self.get_normal_credentials())
# a normal user cannot set subgroups
self.post(subgroups_url3, data=got, expect=403, auth=self.get_nobody_credentials())
# a normal user with inventory edit permissions can associate subgroups
self.post(subgroups_url3, data=got, expect=204, auth=self.get_other_credentials())
checked = self.get(subgroups_url3, expect=200, auth=self.get_normal_credentials())
self.assertEqual(checked['count'], 1)
# FIXME: go back and put in GET requests after all the post stuff
#########################################################
# GROUP CHILDREN ACCESS
# a super user can see the children attached to a group
# a org admin can see the children attached to a group
# a user who is on a team who has read permissions on an inventory can see the children attached to a group
# a regular user cannot see children attached to a group
#########################################################
# DISASSOCIATION TESTS
# hosts from inventory
# groups from inventory
# subgroups from groups
# children from groups
# others?
#########################################################

View File

@ -366,6 +366,38 @@ class GroupsList(BaseList):
).distinct()
return admin_of | has_user_perms | has_team_perms
class GroupsChildrenList(BaseSubList):
model = Group
serializer_class = GroupSerializer
permission_classes = (CustomRbac,)
parent_model = Group
relationship = 'children'
postable = True
inject_primary_key_on_post_as = 'parent'
def _get_queryset(self):
# FIXME: this is the mostly the same as GroupsList, share code similar to how done with Host and Group objects.
parent = Group.objects.get(pk=self.kwargs['pk'])
# FIXME: verify read permissions on this object are still required at a higher level
base = parent.children
if self.request.user.is_superuser:
return base.all()
admin_of = base.filter(inventory__organization__admins__in = [ self.request.user ]).distinct()
has_user_perms = base.filter(
inventory__permissions__user__in = [ self.request.user ],
inventory__permissions__permission_type__in = PERMISSION_TYPES_ALLOWING_INVENTORY_READ,
).distinct()
has_team_perms = base.filter(
inventory__permissions__team__in = self.request.user.teams.all(),
inventory__permissions__permission_type__in = PERMISSION_TYPES_ALLOWING_INVENTORY_READ,
).distinct()
return admin_of | has_user_perms | has_team_perms
class GroupsDetail(BaseDetail):
model = Group

View File

@ -53,6 +53,7 @@ views_InventoryGroupsList = views.InventoryGroupsList.as_view()
views_GroupsList = views.GroupsList.as_view()
views_GroupsDetail = views.GroupsDetail.as_view()
views_GroupsVariableDetail = views.GroupsVariableDetail.as_view()
views_GroupsChildrenList = views.GroupsChildrenList.as_view()
# host service
views_HostsList = views.HostsList.as_view()
@ -117,6 +118,7 @@ urlpatterns = patterns('',
# group service
url(r'^api/v1/groups/$', views_GroupsList),
url(r'^api/v1/groups/(?P<pk>[0-9]+)/$', views_GroupsDetail),
url(r'^api/v1/groups/(?P<pk>[0-9]+)/children/$', views_GroupsChildrenList),
# variable data
url(r'^api/v1/hosts/(?P<pk>[0-9]+)/variable_data/$', views_HostsVariableDetail),