diff --git a/taiga/projects/api.py b/taiga/projects/api.py index 329aebf8..3331d1a3 100644 --- a/taiga/projects/api.py +++ b/taiga/projects/api.py @@ -196,7 +196,11 @@ class MembershipViewSet(ModelCrudViewSet): @detail_route(methods=["POST"]) def resend_invitation(self, request, **kwargs): - services.send_invitation(invitation=self.get_object()) + invitation = self.get_object() + + self.check_permissions(request, 'resend_invitation', invitation.project) + + services.send_invitation(invitation=invitation) return Response(status=status.HTTP_204_NO_CONTENT) def pre_save(self, object): diff --git a/taiga/projects/permissions.py b/taiga/projects/permissions.py index 16da75b7..9185d59b 100644 --- a/taiga/projects/permissions.py +++ b/taiga/projects/permissions.py @@ -42,6 +42,7 @@ class MembershipPermission(ResourcePermission): destroy_perms = IsProjectOwner() list_perms = AllowAny() bulk_create_perms = IsProjectOwner() + resend_invitation_perms = IsProjectOwner() # User Stories diff --git a/tests/factories.py b/tests/factories.py index a53bb766..9e094151 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -128,6 +128,15 @@ class MembershipFactory(Factory): user = factory.SubFactory("tests.factories.UserFactory") +class InvitationFactory(Factory): + FACTORY_FOR = get_model("projects", "Membership") + + token = factory.LazyAttribute(lambda obj: str(uuid.uuid1())) + project = factory.SubFactory("tests.factories.ProjectFactory") + role = factory.SubFactory("tests.factories.RoleFactory") + email = factory.Sequence(lambda n: "user{}@email.com".format(n)) + + class StorageEntryFactory(Factory): FACTORY_FOR = get_model("userstorage", "StorageEntry") diff --git a/tests/integration/resources_permissions/test_projects_choices_resources.py b/tests/integration/resources_permissions/test_projects_choices_resources.py index 792e366b..b4b1f54d 100644 --- a/tests/integration/resources_permissions/test_projects_choices_resources.py +++ b/tests/integration/resources_permissions/test_projects_choices_resources.py @@ -1551,6 +1551,33 @@ def test_membership_action_bulk_create(client, data): assert results == [401, 403, 403, 403, 200] +def test_membership_action_resend_invitation(client, data): + public_invitation = f.InvitationFactory(project=data.public_project, role__project=data.public_project) + private_invitation1 = f.InvitationFactory(project=data.private_project1, role__project=data.private_project1) + private_invitation2 = f.InvitationFactory(project=data.private_project2, role__project=data.private_project2) + + public_url = reverse('memberships-resend-invitation', kwargs={"pk": public_invitation.pk}) + private1_url = reverse('memberships-resend-invitation', kwargs={"pk": private_invitation1.pk}) + private2_url = reverse('memberships-resend-invitation', kwargs={"pk": private_invitation2.pk}) + + users = [ + None, + data.registered_user, + data.project_member_without_perms, + data.project_member_with_perms, + data.project_owner + ] + + results = helper_test_http_method(client, 'post', public_url, None, users) + assert results == [401, 403, 403, 403, 204] + + results = helper_test_http_method(client, 'post', private1_url, None, users) + assert results == [401, 403, 403, 403, 204] + + results = helper_test_http_method(client, 'post', private2_url, None, users) + assert results == [404, 404, 403, 403, 204] + + def test_project_template_retrieve(client, data): url = reverse('project-templates-detail', kwargs={"pk": data.project_template.pk})