def test_attribute_uuid_create_handler(self): from zope.interface import implementer from zope.event import notify from zope.lifecycleevent import ObjectCreatedEvent from zope.lifecycleevent import ObjectCopiedEvent from plone.uuid.interfaces import IAttributeUUID from plone.uuid.interfaces import IUUID from plone.uuid.interfaces import ATTRIBUTE_NAME @implementer(IAttributeUUID) class Context(object): pass context = Context() notify(ObjectCreatedEvent(context)) uuid = IUUID(context, None) self.assertNotEqual(uuid, None) self.assertTrue(isinstance(uuid, str)) # calling handler again won't change if UUID already present: notify(ObjectCreatedEvent(context)) self.assertEqual(uuid, IUUID(context, None)) # ...except when the UUID attribute was the result of a copy copied = Context() setattr(copied, ATTRIBUTE_NAME, IUUID(context, None)) self.assertNotEqual(IUUID(copied, None), None) # mimic copied state self.assertEqual(uuid, IUUID(copied, None)) # before handler notify(ObjectCopiedEvent(copied, original=context)) self.assertNotEqual(uuid, None) self.assertNotEqual(uuid, IUUID(copied, None)) # copy has new UID
def _setter(ob, *args, **kw): if ob.isPrincipiaFolderish: tool = getattr(Acquisition.aq_parent(ob), 'portal_languages') if tool.id in ob.objectIds(): ob._delObject(tool.id) newob = tool._getCopy(tool) newob._setId(tool.id) notify(ObjectCopiedEvent(newob, tool)) ob._setOb(tool.id, newob) ob._objects = ob._objects + (dict(meta_type=tool.meta_type, id=tool.id), ) newob = ob._getOb(tool.id) newob.wl_clearLocks() newob._postCopy(ob, op=0) newob.manage_afterClone(newob) notify(ObjectClonedEvent(newob)) languages = kw.get('languages', None) if languages: if isinstance(languages, tuple): languages = list(languages) elif isinstance(languages, types.StringType) or isinstance( languages, types.UnicodeType): languages = [languages] newob.supported_langs = languages return ["Added language tool to %s" % ob.getId()]
def manage_clone(self, ob, id, REQUEST=None): """Clone an object, creating a new object with the given id. """ if not ob.cb_isCopyable(): raise CopyError('Not Supported') try: self._checkId(id) except Exception: raise CopyError('Invalid Id') self._verifyObjectPaste(ob) try: ob._notifyOfCopyTo(self, op=0) except ConflictError: raise except Exception: raise CopyError('Clone Error') orig_ob = ob ob = ob._getCopy(self) ob._setId(id) notify(ObjectCopiedEvent(ob, orig_ob)) self._setObject(id, ob) ob = self._getOb(id) ob._postCopy(self, op=0) compatibilityCall('manage_afterClone', ob, ob) notify(ObjectClonedEvent(ob)) return ob
def __call__(self): if self.request.method != "POST": raise NotFound(self, "library-insert", self.request) path = self.request.form.get("path") if not path: raise NotFound(self, "library-insert", self.request) # XXX Wrong exception type target = aq_inner(self.context) app = target.getPhysicalRoot() source = app.restrictedTraverse(path) if not is_allowed(target, source): raise NotFound(self, "library-insert", self.request) # XXX Wrong exception type copy = source._getCopy(target) assign_ids(target, copy) notify(ObjectCopiedEvent(copy, source)) target._setObject(copy.id, copy) copy = target[copy.id] copy._postCopy(target, op=0) notify(ObjectClonedEvent(copy)) api.portal.show_message( _( 'Added a copy of "${title}" to your OiRA tool.', mapping={"title": copy.title}, ), request=self.request, type="success", ) self.request.RESPONSE.redirect(copy.absolute_url())
class CopyActionExecutor(object): """The executor for this action. """ implements(IExecutable) adapts(Interface, ICopyAction, Interface) def __init__(self, context, element, event): self.context = context self.element = element self.event = event def __call__(self): portal_url = getToolByName(self.context, 'portal_url', None) if portal_url is None: return False obj = self.event.object path = self.element.target_folder if len(path) > 1 and path[0] == '/': path = path[1:] target = portal_url.getPortalObject().unrestrictedTraverse( str(path), None) if target is None: self.error( obj, _(u"Target folder ${target} does not exist.", mapping={'target': path})) return False try: obj._notifyOfCopyTo(target, op=0) except ConflictError: raise except Exception, e: self.error(obj, str(e)) return False old_id = obj.getId() new_id = self.generate_id(target, old_id) orig_obj = obj obj = obj._getCopy(target) obj._setId(new_id) notify(ObjectCopiedEvent(obj, orig_obj)) target._setObject(new_id, obj) obj = target._getOb(new_id) obj.wl_clearLocks() obj._postCopy(target, op=0) OFS.subscribers.compatibilityCall('manage_afterClone', obj, obj) notify(ObjectClonedEvent(obj)) return True
def __copy(self, content, to_identifier): # Copy a content to to_identifier in the container copy = content._getCopy(self.context) copy._setId(to_identifier) notify(ObjectCopiedEvent(copy, content)) self.context._setObject(to_identifier, copy) copy = self.context._getOb(to_identifier) compatibilityCall('manage_afterClone', copy, copy) notify(ObjectClonedEvent(copy)) return copy
def __call__(self): portal_url = getToolByName(self.context, 'portal_url', None) if portal_url is None: return False obj = self.event.object path = self.element.target_folder if len(path) > 1 and path[0] == '/': path = path[1:] target = portal_url.getPortalObject().unrestrictedTraverse( str(path), None, ) if target is None: self.error( obj, _(u'Target folder ${target} does not exist.', mapping={'target': path})) return False try: obj._notifyOfCopyTo(target, op=0) except ConflictError: raise except Exception as e: self.error(obj, str(e)) return False old_id = obj.getId() new_id = self.generate_id(target, old_id) orig_obj = obj obj = obj._getCopy(target) obj._setId(new_id) notify(ObjectCopiedEvent(obj, orig_obj)) target._setObject(new_id, obj) obj = target._getOb(new_id) obj.wl_clearLocks() obj._postCopy(target, op=0) OFS.subscribers.compatibilityCall('manage_afterClone', obj, obj) notify(ObjectClonedEvent(obj)) return True
def onObjectDeletion(object=None): import transaction from zope.event import notify from zope.app.container.contained import ObjectMovedEvent from zope.app.container.contained import notifyContainerModified from OFS.event import ObjectClonedEvent import OFS.subscribers from zope.lifecycleevent import ObjectCopiedEvent if object <> None: portal = object.portal_url.getPortalObject() org_user = getSecurityManager().getUser() try: objRBin = getPreferredRecycleBin(object) if objRBin <> None: #impersonateUser username = getUserToImpersonate(portal, objRBin) impersonateUser(portal, username) # parent = aq_parent(aq_inner(object)) orig_id = object.getId() id = _get_id(objRBin, orig_id) orig_ob = object object = object._getCopy(parent) object._setId(id) addPropertiesOnDelete(portal, object, orig_ob, org_user, "/".join(parent.getPhysicalPath())) notify(ObjectCopiedEvent(object, orig_ob)) objRBin._setObject(id, object) ob = objRBin._getOb(id) ob._postCopy(objRBin, op=0) OFS.subscribers.compatibilityCall('manage_afterClone', ob, ob) notify(ObjectClonedEvent(ob)) except AttributeError: pass #undo imporsination newSecurityManager(None, org_user)
def backup_form(form, site): formId = form.getId() copyId = 'original-premigration-%s' % formId series = form.__parent__ ## make clone: unwrapped = aq_base(form) copied = unwrapped._getCopy(series) copied._setId(copyId) copied.title = '%s (archival copy, pre-migration)' % copied.title notify(ObjectCopiedEvent(copied, form)) series._setObject(copyId, copied) copied = series._getOb(copyId) notify(ObjectClonedEvent(copied)) ## make clone private: site.portal_workflow.doActionFor(copied, 'hide')
def test_copy_subfolder(self): copied_subfolder = api.content.copy( self.first_classification_subfolder, self.second_classification_folder) notify( ObjectCopiedEvent( self.first_classification_subfolder, copied_subfolder, )) copied_subfolder_indexes = self.get_index_data(copied_subfolder) self.assertEqual(copied_subfolder_indexes["ClassificationFolderSort"], "Folder2|Subfolder1") self.assertIn("folder2", copied_subfolder_indexes["SearchableText"])
def _add_language_tool(country_folder, country_name, languages): log.info('_add_language_tool for %s' % country_name) tool = getToolByName(country_folder, 'portal_languages') newob = tool._getCopy(tool) newob._setId(tool.id) notify(ObjectCopiedEvent(newob, tool)) country_folder._setOb(tool.id, newob) country_folder._objects = country_folder._objects + (dict( meta_type=tool.meta_type, id=tool.id), ) ltool = country_folder._getOb(tool.id) ltool.wl_clearLocks() ltool._postCopy(country_folder, op=0) ltool.manage_afterClone(ltool) notify(ObjectClonedEvent(ltool)) ltool.supported_langs = languages
def translateThis(self, attrs=[]): """ Translates the current object into all languages and transferres the given attributes """ context = Acquisition.aq_inner(self.context) if 'title' not in attrs: attrs.append('title') # Only do this from the canonical context = context.getCanonical() res = [] for lang in self.langs: if context.hasTranslation(lang): res.append("Translation for %s exists" % lang) continue context.addTranslation(lang) trans = context.getTranslation(lang) res.append("Added Translation for %s" % lang) for attr in attrs: val = context.getField(attr).getAccessor(context)() trans.getField(attr).getMutator(trans)(val) res.append(" > Transferred Attribute %s" % attr) if context.portal_type == 'Topic': # copy the contents as well ids = context.objectIds() ids.remove('syndication_information') for id in ids: orig_ob = getattr(context, id) ob = orig_ob._getCopy(context) ob._setId(id) notify(ObjectCopiedEvent(ob, orig_ob)) trans._setObject(id, ob) ob = trans._getOb(id) ob.wl_clearLocks() ob._postCopy(trans, op=0) ob.manage_afterClone(ob) notify(ObjectClonedEvent(ob)) res.append(" > Transferred Topic contents") return res
def manage_clone(self, ob, id, REQUEST=None): """Clone an object, creating a new object with the given id. """ if not ob.cb_isCopyable(): raise CopyError(eNotSupported % escape(ob.getId())) try: self._checkId(id) except: raise CopyError(MessageDialog( title='Invalid Id', message=sys.exc_info()[1], action ='manage_main')) self._verifyObjectPaste(ob) try: ob._notifyOfCopyTo(self, op=0) except ConflictError: raise except: raise CopyError(MessageDialog( title="Clone Error", message=sys.exc_info()[1], action='manage_main')) orig_ob = ob ob = ob._getCopy(self) ob._setId(id) notify(ObjectCopiedEvent(ob, orig_ob)) self._setObject(id, ob) ob = self._getOb(id) ob._postCopy(self, op=0) compatibilityCall('manage_afterClone', ob, ob) notify(ObjectClonedEvent(ob)) return ob
def update(self): req = self.request if req.get('REQUEST_METHOD', 'GET') == 'POST' and 'makeclone' in req: source = self.context parent = source.__parent__ target = source._getCopy(parent) target.title = req.get('clone_title', source.title).decode('utf-8') target.description = req.get( 'clone_description', source.description, ).decode('utf-8') target_id = self.target_id(target, parent) target._setId(target_id) notify(ObjectCopiedEvent(target, source)) parent._setObject(target_id, target) target = parent.get(target_id) target.wl_clearLocks() notify(ObjectClonedEvent(target)) self.status.add( u'Created a new data set with title "%s" cloned from ' u'original data set "%s"' % (target.title, source.title), type=u'info', ) req.response.redirect(target.absolute_url() + '/edit')
def copyTo(self, target, new_name=None): """Copy this object to the `target` given. Returns the new name within the `target`. After the copy is created and before adding it to the target container, an `IObjectCopied` event is published. """ obj = self.context container = obj.__parent__ orig_name = obj.__name__ if new_name is None: new_name = orig_name checkObject(target, new_name, obj) chooser = INameChooser(target) new_name = chooser.chooseName(new_name, obj) new = copy(obj) notify(ObjectCopiedEvent(new, obj)) target[new_name] = new return new_name
def render(self): if self.request.method != 'POST': raise NotFound(self, 'library-insert', self.request) path = self.request.form.get('path') if not path: raise NotFound(self, 'library-insert', self.request) # XXX Wrong exception type target = aq_inner(self.context) app = target.getPhysicalRoot() source = app.restrictedTraverse(path) if not is_allowed(target, source): raise NotFound(self, 'library-insert', self.request) # XXX Wrong exception type copy = source._getCopy(target) assign_ids(target, copy) notify(ObjectCopiedEvent(copy, source)) target._setObject(copy.id, copy) copy = target[copy.id] copy._postCopy(target, op=0) notify(ObjectClonedEvent(copy)) IStatusMessage(self.request).addStatusMessage( _(u'Added a copy of "${title}" to your OiRA tool.', mapping={'title': copy.title}), type='success') self.response.redirect(copy.absolute_url())
def COPY(self, REQUEST, RESPONSE): """Create a duplicate of the source resource whose state and behavior match that of the source resource as closely as possible. Though we may later try to make a copy appear seamless across namespaces (e.g. from Zope to Apache), COPY is currently only supported within the Zope namespace.""" self.dav__init(REQUEST, RESPONSE) if not hasattr(aq_base(self), 'cb_isCopyable') or \ not self.cb_isCopyable(): raise MethodNotAllowed('This object may not be copied.') depth = REQUEST.get_header('Depth', 'infinity') if depth not in ('0', 'infinity'): raise BadRequest('Invalid Depth header.') dest = REQUEST.get_header('Destination', '') while dest and dest[-1] == '/': dest = dest[:-1] if not dest: raise BadRequest('Invalid Destination header.') try: path = REQUEST.physicalPathFromURL(dest) except ValueError: raise BadRequest('Invalid Destination header') name = path.pop() oflag = REQUEST.get_header('Overwrite', 'F').upper() if oflag not in ('T', 'F'): raise BadRequest('Invalid Overwrite header.') try: parent = self.restrictedTraverse(path) except ValueError: raise Conflict('Attempt to copy to an unknown namespace.') except NotFound: raise Conflict('Object ancestors must already exist.') except Exception: raise if hasattr(parent, '__null_resource__'): raise Conflict('Object ancestors must already exist.') existing = hasattr(aq_base(parent), name) if existing and oflag == 'F': raise PreconditionFailed('Destination resource exists.') try: parent._checkId(name, allow_dup=1) except Exception: raise Forbidden(sys.exc_info()[1]) try: parent._verifyObjectPaste(self) except Unauthorized: raise except Exception: raise Forbidden(sys.exc_info()[1]) # Now check locks. The If header on a copy only cares about the # lock on the destination, so we need to check out the destinations # lock status. ifhdr = REQUEST.get_header('If', '') if existing: # The destination itself exists, so we need to check its locks destob = aq_base(parent)._getOb(name) if IWriteLock.providedBy(destob) and destob.wl_isLocked(): if ifhdr: itrue = destob.dav__simpleifhandler( REQUEST, RESPONSE, 'COPY', refresh=1) if not itrue: raise PreconditionFailed() else: raise Locked('Destination is locked.') elif IWriteLock.providedBy(parent) and parent.wl_isLocked(): if ifhdr: parent.dav__simpleifhandler(REQUEST, RESPONSE, 'COPY', refresh=1) else: raise Locked('Destination is locked.') self._notifyOfCopyTo(parent, op=0) ob = self._getCopy(parent) ob._setId(name) if depth == '0' and isDavCollection(ob): for id in ob.objectIds(): ob._delObject(id) notify(ObjectCopiedEvent(ob, self)) if existing: object = getattr(parent, name) self.dav__validate(object, 'DELETE', REQUEST) parent._delObject(name) parent._setObject(name, ob) ob = parent._getOb(name) ob._postCopy(parent, op=0) compatibilityCall('manage_afterClone', ob, ob) notify(ObjectClonedEvent(ob)) # We remove any locks from the copied object because webdav clients # don't track the lock status and the lock token for copied resources ob.wl_clearLocks() RESPONSE.setStatus(existing and 204 or 201) if not existing: RESPONSE.setHeader('Location', dest) RESPONSE.setBody('') return RESPONSE
def manage_pasteObjects(self, cb_copy_data=None, REQUEST=None): """Paste previously copied objects into the current object. If calling manage_pasteObjects from python code, pass the result of a previous call to manage_cutObjects or manage_copyObjects as the first argument. Also sends IObjectCopiedEvent and IObjectClonedEvent or IObjectWillBeMovedEvent and IObjectMovedEvent. """ if cb_copy_data is not None: cp = cb_copy_data elif REQUEST is not None and REQUEST.has_key('__cp'): cp = REQUEST['__cp'] else: cp = None if cp is None: raise CopyError, eNoData try: op, mdatas = _cb_decode(cp) except: raise CopyError, eInvalid oblist = [] app = self.getPhysicalRoot() for mdata in mdatas: m = Moniker.loadMoniker(mdata) try: ob = m.bind(app) except ConflictError: raise except: raise CopyError, eNotFound self._verifyObjectPaste(ob, validate_src=op+1) oblist.append(ob) result = [] if op == 0: # Copy operation for ob in oblist: orig_id = ob.getId() if not ob.cb_isCopyable(): raise CopyError, eNotSupported % escape(orig_id) try: ob._notifyOfCopyTo(self, op=0) except ConflictError: raise except: raise CopyError, MessageDialog( title="Copy Error", message=sys.exc_info()[1], action='manage_main') id = self._get_id(orig_id) result.append({'id': orig_id, 'new_id': id}) orig_ob = ob ob = ob._getCopy(self) ob._setId(id) notify(ObjectCopiedEvent(ob, orig_ob)) self._setObject(id, ob) ob = self._getOb(id) ob.wl_clearLocks() ob._postCopy(self, op=0) OFS.subscribers.compatibilityCall('manage_afterClone', ob, ob) notify(ObjectClonedEvent(ob)) if REQUEST is not None: return self.manage_main(self, REQUEST, update_menu=1, cb_dataValid=1) elif op == 1: # Move operation for ob in oblist: orig_id = ob.getId() if not ob.cb_isMoveable(): raise CopyError, eNotSupported % escape(orig_id) try: ob._notifyOfCopyTo(self, op=1) except ConflictError: raise 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" orig_container = aq_parent(aq_inner(ob)) if aq_base(orig_container) is aq_base(self): id = orig_id else: id = self._get_id(orig_id) result.append({'id': orig_id, 'new_id': id}) notify(ObjectWillBeMovedEvent(ob, orig_container, orig_id, self, id)) # try to make ownership explicit so that it gets carried # along to the new location if needed. ob.manage_changeOwnershipType(explicit=1) try: orig_container._delObject(orig_id, suppress_events=True) except TypeError: # BBB: removed in Zope 2.11 orig_container._delObject(orig_id) warnings.warn( "%s._delObject without suppress_events is deprecated " "and will be removed in Zope 2.11." % orig_container.__class__.__name__, DeprecationWarning) ob = aq_base(ob) ob._setId(id) try: self._setObject(id, ob, set_owner=0, suppress_events=True) except TypeError: # BBB: removed in Zope 2.11 self._setObject(id, ob, set_owner=0) warnings.warn( "%s._setObject without suppress_events is deprecated " "and will be removed in Zope 2.11." % self.__class__.__name__, DeprecationWarning) ob = self._getOb(id) notify(ObjectMovedEvent(ob, orig_container, orig_id, self, id)) notifyContainerModified(orig_container) if aq_base(orig_container) is not aq_base(self): notifyContainerModified(self) 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
def _pasteObjects(self, cp, cb_maxsize=0): """Paste previously copied objects into the current object. ``cp`` is the list of objects for paste as encoded by ``_cb_encode``. If calling _pasteObjects from python code, pass the result of a previous call to manage_cutObjects or manage_copyObjects as the first argument. ``cb_maxsize`` is the maximum size of the JSON representation of the object list. Set it to a non-zero value to prevent DoS attacks with huge object lists or zlib bombs. This method sends IObjectCopiedEvent and IObjectClonedEvent or IObjectWillBeMovedEvent and IObjectMovedEvent. Returns tuple of (operator, list of {'id': orig_id, 'new_id': new_id}). Where `operator` is 0 for a copy operation and 1 for a move operation. """ if cp is None: raise CopyError('No clipboard data found.') try: op, mdatas = _cb_decode(cp, cb_maxsize) except Exception as e: six.raise_from(CopyError('Clipboard Error'), e) oblist = [] app = self.getPhysicalRoot() for mdata in mdatas: m = loadMoniker(mdata) try: ob = m.bind(app) except ConflictError: raise except Exception: raise CopyError('Item Not Found') self._verifyObjectPaste(ob, validate_src=op + 1) oblist.append(ob) result = [] if op == 0: # Copy operation for ob in oblist: orig_id = ob.getId() if not ob.cb_isCopyable(): raise CopyError('Not Supported') try: ob._notifyOfCopyTo(self, op=0) except ConflictError: raise except Exception: raise CopyError('Copy Error') id = self._get_id(orig_id) result.append({'id': orig_id, 'new_id': id}) orig_ob = ob ob = ob._getCopy(self) ob._setId(id) notify(ObjectCopiedEvent(ob, orig_ob)) self._setObject(id, ob) ob = self._getOb(id) ob.wl_clearLocks() ob._postCopy(self, op=0) compatibilityCall('manage_afterClone', ob, ob) notify(ObjectClonedEvent(ob)) elif op == 1: # Move operation for ob in oblist: orig_id = ob.getId() if not ob.cb_isMoveable(): raise CopyError('Not Supported') try: ob._notifyOfCopyTo(self, op=1) except ConflictError: raise except Exception: raise CopyError('Move Error') if not sanity_check(self, ob): raise CopyError("This object cannot be pasted into itself") orig_container = aq_parent(aq_inner(ob)) if aq_base(orig_container) is aq_base(self): id = orig_id else: id = self._get_id(orig_id) result.append({'id': orig_id, 'new_id': id}) notify( ObjectWillBeMovedEvent(ob, orig_container, orig_id, self, id)) # try to make ownership explicit so that it gets carried # along to the new location if needed. ob.manage_changeOwnershipType(explicit=1) try: orig_container._delObject(orig_id, suppress_events=True) except TypeError: orig_container._delObject(orig_id) warnings.warn( "%s._delObject without suppress_events is discouraged." % orig_container.__class__.__name__, DeprecationWarning) ob = aq_base(ob) ob._setId(id) try: self._setObject(id, ob, set_owner=0, suppress_events=True) except TypeError: self._setObject(id, ob, set_owner=0) warnings.warn( "%s._setObject without suppress_events is discouraged." % self.__class__.__name__, DeprecationWarning) ob = self._getOb(id) notify(ObjectMovedEvent(ob, orig_container, orig_id, self, id)) notifyContainerModified(orig_container) if aq_base(orig_container) is not aq_base(self): notifyContainerModified(self) ob._postCopy(self, op=1) # try to make ownership implicit if possible ob.manage_changeOwnershipType(explicit=0) return op, result
def manage_pasteObjects(self, cb_copy_data=None, REQUEST=None): """Paste previously copied objects into the current object. If calling manage_pasteObjects from python code, pass the result of a previous call to manage_cutObjects or manage_copyObjects as the first argument. Also sends IObjectCopiedEvent and IObjectClonedEvent or IObjectWillBeMovedEvent and IObjectMovedEvent. """ cp = cb_copy_data if cp is None and REQUEST is not None and '__cp' in REQUEST: cp = REQUEST['__cp'] if cp is None: raise CopyError('No clipboard data found.') try: op, mdatas = _cb_decode(cp) except Exception as e: six.raise_from(CopyError('Clipboard Error'), e) oblist = [] app = self.getPhysicalRoot() for mdata in mdatas: m = loadMoniker(mdata) try: ob = m.bind(app) except ConflictError: raise except Exception: raise CopyError('Item Not Found') self._verifyObjectPaste(ob, validate_src=op + 1) oblist.append(ob) result = [] if op == 0: # Copy operation for ob in oblist: orig_id = ob.getId() if not ob.cb_isCopyable(): raise CopyError('Not Supported') try: ob._notifyOfCopyTo(self, op=0) except ConflictError: raise except Exception: raise CopyError('Copy Error') id = self._get_id(orig_id) result.append({'id': orig_id, 'new_id': id}) orig_ob = ob ob = ob._getCopy(self) ob._setId(id) notify(ObjectCopiedEvent(ob, orig_ob)) self._setObject(id, ob) ob = self._getOb(id) ob.wl_clearLocks() ob._postCopy(self, op=0) compatibilityCall('manage_afterClone', ob, ob) notify(ObjectClonedEvent(ob)) if REQUEST is not None: return self.manage_main(self, REQUEST, cb_dataValid=1) elif op == 1: # Move operation for ob in oblist: orig_id = ob.getId() if not ob.cb_isMoveable(): raise CopyError('Not Supported') try: ob._notifyOfCopyTo(self, op=1) except ConflictError: raise except Exception: raise CopyError('Move Error') if not sanity_check(self, ob): raise CopyError("This object cannot be pasted into itself") orig_container = aq_parent(aq_inner(ob)) if aq_base(orig_container) is aq_base(self): id = orig_id else: id = self._get_id(orig_id) result.append({'id': orig_id, 'new_id': id}) notify( ObjectWillBeMovedEvent(ob, orig_container, orig_id, self, id)) # try to make ownership explicit so that it gets carried # along to the new location if needed. ob.manage_changeOwnershipType(explicit=1) try: orig_container._delObject(orig_id, suppress_events=True) except TypeError: orig_container._delObject(orig_id) warnings.warn( "%s._delObject without suppress_events is discouraged." % orig_container.__class__.__name__, DeprecationWarning) ob = aq_base(ob) ob._setId(id) try: self._setObject(id, ob, set_owner=0, suppress_events=True) except TypeError: self._setObject(id, ob, set_owner=0) warnings.warn( "%s._setObject without suppress_events is discouraged." % self.__class__.__name__, DeprecationWarning) ob = self._getOb(id) notify(ObjectMovedEvent(ob, orig_container, orig_id, self, id)) notifyContainerModified(orig_container) if aq_base(orig_container) is not aq_base(self): notifyContainerModified(self) 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, cb_dataValid=0) return result
def COPY(self, REQUEST, RESPONSE): """Create a duplicate of the source resource. This is only allowed within the same reflecto directory.""" self.dav__init(REQUEST, RESPONSE) if not hasattr(aq_base(self), 'cb_isCopyable') or \ not self.cb_isCopyable(): raise MethodNotAllowed, 'This object may not be copied.' depth = REQUEST.get_header('Depth', 'infinity') if not depth in ('0', 'infinity'): raise BadRequest, 'Invalid Depth header.' dest = REQUEST.get_header('Destination', '') while dest and dest[-1] == '/': dest = dest[:-1] if not dest: raise BadRequest, 'Invalid Destination header.' try: path = REQUEST.physicalPathFromURL(dest) except ValueError: raise BadRequest, 'Invalid Destination header' name = path.pop() oflag = REQUEST.get_header('Overwrite', 'F').upper() if not oflag in ('T', 'F'): raise BadRequest, 'Invalid Overwrite header.' try: parent = self.restrictedTraverse(path) except ValueError: raise Conflict, 'Attempt to copy to an unknown namespace.' except NotFound: raise Conflict, 'Object ancestors must already exist.' except: t, v, tb = sys.exc_info() raise t, v if hasattr(parent, '__null_resource__'): raise Conflict, 'Object ancestors must already exist.' existing = hasattr(aq_base(parent), name) if existing and oflag == 'F': raise PreconditionFailed, 'Destination resource exists.' try: parent._checkId(name, allow_dup=1) except: raise Forbidden, sys.exc_info()[1] try: parent._verifyObjectPaste(self) except Unauthorized: raise except: raise Forbidden, sys.exc_info()[1] # Now check locks. The If header on a copy only cares about the # lock on the destination, so we need to check out the destinations # lock status. ifhdr = REQUEST.get_header('If', '') if existing: # The destination itself exists, so we need to check its locks destob = aq_base(parent)._getOb(name) if IWriteLock.providedBy(destob) and destob.wl_isLocked(): if ifhdr: itrue = destob.dav__simpleifhandler(REQUEST, RESPONSE, 'COPY', refresh=1) if not itrue: raise PreconditionFailed else: raise Locked, 'Destination is locked.' elif IWriteLock.providedBy(parent) and parent.wl_isLocked(): if ifhdr: parent.dav__simpleifhandler(REQUEST, RESPONSE, 'COPY', refresh=1) else: raise Locked, 'Destination is locked.' self._notifyOfCopyTo(parent, op=0) #### This part is reflecto specific if existing: object = getattr(parent, name) self.dav__validate(object, 'DELETE', REQUEST) parent.manage_delObjects([name]) oldpath = self.getFilesystemPath() newpath = os.path.join(parent.getFilesystemPath(), name) if IReflectoDirectory.providedBy(self): if depth == '0': os.mkdir(newpath, 0775) else: shutil.copytree(oldpath, newpath) else: shutil.copy2(oldpath, newpath) ob = parent[name] ob.indexObject() notify(ObjectCopiedEvent(ob, self)) notify(ObjectClonedEvent(ob)) notifyContainerModified(parent) #### # We remove any locks from the copied object because webdav clients # don't track the lock status and the lock token for copied resources ob.wl_clearLocks() RESPONSE.setStatus(existing and 204 or 201) if not existing: RESPONSE.setHeader('Location', dest) RESPONSE.setBody('') return RESPONSE
def manage_pasteObjects(self, cp): """Paste previously copied objects into the current object.""" op, mdatas = _cb_decode(cp) COPY = op == 0 # Otherwise its a paste operation # Copy or paste always fails without write permission here sman = getSecurityManager() if not sman.checkPermission(AddFilesystemObject, self): raise CopyError, 'Insufficient Privileges' oblist = [] app = self.getPhysicalRoot() # Loading and security checks for mdata in mdatas: m = loadMoniker(mdata) try: ob = m.bind(app) except ConflictError: raise except: raise CopyError, 'Item not found' if not IReflectoProxy.providedBy(ob) or IReflector.providedBy(ob): raise CopyError, 'Cannot paste into this object' parent = aq_parent(aq_inner(ob)) if not sman.validate(None, parent, None, ob): raise Unauthorized(ob.getId()) if not COPY: if not sman.checkPermission(DeleteObjects, parent): raise Unauthorized('Delete not allowed') prefix = os.path.commonprefix( (ob.getFilesystemPath(), self.getFilesystemPath())) if prefix == ob.getFilesystemPath(): raise CopyError, "This object cannot be pasted into itself" oblist.append(ob) result = [] problem_ids = [] path = self.getFilesystemPath() for ob in oblist: old = ob.getId() new = self._generate_copy_id(old) result.append(dict(id=old, new_id=new)) oldpath = ob.getFilesystemPath() newpath = os.path.join(path, new) if COPY: try: if IReflectoDirectory.providedBy(ob): shutil.copytree(oldpath, newpath) else: shutil.copy2(oldpath, newpath) notify(ObjectCopiedEvent(self[new], ob)) notify(ObjectClonedEvent(self[new])) except EnvironmentError: problem_ids.append(result.pop()) else: # paste/move oldparent = aq_parent(aq_inner(ob)) notify(ObjectWillBeMovedEvent(ob, oldparent, old, self, new)) if aq_base(self) is aq_base(oldparent): # No need to move from self to self result[-1]['new_id'] = old # Original CopyContainer does emit events for this case notify(ObjectMovedEvent(ob, self, old, self, old)) continue try: shutil.move(oldpath, newpath) indexview = oldparent.unrestrictedTraverse('@@index') indexview.index() notify( ObjectMovedEvent(self[new], oldparent, old, self, new)) notifyContainerModified(oldparent) except EnvironmentError: if os.path.exists(newpath): # partial move try: if os.path.isdir(newpath): shutil.rmtree(newpath) else: os.unlink(newpath) except EnvironmentError: pass # Really weird access issues, time to bail problem_ids.append(result.pop()) if problem_ids: sm = IStatusMessage(getattr(self, 'REQUEST', None), None) if sm is not None: sm.addStatusMessage( 'Failed to copy or paste some files: %s' % problem_ids, 'stop') if result: indexview = self.unrestrictedTraverse('@@index') indexview.index() notifyContainerModified(self) return result