From 7e9328befbfac68bc9f29bb671fc5811d4c067ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Hermida?= Date: Wed, 13 Jun 2018 16:14:34 +0200 Subject: [PATCH] Add create default duedates view to task and issues --- taiga/projects/api.py | 75 ++++++++++++++- tests/factories.py | 9 ++ tests/integration/test_projects.py | 150 +++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+), 1 deletion(-) diff --git a/taiga/projects/api.py b/taiga/projects/api.py index 55f8a115..c2abb326 100644 --- a/taiga/projects/api.py +++ b/taiga/projects/api.py @@ -601,7 +601,8 @@ class UserStoryDueDateViewSet(BlockedByProjectMixin, ModelCrudViewSet): def pre_delete(self, obj): if obj.by_default: - raise exc.BadRequest(_("You can't delete by default due date")) + raise exc.BadRequest( + _("You can't delete user story by default due date")) @list_route(methods=["POST"]) def create_default(self, request, **kwargs): @@ -675,6 +676,42 @@ class TaskDueDateViewSet(BlockedByProjectMixin, ModelCrudViewSet): with advisory_lock("task-due-date-creation-{}".format(project_id)): return super().create(request, *args, **kwargs) + @list_route(methods=["POST"]) + def create_default(self, request, **kwargs): + context = { + "request": request + } + validator = validators.DueDatesCreationValidator(data=request.DATA, + context=context) + if not validator.is_valid(): + return response.BadRequest(validator.errors) + + project_id = request.DATA.get('project_id') + project = models.Project.objects.get(id=project_id) + + if project.task_duedates.all(): + raise exc.BadRequest(_("Project already have task due dates")) + + project_template = models.ProjectTemplate.objects.get( + id=project.creation_template.id) + + for task_duedate in project_template.task_duedates: + models.TaskDueDate.objects.create( + name=task_duedate["name"], + slug=task_duedate["slug"], + by_default=task_duedate["by_default"], + color=task_duedate["color"], + days_to_due=task_duedate["days_to_due"], + order=task_duedate["order"], + project=project + ) + project.save() + + serializer = self.get_serializer(project.task_duedates.all(), + many=True) + + return response.Ok(serializer.data) + class SeverityViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, ModelCrudViewSet, BulkUpdateOrderMixin): @@ -775,6 +812,42 @@ class IssueDueDateViewSet(BlockedByProjectMixin, ModelCrudViewSet): with advisory_lock("issue-due-date-creation-{}".format(project_id)): return super().create(request, *args, **kwargs) + @list_route(methods=["POST"]) + def create_default(self, request, **kwargs): + context = { + "request": request + } + validator = validators.DueDatesCreationValidator(data=request.DATA, + context=context) + if not validator.is_valid(): + return response.BadRequest(validator.errors) + + project_id = request.DATA.get('project_id') + project = models.Project.objects.get(id=project_id) + + if project.issue_duedates.all(): + raise exc.BadRequest(_("Project already have issue due dates")) + + project_template = models.ProjectTemplate.objects.get( + id=project.creation_template.id) + + for issue_duedate in project_template.issue_duedates: + models.IssueDueDate.objects.create( + name=issue_duedate["name"], + slug=issue_duedate["slug"], + by_default=issue_duedate["by_default"], + color=issue_duedate["color"], + days_to_due=issue_duedate["days_to_due"], + order=issue_duedate["order"], + project=project + ) + project.save() + + serializer = self.get_serializer(project.issue_duedates.all(), + many=True) + + return response.Ok(serializer.data) + ###################################################### ## Project Template diff --git a/tests/factories.py b/tests/factories.py index 6ce96a32..daf47f25 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -388,6 +388,15 @@ class UserStoryStatusFactory(Factory): project = factory.SubFactory("tests.factories.ProjectFactory") +class UserStoryDueDateFactory(Factory): + class Meta: + model = "projects.UserStoryDueDate" + strategy = factory.CREATE_STRATEGY + + name = factory.Sequence(lambda n: "User Story due date {}".format(n)) + project = factory.SubFactory("tests.factories.ProjectFactory") + + class TaskStatusFactory(Factory): class Meta: model = "projects.TaskStatus" diff --git a/tests/integration/test_projects.py b/tests/integration/test_projects.py index 3f7016b0..45f21941 100644 --- a/tests/integration/test_projects.py +++ b/tests/integration/test_projects.py @@ -2289,3 +2289,153 @@ def test_duplicate_public_project_without_enough_memberships_slots(client): assert "current limit of memberships" in response.data["_error_message"] assert response["Taiga-Info-Project-Memberships"] == "2" assert response["Taiga-Info-Project-Is-Private"] == "False" + + +def test_create_us_default_due_dates(client): + project = f.create_project() + + us_duedates = [{ + "name": 'Default', + "slug": 'default', + "by_default": True, + 'color': '#0000', + 'days_to_due': None, + 'order': 0, + }] + creation_template = project.creation_template + creation_template.us_duedates = us_duedates + creation_template.save() + + f.MembershipFactory(user=project.owner, project=project, is_admin=True) + url = reverse('userstory-due-dates-create-default') + data = {"project_id": project.pk} + client.login(project.owner) + + response = client.json.post(url, json.dumps(data)) + + assert response.status_code == 200 + assert project.us_duedates.count() == 1 + + +def test_prevent_create_us_default_due_dates_when_already_exists(client): + us_duedates = [{ + "name": 'Default', + "slug": 'default', + "by_default": True, + 'color': '#0000', + 'days_to_due': None, + 'order': 0, + }] + f.ProjectTemplateFactory.create( + slug=settings.DEFAULT_PROJECT_TEMPLATE, us_duedates=us_duedates) + project = f.create_project() + + f.MembershipFactory(user=project.owner, project=project, is_admin=True) + url = reverse('userstory-due-dates-create-default') + data = {"project_id": project.pk} + client.login(project.owner) + + response = client.json.post(url, json.dumps(data)) + + assert response.status_code == 400 + assert project.us_duedates.count() == 1 + + +def test_create_issue_default_due_dates(client): + project = f.create_project() + + issue_duedates = [{ + "name": 'Default', + "slug": 'default', + "by_default": True, + 'color': '#0000', + 'days_to_due': None, + 'order': 0, + }] + creation_template = project.creation_template + creation_template.issue_duedates = issue_duedates + creation_template.save() + + f.MembershipFactory(user=project.owner, project=project, is_admin=True) + url = reverse('issue-due-dates-create-default') + data = {"project_id": project.pk} + client.login(project.owner) + + response = client.json.post(url, json.dumps(data)) + + assert response.status_code == 200 + assert project.issue_duedates.count() == 1 + + +def test_prevent_create_issue_default_due_dates_when_already_exists(client): + issue_duedates = [{ + "name": 'Default', + "slug": 'default', + "by_default": True, + 'color': '#0000', + 'days_to_due': None, + 'order': 0, + }] + f.ProjectTemplateFactory.create( + slug=settings.DEFAULT_PROJECT_TEMPLATE, issue_duedates=issue_duedates) + project = f.create_project() + + f.MembershipFactory(user=project.owner, project=project, is_admin=True) + url = reverse('issue-due-dates-create-default') + data = {"project_id": project.pk} + client.login(project.owner) + + response = client.json.post(url, json.dumps(data)) + + assert response.status_code == 400 + assert project.issue_duedates.count() == 1 + + +def test_create_task_default_due_dates(client): + project = f.create_project() + + task_duedates = [{ + "name": 'Default', + "slug": 'default', + "by_default": True, + 'color': '#0000', + 'days_to_due': None, + 'order': 0, + }] + creation_template = project.creation_template + creation_template.task_duedates = task_duedates + creation_template.save() + + f.MembershipFactory(user=project.owner, project=project, is_admin=True) + url = reverse('task-due-dates-create-default') + data = {"project_id": project.pk} + client.login(project.owner) + + response = client.json.post(url, json.dumps(data)) + + assert response.status_code == 200 + assert project.task_duedates.count() == 1 + + +def test_prevent_create_task_default_due_dates_when_already_exists(client): + task_duedates = [{ + "name": 'Default', + "slug": 'default', + "by_default": True, + 'color': '#0000', + 'days_to_due': None, + 'order': 0, + }] + f.ProjectTemplateFactory.create( + slug=settings.DEFAULT_PROJECT_TEMPLATE, task_duedates=task_duedates) + project = f.create_project() + + f.MembershipFactory(user=project.owner, project=project, is_admin=True) + url = reverse('task-due-dates-create-default') + data = {"project_id": project.pk} + client.login(project.owner) + + response = client.json.post(url, json.dumps(data)) + + assert response.status_code == 400 + assert project.task_duedates.count() == 1