def extract_what(self): #Archetypes if IObjectInitializedEvent.providedBy(self.event): return 'created', self.get_object_modified_info() elif IObjectEditedEvent.providedBy(self.event): return 'modified', self.get_object_modified_info() # #TODO: plone.app.iterate # elif ICheckinEvent.providedBy(self.event): # return 'checkedin' # elif ICheckoutEvent.providedBy(self.event): # return 'checkedout' # elif IWorkingCopyDeletedEvent.providedBy(self.event): # return 'workingcopydeleted' # DCWorkflow elif IAfterTransitionEvent.providedBy(self.event): return 'statechanged', self.get_transition_info() # CMFCore (useless) # elif IActionSucceededEvent.providedBy(self.event): # return None # return 'statechanged', self.get_action_succeed_info() # zope # elif IObjectAddedEvent.providedBy(self.event): # return 'added', self.get_object_moved_info() elif IObjectCopiedEvent.providedBy(self.event): return 'copied', self.get_object_copied_info() elif IObjectMovedEvent.providedBy(self.event): return 'moved', self.get_object_moved_info() elif IObjectRemovedEvent.providedBy(self.event): return 'removed', self.get_object_moved_info() elif IObjectModifiedEvent.providedBy(self.event): return 'modified', self.get_object_modified_info() return None, {}
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 cktemplate_moved(obj, event): """Managed the annotation for the Service template. Linked to creation, move, rename, delete and copy. """ # TODO move it to ckeditortemplates if IObjectRemovedEvent.providedBy(event): return path = '/'.join(obj.getPhysicalPath()[:-1]) # skip rename or inplace copy if event.oldParent == event.newParent or \ (event.oldParent and path == '/'.join(event.oldParent.getPhysicalPath())): return if '/templates/oem' not in path: return # oem has been renamed index = path.index('/templates/oem') + 14 subpath = path[index + 1:] parts = subpath and subpath.split('/') or [] value = u'' if parts: pcat = obj.portal_catalog brains = pcat.unrestrictedSearchResults(path='{}/{}'.format(path[:index], parts[0]), sort_on='path', ) titles = {br.getPath(): br.Title for br in brains} values = [] current_path = path[:index] for part in parts: current_path += '/{}'.format(part) values.append(titles[current_path].decode('utf8')) value = u' - '.join(values) annot = IAnnotations(obj) annot['dmsmail.cke_tpl_tit'] = value
def projectspace_moved(obj, event): """ When a projectspace is renamed, we correct collections """ if IObjectRemovedEvent.providedBy(event): return portal = api.portal.get() path = '/'.join(obj.getPhysicalPath()) # correct path criteria in collections for brain in portal.portal_catalog(path=path, portal_type='DashboardCollection'): ob = brain.getObject() query = ob.query for elt in query: if elt['i'] == 'path': elt['v'] = path ob.query = query # correct default collection for brain in portal.portal_catalog( path=path, object_provides=ICollectionCategories.__identifier__): ob = brain.getObject() criterion = getCollectionLinkCriterion(ob) criterias = ICriteria(ob) old_uid = criterias.get(criterion.__name__).get('default') old_path = uuidToPhysicalPath(old_uid) old_id = os.path.basename(old_path) if old_path.endswith('/{}/{}'.format(ob.id, old_id)): default_col = ob[old_id].UID() _updateDefaultCollectionFor(ob, default_col) logger.info('Replaced default col {} by {} on {}'.format( old_uid, default_col, ob.absolute_url())) else: raise ValueError("Cannot update default col on {}".format( ob.absolute_url()))
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 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 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 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 content_added(content, event): if (event.object != content or IObjectRemovedEvent.providedBy(event) or event.newParent == event.oldParent): return if IOrderableContainer.providedBy(event.newParent): manager = IOrderManager(event.newParent) manager.add(content)
def mark_contact(contact, event): """ Set a marker interface on contact content. """ if IObjectRemovedEvent.providedBy(event): # at site removal if event.object.portal_type == 'Plone Site': return invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.OMSenderVocabulary') return if '/plonegroup-organization' in contact.absolute_url_path(): if not IPloneGroupContact.providedBy(contact): alsoProvides(contact, IPloneGroupContact) if INotPloneGroupContact.providedBy(contact): noLongerProvides(contact, INotPloneGroupContact) # don't check for IPersonnelContact because we can only add organization in this folder elif '/personnel-folder/' in contact.absolute_url_path(): if not IPersonnelContact.providedBy(contact): alsoProvides(contact, IPersonnelContact) if INotPloneGroupContact.providedBy(contact): noLongerProvides(contact, INotPloneGroupContact) # don't check for IPloneGroupContact because we can't add organization in this folder invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.OMSenderVocabulary') else: if not INotPloneGroupContact.providedBy(contact): alsoProvides(contact, INotPloneGroupContact) if IPloneGroupContact.providedBy(contact): noLongerProvides(contact, IPloneGroupContact) if IPersonnelContact.providedBy(contact): noLongerProvides(contact, IPersonnelContact) invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.OMSenderVocabulary') contact.reindexObject(idxs='object_provides')
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 unrelateOnDeletion(event): """Remove all relationships when an object is deleted.""" if not IObjectRemovedEvent.providedBy(event): return linkset = IRelationshipLinks(event.object, None) if linkset is not None: # event.object may be a ContainedProxy unrelateAll(getProxiedObject(event.object))
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 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 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 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 unrelateCalendarOnDeletion(event): """When you delete an object, relationships of it's calendar should be removed >>> from schooltool.relationship.tests import setUp, tearDown >>> from schooltool.testing.setup import setUpCalendaring >>> setUp() >>> setUpCalendaring() >>> import zope.event >>> old_subscribers = zope.event.subscribers[:] >>> from schooltool.app.overlay import unrelateCalendarOnDeletion >>> zope.event.subscribers.append(unrelateCalendarOnDeletion) We will need some object that implements IHaveCalendar for that: >>> from zope.container.btree import BTreeContainer >>> container = BTreeContainer() >>> from schooltool.person.person import Person >>> container = BTreeContainer() >>> container['jonas'] = jonas = Person(username="******") >>> container['petras'] = petras = Person(username="******") Let's add calendar of Petras to the list of overlaid calendars: >>> jonas.overlaid_calendars.add(ISchoolToolCalendar(petras)) <...CalendarOverlayInfo object at ...> >>> list(jonas.overlaid_calendars) [<schooltool.app.overlay.CalendarOverlayInfo object at ...>] If we delete Petras - Jonas should have no calendars in his overlay list: >>> del container['petras'] >>> list(jonas.overlaid_calendars) [] Restore old subscribers: >>> zope.event.subscribers[:] = old_subscribers >>> tearDown() """ if not IObjectRemovedEvent.providedBy(event): return # event.object may be a ContainedProxy obj = getProxiedObject(event.object) if not IHaveCalendar.providedBy(obj): return calendar = ISchoolToolCalendar(obj) linkset = IRelationshipLinks(calendar, None) if linkset is not None: unrelateAll(calendar)
def _update_workspace_groupings(obj, event): """ If the relevant object is inside a workspace, the workspace grouping parameters (for the sidebar) need to be updated. """ parent = parent_workspace(obj) if parent is None or not IGroupingStoragable.providedBy(parent): return storage = getAdapter(parent, IGroupingStorage) if IObjectRemovedEvent.providedBy(event) or IObjectWillBeRemovedEvent.providedBy(event): storage.remove_from_groupings(obj) else: storage.update_groupings(obj)
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 createdEvent(obj, event): """ It can be a IObjectRemovedEvent - don't do anything IObjectMovedEvent IObjectAddedEvent IObjectCopiedEvent """ if IObjectRemovedEvent.providedBy(event): return portal = getSite() language_tool = getToolByName(portal, 'portal_languages') # On ObjectCopiedEvent and ObjectMovedEvent aq_parent(event.object) is # always equal to event.newParent. parent = aq_parent(event.object) if (language_tool.startNeutral() and ITranslatable.providedBy(obj)): # We leave this untouched by now. # We don't set languages set_recursive_language(obj, LANGUAGE_INDEPENDENT) elif (IPloneSiteRoot.providedBy(parent) and ITranslatable.providedBy(obj) and ILanguage(obj).get_language() == LANGUAGE_INDEPENDENT): # It's a root folder and we set the default language # ( not independent allowed ) language = language_tool.getPreferredLanguage() set_recursive_language(obj, language) elif ITranslatable.providedBy(parent): # Normal use case # We set the tg, linking language = ILanguage(parent).get_language() set_recursive_language(obj, language) sdm = obj.session_data_manager session = sdm.getSessionData() if 'tg' in session.keys() and \ not portal.portal_factory.isTemporary(obj): IMutableTG(obj).set(session['tg']) old_obj = ITranslationManager(obj).get_translation(session['old_lang']) # Copy ILanguage Independent field on on-the-fly translation cloner = ITranslationCloner(old_obj) cloner(obj) reindex_object(obj) del session['tg']
def createdEvent(obj, event): """ It can be a IObjectRemovedEvent - don't do anything IObjectMovedEvent IObjectAddedEvent IObjectCopiedEvent """ if IObjectRemovedEvent.providedBy(event): return portal = getSite() language_tool = getToolByName(portal, 'portal_languages') # On ObjectCopiedEvent and ObjectMovedEvent aq_parent(event.object) is # always equal to event.newParent. parent = aq_parent(event.object) if (language_tool.startNeutral() and ITranslatable.providedBy(obj)): # We leave this untouched by now. # We don't set languages set_recursive_language(obj, LANGUAGE_INDEPENDENT) elif (IPloneSiteRoot.providedBy(parent) and ITranslatable.providedBy(obj) and ILanguage(obj).get_language() == LANGUAGE_INDEPENDENT): # It's a root folder and we set the default language # ( not independent allowed ) language = language_tool.getPreferredLanguage() set_recursive_language(obj, language) elif ITranslatable.providedBy(parent): # Normal use case # We set the tg, linking language = ILanguage(parent).get_language() set_recursive_language(obj, language) sdm = obj.session_data_manager session = sdm.getSessionData() if 'tg' in session.keys() and \ not portal.portal_factory.isTemporary(obj): IMutableTG(obj).set(session['tg']) old_obj = ITranslationManager(obj).get_translation( session['old_lang']) # Copy ILanguage Independent field on on-the-fly translation cloner = ITranslationCloner(old_obj) cloner(obj) reindex_object(obj) del session['tg']
def createdEvent(obj, event): """ Subscriber to set language on the child folder It can be a - IObjectRemovedEvent - don't do anything - IObjectMovedEvent - IObjectAddedEvent - IObjectCopiedEvent """ if IObjectRemovedEvent.providedBy(event): return request = getattr(event.object, 'REQUEST', getRequest()) if not IPloneAppMultilingualInstalled.providedBy(request): return # On ObjectCopiedEvent and ObjectMovedEvent aq_parent(event.object) is # always equal to event.newParent. parent = aq_parent(event.object) # special parent handling if not ITranslatable.providedBy(parent): set_recursive_language(obj, LANGUAGE_INDEPENDENT) return # Normal use case # We set the tg, linking language = ILanguage(parent).get_language() set_recursive_language(obj, language) request = getattr(event.object, 'REQUEST', getRequest()) try: ti = request.translation_info except AttributeError: return # AT check portal = getSite() portal_factory = getToolByName(portal, 'portal_factory', None) if ( not IDexterityContent.providedBy(obj) and portal_factory is not None and not portal_factory.isTemporary(obj) ): return IMutableTG(obj).set(ti['tg']) modified(obj) tm = ITranslationManager(obj) old_obj = tm.get_translation(ti['source_language']) ILanguageIndependentFieldsManager(old_obj).copy_fields(obj)
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 _update_workspace_groupings(obj, event): """ If the relevant object is inside a workspace, the workspace grouping parameters (for the sidebar) need to be updated. """ parent = parent_workspace(obj) if parent is None or not IGroupingStoragable.providedBy(parent): return storage = getAdapter(parent, IGroupingStorage) if IObjectRemovedEvent.providedBy(event) or \ IObjectWillBeRemovedEvent.providedBy(event): storage.remove_from_groupings(obj) else: storage.update_groupings(obj)
def createdEvent(obj, event): """ Subscriber to set language on the child folder It can be a - IObjectRemovedEvent - don't do anything - IObjectMovedEvent - IObjectAddedEvent - IObjectCopiedEvent """ if IObjectRemovedEvent.providedBy(event): return request = getattr(event.object, 'REQUEST', getRequest()) if not IPloneAppMultilingualInstalled.providedBy(request): return # On ObjectCopiedEvent and ObjectMovedEvent aq_parent(event.object) is # always equal to event.newParent. parent = aq_parent(event.object) # special parent handling if not ITranslatable.providedBy(parent): set_recursive_language(obj, LANGUAGE_INDEPENDENT) return # Normal use case # We set the tg, linking language = ILanguage(parent).get_language() set_recursive_language(obj, language) request = getattr(event.object, 'REQUEST', getRequest()) try: ti = request.translation_info except AttributeError: return # AT check portal = getSite() portal_factory = getToolByName(portal, 'portal_factory', None) if (not IDexterityContent.providedBy(obj) and portal_factory is not None and not portal_factory.isTemporary(obj)): return IMutableTG(obj).set(ti['tg']) modified(obj) tm = ITranslationManager(obj) old_obj = tm.get_translation(ti['source_language']) ILanguageIndependentFieldsManager(old_obj).copy_fields(obj)
def mark_contact(contact, event): """ Set a marker interface on contact content. """ if IObjectRemovedEvent.providedBy(event): return if '/personnel-folder/' in contact.absolute_url_path() or '/plonegroup-organization' in contact.absolute_url_path(): if not IPloneGroupContact.providedBy(contact): alsoProvides(contact, IPloneGroupContact) if INotPloneGroupContact.providedBy(contact): noLongerProvides(contact, INotPloneGroupContact) else: if not INotPloneGroupContact.providedBy(contact): alsoProvides(contact, INotPloneGroupContact) if IPloneGroupContact.providedBy(contact): noLongerProvides(contact, IPloneGroupContact) contact.reindexObject(idxs='object_provides')
def organization_modified(obj, event): """ Update the sortable_title index """ # at site removal if IObjectRemovedEvent.providedBy(event): return # zope.container.contained.ContainerModifiedEvent: descriptions is () when it's called after children creation if hasattr(event, 'descriptions') and not event.descriptions: return # zope.lifecycleevent.ObjectAddedEvent: oldParent is None when creation if hasattr(event, 'oldParent') and not event.oldParent: return pc = api.portal.get_tool('portal_catalog') for brain in pc(portal_type='organization', path='/'.join(obj.getPhysicalPath()), sort_on='path')[1:]: brain.getObject().reindexObject(idxs=['sortable_title'])
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 mark_organization(contact, event): """ Set a marker interface on contact content. """ if IObjectRemovedEvent.providedBy(event): return if '/%s' % PLONEGROUP_ORG in contact.absolute_url_path(): if not IPloneGroupContact.providedBy(contact): alsoProvides(contact, IPloneGroupContact) if INotPloneGroupContact.providedBy(contact): noLongerProvides(contact, INotPloneGroupContact) else: if not INotPloneGroupContact.providedBy(contact): alsoProvides(contact, INotPloneGroupContact) if IPloneGroupContact.providedBy(contact): noLongerProvides(contact, IPloneGroupContact) contact.reindexObject(idxs='object_provides')
def organization_modified(obj, event): """ Update the sortable_title index """ # at site removal if IObjectRemovedEvent.providedBy(event): return # zope.container.contained.ContainerModifiedEvent: descriptions is () when it's called after children creation if hasattr(event, 'descriptions') and not event.descriptions: return # zope.lifecycleevent.ObjectAddedEvent: oldParent is None when creation if hasattr(event, 'oldParent') and not event.oldParent: return pc = api.portal.get_tool('portal_catalog') for brain in pc.unrestrictedSearchResults(portal_type='organization', path='/'.join(obj.getPhysicalPath()), sort_on='path')[1:]: brain._unrestrictedGetObject().reindexObject(idxs=['sortable_title'])
def createdEvent(obj, event): """ It can be a IObjectRemovedEvent - don't do anything IObjectMovedEvent IObjectAddedEvent IObjectCopiedEvent """ if IObjectRemovedEvent.providedBy(event): return # On ObjectCopiedEvent and ObjectMovedEvent aq_parent(event.object) is # always equal to event.newParent. parent = aq_parent(event.object) if ITranslatable.providedBy(parent): # Normal use case # We set the tg, linking language = ILanguage(parent).get_language() set_recursive_language(obj, language) sdm = obj.session_data_manager session = sdm.getSessionData() portal = getSite() portal_factory = getToolByName(portal, 'portal_factory', None) request = getattr(event.object, 'REQUEST', getRequest()) has_pam_old_lang_in_form = ( request and 'form.widgets.pam_old_lang' not in request.form ) if (not has_pam_old_lang_in_form and 'tg' in session.keys() and 'old_lang' in session.keys() and (portal_factory is None or not portal_factory.isTemporary(obj))): IMutableTG(obj).set(session['tg']) modified(obj) del session['tg'] old_obj = ITranslationManager(obj)\ .get_translation(session['old_lang']) ILanguageIndependentFieldsManager(old_obj).copy_fields(obj) del session['old_lang'] else: set_recursive_language(obj, LANGUAGE_INDEPENDENT)
def testDeletion(self): from zope.event import subscribers tree = BTreeContainer() item = Contained() tree['42'] = item events = [] def subscriber(event): events.append(event) # events should happen after the deletion, not before) self.assertEqual(len(tree), 0) self.assertEqual(list(tree), []) subscribers.append(subscriber) del tree['42'] self.assertEqual(item.__name__, None) self.assertEqual(item.__parent__, None) self.assertEqual(len(events), 2) self.assertTrue(IObjectRemovedEvent.providedBy(events[0])) self.assertTrue(IContainerModifiedEvent.providedBy(events[1]))
def testDeleteEvents(self): self.assertRaises(KeyError, self.reflecto.manage_delObjects, ('monty',)) self.assertEqual(len(getEvents()), 0) self.assertRaises(KeyError, self.reflecto.manage_delObjects, ('foo', 'monty',)) self.assertEqual(len(getEvents()), 1) events = getEvents(IObjectWillBeRemovedEvent) self.assertEqual(len(events), 1) self.assertEqual(events[0].oldName, 'foo') self.assertEqual(self.reflecto.manage_delObjects(('foo',)), None) events = getEvents() self.assertEqual(len(events), 4) self.assertTrue(IObjectWillBeRemovedEvent.providedBy(events[1])) self.assertTrue(IObjectRemovedEvent.providedBy(events[2])) self.assertEqual(events[2].oldName, 'foo') self.assertTrue(IContainerModifiedEvent.providedBy(events[3])) self.assertTrue(events[3].object is self.reflecto)
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 # Ignore object removals if IObjectRemovedEvent.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 createdEvent(obj, event): """ It can be a IObjectRemovedEvent - don't do anything IObjectMovedEvent IObjectAddedEvent IObjectCopiedEvent """ if IObjectRemovedEvent.providedBy(event): return portal = getSite() # On ObjectCopiedEvent and ObjectMovedEvent aq_parent(event.object) is # always equal to event.newParent. parent = aq_parent(event.object) if ITranslatable.providedBy(parent): # Normal use case # We set the tg, linking language = ILanguage(parent).get_language() set_recursive_language(obj, language) sdm = obj.session_data_manager session = sdm.getSessionData() portal = getSite() if 'tg' in session.keys() and \ 'old_lang' in session.keys() and \ not portal.portal_factory.isTemporary(obj): IMutableTG(obj).set(session['tg']) modified(obj) del session['tg'] old_obj = ITranslationManager(obj)\ .get_translation(session['old_lang']) ILanguageIndependentFieldsManager(old_obj).copy_fields(obj) del session['old_lang'] else: set_recursive_language(obj, LANGUAGE_INDEPENDENT)
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 reindex(obj, event): """Re-index mirrored folder content for all mirrors and master Mirror folder content objects are indexed once for each mirror and the master with different, mirror-specific UUID for each. When ever a mirrored folder content object is modified in some mirror or master, it must be re-indexed for all the other mirrors and master as well. """ if IObjectRemovedEvent.providedBy(event): return info = mirror_info(obj) if info == NOT_MIRRORED: return # We try to access newly indexed objects via the parent in order to avoid # computing partial paths and starting traversal from master or mirrors. # However, the parent being a mirror is an exception in that mirrors' uuid # doesn't follow the pattern for uuids of mirrored objects. parent = aq_parent(obj) master_id = IUUID(info.master) if IMirror.providedBy(parent) or IUUID(parent) == master_id: parent_ids = [master_id] + info.mirror_ids else: parent_master_id = bare_uuid(parent) if not parent_master_id: return parent_ids = [parent_master_id] + [ f'{parent_master_id}@{mirror_id}' for mirror_id in info.mirror_ids ] cat = api.portal.get_tool('portal_catalog') for parent_id in parent_ids: brains = cat.unrestrictedSearchResults(UID=parent_id) for brain in brains: brain.getObject()[obj.id].indexObject()
def reindex_language_independent(ob, event): """Re-index language independent object for other languages Language independent objects are indexed once for each language with different, language code post-fixed, UUID for each. When ever a language independent object is modified in some language, it must be re-indexed for all the other languages as well. """ if not is_language_independent(ob): return if IObjectRemovedEvent.providedBy(event): return pc = getToolByName(ob, 'portal_catalog') parent = aq_parent(ob) # Re-index objects just below the language independent folder if ILanguageIndependentFolder.providedBy(parent): brains = pc.unrestrictedSearchResults(portal_type='LIF') for brain in brains: lif = brain._unrestrictedGetObject() if lif != parent: lif[ob.id].indexObject() # Re-index objects deeper inside language independent folder else: language_tool = getToolByName(ob, 'portal_languages') language_codes = language_tool.supported_langs parent_uuid = IUUID(parent).split('-')[0] + '-' for code in language_codes: results = pc.unrestrictedSearchResults(UID=parent_uuid + code) # When we have results, parent has been indexed and we can reindex: for brain in results: tmp = ob.unrestrictedTraverse(brain.getPath() + '/' + ob.id) tmp.reindexObject()
def testDeleteEvents(self): self.assertRaises(KeyError, self.reflecto.manage_delObjects, ('monty', )) self.assertEqual(len(getEvents()), 0) self.assertRaises(KeyError, self.reflecto.manage_delObjects, ( 'foo', 'monty', )) self.assertEqual(len(getEvents()), 1) events = getEvents(IObjectWillBeRemovedEvent) self.assertEqual(len(events), 1) self.assertEqual(events[0].oldName, 'foo') self.assertEqual(self.reflecto.manage_delObjects(('foo', )), None) events = getEvents() self.assertEqual(len(events), 4) self.assertTrue(IObjectWillBeRemovedEvent.providedBy(events[1])) self.assertTrue(IObjectRemovedEvent.providedBy(events[2])) self.assertEqual(events[2].oldName, 'foo') self.assertTrue(IContainerModifiedEvent.providedBy(events[3])) self.assertTrue(events[3].object is self.reflecto)
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 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 __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 is_uninstalling_plone(self): return IObjectRemovedEvent.providedBy(self.event) \ and IPloneSiteRoot.providedBy(self.event.object)
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 fixOwnership(ob, event): if not IObjectRemovedEvent.providedBy(event): ob.fixOwnership()
def index_task(obj, event): """Index the given task in opengever.globalindex. """ # Skip this handler when trying to remove a Plone site. Otherwise the # component registry is already gone and we'll run into trouble. if IObjectRemovedEvent.providedBy(event) \ and IPloneSiteRoot.providedBy(event.object): return None parent = aq_parent(aq_inner(obj)) client_id = get_client_id() intids = getUtility(IIntIds) try: int_id = intids.getId(obj) except KeyError: try: # In some case (remote task updating etc) # only the base_object provides an intid. int_id = intids.getId(aq_base(obj)) except KeyError: # The intid event handler didn' create a intid for this object # yet. The event will be fired again after creating the id. return session = Session() try: task = session.query(Task).filter(Task.client_id == client_id).filter( Task.int_id == int_id).one() except NoResultFound: task = Task(int_id, client_id) session.add(task) # title maximum_title_length = Task.title.property.columns[0].type.length title = obj.title if not isinstance(title, unicode): title = title.decode('utf-8') title = title[:maximum_title_length] task.title = title # Generate and store the breadcrumb tooltip breadcrumb_titles = [] breadcrumbs_view = getMultiAdapter((obj, obj.REQUEST), name='breadcrumbs_view') for elem in breadcrumbs_view.breadcrumbs(): if isinstance(elem.get('Title'), unicode): breadcrumb_titles.append(elem.get('Title')) else: breadcrumb_titles.append(elem.get('Title').decode('utf-8')) # we prevent to raise database-error, if we have a too long string # Shorten the breadcrumb_title to: mandant1 > repo1 > ... join_value = ' > ' end_value = '...' maximum_length = Task.breadcrumb_title.property.columns[0].type.length maximum_length -= len(end_value) breadcrumb_title = breadcrumb_titles actual_length = 0 for i, breadcrumb in enumerate(breadcrumb_titles): add_length = len(breadcrumb) + len(join_value) + len(end_value) if (actual_length + add_length) > maximum_length: breadcrumb_title = breadcrumb_titles[:i] breadcrumb_title.append(end_value) break actual_length += len(breadcrumb) + len(join_value) task.breadcrumb_title = join_value.join(breadcrumb_title) url_tool = obj.unrestrictedTraverse('@@plone_tools').url() task.physical_path = '/'.join(url_tool.getRelativeContentPath(obj)) wftool = getToolByName(obj, 'portal_workflow') task.review_state = wftool.getInfoFor(obj, 'review_state') task.icon = obj.getIcon() task.responsible = obj.responsible task.issuer = obj.issuer # we need to have python datetime objects for make it work with sqlite etc. task.deadline = obj.deadline task.completed = obj.date_of_completion task.modified = obj.modified().asdatetime().replace(tzinfo=None) task.task_type = obj.task_type task.is_subtask = parent.portal_type == 'opengever.task.task' task.sequence_number = getUtility(ISequenceNumber).get_number(obj) task.reference_number = IReferenceNumber(obj).get_number() #get the containing_dossier value directly with the indexer catalog = getToolByName(obj, 'portal_catalog') task.containing_dossier = getMultiAdapter( (obj, catalog), IIndexer, name='containing_dossier')() # the dossier_sequence_number index is required for generating lists # of tasks as PDFs (LaTeX) as defined by the customer. task.dossier_sequence_number = get_dossier_sequence_number(obj) task.assigned_client = obj.responsible_client # index the predecessor if obj.predecessor: pred_client_id, pred_init_id = obj.predecessor.split(':', 1) try: predecessor = session.query(Task).filter_by( client_id=pred_client_id, int_id=pred_init_id).one() except NoResultFound: # For some reason the referenced predecessor doesn't exist predecessor = None else: predecessor = None task.predecessor = predecessor # index the principal which have View permission. This is according to the # allowedRolesAndUsers index but it does not car of global roles. allowed_roles = rolesForPermissionOn(View, obj) principals = [] for principal, roles in _mergedLocalRoles(obj).items(): for role in roles: if role in allowed_roles: principals.append(principal.decode('utf-8')) break task.principals = principals