Removing the bulk update order for epics and doing that processing on the update
parent
46f6fa71e6
commit
4d4f8a44a1
|
@ -25,6 +25,7 @@ from taiga.base import exceptions as exc
|
||||||
from taiga.base.decorators import list_route, detail_route
|
from taiga.base.decorators import list_route, detail_route
|
||||||
from taiga.base.api import ModelCrudViewSet, ModelListViewSet
|
from taiga.base.api import ModelCrudViewSet, ModelListViewSet
|
||||||
from taiga.base.api.mixins import BlockedByProjectMixin
|
from taiga.base.api.mixins import BlockedByProjectMixin
|
||||||
|
from taiga.base.utils import json
|
||||||
|
|
||||||
from taiga.projects.history.mixins import HistoryResourceMixin
|
from taiga.projects.history.mixins import HistoryResourceMixin
|
||||||
from taiga.projects.models import Project, EpicStatus
|
from taiga.projects.models import Project, EpicStatus
|
||||||
|
@ -89,11 +90,48 @@ class EpicViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin,
|
||||||
if obj.status and obj.status.project != obj.project:
|
if obj.status and obj.status.project != obj.project:
|
||||||
raise exc.WrongArguments(_("You don't have permissions to set this status to this epic."))
|
raise exc.WrongArguments(_("You don't have permissions to set this status to this epic."))
|
||||||
|
|
||||||
|
"""
|
||||||
|
Updating the epic order attribute can affect the ordering of another epics
|
||||||
|
This method generate a key for the epic and can be used to be compared before and after
|
||||||
|
saving
|
||||||
|
If there is any difference it means an extra ordering update must be done
|
||||||
|
"""
|
||||||
|
def _epics_order_key(self, obj):
|
||||||
|
return "{}-{}".format(obj.project_id, obj.epics_order)
|
||||||
|
|
||||||
def pre_save(self, obj):
|
def pre_save(self, obj):
|
||||||
if not obj.id:
|
if not obj.id:
|
||||||
obj.owner = self.request.user
|
obj.owner = self.request.user
|
||||||
|
else:
|
||||||
|
self._old_epics_order_key = self._epics_order_key(self.get_object())
|
||||||
|
|
||||||
super().pre_save(obj)
|
super().pre_save(obj)
|
||||||
|
|
||||||
|
def _reorder_if_needed(self, obj, old_order_key, order_key, order_attr, project):
|
||||||
|
# Executes the extra ordering if there is a difference in the ordering keys
|
||||||
|
if old_order_key != order_key:
|
||||||
|
extra_orders = json.loads(self.request.META.get("HTTP_SET_ORDERS", "{}"))
|
||||||
|
data = [{"epic_id": obj.id, "order": getattr(obj, order_attr)}]
|
||||||
|
for id, order in extra_orders.items():
|
||||||
|
data.append({"epic_id": int(id), "order": order})
|
||||||
|
|
||||||
|
return services.update_epics_order_in_bulk(data,
|
||||||
|
field=order_attr,
|
||||||
|
project=project)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def post_save(self, obj, created=False):
|
||||||
|
if not created:
|
||||||
|
# Let's reorder the related stuff after edit the element
|
||||||
|
orders_updated = self._reorder_if_needed(obj,
|
||||||
|
self._old_epics_order_key,
|
||||||
|
self._epics_order_key(obj),
|
||||||
|
"epics_order",
|
||||||
|
obj.project)
|
||||||
|
self.headers["Taiga-Info-Order-Updated"] = json.dumps(orders_updated)
|
||||||
|
|
||||||
|
super().post_save(obj, created)
|
||||||
|
|
||||||
def update(self, request, *args, **kwargs):
|
def update(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object_or_none()
|
self.object = self.get_object_or_none()
|
||||||
project_id = request.DATA.get('project', None)
|
project_id = request.DATA.get('project', None)
|
||||||
|
@ -188,28 +226,6 @@ class EpicViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin,
|
||||||
|
|
||||||
return response.BadRequest(validator.errors)
|
return response.BadRequest(validator.errors)
|
||||||
|
|
||||||
def _bulk_update_order(self, order_field, request, **kwargs):
|
|
||||||
validator = validators.UpdateEpicsOrderBulkValidator(data=request.DATA)
|
|
||||||
if not validator.is_valid():
|
|
||||||
return response.BadRequest(validator.errors)
|
|
||||||
|
|
||||||
data = validator.data
|
|
||||||
project = get_object_or_404(Project, pk=data["project_id"])
|
|
||||||
|
|
||||||
self.check_permissions(request, "bulk_update_order", project)
|
|
||||||
if project.blocked_code is not None:
|
|
||||||
raise exc.Blocked(_("Blocked element"))
|
|
||||||
|
|
||||||
ret = services.update_epics_order_in_bulk(data["bulk_epics"],
|
|
||||||
project=project,
|
|
||||||
field=order_field)
|
|
||||||
|
|
||||||
return response.Ok(ret)
|
|
||||||
|
|
||||||
@list_route(methods=["POST"])
|
|
||||||
def bulk_update_epics_order(self, request, **kwargs):
|
|
||||||
return self._bulk_update_order("epics_order", request, **kwargs)
|
|
||||||
|
|
||||||
@detail_route(methods=["POST"])
|
@detail_route(methods=["POST"])
|
||||||
def bulk_create_related_userstories(self, request, **kwargs):
|
def bulk_create_related_userstories(self, request, **kwargs):
|
||||||
validator = validators.CrateRelatedUserStoriesBulkValidator(data=request.DATA)
|
validator = validators.CrateRelatedUserStoriesBulkValidator(data=request.DATA)
|
||||||
|
|
|
@ -34,7 +34,6 @@ class EpicPermission(TaigaResourcePermission):
|
||||||
filters_data_perms = AllowAny()
|
filters_data_perms = AllowAny()
|
||||||
csv_perms = AllowAny()
|
csv_perms = AllowAny()
|
||||||
bulk_create_perms = HasProjectPerm('add_epic')
|
bulk_create_perms = HasProjectPerm('add_epic')
|
||||||
bulk_update_order_perms = HasProjectPerm('modify_epic')
|
|
||||||
bulk_create_userstories_perms = HasProjectPerm('modify_epic') & (HasProjectPerm('add_us_to_project') | HasProjectPerm('add_us'))
|
bulk_create_userstories_perms = HasProjectPerm('modify_epic') & (HasProjectPerm('add_us_to_project') | HasProjectPerm('add_us'))
|
||||||
upvote_perms = IsAuthenticated() & HasProjectPerm('view_epics')
|
upvote_perms = IsAuthenticated() & HasProjectPerm('view_epics')
|
||||||
downvote_perms = IsAuthenticated() & HasProjectPerm('view_epics')
|
downvote_perms = IsAuthenticated() & HasProjectPerm('view_epics')
|
||||||
|
|
|
@ -58,15 +58,3 @@ class EpicsBulkValidator(ProjectExistsValidator, EpicExistsValidator,
|
||||||
class CrateRelatedUserStoriesBulkValidator(ProjectExistsValidator, EpicExistsValidator,
|
class CrateRelatedUserStoriesBulkValidator(ProjectExistsValidator, EpicExistsValidator,
|
||||||
validators.Validator):
|
validators.Validator):
|
||||||
userstories = serializers.CharField()
|
userstories = serializers.CharField()
|
||||||
|
|
||||||
|
|
||||||
# Order bulk validators
|
|
||||||
|
|
||||||
class _EpicOrderBulkValidator(EpicExistsValidator, validators.Validator):
|
|
||||||
epic_id = serializers.IntegerField()
|
|
||||||
order = serializers.IntegerField()
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateEpicsOrderBulkValidator(ProjectExistsValidator, validators.Validator):
|
|
||||||
project_id = serializers.IntegerField()
|
|
||||||
bulk_epics = _EpicOrderBulkValidator(many=True)
|
|
||||||
|
|
|
@ -68,6 +68,29 @@ def test_custom_fields_csv_generation():
|
||||||
assert row[17] == "val1"
|
assert row[17] == "val1"
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_epic_order(client):
|
||||||
|
user = f.UserFactory.create()
|
||||||
|
project = f.ProjectFactory.create(owner=user)
|
||||||
|
epic_1 = f.EpicFactory.create(project=project, epics_order=1, status=project.default_us_status)
|
||||||
|
epic_2 = f.EpicFactory.create(project=project, epics_order=2, status=project.default_us_status)
|
||||||
|
epic_3 = f.EpicFactory.create(project=project, epics_order=3, status=project.default_us_status)
|
||||||
|
f.MembershipFactory.create(project=project, user=user, is_admin=True)
|
||||||
|
|
||||||
|
url = reverse('epics-detail', kwargs={"pk": epic_1.pk})
|
||||||
|
data = {
|
||||||
|
"epics_order": 2,
|
||||||
|
"version": epic_1.version
|
||||||
|
}
|
||||||
|
|
||||||
|
client.login(user)
|
||||||
|
response = client.json.patch(url, json.dumps(data))
|
||||||
|
assert json.loads(response.get("taiga-info-order-updated")) == {
|
||||||
|
str(epic_1.id): 2,
|
||||||
|
str(epic_2.id): 3,
|
||||||
|
str(epic_3.id): 4
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_bulk_create_related_userstories(client):
|
def test_bulk_create_related_userstories(client):
|
||||||
user = f.UserFactory.create()
|
user = f.UserFactory.create()
|
||||||
project = f.ProjectFactory.create(owner=user)
|
project = f.ProjectFactory.create(owner=user)
|
||||||
|
@ -81,6 +104,5 @@ def test_bulk_create_related_userstories(client):
|
||||||
}
|
}
|
||||||
client.login(user)
|
client.login(user)
|
||||||
response = client.json.post(url, json.dumps(data))
|
response = client.json.post(url, json.dumps(data))
|
||||||
print(response.data)
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['user_stories_counts'] == {'opened': 2, 'closed': 0}
|
assert response.data['user_stories_counts'] == {'opened': 2, 'closed': 0}
|
||||||
|
|
Loading…
Reference in New Issue