diff --git a/lib/main/models/__init__.py b/lib/main/models/__init__.py index 83c390feef..bae06354d0 100644 --- a/lib/main/models/__init__.py +++ b/lib/main/models/__init__.py @@ -2,6 +2,7 @@ from django.db import models from django.db.models import CASCADE, SET_NULL, PROTECT from django.utils.translation import ugettext_lazy as _ from django.core.urlresolvers import reverse +import exceptions # TODO: jobs and events model TBD # TODO: reporting model TBD @@ -29,6 +30,9 @@ class CommonModel(models.Model): def __unicode__(self): return unicode(self.name) + + def can_user_administrate(self, user): + raise exceptions.NotImplementedError() class Tag(models.Model): ''' @@ -173,6 +177,14 @@ class Project(CommonModel): import lib.urls return reverse(lib.urls.views_ProjectsDetail, args=(self.pk,)) + def can_user_administrate(self, user): + organizations = Organization.filter(admins__in = [ user ]) + organizations = self.organizations() + for org in organizations: + if org in project.organizations(): + return True + return True + class Permission(CommonModel): ''' A permission allows a user, project, or team to be able to use an inventory source. diff --git a/lib/main/tests.py b/lib/main/tests.py index cc8a8504c4..2a9f6a958b 100644 --- a/lib/main/tests.py +++ b/lib/main/tests.py @@ -280,17 +280,26 @@ class OrganizationsTest(BaseTest): a_project = projects0['results'][-1] # attempt to add the project to the 7th org and see what happens - self.post(projects7_url, a_project, expect=202, auth=self.get_super_credentials()) - projects7 = self.get(projects0_url, expect=200, auth=self.get_super_credentials()) - self.assertEquals(projects7['count'], 3) + self.post(projects7_url, a_project, expect=204, auth=self.get_super_credentials()) + projects1 = self.get(projects0_url, expect=200, auth=self.get_super_credentials()) + self.assertEquals(projects1['count'], 3) # make sure we can't add the project again (should generate a conflict error) self.post(projects7_url, a_project, expect=409, auth=self.get_super_credentials()) + projects7 = self.get(projects7_url, expect=200, auth=self.get_super_credentials()) + self.assertEquals(projects7['count'], 6) # make sure adding a project that does not exist, or a missing pk field, results in a 400 self.post(projects7_url, dict(id=99999), expect=400, auth=self.get_super_credentials()) self.post(projects7_url, dict(asdf=1234), expect=400, auth=self.get_super_credentials()) + # test that by posting a pk + disassociate: True we can remove a relationship + a_project['disassociate'] = True + self.post(projects7_url, a_project, expect=204, auth=self.get_super_credentials()) + projects7 = self.get(projects7_url, expect=200, auth=self.get_super_credentials()) + self.assertEquals(projects7['count'], 5) + + def test_post_item_subobjects_users(self): pass diff --git a/lib/main/views.py b/lib/main/views.py index e23f9be4ad..6fa8fe41bd 100644 --- a/lib/main/views.py +++ b/lib/main/views.py @@ -159,11 +159,9 @@ class OrganizationsProjectsList(BaseList): teams__users__in = [ self.request.user ] ).distinct() + # BOOKMARK def post(self, request, *args, **kwargs): - # FIXME: overriden post for add-to-collection - # FIXME: if posted with disassociate: True, do not create object and remove the link - # POST { pk: 7, disassociate: True } organization_id = kwargs['pk'] @@ -178,14 +176,22 @@ class OrganizationsProjectsList(BaseList): # the person who created the project. TODO -- want to defer this question # to the model. (FIXME) - if not request.user.is_superuser or project.created_by == request.user: - raise PermissionDenied() - if project in organization.projects.all(): - return Response(status=status.HTTP_409_CONFLICT) + if not 'disassociate' in request.DATA: + # admin of another org can't add a project to their org + if not request.user.is_superuser or project.created_by == request.user: + raise PermissionDenied() + if project in organization.projects.all(): + return Response(status=status.HTTP_409_CONFLICT) + organization.projects.add(project) + else: + # to disassociate, be the org admin or a superuser + # FIXME: sprinkle these throughout the object layer & simplify + if not request.user.is_superuser and not project.can_user_administrate(request.user): + raise PermissionDenied() + organization.projects.remove(project) + # multiple attempts to delete the same thing aren't an error, we're cool + return Response(status=status.HTTP_204_NO_CONTENT) - organization.projects.add(project) - - return Response(status=status.HTTP_202_ACCEPTED)