def test_moved(self): context = FauxMarkedContext(FauxContainer(), 'new') notify(ObjectMovedEvent(context, FauxContainer(), 'old', context.__parent__, 'new')) self.assertEquals(1, len(self.handler.invocations)) self.assertEquals(context, self.handler.invocations[0].object)
def test_moved(self): context = FauxContent('new').__of__(FauxContent()) notify(ObjectMovedEvent(context, FauxContent(), 'old', context.__parent__, 'new')) self.assertEqual(1, len(self.handler.invocations)) self.assertEqual(context, self.handler.invocations[0].object)
def move_compromisso_para_agendadiaria(event, obj=None): """ Toda vez que um tipo compromisso for criado ou tiver sua data alterada ele sera movido para dentro de uma agenda diaria """ if not obj: obj = event.object if not ICompromisso.providedBy(obj): # nao eh um compromisso return start_date = getattr(obj, 'start_date', None) if not start_date: return formatted_date = start_date.strftime(AGENDADIARIAFMT) origin = aq_parent(obj) agenda = _get_agenda(origin) old_id = obj.getId() destination_id = formatted_date destination = _get_destination(agenda, obj, origin, destination_id) if not IAgendaDiaria.providedBy(destination): logger.warn('Objeto %s nao foi movido' % str(obj)) # Reindexamos o SearchableText de origin origin.reindexObject(idxs=[ 'SearchableText', ]) return None new_id = _generate_id(destination, old_id) # Prepare to move object notify(ObjectWillBeMovedEvent(obj, origin, old_id, destination, new_id)) obj.manage_changeOwnershipType(explicit=1) # Remove object from origin origin._delObject(old_id, suppress_events=True) obj = aq_base(obj) # Set new_id -- which is unique on destination obj._setId(new_id) # Persist object in destination destination._setObject(new_id, obj, set_owner=0, suppress_events=True) obj = destination._getOb(new_id) notify(ObjectMovedEvent(obj, origin, old_id, destination, new_id)) notifyContainerModified(origin) notifyContainerModified(destination) obj._postCopy(destination, op=1) # try to make ownership implicit if possible obj.manage_changeOwnershipType(explicit=0) # Reindexamos o SearchableText de destination destination.reindexObject(idxs=[ 'SearchableText', ])
def test_integration_object_events(self): """ Trigger every event of a objec at least one times and check the journalentries. """ dossier1 = create(Builder('dossier')) dossier2 = create(Builder('dossier')) document = create( Builder('document').within(dossier1).titled(u'Document')) document2 = create( Builder('document').within(dossier2).titled(u'Document')) notify( ObjectMovedEvent( document, dossier1, 'oldName', dossier2, 'newName', )) self.check_annotation( dossier1, action_type='Object moved', action_title='Object moved: %s' % document.title_or_id(), ) # Test that a normal ObjectAddedEvent does not result in an object # moved journal entry. notify(ObjectAddedEvent(document2)) entry1 = get_journal_entry(dossier2, entry=-1) entry2 = get_journal_entry(dossier2, entry=-2) self.assertTrue(entry1.get('action').get('type') != 'Object moved') self.assertTrue(entry2.get('action').get('type') != 'Object moved') notify( ObjectWillBeMovedEvent( document, dossier1, 'oldName', dossier2, 'newName', )) self.check_annotation(dossier1, action_type='Object cut', action_title='Object cut: %s' % document.title_or_id()) # Here we don't have a journal-entry length = get_journal_length(dossier1) notify(ObjectWillBeAddedEvent( document, dossier2, 'newName', )) self.assertTrue(length == get_journal_length(dossier1))
def _replaceBaseline(self, baseline): # move the working copy object to the baseline, returns the # new baseline baseline_id = baseline.getId() # delete the baseline from the folder to make room for the # committed working copy baseline_container = aq_parent(aq_inner(baseline)) # Check if we are a default_page, because this property of the # container might get lost. is_default_page = ( baseline_container.getProperty('default_page', '') == baseline_id) baseline_pos = baseline_container.getObjectPosition(baseline_id) baseline_container._delOb(baseline_id) # uninedxing the deleted baseline object from portal_catalog portal_catalog = getToolByName(self.context, 'portal_catalog') portal_catalog.unindexObject(baseline) # delete the working copy from the its container wc_container = aq_parent(aq_inner(self.context)) # trick out the at machinery to not delete references self.context._v_cp_refs = 1 self.context._v_is_cp = 0 wc_id = self.context.getId() # Bypass AT security check, # checking `iterate : Check in content` should be sufficient with util.adopt_system(): wc_container.manage_delObjects([wc_id]) # move the working copy back to the baseline container working_copy = aq_base(self.context) working_copy.setId(baseline_id) baseline_container._setOb(baseline_id, working_copy) baseline_container.moveObjectToPosition(baseline_id, baseline_pos) new_baseline = baseline_container._getOb(baseline_id) if is_default_page: # Restore default_page to container. Note that the property might # have been removed by an event handler in the mean time. if baseline_container.hasProperty('default_page'): baseline_container._updateProperty('default_page', baseline_id) else: baseline_container._setProperty('default_page', baseline_id) # reregister our references with the reference machinery after moving Referenceable.manage_afterAdd(new_baseline, new_baseline, baseline_container) notify(ObjectMovedEvent(new_baseline, wc_container, wc_id, baseline_container, baseline_id)) return new_baseline
def manage_renameObject(self, id, new_id, REQUEST=None): """Rename a particular sub-object. """ try: self._checkId(new_id) except Exception: raise CopyError('Invalid Id') ob = self._getOb(id) if ob.wl_isLocked(): raise ResourceLockedError('Object "%s" is locked' % ob.getId()) if not ob.cb_isMoveable(): raise CopyError('Not Supported') self._verifyObjectPaste(ob) try: ob._notifyOfCopyTo(self, op=1) except ConflictError: raise except Exception: raise CopyError('Rename Error') notify(ObjectWillBeMovedEvent(ob, self, id, self, new_id)) try: self._delObject(id, suppress_events=True) except TypeError: self._delObject(id) warnings.warn( "%s._delObject without suppress_events is discouraged." % self.__class__.__name__, DeprecationWarning) ob = aq_base(ob) ob._setId(new_id) # Note - because a rename always keeps the same context, we # can just leave the ownership info unchanged. try: self._setObject(new_id, ob, set_owner=0, suppress_events=True) except TypeError: self._setObject(new_id, ob, set_owner=0) warnings.warn( "%s._setObject without suppress_events is discouraged." % self.__class__.__name__, DeprecationWarning) ob = self._getOb(new_id) notify(ObjectMovedEvent(ob, self, id, self, new_id)) notifyContainerModified(self) ob._postCopy(self, op=1) if REQUEST is not None: return self.manage_main(self, REQUEST)
def test_move_subfolder(self): cookie = self.first_classification_folder.manage_cutObjects( ids=("classification_subfolder_1", )) self.second_classification_folder.manage_pasteObjects(cookie) notify( ObjectMovedEvent( self.first_classification_subfolder, self.first_classification_folder, "classification_subfolder_1", self.second_classification_folder, "classification_subfolder_1", )) subfolder_indexes = self.get_index_data( self.first_classification_subfolder) self.assertEqual(subfolder_indexes["ClassificationFolderSort"], "Folder2|Subfolder1") self.assertIn("folder2", subfolder_indexes["SearchableText"])
def manage_renameObjects(self, ids=[], new_ids=[]): """Rename reflected files or directories The objects specified in 'ids' get renamed to 'new_ids'. This emulates the CopyContainer interface enough to support renaming in Plone only. When file renaming fails, errors are communicated through the return of the successful ids and the IStatusMessage utility """ if len(ids) != len(new_ids): raise BadRequest('Please rename each listed object.') if not ids: raise ValueError('No items specified') # To avoid inconsistencies, first test file availability for old, new in zip(ids, new_ids): if not self.has_key(old): raise KeyError(old) if not self.acceptableFilename(new) or self.has_key(new): raise CopyError, 'Invalid Id' notify(ObjectWillBeMovedEvent(self[old], self, old, self, new)) problem_ids = [] path = self.getFilesystemPath() for id in ids: try: os.rename(os.path.join(path, old), os.path.join(path, new)) notify(ObjectMovedEvent(self[new], self, old, self, new)) except OSError: problem_ids.append(old) if problem_ids: sm = IStatusMessage(getattr(self, 'REQUEST', None), None) if sm is not None: sm.addStatusMessage( 'Failed to rename some files: %s' % problem_ids, 'stop') if set(ids) - set(problem_ids): indexview = self.unrestrictedTraverse('@@index') indexview.index() notifyContainerModified(self) return list(set(ids) - set(problem_ids))
def _replaceBaseline(self, baseline): # move the working copy object to the baseline, returns the # new baseline baseline_id = baseline.getId() # delete the baseline from the folder to make room for the # committed working copy baseline_container = aq_parent(aq_inner(baseline)) baseline_pos = baseline_container.getObjectPosition(baseline_id) baseline_container._delOb(baseline_id) # uninedxing the deleted baseline object from portal_catalog portal_catalog = getToolByName(self.context, 'portal_catalog') portal_catalog.unindexObject(baseline) # delete the working copy from the its container wc_container = aq_parent(aq_inner(self.context)) # trick out the at machinery to not delete references self.context._v_cp_refs = 1 self.context._v_is_cp = 0 wc_id = self.context.getId() wc_container.manage_delObjects([wc_id]) # move the working copy back to the baseline container working_copy = aq_base(self.context) working_copy.setId(baseline_id) baseline_container._setOb(baseline_id, working_copy) baseline_container.moveObjectToPosition(baseline_id, baseline_pos) new_baseline = baseline_container._getOb(baseline_id) # reregister our references with the reference machinery after moving Referenceable.manage_afterAdd(new_baseline, new_baseline, baseline_container) notify( ObjectMovedEvent(new_baseline, wc_container, wc_id, baseline_container, baseline_id)) return new_baseline
def __move(self, content, from_container, from_identifier, to_identifier): # Move a content into the container notify( ObjectWillBeMovedEvent(content, from_container, from_identifier, self.context, to_identifier)) from_container._delObject(from_identifier, suppress_events=True) content = aq_base(content) content._setId(to_identifier) self.context._setObject(to_identifier, content, set_owner=0, suppress_events=True) content = self.context._getOb(to_identifier) notify( ObjectMovedEvent(content, from_container, from_identifier, self.context, to_identifier)) return content
def _constructItem(self, data): uuid = data['uuid'] brains = self.context.portal_catalog(remoteUUID=uuid, Language='all') if brains: return brains[0].getObject() tempid = str(time.time()) item = _createObjectByType('News Item', self.context, tempid) notify(ObjectCreatedEvent(item)) notify(ObjectAddedEvent(item)) transaction.savepoint(optimistic=True) oid = INameChooser(self.context).chooseName(data['title'], item) item.unindexObject() item._setId(oid) self.context._delObject(tempid, suppress_events=True) self.context._setObject(oid, item, set_owner=0, suppress_events=True) mutableuuid = IMutableRemoteUUID(item) mutableuuid.set(data['uuid']) notify(ObjectMovedEvent(item, oldParent=self.context, oldName=tempid, newParent=self.context, newName=oid)) return item
def test_handlers(self): logger = IModificationLogger(self.portal) # guarantee that everything is initially empty by pruning days=0 logger.prune(None, days=0) for name in ('modifications', 'moves', 'deletions', 'additions'): facility = getattr(logger, name) self.assertFalse(len(facility)) self.assertFalse(len(facility.keys())) # Add some content we can modify, and throw away content = api.content.create( type='Document', title='Throw away', container=self.portal, ) uid = IUUID(content) # api will have notified ObjectAddedEvent by effect, let's verify: self.assertTrue(len(logger.additions) == 1) self.assertTrue(logger.additions.values()[0].get('uid') == uid) # api create will have also renamed the item, logging a move: self.assertTrue(len(logger.moves.keys()) == 1) # modification logging: self.assertFalse(len(logger.modifications.keys())) notify(ObjectModifiedEvent(content)) self.assertTrue(len(logger.modifications.keys())) self.assertTrue(logger.modifications.values()[0].get('uid') == uid) # move/rename logging: self.assertTrue(len(logger.moves.keys()) == 1) notify( ObjectMovedEvent(content, self.portal, content.getId(), self.portal, 'haha')) self.assertTrue(len(logger.moves.keys()) == 2) # finally removal: self.assertFalse(len(logger.deletions.keys())) notify(ObjectRemovedEvent(content)) self.assertTrue(len(logger.deletions.keys())) self.assertTrue(logger.deletions.values()[0].get('uid') == uid) # clean up after testing: logger.prune(None, days=0)
def move_obj(ob, destination): """ This function has the same effect as: id = obj.getId() cp = origin.manage_cutObjects(id) destination.manage_pasteObjects(cp) but with slightly better performance and **without permission checks**. The code is mostly grabbed from OFS.CopySupport.CopyContainer_pasteObjects """ id = ob.getId() # Notify the object will be copied to destination ob._notifyOfCopyTo(destination, op=1) # Notify that the object will be moved origin = aq_parent(aq_inner(ob)) notify(ObjectWillBeMovedEvent(ob, origin, id, destination, id)) # Effectively move the object from origin to destination origin._delObject(id, suppress_events=True) ob = aq_base(ob) destination._setObject(id, ob, set_owner=0, suppress_events=True) ob = destination._getOb(id) # Since we used "suppress_events=True", we need to manually notify that the # object has been moved and containers modified. This also makes the objects # to be re-catalogued notify(ObjectMovedEvent(ob, origin, id, destination, id)) notifyContainerModified(origin) notifyContainerModified(destination) # Try to make ownership implicit if possible, so it acquires the permissions # from the container ob.manage_changeOwnershipType(explicit=0) return ob
def test_integration_object_events(self): """ Trigger every event of a objec at least one times and check the journalentries. """ portal = self.layer['portal'] dossier1 = createContentInContainer( portal, 'opengever.dossier.businesscasedossier', 'd1') dossier2 = createContentInContainer( portal, 'opengever.dossier.businesscasedossier', 'd2') document = createContentInContainer(dossier1, 'opengever.document.document', 'doc1', title='Document') document2 = createContentInContainer(dossier2, 'opengever.document.document', 'doc2', title='Document2') notify( ObjectMovedEvent( document, dossier1, 'oldName', dossier2, 'newName', )) self.check_annotation( dossier1, action_type='Object moved', action_title='Object moved: %s' % document.title_or_id(), ) # Test that a normal ObjectAddedEvent does not result in an object # moved journal entry. notify(ObjectAddedEvent(document2)) entry1 = get_journal_entry(dossier2, entry=-1) entry2 = get_journal_entry(dossier2, entry=-2) self.assertTrue(entry1.get('action').get('type') != 'Object moved') self.assertTrue(entry2.get('action').get('type') != 'Object moved') notify( ObjectWillBeMovedEvent( document, dossier1, 'oldName', dossier2, 'newName', )) self.check_annotation( dossier1, action_type='Object cut', action_title='Object cut: %s' % document.title_or_id(), ) # Here we don't have a journal-entry length = get_journal_length(dossier1) notify(ObjectWillBeAddedEvent( document, dossier2, 'newName', )) self.assertTrue(length == get_journal_length(dossier1))
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
def unrestricted_move(self, ob): """Move an object from one container to another bypassing certain checks.""" orig_id = ob.getId() if not ob.cb_isMoveable(): raise CopyError('Not supported {}'.format(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) 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)
def containedEvent(object, container, name=None): # pylint:disable=redefined-builtin """Establish the containment of the object in the container The object and necessary event are returned. The object may be a `ContainedProxy` around the original object. The event is an added event, a moved event, or None. If the object implements `IContained`, simply set its ``__parent__`` and ``__name__`` attributes: >>> container = {} >>> item = Contained() >>> x, event = containedEvent(item, container, u'foo') >>> x is item True >>> item.__parent__ is container True >>> item.__name__ u'foo' We have an added event: >>> event.__class__.__name__ 'ObjectAddedEvent' >>> event.object is item True >>> event.newParent is container True >>> event.newName u'foo' >>> event.oldParent >>> event.oldName Now if we call contained again: >>> x2, event = containedEvent(item, container, u'foo') >>> x2 is item True >>> item.__parent__ is container True >>> item.__name__ u'foo' We don't get a new added event: >>> event If the object already had a parent but the parent or name was different, we get a moved event: >>> x, event = containedEvent(item, container, u'foo2') >>> event.__class__.__name__ 'ObjectMovedEvent' >>> event.object is item True >>> event.newParent is container True >>> event.newName u'foo2' >>> event.oldParent is container True >>> event.oldName u'foo' If the *object* implements `ILocation`, but not `IContained`, set its ``__parent__`` and ``__name__`` attributes *and* declare that it implements `IContained`: >>> from zope.location import Location >>> item = Location() >>> IContained.providedBy(item) False >>> x, event = containedEvent(item, container, 'foo') >>> x is item True >>> item.__parent__ is container True >>> item.__name__ 'foo' >>> IContained.providedBy(item) True If the *object* doesn't even implement `ILocation`, put a `ContainedProxy` around it: >>> item = [] >>> x, event = containedEvent(item, container, 'foo') >>> x is item False >>> x.__parent__ is container True >>> x.__name__ 'foo' Make sure we don't lose existing directly provided interfaces. >>> from zope.interface import Interface, directlyProvides >>> class IOther(Interface): ... pass >>> from zope.location import Location >>> item = Location() >>> directlyProvides(item, IOther) >>> IOther.providedBy(item) True >>> x, event = containedEvent(item, container, 'foo') >>> IOther.providedBy(item) True """ if not IContained.providedBy(object): if ILocation.providedBy(object): zope.interface.alsoProvides(object, IContained) else: object = ContainedProxy(object) oldparent = object.__parent__ oldname = object.__name__ if oldparent is container and oldname == name: # No events return object, None object.__parent__ = container object.__name__ = name if oldparent is None or oldname is None: event = ObjectAddedEvent(object, container, name) else: event = ObjectMovedEvent(object, oldparent, oldname, container, name) return object, event
class MoveActionExecutor(object): """The executor for this action. """ implements(IExecutable) adapts(Interface, IMoveAction, 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 parent = aq_parent(aq_inner(obj)) 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 if target.absolute_url() == parent.absolute_url(): # We're already here! return True try: obj._notifyOfCopyTo(target, op=1) except ConflictError: raise except Exception, e: self.error(obj, str(e)) return False # Are we trying to move into the same container that we copied from? if not sanity_check(target, obj): return False old_id = obj.getId() new_id = self.generate_id(target, old_id) notify(ObjectWillBeMovedEvent(obj, parent, old_id, target, new_id)) obj.manage_changeOwnershipType(explicit=1) try: parent._delObject(old_id, suppress_events=True) except TypeError: # BBB: removed in Zope 2.11 parent._delObject(old_id) obj = aq_base(obj) obj._setId(new_id) try: target._setObject(new_id, obj, set_owner=0, suppress_events=True) except TypeError: # BBB: removed in Zope 2.11 target._setObject(new_id, obj, set_owner=0) obj = target._getOb(new_id) notify(ObjectMovedEvent(obj, parent, old_id, target, new_id)) notifyContainerModified(parent) if aq_base(parent) is not aq_base(target): notifyContainerModified(target) obj._postCopy(target, op=1) # try to make ownership implicit if possible obj.manage_changeOwnershipType(explicit=0) return True
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 MOVE(self, REQUEST, RESPONSE): """Move a resource to a new location within the reflector""" self.dav__init(REQUEST, RESPONSE) self.dav__validate(self, 'DELETE', REQUEST) if not hasattr(aq_base(self), 'cb_isMoveable') or \ not self.cb_isMoveable(): raise MethodNotAllowed, 'This object may not be moved.' dest = REQUEST.get_header('Destination', '') try: path = REQUEST.physicalPathFromURL(dest) except ValueError: raise BadRequest, 'No destination given' flag = REQUEST.get_header('Overwrite', 'F') flag = flag.upper() name = path.pop() parent_path = '/'.join(path) try: parent = self.restrictedTraverse(path) except ValueError: raise Conflict, 'Attempt to move to an unknown namespace.' except 'Not Found': raise Conflict, 'The resource %s must exist.' % parent_path except: t, v, tb = sys.exc_info() raise t, v if hasattr(parent, '__null_resource__'): raise Conflict, 'The resource %s must exist.' % parent_path existing = hasattr(aq_base(parent), name) if existing and flag == 'F': raise PreconditionFailed, 'Resource %s exists.' % dest 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. Since we're affecting the resource that we're # moving as well as the destination, we have to check both. 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, 'MOVE', url=dest, refresh=1) if not itrue: raise PreconditionFailed else: raise Locked, 'Destination is locked.' elif IWriteLock.providedBy(parent) and parent.wl_isLocked(): # There's no existing object in the destination folder, so # we need to check the folders locks since we're changing its # member list if ifhdr: itrue = parent.dav__simpleifhandler(REQUEST, RESPONSE, 'MOVE', col=1, url=dest, refresh=1) if not itrue: raise PreconditionFailed, 'Condition failed.' else: raise Locked, 'Destination is locked.' if Lockable.wl_isLocked(self): # Lastly, we check ourselves if ifhdr: itrue = self.dav__simpleifhandler(REQUEST, RESPONSE, 'MOVE', refresh=1) if not itrue: raise PreconditionFailed, 'Condition failed.' else: raise PreconditionFailed, 'Source is locked and no '\ 'condition was passed in.' orig_container = aq_parent(aq_inner(self)) orig_id = self.getId() self._notifyOfCopyTo(parent, op=1) #### This part is reflecto specific notify( ObjectWillBeMovedEvent(self, orig_container, orig_id, parent, name)) self.unindexObject() if existing: object = parent[name] self.dav__validate(object, 'DELETE', REQUEST) parent.manage_delObjects([name]) os.rename(self.getFilesystemPath(), os.path.join(parent.getFilesystemPath(), name)) ob = parent[name] ob.indexObject() #### notify(ObjectMovedEvent(ob, orig_container, orig_id, parent, name)) notifyContainerModified(orig_container) if aq_base(orig_container) is not aq_base(parent): notifyContainerModified(parent) RESPONSE.setStatus(existing and 204 or 201) if not existing: RESPONSE.setHeader('Location', dest) RESPONSE.setBody('') return RESPONSE
def MOVE(self, REQUEST, RESPONSE): """Move a resource to a new location. Though we may later try to make a move appear seamless across namespaces (e.g. from Zope to Apache), MOVE is currently only supported within the Zope namespace.""" self.dav__init(REQUEST, RESPONSE) self.dav__validate(self, 'DELETE', REQUEST) if not hasattr(aq_base(self), 'cb_isMoveable') or \ not self.cb_isMoveable(): raise MethodNotAllowed('This object may not be moved.') dest = REQUEST.get_header('Destination', '') try: path = REQUEST.physicalPathFromURL(dest) except ValueError: raise BadRequest('No destination given') flag = REQUEST.get_header('Overwrite', 'F') flag = flag.upper() name = path.pop() parent_path = '/'.join(path) try: parent = self.restrictedTraverse(path) except ValueError: raise Conflict('Attempt to move to an unknown namespace.') except 'Not Found': raise Conflict('The resource %s must exist.' % parent_path) except Exception: raise if hasattr(parent, '__null_resource__'): raise Conflict('The resource %s must exist.' % parent_path) existing = hasattr(aq_base(parent), name) if existing and flag == 'F': raise PreconditionFailed('Resource %s exists.' % dest) 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. Since we're affecting the resource that we're # moving as well as the destination, we have to check both. 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, 'MOVE', url=dest, refresh=1) if not itrue: raise PreconditionFailed else: raise Locked('Destination is locked.') elif IWriteLock.providedBy(parent) and parent.wl_isLocked(): # There's no existing object in the destination folder, so # we need to check the folders locks since we're changing its # member list if ifhdr: itrue = parent.dav__simpleifhandler(REQUEST, RESPONSE, 'MOVE', col=1, url=dest, refresh=1) if not itrue: raise PreconditionFailed('Condition failed.') else: raise Locked('Destination is locked.') if wl_isLocked(self): # Lastly, we check ourselves if ifhdr: itrue = self.dav__simpleifhandler(REQUEST, RESPONSE, 'MOVE', refresh=1) if not itrue: raise PreconditionFailed('Condition failed.') else: raise Locked('Source is locked and no condition was passed in') orig_container = aq_parent(aq_inner(self)) orig_id = self.getId() self._notifyOfCopyTo(parent, op=1) notify(ObjectWillBeMovedEvent(self, orig_container, orig_id, parent, name)) # try to make ownership explicit so that it gets carried # along to the new location if needed. self.manage_changeOwnershipType(explicit=1) ob = self._getCopy(parent) ob._setId(name) orig_container._delObject(orig_id, suppress_events=True) if existing: object = getattr(parent, name) self.dav__validate(object, 'DELETE', REQUEST) parent._delObject(name) parent._setObject(name, ob, set_owner=0, suppress_events=True) ob = parent._getOb(name) notify(ObjectMovedEvent(ob, orig_container, orig_id, parent, name)) notifyContainerModified(orig_container) if aq_base(orig_container) is not aq_base(parent): notifyContainerModified(parent) ob._postCopy(parent, op=1) # try to make ownership implicit if possible ob.manage_changeOwnershipType(explicit=0) 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. """ 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