def test_replace(events): """If we try to replace an item without deleting it first, we'll get an error. """ container = {} # We create a first item item = Item() setitem(container, container.__setitem__, u'c', item) # We try to override with pytest.raises(KeyError): setitem(container, container.__setitem__, u'c', []) # We have to delete to replace a key del container[u'c'] setitem(container, container.__setitem__, u'c', []) assert len(events) == 4 event = events.popleft() assert IObjectAddedEvent.providedBy(event) event = events.popleft() assert IObjectModifiedEvent.providedBy(event) event = events.popleft() assert IObjectAddedEvent.providedBy(event) event = events.popleft() assert IObjectModifiedEvent.providedBy(event)
def moveIntIdSubscriber(ob, event): """A subscriber to ObjectMovedEvent Updates the stored path for the object in all the unique id utilities. """ if IObjectRemovedEvent.providedBy(event) or \ IObjectAddedEvent.providedBy(event): return utilities = tuple(getAllUtilitiesRegisteredFor(IIntIds)) if utilities: key = None try: key = IKeyReference(ob, None) except NotYet: # @@ temporary fix pass # Update objects that adapt to key reference if key is not None: for utility in utilities: try: uid = utility.getId(ob) utility.refs[uid] = key utility.ids[key] = uid except KeyError: pass
def pstsubaction_moved(obj, event): """ """ if IObjectAddedEvent.providedBy( event): # Already managed in above subscriber return if event.newParent == event.oldParent and event.newName != event.oldName: # it's not a move but a rename return # When deleting an action with a subaction, we pass here but the event context is the action !!!! if IObjectRemovedEvent.providedBy(event) and obj != event.object: return # Move of delete # we manage the flag on the old pstaction to indicate a subaction presence if not event.oldParent.listFolderContents( {'object_provides': IPSTSubAction.__identifier__}): set_to_annotation('imio.project.pst.has_subactions', False, obj=event.oldParent) # move into the moved subaction any existing task found in its new parent action if event.newParent: if getattr(obj, '_link_portal_type', '') == 'subaction_link': raise Invalid( "You cannot move a subaction link. Create a new one !") tasks = event.newParent.listFolderContents({'portal_type': 'task'}) for task in tasks: api.content.move(task, obj) # we set a flag on the pstaction to indicate a subaction presence set_to_annotation('imio.project.pst.has_subactions', True, obj=event.newParent)
def transitionMovedContent(context, action): """Transition objects when they have been moved.""" if IObjectAddedEvent.providedBy(action): return if IObjectRemovedEvent.providedBy(action): return wf = getattr(context, "portal_workflow", None) if getattr(action.oldParent, "getProjectRoomState", None) is not None: if getattr(action.newParent, "getProjectRoomState", None) is None: # If an object is moved out of a project room, take ownership. becomeOwner(context) restoreOwnerPermissions(context) # If it uses the intranett_workflow, also hide it. if "intranett_workflow" in wf.getChainFor(context): wf.doActionFor(context, "hide") return else: # If an object is renamed inside a project room or moved between # project rooms, reapply removeOwnerPermissions. if wf.getInfoFor(context, "review_state") == "published": action.action = "autopublish" # Abuse existing event removeOwnerPermissions(context, action) return # In all other cases the automatic transitions do the right thing. try: wf.doActionFor(context, "auto") except WorkflowException: pass # This workflow is not ProjectRoom aware.
def transitionMovedContent(context, action): """Transition objects when they have been moved.""" if IObjectAddedEvent.providedBy(action): return if IObjectRemovedEvent.providedBy(action): return wf = getattr(context, 'portal_workflow', None) if getattr(action.oldParent, 'getProjectRoomState', None) is not None: if getattr(action.newParent, 'getProjectRoomState', None) is None: # If an object is moved out of a project room, take ownership. becomeOwner(context) restoreOwnerPermissions(context) # If it uses the intranett_workflow, also hide it. if 'intranett_workflow' in wf.getChainFor(context): wf.doActionFor(context, "hide") return else: # If an object is renamed inside a project room or moved between # project rooms, reapply removeOwnerPermissions. if wf.getInfoFor(context, 'review_state') == 'published': action.action = 'autopublish' # Abuse existing event removeOwnerPermissions(context, action) return # In all other cases the automatic transitions do the right thing. try: wf.doActionFor(context, "auto") except WorkflowException: pass # This workflow is not ProjectRoom aware.
def test_move_event(events): """If the item had a parent or name (as in a move or rename), we generate a move event, rather than an add event. """ container = {} # We create a first item item = Item() setitem(container, container.__setitem__, u'c1', item) # Add operation are "moved" events. assert len(events) == 2 event = events.popleft() assert IObjectAddedEvent.providedBy(event) event = events.popleft() assert IObjectModifiedEvent.providedBy(event) assert isinstance(event, ContainerModifiedEvent) # We created an item already contained. item = Item() item.__parent__, item.__name__ = container, 'c2' setitem(container, container.__setitem__, u'c2', item) assert not len(events) # We now rewrite 'c2' under another name # Thus, we created a move event : +1 modification +1 move. setitem(container, container.__setitem__, u'c3', item) assert len(container) == 3 event = events.popleft() assert IObjectMovedEvent.providedBy(event)
def set_what(self, value): if IObjectAddedEvent.providedBy(value): self.data["what"] = "added" self.event = value elif IObjectRemovedEvent.providedBy(value): self.data["what"] = "removed" self.event = value
def threadmoved(conv, event): """ send email notification when a thread was moved """ if IObjectRemovedEvent.providedBy(event) or IObjectAddedEvent.providedBy(event): return n = queryUtility(INotifier) n.thread_moved(conv)
def index_moved_content(content, event): """We index all added content (due to a move). """ if getattr(content, "__initialization__", False): return if not IObjectAddedEvent.providedBy(event) and not IObjectRemovedEvent.providedBy(event): ICataloging(content).index()
def handleComentedObject(ob, event): if IObjectAddedEvent.providedBy(event): catalog_comments(ob) elif IObjectMovedEvent.providedBy(event): if event.newParent is not None: catalog_comments(ob) elif IObjectWillBeMovedEvent.providedBy(event): if event.oldParent is not None: uncatalog_comments(ob)
def index_moved_content(content, event): """We index all added content (due to a move). """ if getattr(content, '__initialization__', False): return if (not IObjectAddedEvent.providedBy(event) and not IObjectRemovedEvent.providedBy(event)): ICataloging(content).index()
def threadmoved(conv, event): """ Send email notification when a thread was moved """ if IObjectRemovedEvent.providedBy(event) or IObjectAddedEvent.providedBy(event): return n = queryUtility(INotifier) n.thread_moved(conv) s = queryUtility(ISubscriptions) s.move_subscribers(event)
def forwardevent(obj, event): """ Trigger an ObjectMovedOrRenamedEvent only if it's not an ObjectAddedEvent or an ObjectRemovedEvent""" if IObjectAddedEvent.providedBy(event) \ or IObjectRemovedEvent.providedBy(event) \ or IObjectMovedOrRenamedEvent.providedBy(event): return notify( ObjectMovedOrRenamedEvent(event.object, event.oldParent, event.oldName, event.newParent, event.newName))
def related_change_on_moved(obj, event): """ Set local roles on related objects after moving """ if IObjectAddedEvent.providedBy(event) or IObjectRemovedEvent.providedBy(event): # not move return if event.oldParent and event.newParent and event.oldParent == event.newParent: # rename return (fti_config, fti) = fti_configuration(obj) if 'static_config' not in fti_config: return related_role_addition(obj, get_state(obj), fti_config)
def todo_set_role(obj, evt): """ update role for assignees """ todo = ITodo(obj) assignee = todo.assignee if not assignee and IObjectAddedEvent.providedBy(evt): assignee = obj.REQUEST.get('assignee') if assignee: obj.manage_addLocalRoles(assignee, [ "Assignee", ])
def moved_event(event): # only execute moved event if it's not a added or removed event since # those are handled elsewhere and they base off of this event class if (IObjectAddedEvent.providedBy(event) or IObjectRemovedEvent.providedBy(event)): return obj = event.object if not (IContentish.providedBy(obj) or IComment.providedBy(obj)): return execute_event(event)
def forwardevent(obj, event): """ Trigger an ObjectMovedOrRenamedEvent only if it's not an ObjectAddedEvent or an ObjectRemovedEvent""" if IObjectAddedEvent.providedBy(event) \ or IObjectRemovedEvent.providedBy(event) \ or IObjectMovedOrRenamedEvent.providedBy(event): return notify(ObjectMovedOrRenamedEvent(event.object, event.oldParent, event.oldName, event.newParent, event.newName))
def test_interface_providing(events): """If the object implements `ILocation`, but not `IContained`, set it's `__parent__` and `__name__` attributes *and* declare that it implements `IContained`. """ container = {} item = Location() assert not IContained.providedBy(item) setitem(container, container.__setitem__, u'l', item) assert container[u'l'] is item assert item.__parent__ is container assert item.__name__ == u'l' assert IContained.providedBy(item) # We get added and modification events: assert len(events) == 2 event = events.popleft() assert IObjectAddedEvent.providedBy(event) event = events.popleft() assert IObjectModifiedEvent.providedBy(event) # If the object doesn't even implement `ILocation`, put a # `ContainedProxy` around it: item = [] setitem(container, container.__setitem__, u'i', item) assert container[u'i'] == [] assert not container[u'i'] is item item = container[u'i'] assert item.__parent__ is container assert item.__name__ == u'i' assert IContained.providedBy(item) event = events.popleft() assert IObjectAddedEvent.providedBy(event) event = events.popleft() assert IObjectModifiedEvent.providedBy(event)
def document_moved_or_added(context, event): if IObjectRemovedEvent.providedBy(event): return if context.REQUEST.get(DISABLE_DOCPROPERTY_UPDATE_FLAG): return if IObjectAddedEvent.providedBy(event): # Be strict when adding new documents to GEVER, lenient on moving # ones that already made it into the system _update_docproperties(context, raise_on_error=True) else: _update_docproperties(context, raise_on_error=False)
def related_change_on_moved(obj, event): """ Set local roles on related objects after moving """ if IObjectAddedEvent.providedBy(event) or IObjectRemovedEvent.providedBy(event): # not move return if event.oldParent and event.newParent and event.oldParent == event.newParent: # rename return (fti_config, fti) = fti_configuration(obj) if not fti_config: return for (name, f) in get_localrole_fields(fti): if name not in fti_config: continue related_role_addition(obj, get_state(obj), fti_config[name], name)
def handle_workspace_move_or_rename(context, event): if IObjectRemovedEvent.providedBy(event): return # not a move with new/old, but a removal -- handled elsewhere if IObjectAddedEvent.providedBy(event): return # not an add, but a move of existing site = getSite() pasgroups = ISiteMembers(site).groups roster = WorkspaceRoster(context) for workgroup in roster.groups.values(): groupname, title = workgroup.pas_group() if groupname not in pasgroups: pasgroups.add(groupname, title=title) else: pasgroups.get(groupname).title = _u(title)
def related_change_on_moved(obj, event): """ Set local roles on related objects after moving """ if IObjectAddedEvent.providedBy(event) or IObjectRemovedEvent.providedBy( event): # not move return if event.oldParent and event.newParent and event.oldParent == event.newParent: # rename return (fti_config, fti) = fti_configuration(obj) if not fti_config: return for (name, f) in get_localrole_fields(fti): if name not in fti_config: continue related_role_addition(obj, get_state(obj), fti_config[name], name)
def purgeOnMovedOrRemoved(object, event): request = getRequest() confirmed_delete = ('delete_confirmation' in request.URL and request.REQUEST_METHOD == 'POST' and 'form.submitted' in request.form) if IObjectRemovedEvent.providedBy(event) and not confirmed_delete: # ignore extra delete events return # Don't purge when added if IObjectAddedEvent.providedBy(event): return if isPurged(object) and 'portal_factory' not in request.URL: notify(Purge(object)) parent = object.getParentNode() if parent: notify(Purge(parent))
def update_budget_splits(obj, event=None): base_obj = obj._link if base_hasattr(obj, '_link_portal_type') else obj expected_objects = {base_obj} if IObjectAddedEvent.providedBy(event): expected_objects.add(obj) for rel in base_obj.back_references(): expected_objects.add(rel) if getattr(base_obj, 'budget_split', None) is None: base_obj.budget_split = [] expected_line_uids = [ expected_obj.UID() for expected_obj in expected_objects ] existing_line_uids = [line['uid'] for line in base_obj.budget_split] # remove old lines for uid_to_remove in set(existing_line_uids).difference( expected_line_uids): line_to_remove = [ line for line in base_obj.budget_split if line['uid'] == uid_to_remove ][0] base_obj.budget_split.remove(line_to_remove) # add new lines (100 % for base object, 0 % for links) for uid_to_add in set(expected_line_uids).difference(existing_line_uids): if obj.UID() == uid_to_add: object_to_add = obj else: object_to_add = api.content.get(UID=uid_to_add) percentage = 0.0 if base_hasattr(object_to_add, '_link_portal_type') else 100.0 title = reference_numbers_title(object_to_add) base_obj.budget_split.append({ 'uid': uid_to_add, 'percentage': percentage, 'title': title, }) # fix percentages if total isn't equal to 100.0 current_percentages = sum( [line['percentage'] for line in base_obj.budget_split]) if current_percentages != 100.0: corrective_coefficient = 100.0 / current_percentages for line in base_obj.budget_split: line['percentage'] *= corrective_coefficient
def object_moved(context, event): # Since IObjectAddedEvent subclasses IObjectMovedEvent this event # handler is also called for IObjectAddedEvent but we should not # do anything in this case. if IObjectAddedEvent.providedBy(event): return # Skip automatically renamed objects during copy & paste process. if ICopyPasteRequestLayer.providedBy(getRequest()): return title = _(u'label_object_moved', default=u'Object moved: ${title}', mapping={'title': context.title_or_id()}) journal_entry_factory(context.aq_inner.aq_parent, OBJECT_MOVED_EVENT, title) return
def object_moved(context, event): # Since IObjectAddedEvent subclasses IObjectMovedEvent this event # handler is also called for IObjectAddedEvent but we should not # do anything in this case. if IObjectAddedEvent.providedBy(event): return # Skip automatically renamed objects during copy & paste process. if ICopyPasteRequestLayer.providedBy(getRequest()): return title = _(u'label_object_moved', default=u'Object moved: ${title}', mapping={'title': context.title_or_id()} ) journal_entry_factory( context.aq_inner.aq_parent, OBJECT_MOVED_EVENT, title) return
def update_todo_state(obj, event): """ After editing a Todo item, set the workflow state to either Open or Planned depending on the state of the Case. Also update access permissions on the Case, which might have changed due to a change in assignment. """ # Do nothing on copy if IObjectCopiedEvent.providedBy(event): return if IObjectAddedEvent.providedBy(event): # This attribute is set when copying from a template # handle_case_workflow_state_changed will take care of everything if getattr(event.newParent, '_v_skip_update_todo_state', None): return obj.set_appropriate_state() obj.reindexObject() parent = parent_workspace(obj) if ICase.providedBy(parent): parent.update_case_access()
def get_what_info(self, event): #Archetypes if IObjectEditedEvent.providedBy(event): return self.get_object_modified_info(event) elif IObjectInitializedEvent.providedBy(event): return self.get_object_modified_info(event) #plone elif IConfigurationChangedEvent.providedBy(event): return self.get_configuration_changed_info(event) # #plone.app.form (formlib) # elif IEditSavedEvent.providedBy(event): # return 'editsaved' # #plone.app.iterate # elif ICheckinEvent.providedBy(event): # return 'checkedin' # elif ICheckoutEvent.providedBy(event): # return 'checkedout' # elif IWorkingCopyDeletedEvent.providedBy(event): # return 'workingcopydeleted' # #plone.app.registry elif IRecordModifiedEvent.providedBy(event): return self.get_record_modified_info(event) # DCWorkflow elif ITransitionEvent.providedBy(event): return self.get_transition_info(event) # CMFCore elif IActionSucceededEvent.providedBy(event): return self.get_action_succeed_info(event) # zope elif IObjectCopiedEvent.providedBy(event): return self.get_object_copied_info(event) elif IObjectMovedEvent.providedBy(event): return self.get_object_moved_info(event) elif IObjectAddedEvent.providedBy(event): return self.get_object_moved_info(event) elif IObjectRemovedEvent.providedBy(event): return self.get_object_moved_info(event)
def __call__(self): req = getRequest() if req.environ.get('disable.auditlog', False): return True event = self.event obj = event.object # order of those checks is important since some interfaces # base off the others rule = inspect.stack()[1][0].f_locals.get('self', None) registry = getUtility(IRegistry) trackWorkingCopies = registry['collective.auditlog.interfaces.IAuditLogSettings.trackworkingcopies'] # noqa if not self.canExecute(rule, req): return True # cut out early, we can't do this event data = { 'info': '' } if IPloneFormGenField.providedBy(obj): # if ploneformgen field, use parent object for modified data data['field'] = obj.getId() obj = aq_parent(obj) # the order of those interface checks matters since some interfaces # inherit from others if IObjectRemovedEvent.providedBy(event): # need to keep track of removed events so it doesn't get called # more than once for each object action = 'removed' elif (IObjectInitializedEvent.providedBy(event) or IObjectCreatedEvent.providedBy(event) or IObjectAddedEvent.providedBy(event)): action = 'added' elif IObjectMovedEvent.providedBy(event): # moves can also be renames. Check the parent object if event.oldParent == event.newParent: if rule is None or 'Rename' in rule.rule.title: info = {'previous_id': event.oldName} data['info'] = json.dumps(info) action = 'rename' else: # cut out here, double action for this event return True else: if rule is None or 'Moved' in rule.rule.title: parent_path = '/'.join(event.oldParent.getPhysicalPath()) previous_location = parent_path + '/' + event.oldName info = {'previous_location': previous_location} data['info'] = json.dumps(info) action = 'moved' else: # step out immediately since this could be a double action return True elif IObjectModifiedEvent.providedBy(event): action = 'modified' elif IActionSucceededEvent.providedBy(event): info = {'transition': event.action, 'comments': self.get_history_comment()} data['info'] = json.dumps(info) action = 'workflow' elif IObjectClonedEvent.providedBy(event): action = 'copied' elif ICheckinEvent.providedBy(event): info = {'message': event.message} data['info'] = json.dumps(info) action = 'checked in' req.environ['disable.auditlog'] = True data['working_copy'] = '/'.join(obj.getPhysicalPath()) obj = event.baseline elif IBeforeCheckoutEvent.providedBy(event): action = 'checked out' req.environ['disable.auditlog'] = True elif ICancelCheckoutEvent.providedBy(event): action = 'cancel check out' req.environ['disable.auditlog'] = True data['working_copy'] = '/'.join(obj.getPhysicalPath()) obj = event.baseline elif IUserLoggedInEvent.providedBy(event): action = 'logged in' info = {'user': event.object.getUserName()} data['info'] = json.dumps(info) elif IUserLoggedOutEvent.providedBy(event): action = 'logged out' else: logger.warn('no action matched') return True if IWorkingCopy.providedBy(obj): # if working copy, iterate, check if Track Working Copies is # enabled if trackWorkingCopies: # if enabled in control panel, use original object and move # working copy path to working_copy data['working_copy'] = '/'.join(obj.getPhysicalPath()) relationships = obj.getReferences( WorkingCopyRelation.relationship) # check relationships, if none, something is wrong, not logging # action if len(relationships) > 0: obj = relationships[0] else: return True else: # if not enabled, we only care about checked messages if 'check' not in action: return True data.update(getObjectInfo(obj)) data['action'] = action addLogEntry(obj, data) return True
def __call__(self): event = self.event service_to_ping = self.element.service_to_ping obj = self.event.object container = obj.getParentNode() noasync_msg = 'No instance for async operations was defined.' def pingCRSDS(service_to_ping, obj_url, create): """ Ping the CR/SDS service """ options = {} options['service_to_ping'] = service_to_ping options['obj_url'] = self.sanitize_url(obj_url) options['create'] = create # Use RabbitMQ if available if self.rabbit_config: options['create'] = 'create' if options.get( 'create', False) else 'update' return ping_RabbitMQ(options) # Use zc.async if available if async_service is None: logger.warn("Can't pingCRSDS, plone.app.async not installed!") return queue = async_service.getQueues()[''] try: async_service.queueJobInQueue( queue, ('rdf',), ping_CRSDS, self.context, options ) except ComponentLookupError: logger.info(noasync_msg) def pingCRSDS_backrel(service_to_ping, obj, create): """ Ping backward relations """ if hasattr(obj, 'getBRefs'): back_relations = obj.getBRefs('relatesTo') else: back_relations = [o.to_object for o in getattr(obj, 'relatedItems') ] for rel in back_relations: if rel is not None: obj_url = "%s/@@rdf" % rel.absolute_url() pingCRSDS(service_to_ping, obj_url, create) def pingCRSDS_children(service_to_ping, obj, create): """ Ping all sub-objects """ if obj.portal_type == "Discussion Item": # 22047 skip object if it's of type Discussion Item return for child in obj.objectIds(): child_obj = obj.get(child) if not child_obj: logger.info( "Couldn't retrieve child id %s for %s", child, obj.absolute_url()) continue obj_url = "%s/@@rdf" % child_obj.absolute_url() pingCRSDS(service_to_ping, obj_url, create) pingCRSDS_children(service_to_ping, child_obj, create) # When no request the task is called from a async task, see #19830 request = getattr(obj, 'REQUEST', None) # Detect special object used to force acquisition, see #18904 if isinstance(request, str): request = None create = IObjectAddedEvent.providedBy(event) if service_to_ping == "": return if hasVersionsInstalled and IVersionEnhanced.providedBy(obj) \ and request: obj_versions = IGetVersions(obj).versions() else: obj_versions = [obj] async_service = queryUtility(IAsyncService) # If object has translations if hasLinguaPloneInstalled and ITranslatable.providedBy(obj): if obj.isCanonical(): # Ping all translations for trans in obj.getTranslations().items(): if trans[0] != 'en': trans_obj = trans[1][0] obj_url = trans_obj.absolute_url() pingCRSDS(service_to_ping, obj_url, create) else: # Ping only canonical can_obj = obj.getCanonical() obj_url = can_obj.absolute_url() pingCRSDS(service_to_ping, obj_url, create) # If object was deleted if IObjectRemovedEvent.providedBy(event): # Ping backward relations pingCRSDS_backrel(service_to_ping, obj, create) # Ping all sub-objects pingCRSDS_children(service_to_ping, obj, create) # If object was moved/renamed first ping with the old object's URL if IObjectMovedOrRenamedEvent.providedBy(event): obj_url = "%s/%s/@@rdf" % (event.oldParent.absolute_url(), event.oldName) pingCRSDS(service_to_ping, obj_url, False) # then ping with the container of the old object obj_url = "%s/@@rdf" % event.oldParent.absolute_url() pingCRSDS(service_to_ping, obj_url, False) # Ping backward relations pingCRSDS_backrel(service_to_ping, obj, create) # Ping all sub-objects pingCRSDS_children(service_to_ping, obj, create) # Ping each version for obj in obj_versions: obj_url = "%s/@@rdf" % obj.absolute_url() pingCRSDS(service_to_ping, obj_url, create) # If no Aquisition there is no container, see #18904 if container: obj_url = "%s/@@rdf" % container.absolute_url() pingCRSDS(service_to_ping, obj_url, False) return True
def __call__(self): event = self.event service_to_ping = self.element.service_to_ping obj = self.event.object container = obj.getParentNode() noasync_msg = 'No instance for async operations was defined.' def pingCRSDS(service_to_ping, obj_url, create): """ Ping the CR/SDS service """ if async_service is None: logger.warn("Can't pingCRSDS, plone.app.async not installed!") return options = {} options['service_to_ping'] = service_to_ping options['obj_url'] = self.sanitize_url(obj_url) options['create'] = create queue = async_service.getQueues()[''] try: async_service.queueJobInQueue(queue, ('rdf', ), ping_CRSDS, self.context, options) except ComponentLookupError: logger.info(noasync_msg) def pingCRSDS_backrel(service_to_ping, obj, create): """ Ping backward relations """ back_relations = obj.getBRefs('relatesTo') for rel in back_relations: if rel is not None: obj_url = "%s/@@rdf" % rel.absolute_url() pingCRSDS(service_to_ping, obj_url, create) def pingCRSDS_children(service_to_ping, obj, create): """ Ping all sub-objects """ if obj.portal_type == "Discussion Item": # 22047 skip object if it's of type Discussion Item return for child in obj.objectIds(): child_obj = obj.get(child) if not child_obj: logger.info("Couldn't retrieve child id %s for %s", child, obj.absolute_url()) continue obj_url = "%s/@@rdf" % child_obj.absolute_url() pingCRSDS(service_to_ping, obj_url, create) pingCRSDS_children(service_to_ping, child_obj, create) # When no request the task is called from a async task, see #19830 request = getattr(obj, 'REQUEST', None) # Detect special object used to force acquisition, see #18904 if isinstance(request, str): request = None create = IObjectAddedEvent.providedBy(event) if service_to_ping == "": return if hasVersionsInstalled and IVersionEnhanced.providedBy(obj) \ and request: obj_versions = IGetVersions(obj).versions() else: obj_versions = [obj] async_service = queryUtility(IAsyncService) # If object has translations if hasLinguaPloneInstalled and ITranslatable.providedBy(obj): if obj.isCanonical(): # Ping all translations for trans in obj.getTranslations().items(): if trans[0] != 'en': trans_obj = trans[1][0] obj_url = trans_obj.absolute_url() pingCRSDS(service_to_ping, obj_url, create) else: # Ping only canonical can_obj = obj.getCanonical() obj_url = can_obj.absolute_url() pingCRSDS(service_to_ping, obj_url, create) # If object was deleted if IObjectRemovedEvent.providedBy(event): # Ping backward relations pingCRSDS_backrel(service_to_ping, obj, create) # Ping all sub-objects pingCRSDS_children(service_to_ping, obj, create) # If object was moved/renamed first ping with the old object's URL if IObjectMovedOrRenamedEvent.providedBy(event): obj_url = "%s/%s/@@rdf" % (event.oldParent.absolute_url(), event.oldName) pingCRSDS(service_to_ping, obj_url, False) # then ping with the container of the old object obj_url = "%s/@@rdf" % event.oldParent.absolute_url() pingCRSDS(service_to_ping, obj_url, False) # Ping backward relations pingCRSDS_backrel(service_to_ping, obj, create) # Ping all sub-objects pingCRSDS_children(service_to_ping, obj, create) # Ping each version for obj in obj_versions: obj_url = "%s/@@rdf" % obj.absolute_url() pingCRSDS(service_to_ping, obj_url, create) # If no Aquisition there is no container, see #18904 if container: obj_url = "%s/@@rdf" % container.absolute_url() pingCRSDS(service_to_ping, obj_url, False) return True
def test_notify_events_by_default(self): create(Builder('book').having(title=u'Testtitle')) created_event, added_event = self.portal.fired_events self.assertTrue(IObjectCreatedEvent.providedBy(created_event)) self.assertTrue(IObjectAddedEvent.providedBy(added_event))
def getLogEntry(self): ''' Get's a log entry for your action ''' event = self.event obj = event.object data = {'info': ''} # order of those checks is important since some interfaces # base off the others if IPloneFormGenField.providedBy(obj): # if ploneformgen field, use parent object for modified data data['field'] = obj.getId() obj = aq_parent(obj) # the order of those interface checks matters since some interfaces # inherit from others if IObjectRemovedEvent.providedBy(event): # need to keep track of removed events so it doesn't get called # more than once for each object action = 'removed' elif (IObjectInitializedEvent.providedBy(event) or IObjectCreatedEvent.providedBy(event) or IObjectAddedEvent.providedBy(event)): action = 'added' elif IObjectMovedEvent.providedBy(event): # moves can also be renames. Check the parent object if event.oldParent == event.newParent: if 'Rename' not in self.rule.rule.title: # cut out here, double action for this event return {} data['info'] = 'previous id: %s' % event.oldName action = 'rename' else: if 'Moved' not in self.rule.rule.title: # step out immediately since this could be a double action return {} data['info'] = 'previous location: %s/%s' % ( '/'.join(event.oldParent.getPhysicalPath()), event.oldName, ) action = 'moved' elif IObjectModifiedEvent.providedBy(event): action = 'modified' elif IActionSucceededEvent.providedBy(event): data['info'] = 'workflow transition: %s; comments: %s' % ( event.action, self.get_history_comment(), ) action = 'workflow' elif IObjectClonedEvent.providedBy(event): action = 'copied' elif ICheckinEvent.providedBy(event): data['info'] = event.message action = 'checked in' self.request.environ['disable.auditlog'] = True data['working_copy'] = '/'.join(obj.getPhysicalPath()) obj = event.baseline elif IBeforeCheckoutEvent.providedBy(event): action = 'checked out' self.request.environ['disable.auditlog'] = True elif ICancelCheckoutEvent.providedBy(event): action = 'cancel check out' self.request.environ['disable.auditlog'] = True data['working_copy'] = '/'.join(obj.getPhysicalPath()) obj = event.baseline else: logger.warn('no action matched') return {} if IWorkingCopy.providedBy(obj): # if working copy, iterate, check if Track Working Copies is # enabled if not self.trackWorkingCopies: # if not enabled, we only care about checked messages if 'check' not in action: return {} # if enabled in control panel, use original object and move # working copy path to working_copy data['working_copy'] = '/'.join(obj.getPhysicalPath()) relationships = obj.getReferences(WorkingCopyRelation.relationship) # check relationships, if none, something is wrong, not logging # action if len(relationships) <= 0: return {} obj = relationships[0] data.update(self._getObjectInfo(obj)) data['action'] = action return data
def log_moved(context, event): is_remove = IObjectRemovedEvent.providedBy(event) is_add = IObjectAddedEvent.providedBy(event) if is_add or is_remove: return ModificationLogger().moved(context)
def getLogEntry(self): ''' Get's a log entry for your action ''' event = self.event obj = event.object data = {'info': ''} # order of those checks is important since some interfaces # base off the others if IPloneFormGenField.providedBy(obj): # if ploneformgen field, use parent object for modified data data['field'] = obj.getId() obj = aq_parent(obj) # the order of those interface checks matters since some interfaces # inherit from others if IObjectRemovedEvent.providedBy(event): # need to keep track of removed events so it doesn't get called # more than once for each object action = 'removed' elif ( IObjectInitializedEvent.providedBy(event) or IObjectCreatedEvent.providedBy(event) or IObjectAddedEvent.providedBy(event) ): action = 'added' elif IObjectMovedEvent.providedBy(event): # moves can also be renames. Check the parent object if event.oldParent == event.newParent: if 'Rename' not in self.rule.rule.title: # cut out here, double action for this event return {} data['info'] = 'previous id: %s' % event.oldName action = 'rename' else: if 'Moved' not in self.rule.rule.title: # step out immediately since this could be a double action return {} data['info'] = 'previous location: %s/%s' % ( '/'.join(event.oldParent.getPhysicalPath()), event.oldName, ) action = 'moved' elif IObjectModifiedEvent.providedBy(event): action = 'modified' elif IActionSucceededEvent.providedBy(event): data['info'] = 'workflow transition: %s; comments: %s' % ( event.action, self.get_history_comment(), ) action = 'workflow' elif IObjectClonedEvent.providedBy(event): action = 'copied' elif ICheckinEvent.providedBy(event): data['info'] = event.message action = 'checked in' self.request.environ['disable.auditlog'] = True data['working_copy'] = '/'.join(obj.getPhysicalPath()) obj = event.baseline elif IBeforeCheckoutEvent.providedBy(event): action = 'checked out' self.request.environ['disable.auditlog'] = True elif ICancelCheckoutEvent.providedBy(event): action = 'cancel check out' self.request.environ['disable.auditlog'] = True data['working_copy'] = '/'.join(obj.getPhysicalPath()) obj = event.baseline else: logger.warn('no action matched') return {} if IWorkingCopy.providedBy(obj): # if working copy, iterate, check if Track Working Copies is # enabled if not self.trackWorkingCopies: # if not enabled, we only care about checked messages if 'check' not in action: return {} # if enabled in control panel, use original object and move # working copy path to working_copy data['working_copy'] = '/'.join(obj.getPhysicalPath()) relationships = obj.getReferences( WorkingCopyRelation.relationship) # check relationships, if none, something is wrong, not logging # action if len(relationships) <= 0: return {} obj = relationships[0] data.update(self._getObjectInfo(obj)) data['action'] = action return data