Merge pull request #783 from taigaio/fixing-issue-when-multiple-attachment-deletion

Removing unnecesary advisory_lock
remotes/origin/issue/4795/notification_even_they_are_disabled
David Barragán Merino 2016-07-28 16:48:18 +02:00 committed by GitHub
commit 0064e6e82a
10 changed files with 69 additions and 60 deletions

View File

@ -18,6 +18,7 @@
from django_pglocks import advisory_lock from django_pglocks import advisory_lock
def detail_route(methods=['get'], **kwargs): def detail_route(methods=['get'], **kwargs):
""" """
Used to mark a method on a ViewSet that should be routed for detail requests. Used to mark a method on a ViewSet that should be routed for detail requests.
@ -51,12 +52,11 @@ def model_pk_lock(func):
""" """
def decorator(self, *args, **kwargs): def decorator(self, *args, **kwargs):
from taiga.base.utils.db import get_typename_for_model_class from taiga.base.utils.db import get_typename_for_model_class
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
pk = self.kwargs.get(self.pk_url_kwarg, None) pk = self.kwargs.get(self.pk_url_kwarg, None)
tn = get_typename_for_model_class(self.get_queryset().model) tn = get_typename_for_model_class(self.get_queryset().model)
key = "{0}:{1}".format(tn, pk) key = "{0}:{1}".format(tn, pk)
with advisory_lock(key) as acquired_key_lock: with advisory_lock(key):
return func(self, *args, **kwargs) return func(self, *args, **kwargs)
return decorator return decorator

View File

@ -26,6 +26,8 @@ from django.http import Http404
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.utils import timezone from django.utils import timezone
from django_pglocks import advisory_lock
from taiga.base import filters from taiga.base import filters
from taiga.base import exceptions as exc from taiga.base import exceptions as exc
from taiga.base import response from taiga.base import response
@ -214,20 +216,22 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin,
if not template_description: if not template_description:
raise response.BadRequest(_("Not valid template description")) raise response.BadRequest(_("Not valid template description"))
template_slug = slugify_uniquely(template_name, models.ProjectTemplate) with advisory_lock("create-project-template") as acquired_key_lock:
template_slug = slugify_uniquely(template_name, models.ProjectTemplate)
project = self.get_object() project = self.get_object()
self.check_permissions(request, 'create_template', project) self.check_permissions(request, 'create_template', project)
template = models.ProjectTemplate( template = models.ProjectTemplate(
name=template_name, name=template_name,
slug=template_slug, slug=template_slug,
description=template_description, description=template_description,
) )
template.load_data_from_project(project) template.load_data_from_project(project)
template.save()
template.save()
return response.Created(serializers.ProjectTemplateSerializer(template).data) return response.Created(serializers.ProjectTemplateSerializer(template).data)
@detail_route(methods=['POST']) @detail_route(methods=['POST'])

View File

