def test_migration_with_custom_fieldmigrator(self): """Migrate a ATDocument to a DXNewsItem using a custom modifier""" from plone.app.contenttypes.interfaces import INewsItem from plone.app.contenttypes.migration.migration import migrateCustomAT at_document = self.createCustomATDocument('foo-document') at_text = ( u'Some | field is | pipe-delimited | in the field\n' ) at_document.setText(at_text) # install pac but only install News Items portal_setup = getToolByName(self.portal, 'portal_setup') portal_setup.runAllImportStepsFromProfile( 'profile-plone.app.contenttypes:default', blacklisted_steps=['typeinfo'], ) installTypeIfNeeded('News Item') fields_mapping = ( {'AT_field_name': 'text', 'DX_field_name': 'creators', 'field_migrator': some_field_migrator}, ) migrateCustomAT( fields_mapping, src_type='Document', dst_type='News Item') dx_newsitem = self.portal['foo-document'] self.assertTrue(INewsItem.providedBy(dx_newsitem)) self.assertTrue(dx_newsitem is not at_document) self.assertEqual(4, len(dx_newsitem.creators)) self.assertEqual(at_document.Title(), dx_newsitem.title)
def test_migrate_extended_document(self): from plone.app.contenttypes.migration.migration import migrateCustomAT from plone.app.contenttypes.interfaces import INewsItem at_document = self.createCustomATDocument('foo-document') qi = self.portal.portal_quickinstaller # install pac but only install News Items qi.installProduct( 'plone.app.contenttypes', profile='plone.app.contenttypes:default', blacklistedSteps=['typeinfo']) installTypeIfNeeded("News Item") fields_mapping = ( {'AT_field_name': 'textExtended', 'AT_field_type': 'Products.Archetypes.Field.TextField', 'DX_field_name': 'text', 'DX_field_type': 'RichText', }, {'AT_field_name': 'stringExtended', 'AT_field_type': 'StringField', 'DX_field_name': 'title', 'DX_field_type': 'StringField', }, ) # migrate extended AT Document to default DX News Item migrateCustomAT( fields_mapping, src_type='Document', dst_type='News Item') dx_newsitem = self.portal['foo-document'] self.assertTrue(INewsItem.providedBy(dx_newsitem)) self.assertTrue(dx_newsitem is not at_document) self.assertEquals(at_document.textExtended(), dx_newsitem.text.raw) self.assertEquals(at_document.stringExtended, dx_newsitem.title)
def test_migrate_extended_document(self): from plone.app.contenttypes.migration.migration import migrateCustomAT from plone.app.contenttypes.interfaces import INewsItem at_document = self.createCustomATDocument('foo-document') # install pac but only install News Items portal_setup = getToolByName(self.portal, 'portal_setup') portal_setup.runAllImportStepsFromProfile( 'profile-plone.app.contenttypes:default', blacklisted_steps=['typeinfo'], ) installTypeIfNeeded('News Item') fields_mapping = ( {'AT_field_name': 'textExtended', 'AT_field_type': 'Products.Archetypes.Field.TextField', 'DX_field_name': 'text', 'DX_field_type': 'RichText', }, {'AT_field_name': 'stringExtended', 'AT_field_type': 'StringField', 'DX_field_name': 'title', 'DX_field_type': 'StringField', }, ) # migrate extended AT Document to default DX News Item migrateCustomAT( fields_mapping, src_type='Document', dst_type='News Item') dx_newsitem = self.portal['foo-document'] self.assertTrue(INewsItem.providedBy(dx_newsitem)) self.assertTrue(dx_newsitem is not at_document) self.assertEqual(at_document.textExtended(), dx_newsitem.text.raw) self.assertEqual(at_document.stringExtended, dx_newsitem.title)
def test_install_dx_type_if_needed_wrong_type_name(self): from plone.app.contenttypes.migration.utils import installTypeIfNeeded self.assertRaises(KeyError, installTypeIfNeeded, ['Unknown']) try: installTypeIfNeeded('Unknown') except KeyError as e: self.assertEqual( e.message, 'Unknown is not one of the default types' )
def test_install_dx_type_if_needed(self): from plone.app.contenttypes.migration.utils import installTypeIfNeeded tt = self.portal.portal_types tt.manage_delObjects('Document') tt.manage_addTypeInformation( 'Factory-based Type Information with dynamic views', id='Document') applyProfile( self.portal, 'plone.app.contenttypes:default', blacklisted_steps=['typeinfo']) fti = tt.getTypeInfo('Document') self.assertFalse(IDexterityFTI.providedBy(fti)) installTypeIfNeeded('Document') fti = tt.getTypeInfo('Document') self.assertTrue(IDexterityFTI.providedBy(fti))
def installTypesWithoutItems(self): catalog = getToolByName(self.context, "portal_catalog") for types_name in DEFAULT_TYPES: if not catalog.unrestrictedSearchResults(portal_type=types_name): installTypeIfNeeded(types_name)
def __call__(self, migrate=False, content_types="all", migrate_schemaextended_content=False, migrate_references=True, from_form=False): portal = self.context if not from_form and migrate not in ['1', 'True', 'true', 1]: url1 = '{0}/@@migrate_from_atct?migrate=1'.format( portal.absolute_url()) url2 = '{0}/@@atct_migrator'.format(portal.absolute_url()) msg = u'Warning \n' msg += u'-------\n' msg += u'You are accessing "@@migrate_from_atct" directly. ' msg += u'This will migrate all content to dexterity!\n\n' msg += u'Really migrate all content now: {0}\n\n'.format(url1) msg += u'First select what to migrate: {0}'.format(url2) return msg helpers = getMultiAdapter((portal, self.request), name="atct_migrator_helpers") if helpers.linguaplone_installed(): msg = 'Warning\n' msg += 'Migration aborted since Products.LinguaPlone is ' msg += 'installed. See ' msg += 'http://github.com/plone/plone.app.contenttypes#migration ' msg += 'for more information.' return msg stats_before = self.stats() starttime = datetime.now() catalog = portal.portal_catalog # switch linkintegrity temp off ptool = queryUtility(IPropertiesTool) site_props = getattr(ptool, 'site_properties', None) link_integrity = site_props.getProperty('enable_link_integrity_checks', False) site_props.manage_changeProperties(enable_link_integrity_checks=False) # switch of setModificationDate on changes self.patchNotifyModified() not_migrated = [] migrated_types = {} for (k, v) in ATCT_LIST.items(): if content_types != "all" and k not in content_types: not_migrated.append(k) continue # test if the ct is extended beyond blobimage and blobfile if len(isSchemaExtended(v['iface'])) > len(v['extended_fields']) \ and not migrate_schemaextended_content: not_migrated.append(k) continue query = { 'object_provides': v['iface'].__identifier__, 'meta_type': v['old_meta_type'], } if HAS_MULTILINGUAL and 'Language' in catalog.indexes(): query['Language'] = 'all' amount_to_be_migrated = len(catalog(query)) starttime_for_current = datetime.now() logger.info("Start migrating %s objects from %s to %s" % ( amount_to_be_migrated, v['old_meta_type'], v['type_name'])) installTypeIfNeeded(v['type_name']) # call the migrator v['migrator'](portal) # logging duration_current = datetime.now() - starttime_for_current duration_human = str(timedelta(seconds=duration_current.seconds)) logger.info("Finished migrating %s objects from %s to %s in %s" % ( amount_to_be_migrated, v['old_meta_type'], v['type_name'], duration_human)) # some data for the results-page migrated_types[k] = {} migrated_types[k]['amount_migrated'] = amount_to_be_migrated migrated_types[k]['old_meta_type'] = v['old_meta_type'] migrated_types[k]['type_name'] = v['type_name'] # if there are blobnewsitems we just migrate them silently. migration.migrate_blobnewsitems(portal) if migrate_references: migration.restoreReferences(portal) # switch linkintegrity back to what it was before migrating site_props.manage_changeProperties( enable_link_integrity_checks=link_integrity ) # switch on setModificationDate on changes self.resetNotifyModified() duration = str(timedelta(seconds=(datetime.now() - starttime).seconds)) if not_migrated: msg = ("The following types were not migrated: \n %s" % "\n".join(not_migrated)) else: msg = "Migration successful\n\n" msg += '\n-----------------------------\n' msg += 'Migration finished in: %s' % duration msg += '\n-----------------------------\n' msg += 'Migration statictics:\n' msg += pformat(migrated_types) msg += '\n-----------------------------\n' msg += 'State before:\n' msg += pformat(stats_before) msg += '\n-----------------------------\n' msg += 'Stats after:\n' msg += pformat(self.stats()) msg += '\n-----------------------------\n' if not from_form: logger.info(msg) return msg else: stats = { 'duration': duration, 'before': stats_before, 'after': self.stats(), 'content_types': content_types, 'migrated_types': migrated_types, } return stats
def test_migrate_atevent_to_dxevent(self): """Tests the custom migration by migrating a default type. It is not meant to be used this way but is a nice way to test the migrations. During this migration the event fti is already replaced by the dx one. """ from DateTime import DateTime from plone.app.contenttypes.migration.migration import migrateCustomAT from plone.app.contenttypes.interfaces import IEvent # create an ATEvent self.portal.invokeFactory('Event', 'event') at_event = self.portal['event'] # Date FORMAT = '%Y-%m-%d %H:%M' start = '2013-02-03 12:15' end = '2013-04-05 13:45' at_event.getField('startDate').set(at_event, DateTime(start)) at_event.getField('endDate').set(at_event, DateTime(end)) # Contact at_event.getField('contactPhone').set(at_event, '123456789') at_event.getField('contactEmail').set(at_event, '*****@*****.**') at_event.getField('contactName').set(at_event, u'Näme') # URL at_event.getField('eventUrl').set(at_event, 'http://www.plone.org') # Attendees at_event.getField('attendees').set(at_event, ('Yöu', 'Me')) # Text at_event.setText('Tütensuppe') at_event.setContentType('text/plain') oldTZ = os.environ.get('TZ', None) TZ = 'Asia/Tbilisi' os.environ['TZ'] = TZ timezone = pytz.timezone(TZ) qi = self.portal.portal_quickinstaller # install pac but only install Event qi.installProduct( 'plone.app.contenttypes', profile='plone.app.contenttypes:default', blacklistedSteps=['typeinfo']) installTypeIfNeeded("Event") fields_mapping = ( {'AT_field_name': 'startDate', 'AT_field_type': 'Products.Archetypes.Field.DateTimeField', 'DX_field_name': 'start', 'DX_field_type': 'Datetime', }, {'AT_field_name': 'endDate', 'AT_field_type': 'Products.Archetypes.Field.DateTimeField', 'DX_field_name': 'end', 'DX_field_type': 'Datetime', }, {'AT_field_name': 'text', 'AT_field_type': 'Products.Archetypes.Field.TextField', 'DX_field_name': 'text', 'DX_field_type': 'RichText', }, {'AT_field_name': 'eventUrl', 'AT_field_type': 'Products.Archetypes.Field.StringField', 'DX_field_name': 'event_url', 'DX_field_type': 'StringField', }, {'AT_field_name': 'contactEmail', 'AT_field_type': 'Products.Archetypes.Field.StringField', 'DX_field_name': 'contact_email', 'DX_field_type': 'StringField', }, {'AT_field_name': 'contactName', 'AT_field_type': 'Products.Archetypes.Field.StringField', 'DX_field_name': 'contact_name', 'DX_field_type': 'StringField', }, {'AT_field_name': 'contactPhone', 'AT_field_type': 'Products.Archetypes.Field.StringField', 'DX_field_name': 'contact_phone', 'DX_field_type': 'StringField', }, {'AT_field_name': 'attendees', 'AT_field_type': 'Products.Archetypes.Field.LinesField', 'DX_field_name': 'attendees', 'DX_field_type': 'Tuple', }, ) # migrate ATEvent to new default Event migrateCustomAT(fields_mapping, src_type='Event', dst_type='Event') dx_event = self.portal['event'] self.assertTrue(IEvent.providedBy(dx_event)) self.assertTrue(dx_event is not at_event) self.assertEquals(safe_unicode( at_event.getText()), dx_event.text.output) self.assertEquals(at_event.eventUrl, dx_event.event_url) self.assertEquals(at_event.contactEmail, dx_event.contact_email) self.assertEquals(at_event.contactName, dx_event.contact_name) self.assertEquals(at_event.contactPhone, dx_event.contact_phone) self.assertEquals(at_event.attendees, dx_event.attendees) self.assertEquals( dx_event.start, timezone.localize(datetime.strptime(start, FORMAT))) self.assertEquals( dx_event.end, timezone.localize(datetime.strptime(end, FORMAT))) if oldTZ: os.environ['TZ'] = oldTZ else: del os.environ['TZ']
def test_migrate_atevent_to_dxnewsitem(self): """Tests the custom migration by migrating a default type. It is not meant to be used this way but is a nice way to test the migrations. During this migration the old event fti is still present. """ from DateTime import DateTime from plone.app.contenttypes.migration.migration import migrateCustomAT from plone.app.contenttypes.interfaces import INewsItem # create an ATEvent self.portal.invokeFactory('Event', 'event') at_event = self.portal['event'] # Date at_event.getField('startDate') \ .set(at_event, DateTime('2013-02-03 12:00')) at_event.getField('endDate') \ .set(at_event, DateTime('2013-04-05 13:00')) # Contact at_event.getField('contactPhone').set(at_event, '123456789') at_event.getField('contactEmail').set(at_event, '*****@*****.**') at_event.getField('contactName').set(at_event, u'Näme') # URL at_event.getField('eventUrl').set(at_event, 'http://www.plone.org') # Attendees at_event.getField('attendees').set(at_event, ('You', 'Me')) # Text at_event.setText('Tütensuppe') at_event.setContentType('text/plain') oldTZ = os.environ.get('TZ', None) os.environ['TZ'] = 'Asia/Tbilisi' qi = self.portal.portal_quickinstaller # install pac but only install News Items qi.installProduct( 'plone.app.contenttypes', profile='plone.app.contenttypes:default', blacklistedSteps=['typeinfo']) installTypeIfNeeded("News Item") fields_mapping = ( {'AT_field_name': 'text', 'AT_field_type': 'Products.Archetypes.Field.TextField', 'DX_field_name': 'text', 'DX_field_type': 'RichText', }, {'AT_field_name': 'contactName', 'AT_field_type': 'StringField', 'DX_field_name': 'image_caption', 'DX_field_type': 'StringField', }, ) # migrate ATCTEvent to default DX News Item migrateCustomAT(fields_mapping, src_type='Event', dst_type='News Item') if oldTZ: os.environ['TZ'] = oldTZ else: del os.environ['TZ'] dx_newsitem = self.portal['event'] self.assertTrue(INewsItem.providedBy(dx_newsitem)) self.assertTrue(dx_newsitem is not at_event) self.assertEquals( safe_unicode(at_event.getText()), dx_newsitem.text.output) self.assertEquals( at_event.contactName, dx_newsitem.image_caption)
def __call__(self, migrate=False, content_types='all', migrate_schemaextended_content=False, migrate_references=True, from_form=False, reindex_catalog=True, patch_searchabletext=False, ): portal = self.context if not from_form and migrate not in ['1', 'True', 'true', 1]: url1 = '{0}/@@migrate_from_atct?migrate=1'.format( portal.absolute_url()) url2 = '{0}/@@atct_migrator'.format(portal.absolute_url()) msg = u'Warning \n' msg += u'-------\n' msg += u'You are accessing "@@migrate_from_atct" directly. ' msg += u'This will migrate all content to dexterity!\n\n' msg += u'Really migrate all content now: {0}\n\n'.format(url1) msg += u'First select what to migrate: {0}'.format(url2) return msg helpers = getMultiAdapter((portal, self.request), name='atct_migrator_helpers') if helpers.linguaplone_installed(): msg = 'Warning\n' msg += 'Migration aborted since Products.LinguaPlone is ' msg += 'installed. See ' msg += 'http://github.com/plone/plone.app.contenttypes#migration ' msg += 'for more information.' return msg stats_before = self.stats() starttime = datetime.now() self.request['plone.app.contenttypes_migration_running'] = True msg = 'Starting Migration\n\n' msg += '\n-----------------------------\n' msg += 'Content statictics:\n' msg += pformat(stats_before) msg += '\n-----------------------------\n' msg += 'Types to be migrated:\n' msg += pformat(content_types) msg += '\n-----------------------------\n' logger.info(msg) # store references on the portal if migrate_references: store_references(portal) catalog = portal.portal_catalog # Patch various things that make migration harder (link_integrity, queue_indexing, patch_searchabletext) = patch_before_migration(patch_searchabletext) not_migrated = [] migrated_types = {} for (k, v) in ATCT_LIST.items(): if content_types != 'all' and k not in content_types: not_migrated.append(k) continue # test if the ct is extended beyond blobimage and blobfile if len(isSchemaExtended(v['iface'])) > len(v['extended_fields']) \ and not migrate_schemaextended_content: not_migrated.append(k) continue query = { 'object_provides': v['iface'].__identifier__, 'meta_type': v['old_meta_type'], } amount_to_be_migrated = len(catalog(query)) starttime_for_current = datetime.now() logger.info( 'Start migrating {0} objects from {1} to {2}'.format( amount_to_be_migrated, v['old_meta_type'], v['type_name'], ) ) installTypeIfNeeded(v['type_name']) # call the migrator v['migrator'](portal) # logging duration_current = datetime.now() - starttime_for_current duration_human = str(timedelta(seconds=duration_current.seconds)) logger.info( 'Finished migrating {0} objects from {1} to {2} in {3}'.format( amount_to_be_migrated, v['old_meta_type'], v['type_name'], duration_human), ) # some data for the results-page migrated_types[k] = {} migrated_types[k]['amount_migrated'] = amount_to_be_migrated migrated_types[k]['old_meta_type'] = v['old_meta_type'] migrated_types[k]['type_name'] = v['type_name'] # if there are blobnewsitems we just migrate them silently. migration.migrate_blobnewsitems(portal) # make sure the view-methods on the plone site are updated use_new_view_names(portal, types_to_fix=['Plone Site']) if reindex_catalog: catalog.clearFindAndRebuild() # restore references if migrate_references: restore_references(portal) # Revert to the original state undo_patch_after_migration( link_integrity, queue_indexing, patch_searchabletext) duration = str(timedelta(seconds=(datetime.now() - starttime).seconds)) if not_migrated: msg = ( 'The following types were not migrated: \n {0}'.format( '\n'.join(not_migrated) ) ) else: msg = 'Migration successful\n\n' msg += '\n-----------------------------\n' msg += 'Migration finished in: {0}'.format(duration) msg += '\n-----------------------------\n' msg += 'Migration statictics:\n' msg += pformat(migrated_types) msg += '\n-----------------------------\n' msg += 'State before:\n' msg += pformat(stats_before) msg += '\n-----------------------------\n' msg += 'Stats after:\n' msg += pformat(self.stats()) msg += '\n-----------------------------\n' if not from_form: logger.info(msg) return msg else: stats = { 'duration': duration, 'before': stats_before, 'after': self.stats(), 'content_types': content_types, 'migrated_types': migrated_types, } logger.info(msg) return stats
def __call__(self, migrate=False, content_types='all', migrate_schemaextended_content=False, migrate_references=True, from_form=False): portal = self.context if content_types == 'all': content_types = DEFAULT_TYPES if not from_form and migrate not in ['1', 'True', 'true', 1]: url1 = '{0}/@@migrate_from_atct?migrate=1'.format( portal.absolute_url()) url2 = '{0}/@@atct_migrator'.format(portal.absolute_url()) msg = u'Warning \n' msg += u'-------\n' msg += u'You are accessing "@@migrate_from_atct" directly. ' msg += u'This will migrate all content to dexterity!\n\n' msg += u'Really migrate all content now: {0}\n\n'.format(url1) msg += u'First select what to migrate: {0}'.format(url2) return msg helpers = getMultiAdapter((portal, self.request), name='atct_migrator_helpers') if helpers.linguaplone_installed(): msg = 'Warning\n' msg += 'Migration aborted since Products.LinguaPlone is ' msg += 'installed. See ' msg += 'http://github.com/plone/plone.app.contenttypes#migration ' msg += 'for more information.' return msg stats_before = self.stats() starttime = datetime.now() # store references on the portal if migrate_references: store_references(portal) catalog = portal.portal_catalog # switch linkintegrity temp off ptool = queryUtility(IPropertiesTool) site_props = getattr(ptool, 'site_properties', None) link_integrity_in_props = False if site_props and site_props.hasProperty( 'enable_link_integrity_checks'): link_integrity_in_props = True link_integrity = site_props.getProperty( 'enable_link_integrity_checks', False) site_props.manage_changeProperties( enable_link_integrity_checks=False) else: # Plone 5 registry = getUtility(IRegistry) editing_settings = registry.forInterface( IEditingSchema, prefix='plone') link_integrity = editing_settings.enable_link_integrity_checks editing_settings.enable_link_integrity_checks = False # switch of setModificationDate on changes self.patchNotifyModified() # patch UUIDIndex patch( UUIDIndex, 'insertForwardIndexEntry', patched_insertForwardIndexEntry) not_migrated = [] migrated_types = {} for (k, v) in ATCT_LIST.items(): if k not in content_types: not_migrated.append(k) continue # test if the ct is extended beyond blobimage and blobfile if len(isSchemaExtended(v['iface'])) > len(v['extended_fields']) \ and not migrate_schemaextended_content: not_migrated.append(k) continue query = { 'object_provides': v['iface'].__identifier__, 'meta_type': v['old_meta_type'], } if HAS_MULTILINGUAL and 'Language' in catalog.indexes(): query['Language'] = 'all' amount_to_be_migrated = len(catalog(query)) starttime_for_current = datetime.now() logger.info( 'Start migrating {0} objects from {1} to {2}'.format( amount_to_be_migrated, v['old_meta_type'], v['type_name'], ) ) installTypeIfNeeded(v['type_name']) # call the migrator v['migrator'](portal) # logging duration_current = datetime.now() - starttime_for_current duration_human = str(timedelta(seconds=duration_current.seconds)) logger.info( 'Finished migrating {0} objects from {1} to {2} in {3}'.format( amount_to_be_migrated, v['old_meta_type'], v['type_name'], duration_human), ) # some data for the results-page migrated_types[k] = {} migrated_types[k]['amount_migrated'] = amount_to_be_migrated migrated_types[k]['old_meta_type'] = v['old_meta_type'] migrated_types[k]['type_name'] = v['type_name'] # if there are blobnewsitems we just migrate them silently. migration.migrate_blobnewsitems(portal) # make sure the view-methods on the plone site are updated use_new_view_names(portal, types_to_fix=['Plone Site']) catalog.clearFindAndRebuild() # restore references if migrate_references: restore_references(portal) # switch linkintegrity back to what it was before migrating if link_integrity_in_props: site_props.manage_changeProperties( enable_link_integrity_checks=link_integrity ) else: editing_settings.enable_link_integrity_checks = link_integrity # switch on setModificationDate on changes self.resetNotifyModified() # unpatch UUIDIndex undoPatch(UUIDIndex, 'insertForwardIndexEntry') duration = str(timedelta(seconds=(datetime.now() - starttime).seconds)) if not_migrated: msg = ( 'The following types were not migrated: \n {0}'.format( '\n'.join(not_migrated) ) ) else: msg = 'Migration successful\n\n' msg += '\n-----------------------------\n' msg += 'Migration finished in: {0}'.format(duration) msg += '\n-----------------------------\n' msg += 'Migration statictics:\n' msg += pformat(migrated_types) msg += '\n-----------------------------\n' msg += 'State before:\n' msg += pformat(stats_before) msg += '\n-----------------------------\n' msg += 'Stats after:\n' msg += pformat(self.stats()) msg += '\n-----------------------------\n' if not from_form: logger.info(msg) return msg else: stats = { 'duration': duration, 'before': stats_before, 'after': self.stats(), 'content_types': content_types, 'migrated_types': migrated_types, } logger.info(msg) return stats
def test_migrate_atevent_to_dxevent(self): """Tests the custom migration by migrating a default type. It is not meant to be used this way but is a nice way to test the migrations. During this migration the event fti is already replaced by the dx one. """ from DateTime import DateTime from plone.app.contenttypes.migration.migration import migrateCustomAT from plone.app.contenttypes.interfaces import IEvent # create an ATEvent self.portal.invokeFactory('Event', 'event') at_event = self.portal['event'] # Date FORMAT = '%Y-%m-%d %H:%M' start = '2013-02-03 12:15' end = '2013-04-05 13:45' at_event.getField('startDate').set(at_event, DateTime(start)) at_event.getField('endDate').set(at_event, DateTime(end)) # Contact at_event.getField('contactPhone').set(at_event, '123456789') at_event.getField('contactEmail').set(at_event, '*****@*****.**') at_event.getField('contactName').set(at_event, u'Näme') # URL at_event.getField('eventUrl').set(at_event, 'http://www.plone.org') # Attendees at_event.getField('attendees').set(at_event, ('Yöu', 'Me')) # Text at_event.setText('Tütensuppe') at_event.setContentType('text/plain') oldTZ = os.environ.get('TZ', None) TZ = 'Asia/Tbilisi' os.environ['TZ'] = TZ timezone = pytz.timezone(TZ) # install pac but only install Event portal_setup = getToolByName(self.portal, 'portal_setup') portal_setup.runAllImportStepsFromProfile( 'profile-plone.app.contenttypes:default', blacklisted_steps=['typeinfo'], ) installTypeIfNeeded('Event') fields_mapping = ( {'AT_field_name': 'startDate', 'AT_field_type': 'Products.Archetypes.Field.DateTimeField', 'DX_field_name': 'start', 'DX_field_type': 'Datetime', }, {'AT_field_name': 'endDate', 'AT_field_type': 'Products.Archetypes.Field.DateTimeField', 'DX_field_name': 'end', 'DX_field_type': 'Datetime', }, {'AT_field_name': 'text', 'AT_field_type': 'Products.Archetypes.Field.TextField', 'DX_field_name': 'text', 'DX_field_type': 'RichText', }, {'AT_field_name': 'eventUrl', 'AT_field_type': 'Products.Archetypes.Field.StringField', 'DX_field_name': 'event_url', 'DX_field_type': 'StringField', }, {'AT_field_name': 'contactEmail', 'AT_field_type': 'Products.Archetypes.Field.StringField', 'DX_field_name': 'contact_email', 'DX_field_type': 'StringField', }, {'AT_field_name': 'contactName', 'AT_field_type': 'Products.Archetypes.Field.StringField', 'DX_field_name': 'contact_name', 'DX_field_type': 'StringField', }, {'AT_field_name': 'contactPhone', 'AT_field_type': 'Products.Archetypes.Field.StringField', 'DX_field_name': 'contact_phone', 'DX_field_type': 'StringField', }, {'AT_field_name': 'attendees', 'AT_field_type': 'Products.Archetypes.Field.LinesField', 'DX_field_name': 'attendees', 'DX_field_type': 'Tuple', }, ) # migrate ATEvent to new default Event migrateCustomAT(fields_mapping, src_type='Event', dst_type='Event') dx_event = self.portal['event'] self.assertTrue(IEvent.providedBy(dx_event)) self.assertTrue(dx_event is not at_event) self.assertEqual(safe_unicode( at_event.getText()), dx_event.text.output) self.assertEqual(at_event.eventUrl, dx_event.event_url) self.assertEqual(at_event.contactEmail, dx_event.contact_email) self.assertEqual(at_event.contactName, dx_event.contact_name) self.assertEqual(at_event.contactPhone, dx_event.contact_phone) self.assertEqual(at_event.attendees, dx_event.attendees) self.assertEqual( dx_event.start, timezone.localize(datetime.strptime(start, FORMAT))) self.assertEqual( dx_event.end, timezone.localize(datetime.strptime(end, FORMAT))) if oldTZ: os.environ['TZ'] = oldTZ else: del os.environ['TZ']
def test_migrate_atevent_to_dxnewsitem(self): """Tests the custom migration by migrating a default type. It is not meant to be used this way but is a nice way to test the migrations. During this migration the old event fti is still present. """ from DateTime import DateTime from plone.app.contenttypes.migration.migration import migrateCustomAT from plone.app.contenttypes.interfaces import INewsItem # create an ATEvent self.portal.invokeFactory('Event', 'event') at_event = self.portal['event'] # Date at_event.getField('startDate') \ .set(at_event, DateTime('2013-02-03 12:00')) at_event.getField('endDate') \ .set(at_event, DateTime('2013-04-05 13:00')) # Contact at_event.getField('contactPhone').set(at_event, '123456789') at_event.getField('contactEmail').set(at_event, '*****@*****.**') at_event.getField('contactName').set(at_event, u'Näme') # URL at_event.getField('eventUrl').set(at_event, 'http://www.plone.org') # Attendees at_event.getField('attendees').set(at_event, ('You', 'Me')) # Text at_event.setText('Tütensuppe') at_event.setContentType('text/plain') oldTZ = os.environ.get('TZ', None) os.environ['TZ'] = 'Asia/Tbilisi' # install pac but only install News Items portal_setup = getToolByName(self.portal, 'portal_setup') portal_setup.runAllImportStepsFromProfile( 'profile-plone.app.contenttypes:default', blacklisted_steps=['typeinfo'], ) installTypeIfNeeded('News Item') fields_mapping = ( {'AT_field_name': 'text', 'AT_field_type': 'Products.Archetypes.Field.TextField', 'DX_field_name': 'text', 'DX_field_type': 'RichText', }, {'AT_field_name': 'contactName', 'AT_field_type': 'StringField', 'DX_field_name': 'image_caption', 'DX_field_type': 'StringField', }, ) # migrate ATCTEvent to default DX News Item migrateCustomAT(fields_mapping, src_type='Event', dst_type='News Item') if oldTZ: os.environ['TZ'] = oldTZ else: del os.environ['TZ'] dx_newsitem = self.portal['event'] self.assertTrue(INewsItem.providedBy(dx_newsitem)) self.assertTrue(dx_newsitem is not at_event) self.assertEqual( safe_unicode(at_event.getText()), dx_newsitem.text.output) self.assertEqual( at_event.contactName, dx_newsitem.image_caption)