Przeglądaj źródła

HUE-5482 [home] Handle multiple home/trash directories by merging them into one.

During deletion or executing queries, when we hit MultipleObjectsReturned exception,
this fix will merge all the duplicate directories into one.
krish 9 lat temu
rodzic
commit
4e62dc8d5a

+ 23 - 2
desktop/core/src/desktop/models.py

@@ -965,6 +965,16 @@ class Document2Manager(models.Manager, Document2QueryMixin):
       return self.get(owner=user, parent_directory=None, name=Document2.HOME_DIR, type='directory')
       return self.get(owner=user, parent_directory=None, name=Document2.HOME_DIR, type='directory')
     except Document2.DoesNotExist:
     except Document2.DoesNotExist:
       return self.create_user_directories(user)
       return self.create_user_directories(user)
+    except Document2.MultipleObjectsReturned:
+      LOG.error('Multiple Home directories detected. Merging all into one.')
+
+      home_dirs = list(self.filter(owner=user, parent_directory=None, name=Document2.HOME_DIR, type='directory').order_by('-last_modified'))
+      parent_home_dir = home_dirs.pop()
+      for dir in home_dirs:
+        dir.children.exclude(name='.Trash').update(parent_directory=parent_home_dir)
+        dir.delete()
+
+      return parent_home_dir
 
 
   def get_by_path(self, user, path):
   def get_by_path(self, user, path):
     """
     """
@@ -1222,8 +1232,19 @@ class Document2(models.Model):
     return self
     return self
 
 
   def trash(self):
   def trash(self):
-    trash_dir = Directory.objects.get(name=self.TRASH_DIR, owner=self.owner)
-    self.move(trash_dir, self.owner)
+    try:
+      trash_dir = Directory.objects.get(name=self.TRASH_DIR, owner=self.owner)
+      self.move(trash_dir, self.owner)
+    except Document2.MultipleObjectsReturned:
+      LOG.error('Multiple Trash directories detected. Merging all into one.')
+
+      trash_dirs = list(Directory.objects.filter(name=self.TRASH_DIR, owner=self.owner).order_by('-last_modified'))
+      parent_trash_dir = trash_dirs.pop()
+      for dir in trash_dirs:
+        dir.children.update(parent_directory=parent_trash_dir)
+        dir.delete()
+
+      self.move(parent_trash_dir, self.owner)
 
 
   # TODO: restore
   # TODO: restore
 
 

+ 63 - 0
desktop/core/src/desktop/tests.py

@@ -918,6 +918,69 @@ class TestDocument(object):
     test_doc.delete()
     test_doc.delete()
     test_dir.delete()
     test_dir.delete()
 
 
+  def test_multiple_home_directories(self):
+    home_dir = Directory.objects.get_home_directory(self.user)
+    test_doc1 = Document2.objects.create(name='test-doc1',
+                                         type='query-hive',
+                                         owner=self.user,
+                                         description='',
+                                         parent_directory=home_dir)
+
+    assert_equal(home_dir.children.count(), 3)
+
+    # Cannot create second home directory directly as it will fail in Document2.validate()
+    second_home_dir = Document2.objects.create(owner=self.user, parent_directory=None, name='second_home_dir', type='directory')
+    Document2.objects.filter(name='second_home_dir').update(name=Document2.HOME_DIR, parent_directory=None)
+    assert_equal(Document2.objects.filter(owner=self.user, name=Document2.HOME_DIR).count(), 2)
+
+    test_doc2 = Document2.objects.create(name='test-doc2',
+                                              type='query-hive',
+                                              owner=self.user,
+                                              description='',
+                                              parent_directory=second_home_dir)
+    assert_equal(second_home_dir.children.count(), 1)
+
+    merged_home_dir = Directory.objects.get_home_directory(self.user)
+    children = merged_home_dir.children.all().order_by('-last_modified')
+    assert_equal(children.count(), 4)
+    assert_equal(test_doc2.name, children[0].name)
+    assert_equal(test_doc1.name, children[1].name)
+
+  def test_multiple_trash_directories(self):
+    home_dir = Directory.objects.get_home_directory(self.user)
+    test_doc1 = Document2.objects.create(name='test-doc1',
+                                         type='query-hive',
+                                         owner=self.user,
+                                         description='',
+                                         parent_directory=home_dir)
+
+    assert_equal(home_dir.children.count(), 3)
+
+    # Cannot create second trash directory directly as it will fail in Document2.validate()
+    Document2.objects.create(owner=self.user, parent_directory=home_dir, name='second_trash_dir', type='directory')
+    Document2.objects.filter(name='second_trash_dir').update(name=Document2.TRASH_DIR)
+    assert_equal(Document2.objects.filter(owner=self.user, name=Document2.TRASH_DIR).count(), 2)
+
+
+    test_doc2 = Document2.objects.create(name='test-doc2',
+                                              type='query-hive',
+                                              owner=self.user,
+                                              description='',
+                                              parent_directory=home_dir)
+    assert_equal(home_dir.children.count(), 5) # Including the second trash
+    assert_raises(Document2.MultipleObjectsReturned, Document2.objects.get, name=Document2.TRASH_DIR)
+
+    test_doc1.trash()
+    assert_equal(home_dir.children.count(), 3) # As trash documents are merged count is back to 3
+    merged_trash_dir = Document2.objects.get(name=Document2.TRASH_DIR)
+
+    test_doc2.trash()
+    children = merged_trash_dir.children.all().order_by('-last_modified')
+    assert_equal(children.count(), 2)
+    assert_equal(test_doc2.name, children[0].name)
+    assert_equal(test_doc1.name, children[1].name)
+
+
   def test_document_copy(self):
   def test_document_copy(self):
     name = 'Test Document2 Copy'
     name = 'Test Document2 Copy'