Fix tasks validators for bulk operations

remotes/origin/issue/4795/notification_even_they_are_disabled
David Barragán Merino 2016-08-02 15:14:07 +02:00
parent d1f7158125
commit 3187bdfed9
2 changed files with 304 additions and 19 deletions

View File

@ -22,23 +22,18 @@ from taiga.base.api import serializers
from taiga.base.api import validators
from taiga.base.exceptions import ValidationError
from taiga.base.fields import PgArrayField
from taiga.projects.milestones.validators import MilestoneExistsValidator
from taiga.projects.milestones.models import Milestone
from taiga.projects.models import TaskStatus
from taiga.projects.notifications.mixins import EditableWatchedResourceSerializer
from taiga.projects.notifications.validators import WatchersValidator
from taiga.projects.tagging.fields import TagsAndTagsColorsField
from taiga.projects.userstories.models import UserStory
from taiga.projects.validators import ProjectExistsValidator
from . import models
class TaskExistsValidator:
def validate_task_id(self, attrs, source):
value = attrs[source]
if not models.Task.objects.filter(pk=value).exists():
msg = _("There's no task with that id")
raise ValidationError(msg)
return attrs
class TaskValidator(WatchersValidator, EditableWatchedResourceSerializer, validators.ModelValidator):
tags = TagsAndTagsColorsField(default=[], required=False)
external_reference = PgArrayField(required=False)
@ -48,25 +43,72 @@ class TaskValidator(WatchersValidator, EditableWatchedResourceSerializer, valida
read_only_fields = ('id', 'ref', 'created_date', 'modified_date', 'owner')
class TasksBulkValidator(ProjectExistsValidator, MilestoneExistsValidator,
TaskExistsValidator, validators.Validator):
class TasksBulkValidator(ProjectExistsValidator, validators.Validator):
project_id = serializers.IntegerField()
sprint_id = serializers.IntegerField()
status_id = serializers.IntegerField(required=False)
us_id = serializers.IntegerField(required=False)
bulk_tasks = serializers.CharField()
def validate_sprint_id(self, attrs, source):
filters = {"project__id": attrs["project_id"]}
filters["id"] = attrs["sprint_id"]
if not Milestone.objects.filter(**filters).exists():
raise ValidationError(_("Invalid sprint id."))
return attrs
def validate_status_id(self, attrs, source):
filters = {"project__id": attrs["project_id"]}
filters["id"] = attrs["status_id"]
if not TaskStatus.objects.filter(**filters).exists():
raise ValidationError(_("Invalid task status id."))
return attrs
def validate_us_id(self, attrs, source):
filters = {"project__id": attrs["project_id"]}
if "sprint_id" in attrs:
filters["milestone__id"] = attrs["sprint_id"]
filters["id"] = attrs["us_id"]
if not UserStory.objects.filter(**filters).exists():
raise ValidationError(_("Invalid sprint id."))
return attrs
# Order bulk validators
class _TaskOrderBulkValidator(TaskExistsValidator, validators.Validator):
class _TaskOrderBulkValidator(validators.Validator):
task_id = serializers.IntegerField()
order = serializers.IntegerField()
class UpdateTasksOrderBulkValidator(ProjectExistsValidator, validators.Validator):
project_id = serializers.IntegerField()
milestone_id = serializers.IntegerField(required=False)
status_id = serializers.IntegerField(required=False)
us_id = serializers.IntegerField(required=False)
milestone_id = serializers.IntegerField(required=False)
bulk_tasks = _TaskOrderBulkValidator(many=True)
def validate(self, data):
filters = {"project__id": data["project_id"]}
if "status_id" in data:
filters["status__id"] = data["status_id"]
if "us_id" in data:
filters["user_story__id"] = data["us_id"]
if "milestone_id" in data:
filters["milestone__id"] = data["milestone_id"]
filters["id__in"] = [t["task_id"] for t in data["bulk_tasks"]]
if models.Task.objects.filter(**filters).count() != len(filters["id__in"]):
raise ValidationError(_("Invalid task ids. All tasks must belong to the same project and, "
"if it exists, to the same status, user story and/or milestone."))
return data

View File

@ -85,10 +85,16 @@ def test_create_task_without_default_values(client):
assert response.data['status'] == None
def test_api_create_in_bulk_with_status(client):
us = f.create_userstory()
f.MembershipFactory.create(project=us.project, user=us.owner, is_admin=True)
us.project.default_task_status = f.TaskStatusFactory.create(project=us.project)
def test_api_create_in_bulk_with_status_milestone_userstory(client):
user = f.UserFactory.create()
project = f.ProjectFactory.create(owner=user, default_task_status=None)
f.MembershipFactory.create(project=project, user=user, is_admin=True)
project.default_task_status = f.TaskStatusFactory.create(project=project)
project.save()
milestone = f.MilestoneFactory(project=project)
us = f.create_userstory(project=project, milestone=milestone)
url = reverse("tasks-bulk-create")
data = {
"bulk_tasks": "Story #1\nStory #2",
@ -98,13 +104,141 @@ def test_api_create_in_bulk_with_status(client):
"status_id": us.project.default_task_status.id
}
client.login(us.owner)
client.login(user)
response = client.json.post(url, json.dumps(data))
assert response.status_code == 200
assert response.data[0]["status"] == us.project.default_task_status.id
def test_api_create_in_bulk_with_status_milestone(client):
user = f.UserFactory.create()
project = f.ProjectFactory.create(owner=user, default_task_status=None)
f.MembershipFactory.create(project=project, user=user, is_admin=True)
project.default_task_status = f.TaskStatusFactory.create(project=project)
project.save()
milestone = f.MilestoneFactory(project=project)
us = f.create_userstory(project=project, milestone=milestone)
url = reverse("tasks-bulk-create")
data = {
"bulk_tasks": "Story #1\nStory #2",
"project_id": us.project.id,
"sprint_id": us.milestone.id,
"status_id": us.project.default_task_status.id
}
client.login(user)
response = client.json.post(url, json.dumps(data))
assert response.status_code == 200
assert response.data[0]["status"] == us.project.default_task_status.id
def test_api_create_in_bulk_with_invalid_status(client):
user = f.UserFactory.create()
project = f.ProjectFactory.create(owner=user, default_task_status=None)
f.MembershipFactory.create(project=project, user=user, is_admin=True)
project.default_task_status = f.TaskStatusFactory.create(project=project)
project.save()
milestone = f.MilestoneFactory(project=project)
us = f.create_userstory(project=project, milestone=milestone)
status = f.TaskStatusFactory.create()
url = reverse("tasks-bulk-create")
data = {
"bulk_tasks": "Story #1\nStory #2",
"us_id": us.id,
"project_id": project.id,
"sprint_id": milestone.id,
"status_id": status.id
}
client.login(user)
response = client.json.post(url, json.dumps(data))
assert response.status_code == 400
def test_api_create_in_bulk_with_invalid_milestone(client):
user = f.UserFactory.create()
project = f.ProjectFactory.create(owner=user, default_task_status=None)
f.MembershipFactory.create(project=project, user=user, is_admin=True)
project.default_task_status = f.TaskStatusFactory.create(project=project)
project.save()
milestone = f.MilestoneFactory()
us = f.create_userstory(project=project)
url = reverse("tasks-bulk-create")
data = {
"bulk_tasks": "Story #1\nStory #2",
"us_id": us.id,
"project_id": project.id,
"sprint_id": milestone.id,
"status_id": project.default_task_status.id
}
client.login(user)
response = client.json.post(url, json.dumps(data))
assert response.status_code == 400
def test_api_create_in_bulk_with_invalid_userstory_1(client):
user = f.UserFactory.create()
project = f.ProjectFactory.create(owner=user, default_task_status=None)
f.MembershipFactory.create(project=project, user=user, is_admin=True)
project.default_task_status = f.TaskStatusFactory.create(project=project)
project.save()
milestone = f.MilestoneFactory(project=project)
us = f.create_userstory()
url = reverse("tasks-bulk-create")
data = {
"bulk_tasks": "Story #1\nStory #2",
"us_id": us.id,
"project_id": project.id,
"sprint_id": milestone.id,
"status_id": project.default_task_status.id
}
client.login(user)
response = client.json.post(url, json.dumps(data))
assert response.status_code == 400
def test_api_create_in_bulk_with_invalid_userstory_2(client):
user = f.UserFactory.create()
project = f.ProjectFactory.create(owner=user, default_task_status=None)
f.MembershipFactory.create(project=project, user=user, is_admin=True)
project.default_task_status = f.TaskStatusFactory.create(project=project)
project.save()
milestone = f.MilestoneFactory(project=project)
us = f.create_userstory(project=project)
url = reverse("tasks-bulk-create")
data = {
"bulk_tasks": "Story #1\nStory #2",
"us_id": us.id,
"project_id": us.project.id,
"sprint_id": milestone.id,
"status_id": us.project.default_task_status.id
}
client.login(user)
response = client.json.post(url, json.dumps(data))
assert response.status_code == 400
def test_api_create_invalid_task(client):
# Associated to a milestone and a user story.
# But the User Story is not associated with the milestone
@ -152,6 +286,115 @@ def test_api_update_order_in_bulk(client):
assert response2.status_code == 200, response2.data
def test_api_update_order_in_bulk_invalid_tasks(client):
project = f.create_project()
f.MembershipFactory.create(project=project, user=project.owner, is_admin=True)
task1 = f.create_task(project=project)
task2 = f.create_task(project=project)
task3 = f.create_task()
url1 = reverse("tasks-bulk-update-taskboard-order")
url2 = reverse("tasks-bulk-update-us-order")
data = {
"project_id": project.id,
"bulk_tasks": [{"task_id": task1.id, "order": 1},
{"task_id": task2.id, "order": 2},
{"task_id": task3.id, "order": 3}]
}
client.login(project.owner)
response1 = client.json.post(url1, json.dumps(data))
response2 = client.json.post(url2, json.dumps(data))
assert response1.status_code == 400, response1.data
assert response2.status_code == 400, response2.data
def test_api_update_order_in_bulk_invalid_status(client):
project = f.create_project()
f.MembershipFactory.create(project=project, user=project.owner, is_admin=True)
task1 = f.create_task(project=project)
task2 = f.create_task(project=project, status=task1.status)
task3 = f.create_task(project=project)
url1 = reverse("tasks-bulk-update-taskboard-order")
url2 = reverse("tasks-bulk-update-us-order")
data = {
"project_id": project.id,
"status_id": task1.status.id,
"bulk_tasks": [{"task_id": task1.id, "order": 1},
{"task_id": task2.id, "order": 2},
{"task_id": task3.id, "order": 3}]
}
client.login(project.owner)
response1 = client.json.post(url1, json.dumps(data))
response2 = client.json.post(url2, json.dumps(data))
assert response1.status_code == 400, response1.data
assert response2.status_code == 400, response2.data
def test_api_update_order_in_bulk_invalid_milestone(client):
project = f.create_project()
f.MembershipFactory.create(project=project, user=project.owner, is_admin=True)
mil1 = f.MilestoneFactory.create(project=project)
task1 = f.create_task(project=project, milestone=mil1)
task2 = f.create_task(project=project, milestone=mil1)
task3 = f.create_task(project=project)
url1 = reverse("tasks-bulk-update-taskboard-order")
url2 = reverse("tasks-bulk-update-us-order")
data = {
"project_id": project.id,
"milestone_id": mil1.id,
"bulk_tasks": [{"task_id": task1.id, "order": 1},
{"task_id": task2.id, "order": 2},
{"task_id": task3.id, "order": 3}]
}
client.login(project.owner)
response1 = client.json.post(url1, json.dumps(data))
response2 = client.json.post(url2, json.dumps(data))
assert response1.status_code == 400, response1.data
assert response2.status_code == 400, response2.data
def test_api_update_order_in_bulk_invalid_user_story(client):
project = f.create_project()
f.MembershipFactory.create(project=project, user=project.owner, is_admin=True)
us1 = f.create_userstory(project=project)
task1 = f.create_task(project=project, user_story=us1)
task2 = f.create_task(project=project, user_story=us1)
task3 = f.create_task(project=project)
url1 = reverse("tasks-bulk-update-taskboard-order")
url2 = reverse("tasks-bulk-update-us-order")
data = {
"project_id": project.id,
"us_id": us1.id,
"bulk_tasks": [{"task_id": task1.id, "order": 1},
{"task_id": task2.id, "order": 2},
{"task_id": task3.id, "order": 3}]
}
client.login(project.owner)
response1 = client.json.post(url1, json.dumps(data))
response2 = client.json.post(url2, json.dumps(data))
assert response1.status_code == 400, response1.data
assert response2.status_code == 400, response2.data
def test_get_invalid_csv(client):
url = reverse("tasks-csv")