Add bulk update order in user story and taskboard for tasks

remotes/origin/enhancement/email-actions
Jesús Espino 2014-12-02 11:44:01 +01:00 committed by David Barragán Merino
parent ad34a06481
commit 1101c5a719
7 changed files with 119 additions and 33 deletions

View File

@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.shortcuts import get_object_or_404
from taiga.base import filters, response from taiga.base import filters, response
from taiga.base import exceptions as exc from taiga.base import exceptions as exc
@ -79,3 +80,27 @@ class TaskViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMixin,
return response.Ok(tasks_serialized.data) return response.Ok(tasks_serialized.data)
return response.BadRequest(serializer.errors) return response.BadRequest(serializer.errors)
def _bulk_update_order(self, order_field, request, **kwargs):
serializer = serializers.UpdateTasksOrderBulkSerializer(data=request.DATA)
if not serializer.is_valid():
return response.BadRequest(serializer.errors)
data = serializer.data
project = get_object_or_404(Project, pk=data["project_id"])
self.check_permissions(request, "bulk_update_order", project)
services.update_tasks_order_in_bulk(data["bulk_tasks"],
project=project,
field=order_field)
services.snapshot_tasks_in_bulk(data["bulk_tasks"], request.user)
return response.NoContent()
@list_route(methods=["POST"])
def bulk_update_taskboard_order(self, request, **kwargs):
return self._bulk_update_order("taskboard_order", request, **kwargs)
@list_route(methods=["POST"])
def bulk_update_us_order(self, request, **kwargs):
return self._bulk_update_order("us_order", request, **kwargs)

View File

@ -27,3 +27,4 @@ class TaskPermission(TaigaResourcePermission):
destroy_perms = HasProjectPerm('delete_task') destroy_perms = HasProjectPerm('delete_task')
list_perms = AllowAny() list_perms = AllowAny()
bulk_create_perms = HasProjectPerm('add_task') bulk_create_perms = HasProjectPerm('add_task')
bulk_update_order_perms = HasProjectPerm('modify_task')

View File

@ -18,9 +18,9 @@ from rest_framework import serializers
from taiga.base.serializers import Serializer, PickleField, NeighborsSerializerMixin, PgArrayField from taiga.base.serializers import Serializer, PickleField, NeighborsSerializerMixin, PgArrayField
from taiga.mdrender.service import render as mdrender from taiga.mdrender.service import render as mdrender
from taiga.projects.validators import ProjectExistsValidator, TaskStatusExistsValidator from taiga.projects.validators import ProjectExistsValidator
from taiga.projects.milestones.validators import SprintExistsValidator from taiga.projects.milestones.validators import SprintExistsValidator
from taiga.projects.userstories.validators import UserStoryExistsValidator from taiga.projects.tasks.validators import TaskExistsValidator
from taiga.projects.notifications.validators import WatchersValidator from taiga.projects.notifications.validators import WatchersValidator
from . import models from . import models
@ -70,10 +70,21 @@ class NeighborTaskSerializer(serializers.ModelSerializer):
depth = 0 depth = 0
class TasksBulkSerializer(ProjectExistsValidator, SprintExistsValidator, TaskStatusExistsValidator, class TasksBulkSerializer(ProjectExistsValidator, SprintExistsValidator,
UserStoryExistsValidator, Serializer): TaskExistsValidator, Serializer):
project_id = serializers.IntegerField() project_id = serializers.IntegerField()
sprint_id = serializers.IntegerField() sprint_id = serializers.IntegerField()
status_id = serializers.IntegerField(required=False) status_id = serializers.IntegerField(required=False)
us_id = serializers.IntegerField(required=False) us_id = serializers.IntegerField(required=False)
bulk_tasks = serializers.CharField() bulk_tasks = serializers.CharField()
## Order bulk serializers
class _TaskOrderBulkSerializer(TaskExistsValidator, Serializer):
task_id = serializers.IntegerField()
order = serializers.IntegerField()
class UpdateTasksOrderBulkSerializer(ProjectExistsValidator, Serializer):
project_id = serializers.IntegerField()
bulk_tasks = _TaskOrderBulkSerializer(many=True)

View File

