Эх сурвалжийг харах

HUE-1915 [core] MultipleObjectsReturned for tags or permissions

Only a strict unique clause in a DB could prevent duplicate tags or permissions
to be created. We clean them up at access time instead of filing as it is safe
to delete the duplicates.

Strick DB that fails when installing the Hue example should click on each individual
example install insteaf of the install all button.
Romain Rigaux 12 жил өмнө
parent
commit
9173a45

+ 24 - 0
desktop/core/src/desktop/api_tests.py

@@ -63,6 +63,30 @@ class TestDocModelTags():
 
     assert_true(DocumentTag.objects.filter(id=tag_id, owner=self.user, tag='my_tag').exists())
 
+  def test_add_duplicate_tag(self):
+    tag_name = 'test_add_duplicate_tag'
+    n = DocumentTag.objects.filter(owner=self.user, tag=tag_name).count()
+
+    tag_id = self.add_tag(tag_name)
+    assert_equal(n + 1, DocumentTag.objects.filter(owner=self.user, tag=tag_name).count())
+
+    tag_id = self.add_tag(tag_name)
+    assert_equal(n + 1, DocumentTag.objects.filter(owner=self.user, tag=tag_name).count())
+
+  def test_add_and_clean_duplicate_tag(self):
+    tag_name = 'test_add_and_clean_duplicate_tag'
+    script, doc = self.add_doc('test-pig')
+    n = DocumentTag.objects.filter(owner=self.user, tag=tag_name).count()
+
+    tag_id = self.add_tag(tag_name)
+    assert_equal(n + 1, DocumentTag.objects.filter(owner=self.user, tag=tag_name).count())
+
+    DocumentTag.objects.create(owner=self.user, tag=tag_name)
+    assert_equal(n + 2, DocumentTag.objects.filter(owner=self.user, tag=tag_name).count())
+
+    tag_id = DocumentTag.objects.tag(self.user, doc.id, tag_name=tag_name)
+    assert_equal(n + 1, DocumentTag.objects.filter(owner=self.user, tag=tag_name).count())
+
   def test_remove_tags(self):
     response = self.client.post("/desktop/api/tag/add_tag", {'name': 'my_tag'})
     tag_id = json.loads(response.content)['tag_id']

+ 27 - 11
desktop/core/src/desktop/models.py

@@ -77,21 +77,29 @@ class DocumentTagManager(models.Manager):
       tag, created = DocumentTag.objects.get_or_create(tag=tag_name, owner=owner)
       return tag
 
-  def get_default_tag(self, user):
-    tag, created = DocumentTag.objects.get_or_create(owner=user, tag=DocumentTag.DEFAULT)
+  def _get_tag(self, user, name):
+    try:
+      tag, created = DocumentTag.objects.get_or_create(owner=user, tag=name)
+    except DocumentTag.MultipleObjectsReturned, ex:
+      # We can delete duplicate tags of a user
+      dups = DocumentTag.objects.filter(owner=user, tag=name)
+      tag = dups[0]
+      for dup in dups[1:]:
+        LOG.warn('Deleting duplicate %s' % dup)
+        dup.delete()
     return tag
 
+  def get_default_tag(self, user):
+    return self._get_tag(user, DocumentTag.DEFAULT)
+
   def get_trash_tag(self, user):
-    tag, created = DocumentTag.objects.get_or_create(owner=user, tag=DocumentTag.TRASH)
-    return tag
+    return self._get_tag(user, DocumentTag.TRASH)
 
   def get_history_tag(self, user):
-    tag, created = DocumentTag.objects.get_or_create(owner=user, tag=DocumentTag.HISTORY)
-    return tag
+    return self._get_tag(user, DocumentTag.HISTORY)
 
   def get_example_tag(self, user):
-    tag, created = DocumentTag.objects.get_or_create(owner=user, tag=DocumentTag.EXAMPLE)
-    return tag
+    return self._get_tag(user, DocumentTag.EXAMPLE)
 
   def tag(self, owner, doc_id, tag_name='', tag_id=None):
     try:
@@ -99,7 +107,7 @@ class DocumentTagManager(models.Manager):
       if tag.tag in DocumentTag.RESERVED:
         raise Exception(_("Can't add %s: it is a reserved tag.") % tag)
     except DocumentTag.DoesNotExist:
-      tag = DocumentTag.objects.create(tag=tag_name, owner=owner)
+      tag = self._get_tag(user=owner, name=tag_name)
 
     doc = Document.objects.get_doc(doc_id, owner)
     doc.add_tag(tag)
@@ -532,7 +540,15 @@ class DocumentPermissionManager(models.Manager):
       perm.delete()
 
   def list(self, document):
-    perm, created = DocumentPermission.objects.get_or_create(doc=document, perms=DocumentPermission.READ_PERM)
+    try:
+      perm, created = DocumentPermission.objects.get_or_create(doc=document, perms=DocumentPermission.READ_PERM)
+    except DocumentPermission.MultipleObjectsReturned, ex:
+      # We can delete duplicate perms of a document
+      dups = DocumentPermission.objects.filter(doc=document, perms=DocumentPermission.READ_PERM)
+      perm = dups[0]
+      for dup in dups[1:]:
+        LOG.warn('Deleting duplicate %s' % dup)
+        dup.delete()
     return perm
 
 
@@ -547,7 +563,7 @@ class DocumentPermission(models.Model):
 
 
   objects = DocumentPermissionManager()
-  #unique_together = ('doc', 'perms')
+  unique_together = ('doc', 'perms')
 
 
 # HistoryTable