From 7e810d5ad105e8d4688e108f0a8be1fe8d3dc4a3 Mon Sep 17 00:00:00 2001
From: Vincent Pelletier <vincent@nexedi.com>
Date: Tue, 20 Feb 2018 17:06:46 +0900
Subject: [PATCH] CopySupport: Factorise clipboard-related methods and code
 paths.

Two almost identical methods, each having two 75% identical code
paths: this screamed "factorisation".
---
 product/ERP5Type/CopySupport.py | 236 ++++++++++++--------------------
 1 file changed, 91 insertions(+), 145 deletions(-)

diff --git a/product/ERP5Type/CopySupport.py b/product/ERP5Type/CopySupport.py
index 41a8cc05d4..1a1a18c0c7 100644
--- a/product/ERP5Type/CopySupport.py
+++ b/product/ERP5Type/CopySupport.py
@@ -423,68 +423,87 @@ class CopyContainer:
                                          new_id=self.id)
 
   def _duplicate(self, cp):
-    try:    cp = _cb_decode(cp)
-    except: raise CopyError, 'Clipboard Error'
+    _, result = self.__duplicate(
+      cp,
+      duplicate=True,
+      is_indexable=True,
+    )
+    return result
 
-    oblist=[]
-    op=cp[0]
+  def __duplicate(self, cp, duplicate, is_indexable):
+    try:
+      cp = _cb_decode(cp)
+    except:
+      raise CopyError(eInvalid)
+    oblist = []
+    op = cp[0]
     app = self.getPhysicalRoot()
-    result = []
-
     for mdata in cp[1]:
       m = Moniker.loadMoniker(mdata)
-      try: ob = m.bind(app)
-      except: raise CopyError, 'Not Found'
-      self._verifyObjectPaste(ob, validate_src=1)
+      try:
+        ob = m.bind(app)
+      except:
+        raise CopyError(eNotFound)
+      self._verifyObjectPaste(ob, validate_src=op + 1)
       oblist.append(ob)
-
-    if op==0:
-      for ob in oblist:
-        if not ob.cb_isCopyable():
-            raise CopyError, 'Not Supported'
-        try:    ob._notifyOfCopyTo(self, op=0)
-        except: raise CopyError, 'Copy Error'
-        ob = ob._getCopy(self)
-        orig_id = ob.getId()
-        id = self._get_id(ob.getId())
-        result.append({'id':orig_id, 'new_id':id})
-        ob._setId(id)
-        self._setObject(id, ob)
-        ob = self._getOb(id)
-        ob._postCopy(self, op=0)
-        ob._postDuplicate()
-        ob.wl_clearLocks()
-
-    if op==1:
-      # Move operation
-      for ob in oblist:
-        id = ob.getId()
-        if not ob.cb_isMoveable():
-          raise CopyError, 'Not Supported'
-        try:    ob._notifyOfCopyTo(self, op=1)
-        except: raise CopyError, 'Move Error'
-        if not sanity_check(self, ob):
-          raise CopyError, 'This object cannot be pasted into itself'
-
+    result = []
+    def doMove(self, ob):
+      aq_parent(aq_inner(ob))._delObject(ob.getId())
+      return aq_base(ob)
+    is_doable_id, notify_error, do_sanity_check, do, set_owner, is_clone = (
+      ( # 0: Copy
+        'cb_isCopyable',
+        'Copy Error',
+        lambda self, ob: True,
+        lambda self, ob: ob._getCopy(self),
+        1, # Take ownership.
+        True,
+      ),
+      ( # 1: Move
+        'cb_isMoveable',
+        'Move Error',
+        sanity_check,
+        doMove,
+        0, # Retain original ownership.
+        False,
+      ),
+    )[op]
+    for ob in oblist:
+      if not getattr(ob, is_doable_id)():
+        raise CopyError(eNotSupported % escape(ob.getId()))
+      try:
+        ob._notifyOfCopyTo(self, op=op)
+      except:
+        raise CopyError(MessageDialog(
+          title=notify_error,
+          message=sys.exc_info()[1],
+          action='manage_main',
+        ))
+      if not do_sanity_check(self, ob):
+        raise CopyError('This object cannot be pasted into itself')
+      if not set_owner:
         # try to make ownership explicit so that it gets carried
         # along to the new location if needed.
         ob.manage_changeOwnershipType(explicit=1)
-
-        aq_parent(aq_inner(ob))._delObject(id)
-        ob = aq_base(ob)
-        orig_id = id
-        id = self._get_id(id)
-        result.append({'id':orig_id, 'new_id':id })
-
-        ob._setId(id)
-        self._setObject(id, ob, set_owner=0)
-        ob = self._getOb(id)
-        ob._postCopy(self, op=1)
-
+      new_ob = do(self, ob)
+      orig_id = ob.getId()
+      new_id = self._get_id(orig_id)
+      result.append({'id': orig_id, 'new_id': new_id})
+      new_ob._setId(new_id)
+      if not is_indexable:
+        new_ob._setNonIndexable()
+      self._setObject(new_id, new_ob, set_owner=set_owner)
+      new_ob = self._getOb(new_id)
+      new_ob._postCopy(self, op=op)
+      if is_clone:
+        new_ob.manage_afterClone(new_ob)
+        new_ob.wl_clearLocks()
+      if duplicate:
+        new_ob._postDuplicate()
+      if not set_owner:
         # try to make ownership implicit if possible
