浏览代码

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 年之前
父节点
当前提交
9173a45
共有 2 个文件被更改,包括 51 次插入11 次删除
  1. 24 0
      desktop/core/src/desktop/api_tests.py
  2. 27 11
      desktop/core/src/desktop/models.py

+ 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