Some hacks to make organizational user object creation possible by posting directly to the subcollection. This is a little complex due to the user (being a Django object) not having any FKs

to our objects.  This should be refactored later but is at least sufficiently operational for the two cases it is used here.
This commit is contained in:
Michael DeHaan 2013-04-29 10:36:16 -04:00
parent 69a9916423
commit 21f4e3a680
3 changed files with 60 additions and 5 deletions

View File

@ -124,8 +124,12 @@ class BaseSubList(BaseList):
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):
raise PermissionDenied()
if self.__class__.model in [ User ]:
if not UserHelper.can_user_add(request.user, ser.init_data):
raise PermissionDenied()
else:
if not self.__class__.model.can_user_add(request.user, ser.init_data):
raise PermissionDenied()
# save the object through the serializer, reload and returned the saved object deserialized
obj = ser.save()
@ -140,10 +144,42 @@ class BaseSubList(BaseList):
if self.__class__.parent_model != User:
if not obj.__class__.can_user_read(request.user, obj):
raise PermissionDenied()
# FIXME: refactor into smaller functions
if obj.__class__ in [ User]:
if self.__class__.parent_model == Organization:
# user can't inject an organization because it's not part of the user
# model so we have to cheat here. This may happen for other cases
# where we are creating a user immediately on a subcollection
# when that user does not already exist. Relations will work post-save.
organization = Organization.objects.get(pk=request.DATA[inject_primary_key])
if not request.user.is_superuser:
if not organization.admins.filter(pk=request.user.pk).count() > 0:
raise PermissionDenied()
else:
raise exceptions.NotImplementedError()
else:
if not obj.__class__.can_user_read(request.user, obj):
raise PermissionDenied()
if not self.__class__.parent_model.can_user_attach(request.user, main, obj, self.__class__.relationship, request.DATA):
raise PermissionDenied()
# FIXME: manual attachment code neccessary for users here, move this into the main code.
# this is because users don't have FKs into what they are attaching. (also refactor)
if self.__class__.parent_model == Organization:
organization = Organization.objects.get(pk=request.DATA[inject_primary_key])
import lib.main.views
if self.__class__ == lib.main.views.OrganizationsUsersList:
organization.users.add(obj)
organization.save()
elif self.__class__ == lib.main.views.OrganizationsAdminsList:
organization.admins.add(obj)
organization.save()
else:
if not UserHelper.can_user_read(request.user, obj):
raise PermissionDenied()

View File

@ -130,6 +130,14 @@ class UserHelper(object):
matching_orgs = obj.organizations.filter(admins__in = [user]).count()
return matching_orgs
@classmethod
def can_user_add(cls, user, data):
# TODO: reuse. make helper functions like "is user an org admin"
# apply throughout permissions code
if user.is_superuser:
return True
return user.admin_of_organizations.count() > 0
@classmethod
def can_user_attach(cls, user, obj, sub_obj, relationship_type, data):
if type(sub_obj) != User:
@ -193,7 +201,9 @@ class PrimordialModel(models.Model):
# in order to attach something you also be able to read what you are attaching
if type(sub_obj) == User:
return UserHelper.can_user_read(user, sub_obj)
# we already check that the user is an admin or org admin up in base_views.py
# because the user doesn't have the attributes on it directly to tie it to the org
return True
else:
return sub_obj.__class__.can_user_read(user, sub_obj)

View File

@ -270,6 +270,15 @@ class OrganizationsTest(BaseTest):
users = self.get(url, expect=200, auth=self.get_normal_credentials())
self.assertEqual(users['count'], 1)
# post a completely new user to verify we can add users to the subcollection directly
new_user = dict(username='NewUser9000')
which_org = self.normal_django_user.admin_of_organizations.all()[0]
url = '/api/v1/organizations/%s/users/' % (which_org.pk)
posted = self.post(url, new_user, expect=201, auth=self.get_normal_credentials())
all_users = self.get(url, expect=200, auth=self.get_normal_credentials())
self.assertEqual(all_users['count'], 2)
def test_post_item_subobjects_admins(self):
url = '/api/v1/organizations/2/admins/'