def test_events(self): from OFS.interfaces import IObjectWillBeAddedEvent from zope.component import adapter from zope.component import provideHandler from zope.container.interfaces import IContainerModifiedEvent from zope.container.interfaces import IObjectAddedEvent from zope.lifecycleevent.interfaces import IObjectCreatedEvent events = [] @adapter(IObjectCreatedEvent) def _handleObjectCreated(event): events.append(event) provideHandler(_handleObjectCreated) @adapter(IObjectWillBeAddedEvent) def _handleObjectWillBeAdded(event): events.append(event) provideHandler(_handleObjectWillBeAdded) @adapter(IObjectAddedEvent) def _handleObjectAdded(event): events.append(event) provideHandler(_handleObjectAdded) @adapter(IContainerModifiedEvent) def _handleContainerModified(event): events.append(event) provideHandler(_handleContainerModified) self.ti.constructInstance(self.f, 'foo') self.assertEqual(len(events), 4) evt = events[0] self.assertTrue(IObjectCreatedEvent.providedBy(evt)) self.assertEqual(evt.object, self.f.foo) evt = events[1] self.assertTrue(IObjectWillBeAddedEvent.providedBy(evt)) self.assertEqual(evt.object, self.f.foo) self.assertEqual(evt.oldParent, None) self.assertEqual(evt.oldName, None) self.assertEqual(evt.newParent, self.f) self.assertEqual(evt.newName, 'foo') evt = events[2] self.assertTrue(IObjectAddedEvent.providedBy(evt)) self.assertEqual(evt.object, self.f.foo) self.assertEqual(evt.oldParent, None) self.assertEqual(evt.oldName, None) self.assertEqual(evt.newParent, self.f) self.assertEqual(evt.newName, 'foo') evt = events[3] self.assertTrue(IContainerModifiedEvent.providedBy(evt)) self.assertEqual(evt.object, self.f)
def test_events(self): from OFS.interfaces import IObjectWillBeAddedEvent from zope.component import adapter from zope.component import provideHandler from zope.container.interfaces import IContainerModifiedEvent from zope.container.interfaces import IObjectAddedEvent from zope.lifecycleevent.interfaces import IObjectCreatedEvent events = [] @adapter(IObjectCreatedEvent) def _handleObjectCreated(event): events.append(event) provideHandler(_handleObjectCreated) @adapter(IObjectWillBeAddedEvent) def _handleObjectWillBeAdded(event): events.append(event) provideHandler(_handleObjectWillBeAdded) @adapter(IObjectAddedEvent) def _handleObjectAdded(event): events.append(event) provideHandler(_handleObjectAdded) @adapter(IContainerModifiedEvent) def _handleContainerModified(event): events.append(event) provideHandler(_handleContainerModified) self.ti.constructInstance(self.f, 'foo') self.assertEquals(len(events), 4) evt = events[0] self.failUnless(IObjectCreatedEvent.providedBy(evt)) self.assertEquals(evt.object, self.f.foo) evt = events[1] self.failUnless(IObjectWillBeAddedEvent.providedBy(evt)) self.assertEquals(evt.object, self.f.foo) self.assertEquals(evt.oldParent, None) self.assertEquals(evt.oldName, None) self.assertEquals(evt.newParent, self.f) self.assertEquals(evt.newName, 'foo') evt = events[2] self.failUnless(IObjectAddedEvent.providedBy(evt)) self.assertEquals(evt.object, self.f.foo) self.assertEquals(evt.oldParent, None) self.assertEquals(evt.oldName, None) self.assertEquals(evt.newParent, self.f) self.assertEquals(evt.newName, 'foo') evt = events[3] self.failUnless(IContainerModifiedEvent.providedBy(evt)) self.assertEquals(evt.object, self.f)
def handleContentishEvent(ob, event): """ Event subscriber for (IContentish, IObjectEvent) events. """ if IObjectAddedEvent.providedBy(event): ob.notifyWorkflowCreated() ob.indexObject() elif IObjectMovedEvent.providedBy(event): if event.newParent is not None: ob.indexObject() elif IObjectWillBeMovedEvent.providedBy(event): if event.oldParent is not None: ob.unindexObject() elif IObjectCopiedEvent.providedBy(event): if hasattr(aq_base(ob), 'workflow_history'): del ob.workflow_history elif IObjectCreatedEvent.providedBy(event): if hasattr(aq_base(ob), 'addCreator'): ob.addCreator()
def handleContentishEvent(ob, event): """ Event subscriber for (IContentish, IObjectEvent) events. """ if IObjectAddedEvent.providedBy(event): ob.notifyWorkflowCreated() ob.indexObject() elif IObjectMovedEvent.providedBy(event): if event.newParent is not None: if hasattr(aq_base(ob), 'notifyModified'): ob.notifyModified() rid = getattr(ob, '__rid', None) if rid: catalog = api.portal.get_tool('portal_catalog') _catalog = catalog._catalog new_path = '/'.join(ob.getPhysicalPath()) old_path = _catalog.paths[rid] del _catalog.uids[old_path] _catalog.uids[new_path] = rid _catalog.paths[rid] = new_path ob.reindexObject(idxs=[ 'path', 'allowedRolesAndUsers', 'modified', 'id', 'getId' ]) delattr(ob, '__rid') elif event.newParent is not None: # This may happen if "collective.indexing" is installed and an object # is added and renamed/moved in the same transaction (e.g. during the # creation of an object with "plone.api" in a subscriber listening # on "IObjectAddedEvent" as in https://github.com/4teamwork/ftw.events/blob/f1a77440866c6d963961497f68781098c1b4bc8f/ftw/events/configure.zcml#L22). ob.indexObject() elif IObjectWillBeMovedEvent.providedBy(event): from ftw.copymovepatches.utils import getQueue # Prepare Rename if indexing queue is implemented if event.oldParent == event.newParent and getQueue is not None: # The queue needs to be processed, since the `renameObjectsByPaths` # script allows the user to rename the object and also sets a new # title if he wants. # In some circumstances this leads to a inconsistent catalog state. # Mainly if other event handler also triggers a `process` queue by # asking the catalog for something. # The result was for example a "reindex" of a already deleted # object. queue = getQueue() queue.process() # Move/Rename if event.oldParent is not None and event.newParent is not None: catalog = api.portal.get_tool('portal_catalog') ob_path = '/'.join(ob.getPhysicalPath()) if ob_path in catalog._catalog.uids: rid = catalog._catalog.uids[ob_path] setattr(ob, '__rid', rid) else: # This may happen if "collective.indexing" is installed and an object # is added and renamed/moved in the same transaction (e.g. during the # creation of an object with "plone.api" in a subscriber listening # on "IObjectAddedEvent" as in https://github.com/4teamwork/ftw.events/blob/f1a77440866c6d963961497f68781098c1b4bc8f/ftw/events/configure.zcml#L22). return elif event.oldParent is not None: # Delete ob.unindexObject() elif IObjectCopiedEvent.providedBy(event): if hasattr(aq_base(ob), 'workflow_history'): del ob.workflow_history elif IObjectCreatedEvent.providedBy(event): if hasattr(aq_base(ob), 'addCreator'): ob.addCreator()
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 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 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