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

HUE-2827 [oozie] Workflows cannot be copied in the editor

Created copy functions for Document and Document2 and consolidated places where we are copying objects (Oozie, Pig, Spark Notebooks, etc). Added tests to verify that copying Doc2 and Doc1 creates corresponding new copies of both objects.
Jenny Kim 10 жил өмнө
parent
commit
d99a931

+ 1 - 5
apps/beeswax/src/beeswax/views.py

@@ -188,11 +188,7 @@ def clone_design(request, design_id):
   copy = design.clone(request.user)
   copy.save()
 
-  copy_doc = Document.objects.link(copy,
-      owner=copy.owner,
-      name=copy.name,
-      description=copy.desc,
-      extra=copy.type)
+  design.doc.get().copy(content_object=copy)
 
   messages.info(request, _('Copied design: %(name)s') % {'name': design.name})
 

+ 9 - 32
apps/oozie/src/oozie/views/editor2.py

@@ -17,7 +17,6 @@
 
 import json
 import logging
-import uuid
 
 from django.core.urlresolvers import reverse
 from django.forms.formsets import formset_factory
@@ -151,20 +150,12 @@ def copy_workflow(request):
 
   for job in jobs:
     doc2 = Document2.objects.get(type='oozie-workflow2', id=job['id'])
+    doc = doc2.doc.get()
 
     name = doc2.name + '-copy'
-    copy_doc = doc2.doc.get().copy(name=name, owner=request.user)
+    doc2 = doc2.copy(name=name, owner=request.user)
 
-    doc2.pk = None
-    doc2.id = None
-    doc2.uuid = str(uuid.uuid4())
-    doc2.name = name
-    doc2.owner = request.user
-    doc2.save()
-
-    doc2.doc.all().delete()
-    doc2.doc.add(copy_doc)
-    doc2.save()
+    doc.copy(content_object=doc2, name=name)
 
     workflow = Workflow(document=doc2)
     workflow.update_name(name)
@@ -461,19 +452,12 @@ def copy_coordinator(request):
 
   for job in jobs:
     doc2 = Document2.objects.get(type='oozie-coordinator2', id=job['id'])
+    doc = doc2.doc.get()
 
     name = doc2.name + '-copy'
-    copy_doc = doc2.doc.get().copy(name=name, owner=request.user)
+    doc2 = doc2.copy(name=name, owner=request.user)
 
-    doc2.pk = None
-    doc2.id = None
-    doc2.uuid = str(uuid.uuid4())
-    doc2.name = name
-    doc2.owner = request.user
-    doc2.save()
-
-    doc2.doc.all().delete()
-    doc2.doc.add(copy_doc)
+    doc.copy(content_object=doc2, name=name)
 
     coordinator_data = Coordinator(document=doc2).get_data_for_json()
     coordinator_data['name'] = name
@@ -681,19 +665,12 @@ def copy_bundle(request):
 
   for job in jobs:
     doc2 = Document2.objects.get(type='oozie-bundle2', id=job['id'])
+    doc = doc2.doc.get()
 
     name = doc2.name + '-copy'
-    copy_doc = doc2.doc.get().copy(name=name, owner=request.user)
-
-    doc2.pk = None
-    doc2.id = None
-    doc2.uuid = str(uuid.uuid4())
-    doc2.name = name
-    doc2.owner = request.user
-    doc2.save()
+    doc2 = doc2.copy(name=name, owner=request.user)
 
-    doc2.doc.all().delete()
-    doc2.doc.add(copy_doc)
+    doc.copy(content_object=doc2, name=name)
 
     bundle_data = Bundle(document=doc2).get_data_for_json()
     bundle_data['name'] = name

+ 3 - 4
apps/pig/src/pig/views.py

@@ -148,7 +148,8 @@ def copy(request):
     raise PopupException(_('POST request required.'))
 
   pig_script = PigScript.objects.get(id=request.POST.get('id'))
-  pig_script.doc.get().can_edit_or_exception(request.user)
+  doc = pig_script.doc.get()
+  doc.can_edit_or_exception(request.user)
 
   existing_script_data = pig_script.dict
 
@@ -169,9 +170,7 @@ def copy(request):
   })
   script_copy.save()
 