-        ob.manage_changeOwnershipType(explicit=0)
-
-    return result
+        new_ob.manage_changeOwnershipType(explicit=0)
+    return op, result
 
   def _postDuplicate(self):
     self_base = aq_base(self)
@@ -522,100 +541,27 @@ class CopyContainer:
     If is_indexable is False, we will avoid indexing the pasted objects and
     subobjects
     """
-    cp=None
+    cp = None
     if cb_copy_data is not None:
-      cp=cb_copy_data
-    else:
-      if REQUEST and REQUEST.has_key('__cp'):
-        cp=REQUEST['__cp']
+      cp = cb_copy_data
+    elif REQUEST is not None and REQUEST.has_key('__cp'):
+      cp = REQUEST['__cp']
     if cp is None:
-      raise CopyError, eNoData
-
-    try:  cp=_cb_decode(cp)
-    except: raise CopyError, eInvalid
-
-    oblist=[]
-    op=cp[0]
-    app = self.getPhysicalRoot()
-    result = []
-
-    for mdata in cp[1]:
-      m = Moniker.loadMoniker(mdata)
-      try: ob = m.bind(app)
-      except: raise CopyError, eNotFound
-      self._verifyObjectPaste(ob, validate_src=op+1)
-      oblist.append(ob)
-
-    if op==0:
-      # Copy operation
-      for ob in oblist:
-        if not ob.cb_isCopyable():
-          raise CopyError, eNotSupported % escape(ob.getId())
-        try:  ob._notifyOfCopyTo(self, op=0)
-        except: raise CopyError, MessageDialog(
-          title='Copy Error',
-          message=sys.exc_info()[1],
-          action ='manage_main')
-        ob=ob._getCopy(self)
-        orig_id=ob.getId()
-        id=self._get_id(ob.getId())
-        result.append({'id':orig_id, 'new_id':id})
-        ob._setId(id)
-        if not is_indexable:
-          ob._setNonIndexable()
-        self._setObject(id, ob)
-        ob = self._getOb(id)
-        ob._postCopy(self, op=0)
-        ob.manage_afterClone(ob)
-        ob.wl_clearLocks()
-
-      if REQUEST is not None:
-        return self.manage_main(self, REQUEST, update_menu=1,
-                    cb_dataValid=1)
-
-    if op==1:
-      # Move operation
-      for ob in oblist:
-        id=ob.getId()
-        if not ob.cb_isMoveable():
-          raise CopyError, eNotSupported % escape(id)
-        try:  ob._notifyOfCopyTo(self, op=1)
-        except: raise CopyError, MessageDialog(
-          title='Move Error',
-          message=sys.exc_info()[1],
-          action ='manage_main')
-        if not sanity_check(self, ob):
-          raise CopyError, 'This object cannot be pasted into itself'
-
-        # try to make ownership explicit so that it gets carried
-        # along to the new location if needed.
-        ob.manage_changeOwnershipType(explicit=1)
-
-        aq_parent(aq_inner(ob))._delObject(id)
-        ob = aq_base(ob)
-        orig_id=id
-        id=self._get_id(id)
-        result.append({'id':orig_id, 'new_id':id })
-
-        ob._setId(id)
-        if not is_indexable:
-          ob._setNonIndexable()
-        self._setObject(id, ob, set_owner=0)
-        ob=self._getOb(id)
-        ob._postCopy(self, op=1)
-
-        # try to make ownership implicit if possible
-        ob.manage_changeOwnershipType(explicit=0)
-
-      if REQUEST is not None:
-        REQUEST['RESPONSE'].setCookie('__cp', 'deleted',
-                  path='%s' % cookie_path(REQUEST),
-                  expires='Wed, 31-Dec-97 23:59:59 GMT')
-        REQUEST['__cp'] = None
-        return self.manage_main(self, REQUEST, update_menu=1,
-                    cb_dataValid=0)
-    return result
-
+      raise CopyError(eNoData)
+    op, result = self.__duplicate(
+      cp,
+      duplicate=False,
+      is_indexable=is_indexable,
+    )
+    if REQUEST is None:
+      return result
+    if op == 0:
+      cb_dataValid = 1
+    else:
+      cb_dataValid = 0
+      REQUEST['RESPONSE'].setCookie('__cp', 'deleted', path='%s' % cookie_path(REQUEST), expires='Wed, 31-Dec-97 23:59:59 GMT')
+      REQUEST['__cp'] = None
+    return self.manage_main(self, REQUEST, update_menu=1, cb_dataValid=cb_dataValid)
 #### Helper methods
 
 def tryMethodCallWithTemporaryPermission(context, permission, method,
-- 
2.30.9