def _delObject(self, id, dp=1, suppress_events=False): """Delete an object from this container. Also sends IObjectWillBeRemovedEvent and IObjectRemovedEvent. """ ob = self._getOb(id) compatibilityCall('manage_beforeDelete', ob, ob, self) if not suppress_events: notify(ObjectWillBeRemovedEvent(ob, self, id)) self._objects = tuple([i for i in self._objects if i['id'] != id]) self._delOb(id) # Indicate to the object that it has been deleted. This is # necessary for object DB mount points. Note that we have to # tolerate failure here because the object being deleted could # be a Broken object, and it is not possible to set attributes # on Broken objects. try: ob._v__object_deleted__ = 1 except: pass if not suppress_events: notify(ObjectRemovedEvent(ob, self, id)) notifyContainerModified(self)
def move(self, pos): """ AJAX method to change field position within its schema. The position is relative to the fieldset. """ schema = IEditableSchema(self.schema) fieldname = self.field.__name__ pos = int(pos) ordered_field_ids = [name for (name, field) in sortedFields(self.schema)] for fieldset in self.schema.getTaggedValue(FIELDSETS_KEY): # if we are in a fieldset, pos is the position relative to the fieldset if fieldname in fieldset.fields: old_field_of_position = fieldset.fields[pos] absolute_position = ordered_field_ids.index(old_field_of_position) break else: # in default fieldset, the relative position == the absolute position fieldset = None absolute_position = pos schema.moveField(fieldname, absolute_position) # if field is in a fieldset, also reorder fieldset tagged value ordered_field_ids = [name for (name, field) in sortedFields(self.schema)] if fieldset is not None: fieldset.fields = sorted(fieldset.fields, key=lambda x: ordered_field_ids.index(x)) notifyContainerModified(self.schema) notify(SchemaModifiedEvent(self.aq_parent.aq_parent))
def move(self, pos, fieldset_index): """ AJAX method to change field position within its schema. The position is relative to the fieldset. """ schema = IEditableSchema(self.schema) fieldname = self.field.__name__ pos = int(pos) fieldset_index = int(fieldset_index) fieldset_index -= 1 # index 0 is default fieldset fieldsets = self.schema.queryTaggedValue(FIELDSETS_KEY, []) new_fieldset = fieldset_index >= 0 and fieldsets[ fieldset_index] or None schema.changeFieldFieldset(fieldname, new_fieldset) ordered_field_ids = [info[0] for info in sortedFields(self.schema)] if new_fieldset: old_field_of_position = new_fieldset.fields[pos] new_absolute_position = ordered_field_ids.index( old_field_of_position) else: new_absolute_position = pos # if fieldset changed, update fieldsets schema.moveField(fieldname, new_absolute_position) notifyContainerModified(self.schema) notify(SchemaModifiedEvent(self.__parent__.__parent__))
def mover(self): any_moves = False def do_move(from_container, content): from_identifier = content.getId() to_identifier = self.__make_id('move', from_identifier) content = self.__move( content, from_container, from_identifier, to_identifier) content.manage_changeOwnershipType(explicit=0) notifyContainerModified(from_container) return content content = yield while content is not None: result = self.__verify_moveable(content) if result is None: from_container = aq_parent(aq_inner(content)) if (aq_base(from_container) is not aq_base(self.context)): result = do_move(from_container, content) any_moves = True else: result = ContainerError( _(u"Content already in the target container."), content) content = yield result if any_moves: notifyContainerModified(self.context)
def __setitem__(self, key, value): if not key: raise ValueError("empty names are not allowed") object, event = containedEvent(value, self, key) self._setitemf(key, value) if event: notify(event) notifyContainerModified(self)
def _delObject(self, id): object = self._getOb(id) notify(ObjectWillBeRemovedEvent(object, self, id)) if hasattr(aq_base(object), 'manage_beforeDelete'): object.manage_beforeDelete(object, self) self._delOb(id) notify(ObjectRemovedEvent(object, self, id)) notifyContainerModified(self)
def move(self, pos): """ AJAX method to change field position within its schema. """ schema = IEditableSchema(self.schema) fieldname = self.field.__name__ schema.moveField(fieldname, int(pos)) notifyContainerModified(self.schema) notify(SchemaModifiedEvent(self.aq_parent.aq_parent))
def change(self, fieldset_index): """ AJAX method to change the fieldset of a field """ fieldset_index = int(fieldset_index) fieldsets = self.schema.getTaggedValue(FIELDSETS_KEY) field_name = self.field.__name__ # get current fieldset fieldset_fields = [] current_fieldset = None for fieldset in fieldsets: if field_name in fieldset.fields: current_fieldset = fieldset fieldset_fields.extend(fieldset.fields) # get future fieldset if len(sortedFields(self.schema)) != len(fieldset_fields): # we have a default fieldset fieldset_index -= 1 if fieldset_index >= 0: # the field has not been moved into default next_fieldset = fieldsets[fieldset_index] else: next_fieldset = None # computing new Position, which is the last position of the new fieldset ordered_field_ids = [name for (name, field) in sortedFields(self.schema)] if next_fieldset is None: # if this is the default, new_position = ordered_field_ids.index(fieldset_fields[0]) else: # first we get the first of the fieldsets after the new one new_position = None for fieldset in fieldsets[fieldsets.index(next_fieldset)+1:]: if len(fieldset.fields) > 0: new_position = ordered_field_ids.index(fieldset.fields[0]) - 1 break else: new_position = len(ordered_field_ids) - 1 schema = IEditableSchema(self.schema) schema.moveField(field_name, new_position) # move field if next_fieldset is not None: next_fieldset.fields.append(field_name) if current_fieldset is not None: current_fieldset.fields.remove(field_name) notifyContainerModified(self.schema) notify(SchemaModifiedEvent(self.aq_parent.aq_parent))
def moveObjectsByDelta( self, ids, delta, subset_ids=None, suppress_events=False ): """Move specified sub-objects by delta.""" if isinstance(ids, basestring): ids = (ids,) min_position = 0 objects = list(self._objects) if subset_ids is None: subset_ids = self.getIdsSubset(objects) else: subset_ids = list(subset_ids) # unify moving direction if delta > 0: ids = list(ids) ids.reverse() subset_ids.reverse() counter = 0 for id in ids: old_position = subset_ids.index(id) new_position = max(old_position - abs(delta), min_position) if new_position == min_position: min_position += 1 if not old_position == new_position: subset_ids.remove(id) subset_ids.insert(new_position, id) counter += 1 if counter > 0: if delta > 0: subset_ids.reverse() obj_dict = {} for obj in objects: obj_dict[obj['id']] = obj pos = 0 for i in range(len(objects)): if objects[i]['id'] in subset_ids: try: objects[i] = obj_dict[subset_ids[pos]] pos += 1 except KeyError: raise ValueError('The object with the id "%s" does ' 'not exist.' % subset_ids[pos]) self._objects = tuple(objects) if not suppress_events: notifyContainerModified(self) return counter
def do_move(from_container, content): from_identifier = content.getId() to_identifier = self.__make_id('move', from_identifier) content = self.__move( content, from_container, from_identifier, to_identifier) content.manage_changeOwnershipType(explicit=0) notifyContainerModified(from_container) return content
def set_container_order(self, order): if not isinstance(order, ListType) and \ not isinstance(order, TupleType): raise TypeError('order must be a tuple or a list.') for i in order: if i not in self: raise ValueError('order item not in container.') self._container_order = PersistentList(order) notifyContainerModified(self)
def _setObject(self, id, object, suppress_events=False): if not suppress_events: notify(ObjectWillBeAddedEvent(object, self, id)) self._setOb(id, object) object = self._getOb(id) if hasattr(aq_base(object), 'manage_afterAdd'): object.manage_afterAdd(object, self) if not suppress_events: notify(ObjectAddedEvent(object, self, id)) notifyContainerModified(self) return object
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 moveObjectsByDelta(self, ids, delta, subset_ids=None, # noqa: C901 FIXME suppress_events=False): """Move the specified ids (a sequence, or a single string id) by the given delta (a positive or negative number). By default, this moves the objects within the whole set of sub-items in the context container, but if subset_ids is specified, it gives a subset of ids to consider. Should return the number of objects that changed position. """ # changes for reverse ordering are marked with "# reversed" delta = -delta # reversed order = self._order() pos = self._pos() min_position = 0 if isinstance(ids, basestring): ids = [ids] if subset_ids is None: # delegate to default implementation subset_ids = super(ReversedOrdering, self).idsInOrder() # reversed elif not isinstance(subset_ids, list): subset_ids = list(subset_ids) subset_ids.reverse() # reversed if delta > 0: # unify moving direction ids = reversed(ids) subset_ids.reverse() counter = 0 for id in ids: try: old_position = subset_ids.index(id) except ValueError: continue new_position = max(old_position - abs(delta), min_position) if new_position == min_position: min_position += 1 if not old_position == new_position: subset_ids.remove(id) subset_ids.insert(new_position, id) counter += 1 if counter > 0: if delta > 0: subset_ids.reverse() idx = 0 for i in range(len(order)): if order[i] in subset_ids: id = subset_ids[idx] try: order[i] = id pos[id] = i idx += 1 except KeyError: raise ValueError('No object with id "{0}" exists.'.format(id)) if not suppress_events: notifyContainerModified(self.context) return counter
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 __iter__(self): # Store positions in a mapping containing an id to position mapping for # each parent path {parent_path: {item_id: item_pos}}. positions_mapping = {} for item in self.previous: keys = item.keys() pathkey = self.pathkey(*keys)[0] poskey = self.poskey(*keys)[0] if not (pathkey and poskey): yield item continue item_id = item[pathkey].split('/')[-1] parent_path = '/'.join(item[pathkey].split('/')[:-1]) if parent_path not in positions_mapping: positions_mapping[parent_path] = {} positions_mapping[parent_path][item_id] = item[poskey] yield item # Set positions on every parent for path, positions in positions_mapping.items(): # Normalize positions ordered_keys = sorted(positions.keys(), key=lambda x: positions[x]) normalized_positions = {} for pos, key in enumerate(ordered_keys): normalized_positions[key] = pos # TODO: After the new collective.transmogrifier release (>1.4), the # utils.py provides a traverse method. # from collective.transmogrifier.utils import traverse # parent = traverse(self.context, path) parent = self.context.unrestrictedTraverse(path.lstrip('/')) if not parent: continue parent_base = aq_base(parent) if hasattr(parent_base, 'getOrdering'): ordering = parent.getOrdering() # Only DefaultOrdering of p.folder is supported if (not hasattr(ordering, '_order') and not hasattr(ordering, '_pos')): continue order = ordering._order() pos = ordering._pos() order.sort(key=lambda x: normalized_positions.get(x, pos.get(x, self.default_pos))) for i, id_ in enumerate(order): pos[id_] = i notifyContainerModified(parent)
def _setObject(self, id, object, roles=None, user=None, set_owner=1, suppress_events=False): """Set an object into this container. Also sends IObjectWillBeAddedEvent and IObjectAddedEvent. """ ob = object # better name, keep original function signature v = self._checkId(id) if v is not None: id = v # If an object by the given id already exists, remove it. makeKeyFromId = IKeyIdSubobjectSupport(self).makeKeyFromId key = makeKeyFromId(id) query = select([self.item_class.key], self.item_class.key == key) cursor = self.saSession.execute(query) try: rows = cursor.fetchall() if len(rows): self._delObject(id) except: pass if not suppress_events: notify(ObjectWillBeAddedEvent(ob, self, id)) self._setOb(id, ob) ob = self._getOb(id) if set_owner: # TODO: eventify manage_fixupOwnershipAfterAdd # This will be called for a copy/clone, or a normal _setObject. ob.manage_fixupOwnershipAfterAdd() # Try to give user the local role "Owner", but only if # no local roles have been set on the object yet. if getattr(ob, '__ac_local_roles__', _marker) is None: user = getSecurityManager().getUser() if user is not None: userid = user.getId() if userid is not None: ob.manage_setLocalRoles(userid, ['Owner']) if not suppress_events: notify(ObjectAddedEvent(ob, self, id)) notifyContainerModified(self) OFS.subscribers.compatibilityCall('manage_afterAdd', ob, ob, self) return id
def moveObjectsByDelta( self, ids, delta, subset_ids=None, suppress_events=False ): """ see interfaces.py """ order = self._order() pos = self._pos() min_position = 0 if isinstance(ids, basestring): ids = [ids] if subset_ids is None: subset_ids = self.idsInOrder() elif not isinstance(subset_ids, list): subset_ids = list(subset_ids) if delta > 0: # unify moving direction ids = reversed(ids) subset_ids.reverse() counter = 0 for obj_id in ids: try: old_position = subset_ids.index(obj_id) except ValueError: continue new_position = max(old_position - abs(delta), min_position) if new_position == min_position: min_position += 1 if not old_position == new_position: subset_ids.remove(obj_id) subset_ids.insert(new_position, obj_id) counter += 1 if counter > 0: if delta > 0: subset_ids.reverse() idx = 0 for i in range(len(order)): if order[i] not in subset_ids: continue obj_id = subset_ids[idx] try: order[i] = obj_id pos[obj_id] = i idx += 1 except KeyError: raise ValueError( 'No object with id "{0:s}" exists.'.format(obj_id) ) if not suppress_events: notifyContainerModified(self.context) return counter
def _delObject(self, id, dp=1, suppress_events=False): ob = self._getOb(id) compatibilityCall('manage_beforeDelete', ob, ob, self) if not suppress_events: notify(ObjectWillBeRemovedEvent(ob, self, id)) self._delOb(id) if not suppress_events: notify(ObjectRemovedEvent(ob, self, id)) notifyContainerModified(self)
def add(self, new_fieldset): schema = self.context.schema fieldsets = schema.getTaggedValue(FIELDSETS_KEY) for fieldset in fieldsets: if fieldset.__name__ == new_fieldset.__name__: raise WidgetActionExecutionError('__name__', Invalid(_(u'Please select a fieldset name that is not already used.'))) fieldsets.append(new_fieldset) schema.setTaggedValue(FIELDSETS_KEY, fieldsets) notifyContainerModified(schema) notify(SchemaModifiedEvent(self.context)) self.status = _(u"Fieldset added successfully.")
def change(self, fieldset_index): """ AJAX method to change the fieldset of a field """ schema = self.context.field.interface field_name = self.context.field.__name__ fieldset = get_fieldset_from_index(schema, fieldset_index) position = new_field_position(schema, fieldset_index) editable_schema = IEditableSchema(schema) editable_schema.changeFieldFieldset(field_name, fieldset) editable_schema.moveField(field_name, position) notifyContainerModified(schema) notify(SchemaModifiedEvent(self.__parent__.__parent__))
def deleter(self): to_delete = [] container_ids = set(self.context.objectIds()) try: protected = self.context._reserved_names except: protected = () content = yield while content is not None: try: content.is_deletable() except ContentError as error: result = error else: content_id = content.getId() if (content_id in container_ids and content_id not in protected and aq_base(self.context) is aq_base(aq_parent(content))): to_delete.append((content_id, content)) result = content else: result = ContentError( _(u"Cannot delete content."), content) content = yield result # Event for identifier, content in to_delete: compatibilityCall('manage_beforeDelete', content, content, self.context) notify(ObjectWillBeRemovedEvent(content, self.context, identifier)) # Delete for identifier, content in to_delete: self.context._objects = tuple( [i for i in self.context._objects if i['id'] != identifier]) self.context._delOb(identifier) try: content._v__object_deleted__ = 1 except: pass # Event for identifier, content in to_delete: notify(ObjectRemovedEvent(content, self.context, identifier)) if to_delete: notifyContainerModified(self.context)
def updateOrder(self, order): """Impose a new order on the items in this container. Items in this container are, by default, returned in the order in which they were inserted. To change the order, provide an argument to this method that is a sequence containing every key already in the container, but in a new order. """ if set(order) != set(self._order): raise ValueError("Incompatible key set.") self._order = PersistentList() self._order.extend(order) notifyContainerModified(self)
def renamer(self): any_renames = False data = yield while data is not None: content, to_identifier, to_title = data result = None # Rename identifier from_identifier = content.getId() if to_identifier is not None and from_identifier != to_identifier: result = self.__verify_moveable(content) if result is None: try: ISilvaNameChooser(self.context).checkName( to_identifier, content) except ContentError as e: result = ContainerError(reason=e.reason, content=content) if result is None: content = self.__move( content, self.context, from_identifier, to_identifier) any_renames = True # Update title if to_title is not None: if not isinstance(to_title, unicode): to_title = to_title.decode('utf-8') editable = content.get_editable() if editable is None: if result is None: result = ContentError( _(u"There is no editable version to set the title on."), content) elif editable.get_title() != to_title: try: editable.set_title(to_title) except ContentError as error: result = error if result is None: result = content data = yield result if any_renames: notifyContainerModified(self.context)
def manage_delObjects(self, ids=[], REQUEST=None): """Delete reflected files or directories The objects specified in 'ids' get deleted. This emulates the ObjectManager interface enough to support deletion in Plone only. When file removal fails, errors are communicated through the return of the successful ids and the IStatusMessage utility """ if type(ids) is StringType: ids = [ids] if not ids: raise ValueError('No items specified') # To avoid inconsistencies, first test file availability for id in ids: if not self.has_key(id): raise KeyError(id) notify(ObjectWillBeRemovedEvent(self[id], self, id)) problem_ids = [] path = self.getFilesystemPath() for id in ids: subpath = os.path.join(path, id) ob = self[id] try: if os.path.isdir(subpath): shutil.rmtree(subpath) else: os.unlink(subpath) notify(ObjectRemovedEvent(ob, self, id)) except OSError: problem_ids.append(id) if problem_ids: sm = IStatusMessage(getattr(self, 'REQUEST', None), None) if sm is not None: sm.addStatusMessage( 'Failed to remove some files: %s' % problem_ids, 'stop') if set(ids) - set(problem_ids): indexview = self.unrestrictedTraverse('@@index') indexview.index() notifyContainerModified(self) return problem_ids or None # None expected by webdav on success
def _setObject(self, id, object, roles=None, user=None, set_owner=1, suppress_events=False): """Set an object into this container. Also sends IObjectWillBeAddedEvent and IObjectAddedEvent. """ ob = object # better name, keep original function signature v = self._checkId(id) if v is not None: id = v t = getattr(ob, 'meta_type', None) # If an object by the given id already exists, remove it. for object_info in self._objects: if object_info['id'] == id: self._delObject(id) break if not suppress_events: notify(ObjectWillBeAddedEvent(ob, self, id)) self._objects = self._objects + ({'id': id, 'meta_type': t},) self._setOb(id, ob) ob = self._getOb(id) if set_owner: # TODO: eventify manage_fixupOwnershipAfterAdd # This will be called for a copy/clone, or a normal _setObject. ob.manage_fixupOwnershipAfterAdd() # Try to give user the local role "Owner", but only if # no local roles have been set on the object yet. if getattr(ob, '__ac_local_roles__', _marker) is None: user = getSecurityManager().getUser() if user is not None: userid = user.getId() if userid is not None: ob.manage_setLocalRoles(userid, ['Owner']) if not suppress_events: notify(ObjectAddedEvent(ob, self, id)) notifyContainerModified(self) compatibilityCall('manage_afterAdd', ob, ob, self) return id
def moveObjectsByDelta(self, ids, delta, subset_ids=None, suppress_events=False): """ see interfaces.py """ min_position = 0 if isinstance(ids, basestring): ids = [ids] if subset_ids is None: subset_ids = self.idsInOrder(onlyOrderables=True) elif not isinstance(subset_ids, list): subset_ids = list(subset_ids) if delta > 0: # unify moving direction ids = reversed(ids) subset_ids.reverse() counter = 0 for id in ids: try: old_position = subset_ids.index(id) except ValueError: continue new_position = max(old_position - abs(delta), min_position) if new_position == min_position: min_position += 1 if not old_position == new_position: subset_ids.remove(id) subset_ids.insert(new_position, id) counter += 1 if counter > 0: if delta > 0: subset_ids.reverse() idx = 0 for i, value in enumerate(self.order): if value in subset_ids: id = subset_ids[idx] try: self.order[i] = id idx += 1 except KeyError: raise ValueError('No object with id "%s" exists.' % id) if idx > 0: self.context._p_changed = True # the order was changed if not suppress_events: notifyContainerModified(self.context) return counter
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 replace_in_parent(self, old_object, new_object): parent = aq_parent(aq_inner(old_object)) new_object = aq_base(new_object) parent._delOb(old_object.id) objects = [info for info in parent._objects if info['id'] != new_object.id] objects = tuple(objects) objects += ({'id': new_object.id, 'meta_type': getattr(new_object, 'meta_type', None)},) parent._objects = objects parent._setOb(new_object.id, new_object) notifyContainerModified(parent) if hasattr(aq_base(parent), '_tree'): del parent._tree[new_object.id] parent._tree[new_object.id] = new_object return parent._getOb(new_object.id)
def _constructInstance(self, container, id, *args, **kw): """Build a bare instance of the appropriate type. Does not do any security checks. """ constructor = self.restrictedTraverse( self.constructor_path ) # make sure ownership is explicit before switching the context if not hasattr( aq_base(constructor), '_owner' ): constructor._owner = aq_get(constructor, '_owner') # Rewrap to get into container's context. constructor = aq_base(constructor).__of__( container ) id = str(id) obj = constructor(container, id, *args, **kw) if hasattr(obj, '_setPortalTypeName'): obj._setPortalTypeName(self.getId()) notify(ObjectAddedEvent(obj, container, obj.getId())) notifyContainerModified(container) return obj
def updateOrder(self, order): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc['foo'] = 'bar' >>> oc['baz'] = 'quux' >>> oc['zork'] = 'grue' >>> oc.keys() ['foo', 'baz', 'zork'] >>> oc.updateOrder(['baz', 'foo', 'zork']) >>> oc.keys() ['baz', 'foo', 'zork'] >>> oc.updateOrder(['baz', 'zork', 'foo']) >>> oc.keys() ['baz', 'zork', 'foo'] >>> oc.updateOrder(['baz', 'zork', 'foo']) >>> oc.keys() ['baz', 'zork', 'foo'] >>> oc.updateOrder(('zork', 'foo', 'baz')) >>> oc.keys() ['zork', 'foo', 'baz'] >>> oc.updateOrder(['baz', 'zork']) Traceback (most recent call last): ... ValueError: Incompatible key set. >>> oc.updateOrder(['foo', 'bar', 'baz', 'quux']) Traceback (most recent call last): ... ValueError: Incompatible key set. >>> oc.updateOrder(1) Traceback (most recent call last): ... TypeError: order must be a tuple or a list. >>> oc.updateOrder('bar') Traceback (most recent call last): ... TypeError: order must be a tuple or a list. >>> oc.updateOrder(['baz', 'zork', 'quux']) Traceback (most recent call last): ... ValueError: Incompatible key set. >>> del oc['baz'] >>> del oc['zork'] >>> del oc['foo'] >>> len(oc) 0 """ if not isinstance(order, list) and \ not isinstance(order, tuple): raise TypeError('order must be a tuple or a list.') if len(order) != len(self._order): raise ValueError("Incompatible key set.") was_dict = {} will_be_dict = {} new_order = PersistentList() for i in range(len(order)): was_dict[self._order[i]] = 1 will_be_dict[order[i]] = 1 new_order.append(order[i]) if will_be_dict != was_dict: raise ValueError("Incompatible key set.") self._order = new_order notifyContainerModified(self)
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: raise CopyError('Clipboard Error') from 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, 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 manage_renameObject(self, id, new_id, REQUEST=None): """Rename a particular sub-object. """ try: self._checkId(new_id) except: raise CopyError(MessageDialog( title='Invalid Id', message=sys.exc_info()[1], action ='manage_main')) ob = self._getOb(id) if ob.wl_isLocked(): raise ResourceLockedError('Object "%s" is locked via WebDAV' % ob.getId()) if not isRenameable(ob): raise CopyError(eNotSupported % escape(id)) self._verifyObjectPaste(ob) try: ob._notifyOfCopyTo(self, op=1) except ConflictError: raise except: raise CopyError(MessageDialog( title="Rename Error", message=sys.exc_info()[1], action ='manage_main')) 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, update_menu=1) return None
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 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: 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: 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 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. """ 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 = 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) 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: 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, update_menu=1, cb_dataValid=0) return result
def updateOrder(self, order): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc['foo'] = 'bar' >>> oc['baz'] = 'quux' >>> oc['zork'] = 'grue' >>> oc.keys() ['foo', 'baz', 'zork'] >>> oc.updateOrder(['baz', 'foo', 'zork']) >>> oc.keys() ['baz', 'foo', 'zork'] >>> oc.updateOrder(['baz', 'zork', 'foo']) >>> oc.keys() ['baz', 'zork', 'foo'] >>> oc.updateOrder(['baz', 'zork', 'foo']) >>> oc.keys() ['baz', 'zork', 'foo'] >>> oc.updateOrder(('zork', 'foo', 'baz')) >>> oc.keys() ['zork', 'foo', 'baz'] >>> oc.updateOrder(['baz', 'zork']) Traceback (most recent call last): ... ValueError: Incompatible key set. >>> oc.updateOrder(['foo', 'bar', 'baz', 'quux']) Traceback (most recent call last): ... ValueError: Incompatible key set. >>> oc.updateOrder(1) Traceback (most recent call last): ... TypeError: order must be a tuple or a list. >>> oc.updateOrder('bar') Traceback (most recent call last): ... TypeError: order must be a tuple or a list. >>> oc.updateOrder(['baz', 'zork', 'quux']) Traceback (most recent call last): ... ValueError: Incompatible key set. >>> del oc['baz'] >>> del oc['zork'] >>> del oc['foo'] >>> len(oc) 0 """ if not isinstance(order, (list, tuple)): raise TypeError('order must be a tuple or a list.') if len(order) != len(self._order): raise ValueError("Incompatible key set.") order = [checkAndConvertName(x) for x in order] if frozenset(order) != frozenset(self._order): raise ValueError("Incompatible key set.") if order == self._order: return self._order[:] = order notifyContainerModified(self)