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
Exemple #11
0
    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
Exemple #12
0
    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']
Exemple #13
0
    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)