diff --git a/taiga/projects/api.py b/taiga/projects/api.py index 0efb9911..695376a2 100644 --- a/taiga/projects/api.py +++ b/taiga/projects/api.py @@ -274,6 +274,11 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin, project.save() return uuid_value + def _delete_csv_uuid(self, project, field): + setattr(project, field, None) + project.save() + return getattr(project, field) + @detail_route(methods=["POST"]) def regenerate_epics_csv_uuid(self, request, pk=None): project = self.get_object() @@ -306,6 +311,38 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin, data = {"uuid": self._regenerate_csv_uuid(project, "issues_csv_uuid")} return response.Ok(data) + @detail_route(methods=["POST"]) + def delete_epics_csv_uuid(self, request, pk=None): + project = self.get_object() + self.check_permissions(request, "delete_epics_csv_uuid", project) + self.pre_conditions_on_save(project) + data = {"uuid": self._delete_csv_uuid(project, "epics_csv_uuid")} + return response.Ok(data) + + @detail_route(methods=["POST"]) + def delete_userstories_csv_uuid(self, request, pk=None): + project = self.get_object() + self.check_permissions(request, "delete_userstories_csv_uuid", project) + self.pre_conditions_on_save(project) + data = {"uuid": self._delete_csv_uuid(project, "userstories_csv_uuid")} + return response.Ok(data) + + @detail_route(methods=["POST"]) + def delete_tasks_csv_uuid(self, request, pk=None): + project = self.get_object() + self.check_permissions(request, "delete_tasks_csv_uuid", project) + self.pre_conditions_on_save(project) + data = {"uuid": self._delete_csv_uuid(project, "tasks_csv_uuid")} + return response.Ok(data) + + @detail_route(methods=["POST"]) + def delete_issues_csv_uuid(self, request, pk=None): + project = self.get_object() + self.check_permissions(request, "delete_issues_csv_uuid", project) + self.pre_conditions_on_save(project) + data = {"uuid": self._delete_csv_uuid(project, "issues_csv_uuid")} + return response.Ok(data) + @list_route(methods=["GET"]) def by_slug(self, request, *args, **kwargs): slug = request.QUERY_PARAMS.get("slug", None) diff --git a/taiga/projects/permissions.py b/taiga/projects/permissions.py index 3e1452de..e7b15c9a 100644 --- a/taiga/projects/permissions.py +++ b/taiga/projects/permissions.py @@ -66,6 +66,10 @@ class ProjectPermission(TaigaResourcePermission): regenerate_userstories_csv_uuid_perms = IsProjectAdmin() regenerate_issues_csv_uuid_perms = IsProjectAdmin() regenerate_tasks_csv_uuid_perms = IsProjectAdmin() + delete_epics_csv_uuid_perms = IsProjectAdmin() + delete_userstories_csv_uuid_perms = IsProjectAdmin() + delete_issues_csv_uuid_perms = IsProjectAdmin() + delete_tasks_csv_uuid_perms = IsProjectAdmin() tags_perms = HasProjectPerm('view_project') tags_colors_perms = HasProjectPerm('view_project') like_perms = IsAuthenticated() & HasProjectPerm('view_project') diff --git a/tests/integration/resources_permissions/test_projects_resource.py b/tests/integration/resources_permissions/test_projects_resource.py index 9f2fbed2..89a0ad4a 100644 --- a/tests/integration/resources_permissions/test_projects_resource.py +++ b/tests/integration/resources_permissions/test_projects_resource.py @@ -521,6 +521,31 @@ def test_regenerate_epics_csv_uuid(client, data): assert results == [404, 404, 403, 451] +def test_delete_epics_csv_uuid(client, data): + public_url = reverse('projects-delete-epics-csv-uuid', kwargs={"pk": data.public_project.pk}) + private1_url = reverse('projects-delete-epics-csv-uuid', kwargs={"pk": data.private_project1.pk}) + private2_url = reverse('projects-delete-epics-csv-uuid', kwargs={"pk": data.private_project2.pk}) + blocked_url = reverse('projects-delete-epics-csv-uuid', kwargs={"pk": data.blocked_project.pk}) + + users = [ + None, + data.registered_user, + data.project_member_with_perms, + data.project_owner + ] + results = helper_test_http_method(client, 'post', public_url, None, users) + assert results == [401, 403, 403, 200] + + results = helper_test_http_method(client, 'post', private1_url, None, users) + assert results == [401, 403, 403, 200] + + results = helper_test_http_method(client, 'post', private2_url, None, users) + assert results == [404, 404, 403, 200] + + results = helper_test_http_method(client, 'post', blocked_url, None, users) + assert results == [404, 404, 403, 451] + + def test_regenerate_userstories_csv_uuid(client, data): public_url = reverse('projects-regenerate-userstories-csv-uuid', kwargs={"pk": data.public_project.pk}) private1_url = reverse('projects-regenerate-userstories-csv-uuid', kwargs={"pk": data.private_project1.pk}) @@ -546,6 +571,31 @@ def test_regenerate_userstories_csv_uuid(client, data): assert results == [404, 404, 403, 451] +def test_delete_userstories_csv_uuid(client, data): + public_url = reverse('projects-delete-userstories-csv-uuid', kwargs={"pk": data.public_project.pk}) + private1_url = reverse('projects-delete-userstories-csv-uuid', kwargs={"pk": data.private_project1.pk}) + private2_url = reverse('projects-delete-userstories-csv-uuid', kwargs={"pk": data.private_project2.pk}) + blocked_url = reverse('projects-delete-userstories-csv-uuid', kwargs={"pk": data.blocked_project.pk}) + + users = [ + None, + data.registered_user, + data.project_member_with_perms, + data.project_owner + ] + results = helper_test_http_method(client, 'post', public_url, None, users) + assert results == [401, 403, 403, 200] + + results = helper_test_http_method(client, 'post', private1_url, None, users) + assert results == [401, 403, 403, 200] + + results = helper_test_http_method(client, 'post', private2_url, None, users) + assert results == [404, 404, 403, 200] + + results = helper_test_http_method(client, 'post', blocked_url, None, users) + assert results == [404, 404, 403, 451] + + def test_regenerate_tasks_csv_uuid(client, data): public_url = reverse('projects-regenerate-tasks-csv-uuid', kwargs={"pk": data.public_project.pk}) private1_url = reverse('projects-regenerate-tasks-csv-uuid', kwargs={"pk": data.private_project1.pk}) @@ -571,6 +621,31 @@ def test_regenerate_tasks_csv_uuid(client, data): assert results == [404, 404, 403, 451] +def test_delete_tasks_csv_uuid(client, data): + public_url = reverse('projects-delete-tasks-csv-uuid', kwargs={"pk": data.public_project.pk}) + private1_url = reverse('projects-delete-tasks-csv-uuid', kwargs={"pk": data.private_project1.pk}) + private2_url = reverse('projects-delete-tasks-csv-uuid', kwargs={"pk": data.private_project2.pk}) + blocked_url = reverse('projects-delete-tasks-csv-uuid', kwargs={"pk": data.blocked_project.pk}) + + users = [ + None, + data.registered_user, + data.project_member_with_perms, + data.project_owner + ] + results = helper_test_http_method(client, 'post', public_url, None, users) + assert results == [401, 403, 403, 200] + + results = helper_test_http_method(client, 'post', private1_url, None, users) + assert results == [401, 403, 403, 200] + + results = helper_test_http_method(client, 'post', private2_url, None, users) + assert results == [404, 404, 403, 200] + + results = helper_test_http_method(client, 'post', blocked_url, None, users) + assert results == [404, 404, 403, 451] + + def test_regenerate_issues_csv_uuid(client, data): public_url = reverse('projects-regenerate-issues-csv-uuid', kwargs={"pk": data.public_project.pk}) private1_url = reverse('projects-regenerate-issues-csv-uuid', kwargs={"pk": data.private_project1.pk}) @@ -596,6 +671,31 @@ def test_regenerate_issues_csv_uuid(client, data): assert results == [404, 404, 403, 451] +def test_delete_issues_csv_uuid(client, data): + public_url = reverse('projects-delete-issues-csv-uuid', kwargs={"pk": data.public_project.pk}) + private1_url = reverse('projects-delete-issues-csv-uuid', kwargs={"pk": data.private_project1.pk}) + private2_url = reverse('projects-delete-issues-csv-uuid', kwargs={"pk": data.private_project2.pk}) + blocked_url = reverse('projects-delete-issues-csv-uuid', kwargs={"pk": data.blocked_project.pk}) + + users = [ + None, + data.registered_user, + data.project_member_with_perms, + data.project_owner + ] + results = helper_test_http_method(client, 'post', public_url, None, users) + assert results == [401, 403, 403, 200] + + results = helper_test_http_method(client, 'post', private1_url, None, users) + assert results == [401, 403, 403, 200] + + results = helper_test_http_method(client, 'post', private2_url, None, users) + assert results == [404, 404, 403, 200] + + results = helper_test_http_method(client, 'post', blocked_url, None, users) + assert results == [404, 404, 403, 451] + + def test_project_action_watch(client, data): public_url = reverse('projects-watch', kwargs={"pk": data.public_project.pk}) private1_url = reverse('projects-watch', kwargs={"pk": data.private_project1.pk})