def test_object_modified_related(self): self.assertDictEqual( get_related_roles(self.portal, self.item.UID()), { u'mail_editor': set(['Editor']), u'john': set(['Reviewer', 'Reader']), u'kate': set(['Reader', 'Manager']) }) self.item.localrole_field = ['support'] self.item.localrole_user_field = ['jane', 'tom'] self.item.mono_localrole_field = 'basic-user' zope.event.notify( ObjectModifiedEvent( self.item, Attributes(ITestingBehavior, 'ITestingBehavior.mono_localrole_field'), Attributes(ITestingType, 'localrole_field', 'localrole_user_field'), )) self.assertDictEqual( get_related_roles(self.portal, self.item.UID()), { u'support_editor': set(['Editor']), u'jane': set(['Reader']), u'tom': set(['Reader']), u'basic-user': set(['Reviewer']), u'kate': set(['Manager']) })
def test_object_modified(self): doc = api.content.create(container=self.item, type='Document', id='doc', title='Document') ctool = self.portal.portal_catalog allowedRolesAndUsers = ctool.getIndexDataForUID('/'.join( self.item.getPhysicalPath()))['allowedRolesAndUsers'] self.assertSetEqual( set([ 'Manager', 'Site Administrator', 'Reader', 'Editor', 'Contributor', 'user:admin', 'user:test_user_1_', 'user:kate', u'user:mail_editor', u'user:mail_reviewer', u'user:john' ]), set(allowedRolesAndUsers)) allowedRolesAndUsers = ctool.getIndexDataForUID('/'.join( doc.getPhysicalPath()))['allowedRolesAndUsers'] self.assertSetEqual( set([ 'Manager', 'Site Administrator', 'Reader', 'Editor', 'Contributor', 'user:admin', 'user:test_user_1_', 'user:kate', u'user:mail_editor', u'user:mail_reviewer', u'user:john' ]), set(allowedRolesAndUsers)) self.item.localrole_field = ['support'] self.item.localrole_user_field = ['jane', 'tom'] self.item.mono_localrole_field = 'basic-user' zope.event.notify( ObjectModifiedEvent( self.item, Attributes(ITestingBehavior, 'ITestingBehavior.mono_localrole_field'), Attributes(ITestingType, 'localrole_field', 'localrole_user_field'), )) allowedRolesAndUsers = ctool.getIndexDataForUID('/'.join( self.item.getPhysicalPath()))['allowedRolesAndUsers'] self.assertSetEqual( set([ 'Manager', 'Site Administrator', 'Reader', 'Editor', 'Contributor', 'user:admin', 'user:test_user_1_', 'user:kate', u'user:support_editor', u'user:support_reviewer', u'user:jane', u'user:tom' ]), set(allowedRolesAndUsers)) allowedRolesAndUsers = ctool.getIndexDataForUID('/'.join( doc.getPhysicalPath()))['allowedRolesAndUsers'] self.assertSetEqual( set([ 'Manager', 'Site Administrator', 'Reader', 'Editor', 'Contributor', 'user:admin', 'user:test_user_1_', 'user:kate', u'user:support_editor', u'user:support_reviewer', u'user:jane', u'user:tom' ]), set(allowedRolesAndUsers))
def save_schema(context, schema=None, xml=None, language=u''): if schema: # Update XML schema (got update from model designer) try: context.schema = update_schema( aq_base(context).schema, schema, language=language, ) # TODO: synchronize languages except AttributeError: context.schema = serializeSchema(schema, name=u'') for name in schema: value_type = getattr(schema[name], 'value_type', None) if isinstance(value_type, Object): context.schema = update_schema( aq_base(context).schema, value_type.schema, name=name, ) else: # Override with new XML (got update from modelxml editor) context.schema = xml # Update schema digest context.schema_digest = hashlib.md5(context.schema).hexdigest() # Notify that object has been modified notify( ObjectModifiedEvent( context, Attributes(IFlowFolder, 'schema', 'schema_digest'), ), )
def applyChanges(self, data): content = self.getContent() changes = applyChanges(self, content, data) # ``changes`` is a dictionary; if empty, there were no changes if changes: # Construct change-descriptions for the object-modified event descriptions = [] for interface, attrs in changes.items(): if interface == IAdmUtilEvent: #print "##### Event #######" pass elif IEventIfSuperclass.isEqualOrExtendedBy(interface): #print "##### Superclass #######" pass names = attrs.keys() #for attr in attrs: #print "attr: %s (I:%s)" % (attr, interface) #print " old: ", attrs[attr]['oldval'] #print " new: ", attrs[attr]['newval'] descriptions.append(Attributes(interface, *names)) # Send out a detailed object-modified event zope.event.notify(ObjectModifiedEvent(content, *descriptions)) # workaround for gocept.objectquery import transaction transaction.savepoint() return changes
def edit(self): try: dc = IZopeDublinCore(self.context) except TypeError: return None request = self.request formatter = self.request.locale.dates.getFormatter( 'dateTime', 'medium') message = '' if 'dctitle' in request: dc.title = unicode(request['dctitle']) dc.description = unicode(request['dcdescription']) description = Attributes(IZopeDublinCore, 'title', 'description') notify(ObjectModifiedEvent(self.context, description)) message = "Changed data %s" % formatter.format(datetime.utcnow()) return {'message': message, 'dctitle': dc.title, 'dcdescription': dc.description, 'modified': (dc.modified or dc.created) and \ formatter.format(dc.modified or dc.created) or '', 'created': dc.created and formatter.format(dc.created) or '', 'creators': dc.creators}
def handle_edit_action(self, action, data): descriptions = applyData(self.context, self.form_fields, data, self.adapters) if descriptions: descriptions = [ Attributes(interface, *tuple(keys)) for interface, keys in descriptions.items() ] zope.event.notify(ObjectModifiedEvent(self.context, *descriptions)) formatter = self.request.locale.dates.getFormatter( 'dateTime', 'medium') try: time_zone = idatetime.ITZInfo(self.request) except TypeError: time_zone = pytz.UTC status = _("Updated on ${date_time}", mapping={ 'date_time': formatter.format(datetime.datetime.now(time_zone)) }) self.status = status else: self.status = _('No changes')
def update(self): if self.update_status is not None: # We've been called before. Just return the status we previously # computed. return self.update_status status = '' content = self.adapted if Update in self.request: changed = False try: changed = applyWidgetsChanges(self, self.schema, target=content, names=self.fieldNames) # We should not generate events when an adapter is used. # That's the adapter's job. if changed and self.context is self.adapted: description = Attributes(self.schema, *self.fieldNames) notify(ObjectModifiedEvent(content, description)) except WidgetsError, errors: self.errors = errors status = _("An error occurred.") transaction.doom() else: setUpEditWidgets(self, self.schema, source=self.adapted, ignoreStickyValues=True, names=self.fieldNames) if changed: self.changed() formatter = self.request.locale.dates.getFormatter( 'dateTime', 'medium') status = _("Updated on ${date_time}", mapping={'date_time': formatter.format(datetime.utcnow())})
def test_strategicobjectives_columns(self): """Test dashboard columns config. remove select_row in strategicobjectives_columns and assert that dashboard config has been adapted """ # Test dashboard columns config self.assertEquals(self.pst.strategicobjectives_columns, [ u'select_row', u'pretty_link', u'review_state', u'categories', u'ModificationDate', u'history_actions' ]) self.pst.strategicobjectives_columns.remove('select_row') self.assertEquals(self.pst.strategicobjectives_columns, [ u'pretty_link', u'review_state', u'categories', u'ModificationDate', u'history_actions' ]) self.assertEquals( self.pst.strategicobjectives.all.customViewFields, (u'select_row', u'pretty_link', u'review_state', u'categories', u'ModificationDate', u'history_actions')) notify( ObjectModifiedEvent( self.pst, Attributes(Interface, 'strategicobjectives_columns'))) self.assertEquals(self.pst.strategicobjectives.all.customViewFields, (u'pretty_link', u'review_state', u'categories', u'ModificationDate', u'history_actions'))
def apply_changes(self, data): """Apply updates to form context""" changes = {} contents, changed_contents = {}, {} for form in self.get_forms(): if form.mode == DISPLAY_MODE: continue content = form.get_content() form_changes = apply_changes(form, content, data) if form_changes: merge_changes(changes, form_changes) content_hash = ICacheKeyValue(content) contents[content_hash] = content merge_changes(changed_contents.setdefault(content_hash, {}), form_changes) if changes: # Construct change-descriptions for the object-modified event for content_hash, content_changes in changed_contents.items(): descriptions = [] for interface, names in content_changes.items(): descriptions.append(Attributes(interface, *names)) # Send out a detailed object-modified event self.request.registry.notify( ObjectModifiedEvent(contents[content_hash], *descriptions)) return changes
def test_dmsmainfile_modified(self): pc = self.portal.portal_catalog rid = pc(id='c1')[0].getRID() # before mainfile creation index_value = pc._catalog.getIndex("SearchableText").getEntryForObject( rid, default=[]) self.assertListEqual(index_value, ['e0010', 'title']) # after mainfile creation f1 = createContentInContainer(self.imail, 'dmsmainfile', id='f1', scan_id='010999900000690') index_value = pc._catalog.getIndex("SearchableText").getEntryForObject( rid, default=[]) self.assertListEqual(index_value, [ 'e0010', 'title', u'010999900000690', 'imio010999900000690', u'690' ]) # after mainfile modification f1.scan_id = '010999900000691' zope.event.notify( ObjectModifiedEvent(f1, Attributes(IScanFields, 'IScanFields.scan_id'))) index_value = pc._catalog.getIndex("SearchableText").getEntryForObject( rid, default=[]) self.assertListEqual(index_value, [ 'e0010', 'title', u'010999900000691', 'imio010999900000691', u'691' ]) # event without scan_id attribute zope.event.notify(ObjectModifiedEvent(f1))
def _populate_record(self, record, data): """ Given mapping of data, copy values to attributes on record. Subclasses may override to provide schema validation, selective copy of names, and normalization of values if/as necessary. """ changelog = [] for key, value in data.items(): if key.startswith('_'): continue # invalid key if key == 'record_uid': self.record_uid = str(value) continue try: self._type_whitelist_validation(value) except ValueError: continue # skip problem name! existing_value = getattr(self, key, None) if value != existing_value: changelog.append(key) setattr(record, key, value) if changelog: record._p_changed = True changelog = [ Attributes(self.RECORD_INTERFACE, name) for name in changelog ] notify(ObjectModifiedEvent(record, *changelog))
def applyChanges(self, data): changes = save_form(self, data, self.context) descriptions = [] if changes: for interface, names in changes.items(): descriptions.append(Attributes(interface, *names)) notify(ObjectModifiedEvent(self.context, *descriptions)) return changes
def section(self, value): """ Setter """ anno = IAnnotations(self.context) mapping = anno.get(KEY) mapping['section'] = value info = Attributes(INavigationSectionPosition, 'section') notify(ObjectModifiedEvent(self.context, info))
def setr(self, value): """ Set related """ anno = IAnnotations(self.context) mapping = anno.get(KEY) mapping['related'] = PersistentList(value) info = Attributes(IThemeRelation, 'related') notify(ObjectModifiedEvent(self.context, info))
def _apply(self, **data): if data['assigned_user']: if data['assigned_user'] == '__none__': data['assigned_user'] = None for brain in self.brains: obj = brain.getObject() obj.assigned_user = data['assigned_user'] modified(obj, Attributes(ITask, 'ITask.assigned_user'))
def createAndAdd(self, data): """Add the desired object using the data in the data argument. The data argument is a dictionary with the data entered in the form. """ args = [] if self._arguments: for name in self._arguments: args.append(data[name]) kw = {} if self._keyword_arguments: for name in self._keyword_arguments: if name in data: kw[str(name)] = data[name] content = self.create(*args, **kw) errors = [] if self._set_before_add: adapted = self.schema(content) for name in self._set_before_add: if name in data: field = self.schema[name] try: field.set(adapted, data[name]) except ValidationError: errors.append(sys.exc_info()[1]) if errors: raise WidgetsError(*errors) notify(ObjectCreatedEvent(content)) content = self.add(content) if self._set_after_add: adapted = self.schema(content) for name in self._set_after_add: if name in data: if data[name] is not None: field = self.schema[name] try: field.set(adapted, data[name]) except ValidationError: errors.append(sys.exc_info()[1]) # We have modified the object, so we need to publish an # object-modified event: description = Attributes(self.schema, *self._set_after_add) notify(ObjectModifiedEvent(content, description)) if errors: raise WidgetsError(*errors) return content
def changeTitle(self): """Given a sequence of tuples of old, new ids we rename""" request = self.request id = request.get("retitle_id") new = request.get("new_value") item = self.context[id] dc = IDCDescriptiveProperties(item) dc.title = new notify(ObjectModifiedEvent(item, Attributes(IZopeDublinCore, 'title')))
def test_authorships_should_clear_authors_when_empty(self): from zope.lifecycleevent import ObjectModifiedEvent, Attributes from zeit.cms.content.interfaces import ICommonMetadata from zeit.content.author.author import update_author_freetext content = mock.Mock() content.authors = mock.sentinel.unchanged content.authorships = () event = ObjectModifiedEvent(content, Attributes(ICommonMetadata, 'authorships')) update_author_freetext(content, event) self.assertEqual([], content.authors)
def test_taskContent_modified(self): # initial state self.assertEqual(self.task1.parents_assigned_groups, None) self.assertEqual(self.task2.parents_assigned_groups, None) self.assertEqual(self.task3.parents_assigned_groups, ['Administrators']) self.assertListEqual(self.task4.parents_assigned_groups, ['Administrators', 'Reviewers']) self.assertEqual(self.task1.parents_enquirers, None) self.assertEqual(self.task2.parents_enquirers, None) self.assertEqual(self.task3.parents_enquirers, ['Administrators']) self.assertListEqual(self.task4.parents_enquirers, ['Administrators', 'Site Administrators']) # change value self.task2.assigned_group = 'Site Administrators' self.task2.enquirer = 'Reviewers' modified(self.task2, Attributes(Interface, "ITask.assigned_group"), Attributes(Interface, "ITask.enquirer")) self.assertEqual(self.task2.parents_assigned_groups, None) self.assertEqual(self.task3.parents_assigned_groups, ['Site Administrators']) self.assertListEqual(self.task4.parents_assigned_groups, ['Site Administrators', 'Reviewers']) self.assertEqual(self.task2.parents_enquirers, None) self.assertEqual(self.task3.parents_enquirers, ['Reviewers']) self.assertListEqual(self.task4.parents_enquirers, ['Reviewers', 'Site Administrators'])
def test_authorships_should_not_be_copied_for_other_field_change(self): from zope.lifecycleevent import ObjectModifiedEvent, Attributes from zeit.cms.content.interfaces import ICommonMetadata from zeit.content.author.author import update_author_freetext content = mock.Mock() content.authors = mock.sentinel.unchanged author1, author2 = mock.Mock(), mock.Mock() content.authorships = (author1, author2) event = ObjectModifiedEvent(content, Attributes(ICommonMetadata, 'some-field')) update_author_freetext(content, event) self.assertEqual(mock.sentinel.unchanged, content.authors)
def applyChanges(self, data): content = self.getContent() changes = applyChanges(self, content, data) # ``changes`` is a dictionary; if empty, there were no changes if changes: #import pdb;pdb.set_trace() # Construct change-descriptions for the object-modified event descriptions = [] for interface, attrs in changes.items(): if interface == IAdmUtilEvent: print "##### Event 2 #######" elif IEventIfSuperclass.isEqualOrExtendedBy(interface): print "##### Superclass 2 #######" names = attrs.keys() for attr in attrs: if attr.find("eventInpObjs_" ) == 0: # attribute name starts with ... functionName = attr[len('eventInpObjs_'):] print "attr: %s (I:%s)" % (attr, interface) print " old: ", attrs[attr]['oldval'] print " new: ", attrs[attr]['newval'] newSet = attrs[attr]['newval'] oldSet = attrs[attr]['oldval'] if type(newSet) == type(set()) and \ type(oldSet) == type(set()): newEntries = newSet.difference(oldSet) oldEntries = oldSet.difference(newSet) for oldOid in oldEntries: my_catalog = zapi.getUtility(ICatalog) for resObj in my_catalog.searchResults( oid_index=oldOid): if IAdmUtilEvent.providedBy(resObj): resObj.removeOidFromOutObjects( content.objectID + "." + functionName) resObj.removeInvalidOidFromInpOutObjects( ) resObj._p_changed = True for newOid in newEntries: my_catalog = zapi.getUtility(ICatalog) for resObj in my_catalog.searchResults( oid_index=newOid): if IAdmUtilEvent.providedBy(resObj): resObj.addOidToOutObjects( content.objectID + "." + functionName) resObj.removeInvalidOidFromInpOutObjects( ) resObj._p_changed = True descriptions.append(Attributes(interface, *names)) # Send out a detailed object-modified event zope.event.notify(ObjectModifiedEvent(content, *descriptions)) return changes
def test_ssoid_is_updated_on_checked_out_item(self): with self.acs(self.author.email, id=12345): self.repository['author'] = self.author self.assertEqual(12345, self.author.ssoid) with self.acs(u'hans.mü[email protected]', id=67890): with checked_out(self.repository['author']) as co: co.email = u'hans.mü[email protected]' zope.event.notify(ObjectModifiedEvent( co, Attributes(ICommonMetadata, 'email'))) self.assertEqual(67890, co.ssoid) self.assertEqual(12345, self.repository['author'].ssoid)
def test_dmsdocument_modified(self): # owner changing test orgs = get_registry_organizations() with api.env.adopt_user(username='******'): imail = sub_create( self.portal['incoming-mail'], 'dmsincomingmail', datetime.now(), 'my-id', **{ 'title': u'IMail created by scanner', 'treating_groups': orgs[0] }) dfile = createContentInContainer( imail, 'dmsmainfile', **{'title': 'File created by scanner'}) self.assertEquals(imail.Creator(), 'scanner') self.assertEquals(imail.owner_info()['id'], 'scanner') self.assertEquals(imail.get_local_roles_for_userid('scanner'), ('Owner', )) self.assertEquals(dfile.Creator(), 'scanner') self.assertEquals(dfile.owner_info()['id'], 'scanner') self.assertEquals(dfile.get_local_roles_for_userid('scanner'), ('Owner', )) with api.env.adopt_user(username='******'): imail.setTitle('IMail modified by encodeur') zope.event.notify(ObjectModifiedEvent(imail)) self.assertEquals(imail.Creator(), 'encodeur') self.assertEquals(imail.owner_info()['id'], 'encodeur') self.assertEquals(imail.get_local_roles_for_userid('encodeur'), ('Owner', )) self.assertEquals(imail.get_local_roles_for_userid('scanner'), ()) self.assertEquals(dfile.Creator(), 'encodeur') self.assertEquals(dfile.owner_info()['id'], 'encodeur') self.assertEquals(dfile.get_local_roles_for_userid('encodeur'), ('Owner', )) self.assertEquals(dfile.get_local_roles_for_userid('scanner'), ()) # tasks update test task1 = api.content.create(container=imail, type='task', title='task1', id='t1', assigned_group=orgs[1]) self.assertListEqual(task1.parents_assigned_groups, [orgs[0]]) task2 = api.content.create(container=task1, type='task', title='task2', id='t2', assigned_group=orgs[2]) self.assertListEqual(task2.parents_assigned_groups, [orgs[0], orgs[1]]) imail.treating_groups = orgs[4] zope.event.notify( ObjectModifiedEvent(imail, Attributes(Interface, 'treating_groups'))) self.assertListEqual(task1.parents_assigned_groups, [orgs[4]]) self.assertListEqual(task2.parents_assigned_groups, [orgs[4], orgs[1]])
def notify_modified(subscriber, container=None, *interfaces_attributes): descriptions = [ Attributes(params[0], *params[1:]) for params in interfaces_attributes ] # Some people may call stuff like .restrictedTraverse('@@some-view') in the # subscriber object in an event hander, so wrap it in its container in # order to make it provide .REQUEST through acquisition (otherwise # .restrictedTraverse('@@some-view') will fail). Of course we can do this # only if we know the container on which this subscriber is being added. if container is not None: subscriber = subscriber.__of__(container) event = ObjectModifiedEvent(subscriber, *descriptions) notify(event)
def notify_changes(content, changes, event=ObjectModifiedEvent): """Builds a list of descriptions, made of Attributes objects, defining the changes made on the content and the related interface. """ assert event is not None if changes: descriptions = [] for interface, names in changes.items(): descriptions.append(Attributes(interface, *names)) notify(event(content, *descriptions)) return descriptions return None
def reindex_translation(self, translation): """Once the modification is done, reindex translation""" translation.reindexObject() fti = getUtility(IDexterityFTI, name=translation.portal_type) schema = fti.lookupSchema() descriptions = Attributes(schema) # where is this information needed? # XXX behaviors need to be considered here # use plone.dexterity.utils.iterSchemata or similiar # Pass the canonical object as a event description notify(ObjectModifiedEvent(translation, descriptions, self.canonical))
def update(self): if self.update_status is not None: # We've been called before. Just return the status we previously # computed. return self.update_status status = '' content = self.adapted if Update in self.request.form.keys(): changed = False try: changed = applyWidgetsChanges(self, self.schema, target=content, names=self.fieldNames) # We should not generate events when an adapter is used. # That's the adapter's job. We need to unwrap the objects to # compare them, as they are wrapped differently. # Additionally, we can't use Acquisition.aq_base() because # it strangely returns different objects for these two even # when they are identical. In particular # aq_base(self.adapted) != self.adapted.aq_base :-( if changed and getattr(self.context, 'aq_base', self.context)\ is getattr(self.adapted, 'aq_base', self.adapted): description = Attributes(self.schema, *self.fieldNames) notify(ObjectModifiedEvent(content, description)) except WidgetsError as errors: self.errors = errors status = _("An error occurred.") transaction.abort() else: setUpEditWidgets(self, self.schema, source=self.adapted, ignoreStickyValues=True, names=self.fieldNames) if changed: self.changed() formatter = self.request.locale.dates.getFormatter( 'dateTime', 'medium') status = _("Updated on ${date_time}", mapping={ 'date_time': formatter.format(datetime.utcnow()) }) self.update_status = status return status
def test_authorships_should_be_copied_to_freetext(self): from zope.lifecycleevent import ObjectModifiedEvent, Attributes from zeit.cms.content.interfaces import ICommonMetadata from zeit.content.author.author import update_author_freetext content = mock.Mock() author1, author2 = mock.Mock(), mock.Mock() author1.target.display_name = mock.sentinel.author1 author2.target.display_name = mock.sentinel.author2 content.authorships = (author1, author2) event = ObjectModifiedEvent(content, Attributes(ICommonMetadata, 'authorships')) update_author_freetext(content, event) self.assertEqual([mock.sentinel.author1, mock.sentinel.author2], content.authors)
def handle_edit_action(self, action, data): """ handle edit """ changed = applyChanges(self.context, self.form_fields, data, self.adapters) if changed: attrs = Attributes(interfaces.IPublication, *changed) event.notify(ObjectModifiedEvent(self.context, attrs)) # TODO: Needs locale support. See also Five.form.EditView. self.status = _("Successfully updated") else: self.status = _('No changes') statusmessages_ifaces.IStatusMessage(self.request).addStatusMessage( self.status, 'info') redirect = self.request.response.redirect return redirect(self.context.absolute_url() + '/view')
def testAttributes(self): from zope.interface import implementer, Interface, Attribute class ISample(Interface): field = Attribute("A test field") @implementer(ISample) class Sample(object): pass obj = Sample() obj.field = 42 attrs = Attributes(ISample, "field") modified(obj, attrs) self.assertEqual(self.listener[-1].object, obj) self.assertEqual(self.listener[-1].descriptions, (attrs,))