Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cherry-pick custom_migration spaces fix #284

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@ Changelog
1.1b6 (2015-10-17)
------------------

- Fix custom migration from and to types with spaces in the type-name.
[pbauer]


1.2.4 (2015-09-27)
------------------

- fix full_view error when collection contains itself
[vangheem]

- test_content_profile: do not appy Products.CMFPlone:plone.
[maurits]


1.2.3 (2015-09-20)
------------------

- Do not raise an exception for items where @@full_view_item throws an
exception. Instead hide the object.
[pbauer]

- Do not raise errors when IPrimaryFieldInfo(obj) fails (e.g. when the
Schema-Cache is gone).
Fixes https://github.com/plone/Products.CMFPlone/issues/839
Expand Down
23 changes: 15 additions & 8 deletions plone/app/contenttypes/migration/custom_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,20 +226,27 @@ def migrate(self, dry_run=False):
if not form[k] or (dry_run and k != form.get('tested_type')):
# nothing selected in this select, continue
continue
at_typename = k[10:]
dx_typename = form[k]
form_at_typename = k[10:]
form_dx_typename = form[k]
at_typename = form_at_typename.replace('_space_', ' ')
dx_typename = form_dx_typename.replace('_space_', ' ')

data[at_typename] = {'target_type': dx_typename,
'field_mapping': []}
# now handle fields mapping for found DX/AT type migration
# definition we have 2 keys we relevant mappings, first key
# definition we have 2 keys with relevant mappings, first key
# is the AT typename second key is a particular key like
# 'dx_DXPortalType__for__MyATPortalType
safe_dx = dx_typename.replace('_space_', '')
safe_at = at_typename.replace('_space_', '')
dx_key = 'dx_%s__for__%s' % (safe_dx, safe_at)
for at_field in form[at_typename]:
dx_field = form[dx_key][form[at_typename].index(at_field)]
dx_key = 'dx_%s__for__%s' % (form_dx_typename,
form_at_typename)
for at_field in form[form_at_typename]:
if form.get(dx_key) is None:
# No field-mappings
continue
dx_field = form[dx_key][form[form_at_typename].index(
at_field)]
if not dx_field:
# Do not migrate field
continue
at_field_name, at_field_type = at_field.split('__type__')
dx_field_name, dx_field_type = dx_field.split('__type__')
Expand Down
2 changes: 1 addition & 1 deletion plone/app/contenttypes/migration/field_migrators.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def migrate_blobimagefield(src_obj, dst_obj, src_fieldname, dst_fieldname):
"""
migrate an image field.
Actually this field needs only to copy the existing NamedBlobImage instance
to the new dst_obj, but we do a little more in detail and create new fields
to the new dst_obj, but we do some more in detail and create new fields.
"""
old_image = getattr(src_obj, src_fieldname)
if old_image == '':
Expand Down
19 changes: 12 additions & 7 deletions plone/app/contenttypes/migration/migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,13 +467,18 @@ def migrateCustomAT(fields_mapping, src_type, dst_type, dry_run=False):
if fti is None or IDexterityFTI.providedBy(fti):
# Get the needed info from an instance of the type
catalog = portal.portal_catalog
brain = catalog(portal_type=src_type, sort_limit=1)[0]
src_obj = brain.getObject()
if IDexterityContent.providedBy(src_obj):
logger.error(
'%s should not be dexterity object!' % src_obj.absolute_url())
is_folderish = getattr(src_obj, 'isPrincipiaFolderish', False)
src_meta_type = src_obj.meta_type
brains = catalog(portal_type=src_type, sort_limit=1)
if not brains:
# no item? assume stuff
is_folderish = False
src_meta_type = src_type
else:
src_obj = brains[0].getObject()
if IDexterityContent.providedBy(src_obj):
logger.error(
'%s should not be dexterity object!' % src_obj.absolute_url())
is_folderish = getattr(src_obj, 'isPrincipiaFolderish', False)
src_meta_type = src_obj.meta_type
else:
# Get info from at-fti
src_meta_type = fti.content_meta_type
Expand Down
5 changes: 5 additions & 0 deletions plone/app/contenttypes/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ def setUpPloneSite(self, portal):
bases=(PLONE_APP_CONTENTTYPES_FIXTURE,),
name="PloneAppContenttypes:Functional"
)
PLONE_APP_CONTENTTYPES_MIGRATION_FUNCTIONAL_FIXTURE = PloneAppContenttypesMigration() # noqa
PLONE_APP_CONTENTTYPES_MIGRATION_FUNCTIONAL_TESTING = FunctionalTesting(
bases=(PLONE_APP_CONTENTTYPES_MIGRATION_FUNCTIONAL_FIXTURE,),
name="PloneAppContenttypes:Migration_Functional"
)
PLONE_APP_CONTENTTYPES_ROBOT_TESTING = FunctionalTesting(
bases=(
PLONE_APP_CONTENTTYPES_FIXTURE,
Expand Down
123 changes: 123 additions & 0 deletions plone/app/contenttypes/tests/test_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from plone.app.contenttypes.migration.utils import restore_references
from plone.app.contenttypes.migration.utils import store_references
from plone.app.contenttypes.testing import PLONE_APP_CONTENTTYPES_FUNCTIONAL_TESTING # noqa
from plone.app.contenttypes.testing import PLONE_APP_CONTENTTYPES_MIGRATION_FUNCTIONAL_TESTING # noqa
from plone.app.contenttypes.testing import PLONE_APP_CONTENTTYPES_MIGRATION_TESTING # noqa
from plone.app.contenttypes.testing import set_browserlayer
from plone.app.referenceablebehavior.referenceable import IReferenceable
Expand Down Expand Up @@ -42,6 +43,7 @@
import json
import os.path
import time
import transaction
import unittest2 as unittest


Expand Down Expand Up @@ -1972,3 +1974,124 @@ def test_dxmigration_migrate_check_migration_successful_message(self):
self.browser.getControl('Update').click()
self.assertIn(
self.good_info_message_template.format(1), self.browser.contents)


class MigrationFunctionalTests(unittest.TestCase):

layer = PLONE_APP_CONTENTTYPES_MIGRATION_FUNCTIONAL_TESTING

def setUp(self):
app = self.layer['app']
self.portal = self.layer['portal']
self.request = self.layer['request']
self.request['ACTUAL_URL'] = self.portal.absolute_url()
self.request['URL'] = self.portal.absolute_url()
self.catalog = getToolByName(self.portal, "portal_catalog")
self.portal.acl_users.userFolderAddUser('admin',
'secret',
['Manager'],
[])
login(self.portal, 'admin')
self.portal.portal_workflow.setDefaultChain(
"simple_publication_workflow")
self.portal_url = self.portal.absolute_url()

self.browser = Browser(app)
self.browser.handleErrors = False
self.browser.addHeader(
'Authorization',
'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,)
)

def tearDown(self):
try:
applyProfile(self.portal, 'plone.app.contenttypes:uninstall')
except KeyError:
pass

def test_pac_installer_cancel(self):
qi = self.portal.portal_quickinstaller
portal_types = self.portal.portal_types
self.browser.open('%s/@@pac_installer' % self.portal_url)
self.assertFalse(qi.isProductInstalled('plone.app.contenttypes'))
self.browser.getControl('Cancel').click()
self.assertFalse(IDexterityFTI.providedBy(portal_types['Document']))
self.assertFalse(qi.isProductInstalled('plone.app.contenttypes'))
self.assertEqual(self.browser.url, self.portal_url)

def test_pac_installer_without_content(self):
qi = self.portal.portal_quickinstaller
portal_types = self.portal.portal_types
self.browser.open('%s/@@pac_installer' % self.portal_url)
self.assertFalse(qi.isProductInstalled('plone.app.contenttypes'))
self.assertFalse(IDexterityFTI.providedBy(portal_types['Document']))
self.assertIn('proceed to the migration-form?', self.browser.contents)
self.browser.getControl('Install').click()
self.assertTrue(IDexterityFTI.providedBy(portal_types['Document']))
self.assertTrue(IDexterityFTI.providedBy(portal_types['News Item']))
self.assertTrue(qi.isProductInstalled('plone.app.contenttypes'))
self.assertIn('Migration control panel', self.browser.contents)
self.assertIn('No content to migrate.', self.browser.contents)

def test_pac_installer_with_content(self):
# add some at content:
self.portal.invokeFactory('Document', 'doc1')
transaction.commit()
qi = self.portal.portal_quickinstaller
portal_types = self.portal.portal_types
self.browser.open('%s/@@pac_installer' % self.portal_url)
self.assertFalse(IDexterityFTI.providedBy(portal_types['Document']))
self.assertFalse(qi.isProductInstalled('plone.app.contenttypes'))
self.assertIn('proceed to the migration-form?', self.browser.contents)
self.browser.getControl('Install').click()
self.assertFalse(IDexterityFTI.providedBy(portal_types['Document']))
self.assertTrue(IDexterityFTI.providedBy(portal_types['News Item']))
self.assertTrue(qi.isProductInstalled('plone.app.contenttypes'))
self.assertIn('Migration control panel', self.browser.contents)
self.assertIn('You currently have <span class="strong">1</span> archetypes objects to be migrated.', self.browser.contents) # noqa

def test_atct_migration_form(self):
# setup session
# taken from Products.Sessions.tests.testSessionDataManager._populate
tf_name = 'temp_folder'
idmgr_name = 'browser_id_manager'
toc_name = 'temp_transient_container'
sdm_name = 'session_data_manager'
from Products.Sessions.BrowserIdManager import BrowserIdManager
from Products.Sessions.SessionDataManager import SessionDataManager
from Products.TemporaryFolder.TemporaryFolder import MountedTemporaryFolder # noqa
from Products.Transience.Transience import TransientObjectContainer
bidmgr = BrowserIdManager(idmgr_name)
tf = MountedTemporaryFolder(tf_name, title="Temporary Folder")
toc = TransientObjectContainer(
toc_name,
title='Temporary Transient Object Container',
timeout_mins=20)
session_data_manager = SessionDataManager(
id=sdm_name,
path=tf_name+'/'+toc_name,
title='Session Data Manager',
requestName='TESTOFSESSION')
self.portal._setObject(idmgr_name, bidmgr)
self.portal._setObject(sdm_name, session_data_manager)
self.portal._setObject(tf_name, tf)
transaction.commit()
self.portal.temp_folder._setObject(toc_name, toc)

# add some at content:
self.portal.invokeFactory('Document', 'doc1')
transaction.commit()
qi = self.portal.portal_quickinstaller
portal_types = self.portal.portal_types
from zExceptions import NotFound
self.assertRaises(NotFound, self.browser.open, '%s/@@atct_migrator' % self.portal_url) # noqa
self.browser.open('%s/@@pac_installer' % self.portal_url)
self.browser.getControl('Install').click()
self.assertIn('You currently have <span class="strong">1</span> archetypes objects to be migrated.', self.browser.contents) # noqa

self.browser.getControl(name='form.widgets.content_types:list').value = ['Document'] # noqa
self.assertEqual(self.browser.getControl(name='form.widgets.migrate_references:list').value, ['selected']) # noqa
self.browser.getControl(name='form.buttons.migrate').click()
self.assertIn('Congratulations! You migrated from Archetypes to Dexterity.', self.browser.contents) # noqa
msg = "<td>ATDocument</td>\n <td>Document</td>\n <td>1</td>"
self.assertIn(msg, self.browser.contents)
Loading