Add related resources from a user object, as a rapid way to list what organizations or projects they belong to.

This commit is contained in:
Michael DeHaan 2013-03-24 15:00:01 -04:00
parent 1ae2e69e8a
commit 18eaec143c
5 changed files with 131 additions and 22 deletions

View File

@ -316,7 +316,7 @@ class Team(CommonModel):
projects = models.ManyToManyField('Project', blank=True, related_name='teams')
users = models.ManyToManyField('auth.User', blank=True, related_name='teams')
organization = models.ManyToManyField('Organization', related_name='teams')
organizations = models.ManyToManyField('Organization', related_name='teams')
class Project(CommonModel):
'''

View File

@ -78,6 +78,21 @@ class ProjectSerializer(BaseSerializer):
# FIXME: add related resources: inventories
return dict()
class TeamSerializer(BaseSerializer):
# add the URL and related resources
url = serializers.CharField(source='get_absolute_url', read_only=True)
related = serializers.SerializerMethodField('get_related')
class Meta:
model = Team
fields = ('url', 'id', 'related', 'name', 'description', 'creation_date')
def get_related(self, obj):
# FIXME: add related resources: projects, users, organizations
return dict()
class UserSerializer(BaseSerializer):
# add the URL and related resources
@ -89,8 +104,12 @@ class UserSerializer(BaseSerializer):
fields = ('url', 'id', 'username', 'first_name', 'last_name', 'email', 'is_active', 'is_superuser', 'related')
def get_related(self, obj):
# FIXME: add related lookups?
return dict()
return dict(
teams = reverse(lib.urls.views_UsersTeamsList, args=(obj.pk,)),
organizations = reverse(lib.urls.views_UsersOrganizationsList, args=(obj.pk,)),
admin_of_organizations = reverse(lib.urls.views_UsersAdminOrganizationsList, args=(obj.pk,)),
)
def get_absolute_url_override(self, obj):
import lib.urls

View File

@ -25,6 +25,7 @@ class UsersTest(BaseTest):
self.organizations = self.make_organizations(self.super_django_user, 1)
self.organizations[0].admins.add(self.normal_django_user)
self.organizations[0].users.add(self.other_django_user)
self.organizations[0].users.add(self.normal_django_user)
def test_only_super_user_or_org_admin_can_add_users(self):
url = '/api/v1/users/'
@ -153,11 +154,47 @@ class UsersTest(BaseTest):
self.assertEquals(data['results'][0]['username'], 'admin')
self.assertEquals(data['count'], 1)
# TODO:
# possibly nice to have, some quick lookup functions that are not postable:
# /users/2/organizations
# /users/2/projects
# /users/2/teams
def test_user_related_resources(self):
# organizations the user is a member of, should be 1
url = '/api/v1/users/2/organizations/'
data = self.get(url, expect=200, auth=self.get_normal_credentials())
self.assertEquals(data['count'], 1)
# also accessible via superuser
data = self.get(url, expect=200, auth=self.get_super_credentials())
self.assertEquals(data['count'], 1)
# but not by other user
data = self.get(url, expect=403, auth=self.get_other_credentials())
# organizations the user is an admin of, should be 1
url = '/api/v1/users/2/admin_of_organizations/'
data = self.get(url, expect=200, auth=self.get_normal_credentials())
self.assertEquals(data['count'], 1)
# also accessible via superuser
data = self.get(url, expect=200, auth=self.get_super_credentials())
self.assertEquals(data['count'], 1)
# but not by other user
data = self.get(url, expect=403, auth=self.get_other_credentials())
# teams the user is on, should be 0
url = '/api/v1/users/2/teams/'
data = self.get(url, expect=200, auth=self.get_normal_credentials())
self.assertEquals(data['count'], 0)
# also accessible via superuser
data = self.get(url, expect=200, auth=self.get_super_credentials())
self.assertEquals(data['count'], 0)
# but not by other user
data = self.get(url, expect=403, auth=self.get_other_credentials())
# verify org admin can still read other user data too
url = '/api/v1/users/3/organizations/'
data = self.get(url, expect=200, auth=self.get_normal_credentials())
self.assertEquals(data['count'], 1)
url = '/api/v1/users/3/admin_of_organizations/'
data = self.get(url, expect=200, auth=self.get_normal_credentials())
self.assertEquals(data['count'], 0)
url = '/api/v1/users/3/teams/'
data = self.get(url, expect=200, auth=self.get_normal_credentials())
self.assertEquals(data['count'], 0)

View File

@ -193,6 +193,51 @@ class UsersMeList(BaseList):
''' a quick way to find my user record '''
return User.objects.filter(pk=self.request.user.pk)
class UsersTeamsList(BaseSubList):
model = Team
serializer_class = TeamSerializer
permission_classes = (CustomRbac,)
parent_model = User
relationship = 'teams'
postable = False
def _get_queryset(self):
user = User.objects.get(pk=self.kwargs['pk'])
if not UserHelper.can_user_administrate(self.request.user, user):
raise PermissionDenied()
return Team.objects.filter(users__in = [ user ])
class UsersOrganizationsList(BaseSubList):
model = Organization
serializer_class = OrganizationSerializer
permission_classes = (CustomRbac,)
parent_model = User
relationship = 'organizations'
postable = False
def _get_queryset(self):
user = User.objects.get(pk=self.kwargs['pk'])
if not UserHelper.can_user_administrate(self.request.user, user):
raise PermissionDenied()
return Organization.objects.filter(users__in = [ user ])
class UsersAdminOrganizationsList(BaseSubList):
model = Organization
serializer_class = OrganizationSerializer
permission_classes = (CustomRbac,)
parent_model = User
relationship = 'admin_of_organizations'
postable = False
def _get_queryset(self):
user = User.objects.get(pk=self.kwargs['pk'])
if not UserHelper.can_user_administrate(self.request.user, user):
raise PermissionDenied()
return Organization.objects.filter(admins__in = [ user ])
class UsersDetail(BaseDetail):
model = User

View File

@ -20,18 +20,23 @@ from django.conf.urls import *
import lib.main.views as views
# organizations service
views_OrganizationsList = views.OrganizationsList.as_view()
views_OrganizationsDetail = views.OrganizationsDetail.as_view()
views_OrganizationsAuditTrailList = views.OrganizationsAuditTrailList.as_view()
views_OrganizationsUsersList = views.OrganizationsUsersList.as_view()
views_OrganizationsAdminsList = views.OrganizationsAdminsList.as_view()
views_OrganizationsProjectsList = views.OrganizationsProjectsList.as_view()
views_OrganizationsTagsList = views.OrganizationsTagsList.as_view()
views_OrganizationsList = views.OrganizationsList.as_view()
views_OrganizationsDetail = views.OrganizationsDetail.as_view()
views_OrganizationsAuditTrailList = views.OrganizationsAuditTrailList.as_view()
views_OrganizationsUsersList = views.OrganizationsUsersList.as_view()
views_OrganizationsAdminsList = views.OrganizationsAdminsList.as_view()
views_OrganizationsProjectsList = views.OrganizationsProjectsList.as_view()
views_OrganizationsTagsList = views.OrganizationsTagsList.as_view()
# users service
views_UsersList = views.UsersList.as_view()
views_UsersDetail = views.UsersDetail.as_view()
views_UsersMeList = views.UsersMeList.as_view()
views_UsersList = views.UsersList.as_view()
views_UsersDetail = views.UsersDetail.as_view()
views_UsersMeList = views.UsersMeList.as_view()
views_UsersTeamsList = views.UsersTeamsList.as_view()
views_UsersOrganizationsList = views.UsersOrganizationsList.as_view()
views_UsersAdminOrganizationsList = views.UsersAdminOrganizationsList.as_view()
# projects service
views_ProjectsDetail = views.OrganizationsDetail.as_view()
@ -69,9 +74,12 @@ urlpatterns = patterns('',
url(r'^api/v1/organizations/(?P<pk>[0-9]+)/tags/$', views_OrganizationsTagsList),
# users service
url(r'^api/v1/users/$', views_UsersList),
url(r'^api/v1/users/(?P<pk>[0-9]+)/$', views_UsersDetail),
url(r'^api/v1/me/$', views_UsersMeList),
url(r'^api/v1/users/$', views_UsersList),
url(r'^api/v1/users/(?P<pk>[0-9]+)/$', views_UsersDetail),
url(r'^api/v1/me/$', views_UsersMeList),
url(r'^api/v1/users/(?P<pk>[0-9]+)/teams/$', views_UsersTeamsList),
url(r'^api/v1/users/(?P<pk>[0-9]+)/organizations/$', views_UsersOrganizationsList),
url(r'^api/v1/users/(?P<pk>[0-9]+)/admin_of_organizations/$', views_UsersAdminOrganizationsList),
# projects service
url(r'^api/v1/projects/(?P<pk>[0-9]+)/$', views_ProjectsDetail),