@ -74,7 +74,7 @@ class BaseAttachmentViewSet(HistoryResourceMixin, WatchedResourceMixin,
# NOTE: When destroy an attachment, the content_object change # NOTE: When destroy an attachment, the content_object change
# after and not before # after and not before
self.persist_history_snapshot(obj, delete=True) self.persist_history_snapshot(obj, delete=True)
super().pre_delete(obj) super().post_delete(obj)
def get_object_for_snapshot(self, obj): def get_object_for_snapshot(self, obj):
return obj.content_object return obj.content_object

View File

@ -62,7 +62,7 @@ class HistoryResourceMixin(object):
obj = self.get_object() obj = self.get_object()
sobj = self.get_object_for_snapshot(obj) sobj = self.get_object_for_snapshot(obj)
if sobj != obj and delete: if sobj != obj:
delete = False delete = False
notifications_services.analize_object_for_watchers(obj, comment, user) notifications_services.analize_object_for_watchers(obj, comment, user)

View File

@ -312,7 +312,7 @@ def take_snapshot(obj: object, *, comment: str="", user=None, delete: bool=False
""" """
key = make_key_from_model_object(obj) key = make_key_from_model_object(obj)
with advisory_lock(key): with advisory_lock("history-"+key):
typename = get_typename_for_model_class(obj.__class__) typename = get_typename_for_model_class(obj.__class__)
new_fobj = freeze_model_instance(obj) new_fobj = freeze_model_instance(obj)

View File

@ -16,9 +16,8 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# 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.apps import apps
from django.db import models from django.db import models
from django.db.models import Prefetch, Count from django.db.models import Count
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone from django.utils import timezone
@ -28,7 +27,7 @@ from django.utils.functional import cached_property
from taiga.base.utils.slug import slugify_uniquely from taiga.base.utils.slug import slugify_uniquely
from taiga.base.utils.dicts import dict_sum from taiga.base.utils.dicts import dict_sum
from taiga.projects.notifications.mixins import WatchedModelMixin from taiga.projects.notifications.mixins import WatchedModelMixin
from taiga.projects.userstories.models import UserStory from django_pglocks import advisory_lock
import itertools import itertools
import datetime import datetime
@ -84,9 +83,11 @@ class Milestone(WatchedModelMixin, models.Model):
if not self._importing or not self.modified_date: if not self._importing or not self.modified_date:
self.modified_date = timezone.now() self.modified_date = timezone.now()
if not self.slug: if not self.slug:
self.slug = slugify_uniquely(self.name, self.__class__) with advisory_lock("milestone-creation-{}".format(self.project_id)):
self.slug = slugify_uniquely(self.name, self.__class__)
super().save(*args, **kwargs) super().save(*args, **kwargs)
else:
super().save(*args, **kwargs)
@cached_property @cached_property
def cached_user_stories(self): def cached_user_stories(self):

View File

@ -16,27 +16,23 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import itertools
import uuid
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.db.models import signals, Q from django.db.models import Q
from django.apps import apps from django.apps import apps
from django.conf import settings
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone from django.utils import timezone
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django_pglocks import advisory_lock
from django_pgjson.fields import JsonField from django_pgjson.fields import JsonField
from taiga.projects.tagging.models import TaggedMixin from taiga.projects.tagging.models import TaggedMixin
from taiga.projects.tagging.models import TagsColorsdMixin from taiga.projects.tagging.models import TagsColorsdMixin
from taiga.base.utils.dicts import dict_sum
from taiga.base.utils.files import get_file_path from taiga.base.utils.files import get_file_path
from taiga.base.utils.sequence import arithmetic_progression from taiga.base.utils.sequence import arithmetic_progression
from taiga.base.utils.slug import slugify_uniquely from taiga.base.utils.slug import slugify_uniquely
@ -270,16 +266,6 @@ class Project(ProjectDefaults, TaggedMixin, TagsColorsdMixin, models.Model):
if not self._importing or not self.modified_date: if not self._importing or not self.modified_date:
self.modified_date = timezone.now() self.modified_date = timezone.now()
if not self.slug:
base_name = "{}-{}".format(self.owner.username, self.name)
base_slug = slugify_uniquely(base_name, self.__class__)
slug = base_slug
for i in arithmetic_progression():
if not type(self).objects.filter(slug=slug).exists() or i > 100:
break
slug = "{}-{}".format(base_slug, i)
self.slug = slug
if not self.is_backlog_activated: if not self.is_backlog_activated:
self.total_milestones = None self.total_milestones = None
self.total_story_points = None self.total_story_points = None
@ -290,13 +276,25 @@ class Project(ProjectDefaults, TaggedMixin, TagsColorsdMixin, models.Model):
if not self.is_looking_for_people: if not self.is_looking_for_people:
self.looking_for_people_note = "" self.looking_for_people_note = ""
if self.anon_permissions == None: if self.anon_permissions is None:
self.anon_permissions = [] self.anon_permissions = []
if self.public_permissions == None: if self.public_permissions is None:
self.public_permissions = [] self.public_permissions = []
super().save(*args, **kwargs) if not self.slug:
with advisory_lock("project-creation"):
base_name = "{}-{}".format(self.owner.username, self.name)
base_slug = slugify_uniquely(base_name, self.__class__)
slug = base_slug
for i in arithmetic_progression():
if not type(self).objects.filter(slug=slug).exists() or i > 100:
break
slug = "{}-{}".format(base_slug, i)
self.slug = slug
super().save(*args, **kwargs)
else:
super().save(*args, **kwargs)
def refresh_totals(self, save=True): def refresh_totals(self, save=True):
now = timezone.now() now = timezone.now()

View File

@ -59,7 +59,7 @@ def update_role_points_when_create_or_edit_us(sender, instance, **kwargs):
def update_milestone_of_tasks_when_edit_us(sender, instance, created, **kwargs): def update_milestone_of_tasks_when_edit_us(sender, instance, created, **kwargs):
if not created: if not created:
instance.tasks.update(milestone=instance.milestone) instance.tasks.exclude(milestone=instance.milestone).update(milestone=instance.milestone)
for task in instance.tasks.all(): for task in instance.tasks.all():
take_snapshot(task) take_snapshot(task)

View File

@ -21,6 +21,8 @@ from django.contrib.contenttypes.fields import GenericRelation
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone from django.utils import timezone
from django_pglocks import advisory_lock
from taiga.base.utils.slug import slugify_uniquely_for_queryset from taiga.base.utils.slug import slugify_uniquely_for_queryset
from taiga.projects.notifications.mixins import WatchedModelMixin from taiga.projects.notifications.mixins import WatchedModelMixin
from taiga.projects.occ import OCCModelMixin from taiga.projects.occ import OCCModelMixin
@ -84,7 +86,9 @@ class WikiLink(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.href: if not self.href:
wl_qs = self.project.wiki_links.all() with advisory_lock("wiki-page-creation-{}".format(self.project_id)):
self.href = slugify_uniquely_for_queryset(self.title, wl_qs, slugfield="href") wl_qs = self.project.wiki_links.all()
self.href = slugify_uniquely_for_queryset(self.title, wl_qs, slugfield="href")
super().save(*args, **kwargs) super().save(*args, **kwargs)
else:
super().save(*args, **kwargs)

View File

@ -35,6 +35,7 @@ from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_pgjson.fields import JsonField from django_pgjson.fields import JsonField
from django_pglocks import advisory_lock
from taiga.auth.tokens import get_token_for_user from taiga.auth.tokens import get_token_for_user
from taiga.base.utils.slug import slugify_uniquely from taiga.base.utils.slug import slugify_uniquely
@ -265,20 +266,21 @@ class User(AbstractBaseUser, PermissionsMixin):
super().save(*args, **kwargs) super().save(*args, **kwargs)
def cancel(self): def cancel(self):
self.username = slugify_uniquely("deleted-user", User, slugfield="username") with advisory_lock("delete-user"):
self.email = "{}@taiga.io".format(self.username) self.username = slugify_uniquely("deleted-user", User, slugfield="username")
self.is_active = False self.email = "{}@taiga.io".format(self.username)
self.full_name = "Deleted user" self.is_active = False
self.color = "" self.full_name = "Deleted user"
self.bio = "" self.color = ""
self.lang = "" self.bio = ""
self.theme = "" self.lang = ""
self.timezone = "" self.theme = ""
self.colorize_tags = True self.timezone = ""
self.token = None self.colorize_tags = True
self.set_unusable_password() self.token = None
self.photo = None self.set_unusable_password()
self.save() self.photo = None
self.save()
self.auth_data.all().delete() self.auth_data.all().delete()
# Blocking all owned projects # Blocking all owned projects