diff --git a/taiga/projects/api.py b/taiga/projects/api.py index 5284f44e..a3ca3445 100644 --- a/taiga/projects/api.py +++ b/taiga/projects/api.py @@ -474,6 +474,11 @@ class EpicStatusViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, move_on_destroy_related_field = "status" move_on_destroy_project_default_field = "default_epic_status" + def create(self, request, *args, **kwargs): + project_id = request.DATA.get("project", 0) + with advisory_lock("epic-status-creation-{}".format(project_id)): + return super().create(request, *args, **kwargs) + class UserStoryStatusViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, ModelCrudViewSet, BulkUpdateOrderMixin): @@ -491,6 +496,11 @@ class UserStoryStatusViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, move_on_destroy_related_field = "status" move_on_destroy_project_default_field = "default_us_status" + def create(self, request, *args, **kwargs): + project_id = request.DATA.get("project", 0) + with advisory_lock("epic-user-story-status-creation-{}".format(project_id)): + return super().create(request, *args, **kwargs) + class PointsViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, ModelCrudViewSet, BulkUpdateOrderMixin): @@ -508,6 +518,11 @@ class PointsViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, move_on_destroy_related_field = "points" move_on_destroy_project_default_field = "default_points" + def create(self, request, *args, **kwargs): + project_id = request.DATA.get("project", 0) + with advisory_lock("points-creation-{}".format(project_id)): + return super().create(request, *args, **kwargs) + class TaskStatusViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, ModelCrudViewSet, BulkUpdateOrderMixin): @@ -525,6 +540,11 @@ class TaskStatusViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, move_on_destroy_related_field = "status" move_on_destroy_project_default_field = "default_task_status" + def create(self, request, *args, **kwargs): + project_id = request.DATA.get("project", 0) + with advisory_lock("task-status-creation-{}".format(project_id)): + return super().create(request, *args, **kwargs) + class SeverityViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, ModelCrudViewSet, BulkUpdateOrderMixin): @@ -542,6 +562,11 @@ class SeverityViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, move_on_destroy_related_field = "severity" move_on_destroy_project_default_field = "default_severity" + def create(self, request, *args, **kwargs): + project_id = request.DATA.get("project", 0) + with advisory_lock("severity-creation-{}".format(project_id)): + return super().create(request, *args, **kwargs) + class PriorityViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, ModelCrudViewSet, BulkUpdateOrderMixin): @@ -558,6 +583,11 @@ class PriorityViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, move_on_destroy_related_field = "priority" move_on_destroy_project_default_field = "default_priority" + def create(self, request, *args, **kwargs): + project_id = request.DATA.get("project", 0) + with advisory_lock("priority-creation-{}".format(project_id)): + return super().create(request, *args, **kwargs) + class IssueTypeViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, ModelCrudViewSet, BulkUpdateOrderMixin): @@ -574,6 +604,11 @@ class IssueTypeViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, move_on_destroy_related_field = "type" move_on_destroy_project_default_field = "default_issue_type" + def create(self, request, *args, **kwargs): + project_id = request.DATA.get("project", 0) + with advisory_lock("issue-type-creation-{}".format(project_id)): + return super().create(request, *args, **kwargs) + class IssueStatusViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, ModelCrudViewSet, BulkUpdateOrderMixin): @@ -590,6 +625,12 @@ class IssueStatusViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, move_on_destroy_related_field = "status" move_on_destroy_project_default_field = "default_issue_status" + def create(self, request, *args, **kwargs): + project_id = request.DATA.get("project", 0) + with advisory_lock("issue-status-creation-{}".format(project_id)): + return super().create(request, *args, **kwargs) + + ###################################################### ## Project Template diff --git a/taiga/projects/milestones/api.py b/taiga/projects/milestones/api.py index 2e0047fc..820e90c7 100644 --- a/taiga/projects/milestones/api.py +++ b/taiga/projects/milestones/api.py @@ -37,6 +37,7 @@ from . import models from . import permissions from . import utils as milestones_utils +from django_pglocks import advisory_lock import datetime @@ -53,6 +54,11 @@ class MilestoneViewSet(HistoryResourceMixin, WatchedResourceMixin, ) queryset = models.Milestone.objects.all() + def create(self, request, *args, **kwargs): + project_id = request.DATA.get("project", 0) + with advisory_lock("milestone-creation-{}".format(project_id)): + return super().create(request, *args, **kwargs) + def list(self, request, *args, **kwargs): res = super().list(request, *args, **kwargs) self._add_taiga_info_headers() diff --git a/taiga/projects/milestones/models.py b/taiga/projects/milestones/models.py index ef58437d..86eb3251 100644 --- a/taiga/projects/milestones/models.py +++ b/taiga/projects/milestones/models.py @@ -27,7 +27,6 @@ from django.utils.functional import cached_property from taiga.base.utils.slug import slugify_uniquely from taiga.base.utils.dicts import dict_sum from taiga.projects.notifications.mixins import WatchedModelMixin -from django_pglocks import advisory_lock import itertools import datetime @@ -83,11 +82,8 @@ class Milestone(WatchedModelMixin, models.Model): if not self._importing or not self.modified_date: self.modified_date = timezone.now() if not self.slug: - with advisory_lock("milestone-creation-{}".format(self.project_id)): - self.slug = slugify_uniquely(self.name, self.__class__) - super().save(*args, **kwargs) - else: - super().save(*args, **kwargs) + self.slug = slugify_uniquely(self.name, self.__class__) + super().save(*args, **kwargs) @cached_property def cached_user_stories(self):