From dba0597c9c5d67fb48867b037f99956843d21a50 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 9 Feb 2016 14:43:16 +0100 Subject: [PATCH] Status and default status can be None --- taiga/projects/history/freeze_impl.py | 6 +++--- taiga/projects/issues/models.py | 2 +- taiga/projects/issues/services.py | 2 +- taiga/projects/issues/signals.py | 2 ++ taiga/projects/milestones/services.py | 2 +- taiga/projects/services/stats.py | 2 +- taiga/projects/tasks/serializers.py | 2 +- taiga/projects/tasks/services.py | 4 ++-- taiga/projects/tasks/signals.py | 2 ++ taiga/projects/userstories/services.py | 6 +++--- tests/integration/test_issues.py | 21 +++++++++++++++++++++ tests/integration/test_tasks.py | 13 +++++++++++++ tests/integration/test_userstories.py | 13 +++++++++++++ 13 files changed, 64 insertions(+), 13 deletions(-) diff --git a/taiga/projects/history/freeze_impl.py b/taiga/projects/history/freeze_impl.py index ba0c10fe..07de4bfc 100644 --- a/taiga/projects/history/freeze_impl.py +++ b/taiga/projects/history/freeze_impl.py @@ -266,7 +266,7 @@ def userstory_freezer(us) -> dict: snapshot = { "ref": us.ref, "owner": us.owner_id, - "status": us.status_id, + "status": us.status.id if us.status else None, "is_closed": us.is_closed, "finish_date": str(us.finish_date), "backlog_order": us.backlog_order, @@ -297,7 +297,7 @@ def issue_freezer(issue) -> dict: snapshot = { "ref": issue.ref, "owner": issue.owner_id, - "status": issue.status_id, + "status": issue.status.id if issue.status else None, "priority": issue.priority_id, "severity": issue.severity_id, "type": issue.type_id, @@ -321,7 +321,7 @@ def task_freezer(task) -> dict: snapshot = { "ref": task.ref, "owner": task.owner_id, - "status": task.status_id, + "status": task.status.id if task.status else None, "milestone": task.milestone_id, "subject": task.subject, "description": task.description, diff --git a/taiga/projects/issues/models.py b/taiga/projects/issues/models.py index 07fd2247..3faac676 100644 --- a/taiga/projects/issues/models.py +++ b/taiga/projects/issues/models.py @@ -98,4 +98,4 @@ class Issue(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, models. @property def is_closed(self): - return self.status.is_closed + return self.status is not None and self.status.is_closed diff --git a/taiga/projects/issues/services.py b/taiga/projects/issues/services.py index 6d1871e3..6da95c9b 100644 --- a/taiga/projects/issues/services.py +++ b/taiga/projects/issues/services.py @@ -117,7 +117,7 @@ def issues_to_csv(project, queryset): "owner_full_name": issue.owner.get_full_name() if issue.owner else None, "assigned_to": issue.assigned_to.username if issue.assigned_to else None, "assigned_to_full_name": issue.assigned_to.get_full_name() if issue.assigned_to else None, - "status": issue.status.name, + "status": issue.status.name if issue.status else None, "severity": issue.severity.name, "priority": issue.priority.name, "type": issue.type.name, diff --git a/taiga/projects/issues/signals.py b/taiga/projects/issues/signals.py index a46bfe35..b92418ee 100644 --- a/taiga/projects/issues/signals.py +++ b/taiga/projects/issues/signals.py @@ -23,6 +23,8 @@ from django.utils import timezone #################################### def set_finished_date_when_edit_issue(sender, instance, **kwargs): + if instance.status is None: + return if instance.status.is_closed and not instance.finished_date: instance.finished_date = timezone.now() elif not instance.status.is_closed and instance.finished_date: diff --git a/taiga/projects/milestones/services.py b/taiga/projects/milestones/services.py index 785a8bc7..a717e04f 100644 --- a/taiga/projects/milestones/services.py +++ b/taiga/projects/milestones/services.py @@ -23,7 +23,7 @@ from . import models def calculate_milestone_is_closed(milestone): return (milestone.user_stories.all().count() > 0 and - all([task.status.is_closed for task in milestone.tasks.all()]) and + all([task.status is not None and task.status.is_closed for task in milestone.tasks.all()]) and all([user_story.is_closed for user_story in milestone.user_stories.all()])) diff --git a/taiga/projects/services/stats.py b/taiga/projects/services/stats.py index 44230046..f0d70f1c 100644 --- a/taiga/projects/services/stats.py +++ b/taiga/projects/services/stats.py @@ -84,7 +84,7 @@ def get_stats_for_project_issues(project): ) for issue in issues: project_issues_stats['total_issues'] += 1 - if issue.status.is_closed: + if issue.status is not None and issue.status.is_closed: project_issues_stats['closed_issues'] += 1 else: project_issues_stats['opened_issues'] += 1 diff --git a/taiga/projects/tasks/serializers.py b/taiga/projects/tasks/serializers.py index b10ef5a7..5bf022f7 100644 --- a/taiga/projects/tasks/serializers.py +++ b/taiga/projects/tasks/serializers.py @@ -68,7 +68,7 @@ class TaskSerializer(WatchersValidator, VoteResourceSerializerMixin, EditableWat return mdrender(obj.project, obj.description) def get_is_closed(self, obj): - return obj.status.is_closed + return obj.status is not None and obj.status.is_closed class TaskListSerializer(TaskSerializer): diff --git a/taiga/projects/tasks/services.py b/taiga/projects/tasks/services.py index 7fad684d..7e3e97ce 100644 --- a/taiga/projects/tasks/services.py +++ b/taiga/projects/tasks/services.py @@ -129,9 +129,9 @@ def tasks_to_csv(project, queryset): "owner_full_name": task.owner.get_full_name() if task.owner else None, "assigned_to": task.assigned_to.username if task.assigned_to else None, "assigned_to_full_name": task.assigned_to.get_full_name() if task.assigned_to else None, - "status": task.status.name, + "status": task.status.name if task.status else None, "is_iocaine": task.is_iocaine, - "is_closed": task.status.is_closed, + "is_closed": task.status is not None and task.status.is_closed, "us_order": task.us_order, "taskboard_order": task.taskboard_order, "attachments": task.attachments.count(), diff --git a/taiga/projects/tasks/signals.py b/taiga/projects/tasks/signals.py index 893869a1..5f1ae65a 100644 --- a/taiga/projects/tasks/signals.py +++ b/taiga/projects/tasks/signals.py @@ -100,6 +100,8 @@ def _try_to_close_milestone_when_delete_task(instance): #################################### def set_finished_date_when_edit_task(sender, instance, **kwargs): + if instance.status is None: + return if instance.status.is_closed and not instance.finished_date: instance.finished_date = timezone.now() elif not instance.status.is_closed and instance.finished_date: diff --git a/taiga/projects/userstories/services.py b/taiga/projects/userstories/services.py index 4270ec54..b8a0533c 100644 --- a/taiga/projects/userstories/services.py +++ b/taiga/projects/userstories/services.py @@ -106,9 +106,9 @@ def calculate_userstory_is_closed(user_story): return False if user_story.tasks.count() == 0: - return user_story.status.is_closed + return user_story.status is not None and user_story.status.is_closed - if all([task.status.is_closed for task in user_story.tasks.all()]): + if all([task.status is not None and task.status.is_closed for task in user_story.tasks.all()]): return True return False @@ -179,7 +179,7 @@ def userstories_to_csv(project,queryset): "owner_full_name": us.owner.get_full_name() if us.owner else None, "assigned_to": us.assigned_to.username if us.assigned_to else None, "assigned_to_full_name": us.assigned_to.get_full_name() if us.assigned_to else None, - "status": us.status.name, + "status": us.status.name if us.status else None, "is_closed": us.is_closed, "backlog_order": us.backlog_order, "sprint_order": us.sprint_order, diff --git a/tests/integration/test_issues.py b/tests/integration/test_issues.py index 02551a68..b24e54fb 100644 --- a/tests/integration/test_issues.py +++ b/tests/integration/test_issues.py @@ -71,6 +71,27 @@ def test_create_issue_without_status(client): assert response.data['type'] == project.default_issue_type.id +def test_create_issue_without_status_in_project_without_default_values(client): + user = f.UserFactory.create() + project = f.ProjectFactory.create(owner=user, + default_issue_status=None, + default_priority=None, + default_severity=None, + default_issue_type = None) + + f.MembershipFactory.create(project=project, user=user, is_owner=True) + url = reverse("issues-list") + + data = {"subject": "Test user story", "project": project.id} + client.login(user) + response = client.json.post(url, json.dumps(data)) + assert response.status_code == 201 + assert response.data['status'] == None + assert response.data['severity'] == None + assert response.data['priority'] == None + assert response.data['type'] == None + + def test_api_create_issues_in_bulk(client): project = f.create_project() f.MembershipFactory(project=project, user=project.owner, is_owner=True) diff --git a/tests/integration/test_tasks.py b/tests/integration/test_tasks.py index 08825955..2fb2fc78 100644 --- a/tests/integration/test_tasks.py +++ b/tests/integration/test_tasks.py @@ -53,6 +53,19 @@ def test_create_task_without_status(client): assert response.data['status'] == project.default_task_status.id +def test_create_task_without_default_values(client): + user = f.UserFactory.create() + project = f.ProjectFactory.create(owner=user, default_task_status=None) + f.MembershipFactory.create(project=project, user=user, is_owner=True) + url = reverse("tasks-list") + + data = {"subject": "Test user story", "project": project.id} + client.login(user) + response = client.json.post(url, json.dumps(data)) + assert response.status_code == 201 + assert response.data['status'] == None + + def test_api_update_task_tags(client): project = f.ProjectFactory.create() task = f.create_task(project=project, status__project=project, milestone=None, user_story=None) diff --git a/tests/integration/test_userstories.py b/tests/integration/test_userstories.py index 8502c4ca..c50a9710 100644 --- a/tests/integration/test_userstories.py +++ b/tests/integration/test_userstories.py @@ -79,6 +79,19 @@ def test_create_userstory_without_status(client): assert response.data['status'] == project.default_us_status.id +def test_create_userstory_without_default_values(client): + user = f.UserFactory.create() + project = f.ProjectFactory.create(owner=user, default_us_status=None) + f.MembershipFactory.create(project=project, user=user, is_owner=True) + url = reverse("userstories-list") + + data = {"subject": "Test user story", "project": project.id} + client.login(user) + response = client.json.post(url, json.dumps(data)) + assert response.status_code == 201 + assert response.data['status'] == None + + def test_api_delete_userstory(client): us = f.UserStoryFactory.create() f.MembershipFactory.create(project=us.project, user=us.owner, is_owner=True)