-  copy_doc = Document.objects.link(script_copy,
-      owner=copy.owner,
-      name=copy.name)
+  copy_doc = doc.copy(content_object=script_copy, name=name, owner=owner)
 
   response = {
     'id': script_copy.id,

+ 8 - 14
apps/search/src/search/search_controller.py

@@ -85,24 +85,18 @@ class SearchController(object):
     try:
       for doc2 in self.get_shared_search_collections():
         if doc2.id in collection_ids:
-          name = doc2.name + '-copy'
+          doc2 = Document2.objects.get(uuid=notebook['uuid'])
+          doc = doc2.doc.get()
 
-          doc2.pk = None
-          doc2.id = None
-          doc2.uuid = str(uuid.uuid4())
-          doc2.name = name
-          doc2.owner = self.user
-          doc2.save()
+          name = doc2.name + '-copy'
+          doc2 = doc2.copy(name=name, owner=request.user)
 
-          copy_doc = Document.objects.link(doc2,
-              owner=copy.owner,
-              name=copy.name,
-              description=copy.description)
+          doc.copy(content_object=doc2, name=name)
 
-          copy = Collection2(self.user, document=doc2)
-          copy.data['collection']['label'] = name
+          collection = Collection2(self.user, document=doc2)
+          collection.data['collection']['label'] = name
 
-          doc2.update_data({'collection': copy.data['collection']})
+          doc2.update_data({'collection': collection.data['collection']})
           doc2.save()
       result['status'] = 0
     except Exception, e:

+ 4 - 9
apps/spark/src/spark/views.py

@@ -100,17 +100,12 @@ def copy(request):
 
   for notebook in notebooks:
     doc2 = Document2.objects.get(uuid=notebook['uuid'])
+    doc = doc2.doc.get()
 
-    doc2.pk = None
-    doc2.id = None
-    doc2.uuid = str(uuid.uuid4())
-    doc2.owner = request.user
-    doc2.save()
+    name = doc2.name + '-copy'
+    doc2 = doc2.copy(name=name, owner=request.user)
 
-    copy_doc = Document.objects.link(doc2,
-        owner=copy.owner,
-        name=copy.name,
-        description=copy.description)
+    doc.copy(content_object=doc2, name=name)
 
   return JsonResponse({})
 

+ 40 - 0
desktop/core/src/desktop/models.py

@@ -521,6 +521,32 @@ class Document(models.Model):
     else:
       raise exception_class(_("Document does not exist or you don't have the permission to access it."))
 
+  def copy(self, content_object, **kwargs):
+    if content_object:
+      copy_doc = self
+
+      for k, v in kwargs.iteritems():
+        if hasattr(copy_doc, k):
+          setattr(copy_doc, k, v)
+
+      copy_doc.pk = None
+      copy_doc.id = None
+
+      copy_doc = Document.objects.link(content_object,
+                                       owner=copy_doc.owner,
+                                       name=copy_doc.name,
+                                       description=copy_doc.description,
+                                       extra=copy_doc.extra)
+
+      # Update reverse Document relation to new copy
+      if content_object.doc.get():
+        content_object.doc.get().delete()
+      content_object.doc.add(copy_doc)
+
+      return copy_doc
+    else:
+      raise PopupException(_("Document copy method requires a content_object argument."))
+
   @property
   def icon(self):
     apps = appmanager.get_apps_dict()
@@ -730,6 +756,20 @@ class Document2(models.Model):
 
     return data_python
 
+  def copy(self, **kwargs):
+    copy_doc = self
+
+    for k, v in kwargs.iteritems():
+      if hasattr(copy_doc, k):
+        setattr(copy_doc, k, v)
+
+    copy_doc.pk = None
+    copy_doc.id = None
+    copy_doc.uuid = str(uuid.uuid4())
+    copy_doc.save()
+
+    return copy_doc
+
   def update_data(self, post_data):
     data_dict = self.data_dict
 

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

@@ -49,7 +49,7 @@ from desktop.lib.conf import validate_path
 from desktop.lib.django_util import TruncatingModel
 from desktop.lib.exceptions_renderable import PopupException
 from desktop.lib.test_utils import grant_access
-from desktop.models import Document
+from desktop.models import Document, Document2
 from desktop.views import check_config, home
 from pig.models import PigScript
 
@@ -127,7 +127,6 @@ def test_home():
   assert_equal([], tags['trash']['docs'], tags)
   assert_equal([], tags['history']['docs'], tags) # We currently don't fetch [doc.id]
 
-
 def test_skip_wizard():
   c = make_logged_in_client() # is_superuser
 
@@ -855,3 +854,65 @@ class TestSMTPPasswordConfig(BaseTestPasswordConfig):
 
   def test_password_script_raises_exception(self):
     self.run_test_password_script_raises_exception()
+
+
+class TestDocument(object):
+
+  def setUp(self):
+    make_logged_in_client(username="test_doc", groupname="test_doc", recreate=True, is_superuser=False)
+    user = User.objects.get(username="test_doc")
+
+    # Get count of existing Document objects
+    self.doc2_count = Document2.objects.count()
+    self.doc1_count = Document.objects.count()
+
+    self.document2 = Document2.objects.create(name='Test Document2',
+                                              type='search-dashboard',
+                                              owner=user,
+                                              description='Test Document2')
+    self.document = Document.objects.link(content_object=self.document2,
+                                          owner=user,
+                                          name='Test Document',
+                                          description='Test Document',
+                                          extra='test')
+    self.document.save()
+    self.document2.doc.add(self.document)
+
+  def tearDown(self):
+    # Get any Doc2 objects that were created and delete them, Doc1 child objects will be deleted in turn
+    test_docs = Document2.objects.filter(name__contains='Test Document2')
+    test_docs.delete()
+
+  def test_document_create(self):
+    assert_equal(Document2.objects.count(), self.doc2_count + 1)
+    assert_equal(Document.objects.count(), self.doc1_count + 1)
+    assert_equal(Document2.objects.get(name='Test Document2').id, self.document2.id)
+    assert_equal(Document.objects.get(name='Test Document').id, self.document.id)
+
+  def test_document_copy(self):
+    name = 'Test Document2 Copy'
+    doc2 = self.document2.copy(name=name)
+
+    # Test that copying a Document2 object creates another object
+    assert_equal(Document2.objects.count(), self.doc2_count + 2)
+    assert_equal(Document.objects.count(), self.doc1_count + 1)
+
+    # Test that the content object is not pointing to the same object
+    assert_not_equal(self.document2.doc, doc2.doc)
+
+    # Test that copying enables attribute overrides
+    assert_equal(Document2.objects.filter(name=name).count(), 1)
+    assert_equal(doc2.description, self.document2.description)
+
+    doc = self.document.copy(doc2, name=name)
+
+    # Test that copying a Document object creates another Document2 and Document object
+    assert_equal(Document2.objects.count(), self.doc2_count + 2)
+    assert_equal(Document.objects.count(), self.doc1_count + 2)
+
+    # Test that the content object is not pointing to the same object
+    assert_not_equal(self.document.content_object, doc.content_object)
+
+    # Test that copying enables attribute overrides
+    assert_equal(Document.objects.filter(name=name).count(), 1)
+    assert_equal(doc.description, self.document.description)