@ -15,6 +15,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from taiga.base.utils import db, text from taiga.base.utils import db, text
from taiga.projects.history.services import take_snapshot
from taiga.events import events
from . import models from . import models
@ -43,3 +45,33 @@ def create_tasks_in_bulk(bulk_data, callback=None, precall=None, **additional_fi
tasks = get_tasks_from_bulk(bulk_data, **additional_fields) tasks = get_tasks_from_bulk(bulk_data, **additional_fields)
db.save_in_bulk(tasks, callback, precall) db.save_in_bulk(tasks, callback, precall)
return tasks return tasks
def update_tasks_order_in_bulk(bulk_data:list, field:str, project:object):
"""
Update the order of some tasks.
`bulk_data` should be a list of tuples with the following format:
[(<task id>, {<field>: <value>, ...}), ...]
"""
task_ids = []
new_order_values = []
for task_data in bulk_data:
task_ids.append(task_data["task_id"])
new_order_values.append({field: task_data["order"]})
events.emit_event_for_ids(ids=task_ids,
content_type="tasks.task",
projectid=project.pk)
db.update_in_bulk_with_ids(task_ids, new_order_values, model=models.Task)
def snapshot_tasks_in_bulk(bulk_data, user):
task_ids = []
for task_data in bulk_data:
try:
task = models.Task.objects.get(pk=task_data['task_id'])
take_snapshot(task, user=user)
except models.UserStory.DoesNotExist:
pass

View File

@ -0,0 +1,14 @@
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
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 serializers.ValidationError(msg)
return attrs

View File

@ -110,8 +110,7 @@ class UserStoryViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMi
return response.Ok(user_stories_serialized.data) return response.Ok(user_stories_serialized.data)
return response.BadRequest(serializer.errors) return response.BadRequest(serializer.errors)
@list_route(methods=["POST"]) def _bulk_update_order(self, order_field, request, **kwargs):
def bulk_update_backlog_order(self, request, **kwargs):
serializer = serializers.UpdateUserStoriesOrderBulkSerializer(data=request.DATA) serializer = serializers.UpdateUserStoriesOrderBulkSerializer(data=request.DATA)
if not serializer.is_valid(): if not serializer.is_valid():
return response.BadRequest(serializer.errors) return response.BadRequest(serializer.errors)
@ -122,42 +121,22 @@ class UserStoryViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMi
self.check_permissions(request, "bulk_update_order", project) self.check_permissions(request, "bulk_update_order", project)
services.update_userstories_order_in_bulk(data["bulk_stories"], services.update_userstories_order_in_bulk(data["bulk_stories"],
project=project, project=project,
field="backlog_order") field=order_field)
services.snapshot_userstories_in_bulk(data["bulk_stories"], request.user) services.snapshot_userstories_in_bulk(data["bulk_stories"], request.user)
return response.NoContent() return response.NoContent()
@list_route(methods=["POST"])
def bulk_update_backlog_order(self, request, **kwargs):
return self._bulk_update_order("backlog_order", request, **kwargs)
@list_route(methods=["POST"]) @list_route(methods=["POST"])
def bulk_update_sprint_order(self, request, **kwargs): def bulk_update_sprint_order(self, request, **kwargs):
serializer = serializers.UpdateUserStoriesOrderBulkSerializer(data=request.DATA) return self._bulk_update_order("sprint_order", request, **kwargs)
if not serializer.is_valid():
return response.BadRequest(serializer.errors)
data = serializer.data
project = get_object_or_404(Project, pk=data["project_id"])
self.check_permissions(request, "bulk_update_order", project)
services.update_userstories_order_in_bulk(data["bulk_stories"],
project=project,
field="sprint_order")
services.snapshot_userstories_in_bulk(data["bulk_stories"], request.user)
return response.NoContent()
@list_route(methods=["POST"]) @list_route(methods=["POST"])
def bulk_update_kanban_order(self, request, **kwargs): def bulk_update_kanban_order(self, request, **kwargs):
serializer = serializers.UpdateUserStoriesOrderBulkSerializer(data=request.DATA) return self._bulk_update_order("kanban_order", request, **kwargs)
if not serializer.is_valid():
return response.BadRequest(serializer.errors)
data = serializer.data
project = get_object_or_404(Project, pk=data["project_id"])
self.check_permissions(request, "bulk_update_order", project)
services.update_userstories_order_in_bulk(data["bulk_stories"],
project=project,
field="kanban_order")
services.snapshot_userstories_in_bulk(data["bulk_stories"], request.user)
return response.NoContent()
@transaction.atomic @transaction.atomic
def create(self, *args, **kwargs): def create(self, *args, **kwargs):

View File

@ -87,3 +87,27 @@ def test_api_create_invalid_task(client):
client.login(us.owner) client.login(us.owner)
response = client.json.post(url, json.dumps(data)) response = client.json.post(url, json.dumps(data))
assert response.status_code == 400 assert response.status_code == 400
def test_api_update_order_in_bulk(client):
project = f.create_project()
f.MembershipFactory.create(project=project, user=project.owner, is_owner=True)
task1 = f.create_task(project=project)
task2 = f.create_task(project=project)
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}]
}
client.login(project.owner)
response1 = client.json.post(url1, json.dumps(data))
response2 = client.json.post(url2, json.dumps(data))
assert response1.status_code == 204, response1.data
assert response2.status_code == 204, response2.data