Automigration of ZTK site manager and translations

Sites migrated from Zope 2.8 don't have a configured component manager (a.k.a.
SiteManager) and because of that, and its consequent lack of registration of
the Localizer Message Catalogs as ITranslationDomain utilities, they don't
perform translation correctly.

Here we add a no-additional-cost migration by overriding the
ObjectManager.getSiteManager() method, and automatically configuring the
component manager, including translation domains.
parent 42625ce0
...@@ -252,6 +252,78 @@ class ERP5Site(FolderMixIn, CMFSite, CacheCookieMixin): ...@@ -252,6 +252,78 @@ class ERP5Site(FolderMixIn, CMFSite, CacheCookieMixin):
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
def _createInitialSiteManager(self):
# This section of code is inspired by
# Products.CMFDefault.upgrade.to21.upgrade_root_site_manager(),
# specificallythe 'except ComponentLookupError:' clause, and also
# by Products.CMFDefault.PortalObjectBase.__init__
from zope.component.globalregistry import base
from five.localsitemanager import (PersistentComponents,
find_next_sitemanager)
next = find_next_sitemanager(self)
if next is None:
next = base
name = '++etc++site'
sm = PersistentComponents(name, (next,))
sm.__parent__ = aq_base(self)
self.setSiteManager(sm)
LOG('ERP5Site', 0, "Site manager '%s' added." % name)
def _doTranslationDomainRegistration(self):
from zope.i18n.interfaces import ITranslationDomain
from Products.ERP5Type.patches.Localizer import (
message_catalog_alias_sources
)
sm = self.getSiteManager()
for message_catalog in self.Localizer.objectValues():
sm.registerUtility(message_catalog,
provided=ITranslationDomain,
name=message_catalog.getId())
for alias in message_catalog_alias_sources.get(message_catalog.getId()):
sm.registerUtility(message_catalog,
provided=ITranslationDomain,
name=alias)
def _doInitialSiteManagerMigration(self):
self._createInitialSiteManager()
# Now that we have a sitemanager, se can do things that require
# one. Including setting up ZTK style utilities and adapters. We
# can even call setSite(self), as long as we roll back that later,
# since we are actually in the middle of a setSite() call.
from zope.site.hooks import getSite, setSite
old_site = getSite()
try:
setSite(self)
# setSite(self) is not really necessary for the migration below, but
# could be needed by other migrations to be added here.
self._doTranslationDomainRegistration()
finally:
setSite(old_site)
# backward compatibility auto-migration
def getSiteManager(self):
# NOTE: do not add a docstring! This method is private by virtue of
# not having it.
# XXX-Leo: Consider moving this method and all methods that it calls
# into a monkeypatch of an optional product. This product could have
# its own tests for migration without actually cluttering the original
# source code and would only need to be installed in sites needing
# migration from Zope 2.8
# This code is an alteration of
# OFS.ObjectManager.ObjectManager.getSiteManager(), and is exactly
# as cheap as it is on the case that self._components is already
# set.
_components = self._components
if _components is not None:
return _components
# This method below can take as (reasonably) long as it pleases
# since it will not be run ever again
self._doInitialSiteManagerMigration()
assert self._components is not None, 'Migration Failed!'
return self._components
security.declareProtected(Permissions.View, 'view') security.declareProtected(Permissions.View, 'view')
def view(self): def view(self):
""" """
......
...@@ -502,6 +502,44 @@ class TestERP5Core(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -502,6 +502,44 @@ class TestERP5Core(ERP5TypeTestCase, ZopeTestCase.Functional):
error_list.append((i.getId(), i.getUid(), i.getProperty('uid'))) error_list.append((i.getId(), i.getUid(), i.getProperty('uid')))
self.assertEquals(error_list, []) self.assertEquals(error_list, [])
def test_site_manager_and_translation_migration(self):
from zope.site.hooks import getSite, setSite
from zope.component import queryUtility
from zope.i18n.interfaces import ITranslationDomain
# check translation is working normaly
erp5_ui_catalog = self.portal.Localizer.erp5_ui
self.assertEqual(queryUtility(ITranslationDomain, 'erp5_ui'),
erp5_ui_catalog)
self.assertEqual(queryUtility(ITranslationDomain, 'ui'), erp5_ui_catalog)
# let's damage it intentionally to see how it is rebuild from scratch
# in a migration from Zope 2.8
sm = self.portal.getSiteManager()
sm.unregisterUtility(provided=ITranslationDomain, name=u'ui')
self.assertEqual(queryUtility(ITranslationDomain, 'erp5_ui'),
erp5_ui_catalog)
self.assertEqual(queryUtility(ITranslationDomain, 'ui'), None)
# now let's simulate a site just migrated from Zope 2.8 that's being
# accessed for the first time:
old_site = getSite()
try:
setSite()
# Sites from Zope2.8 don't have a site_manager yet.
del self.portal._components
# check that we can't get any translation utility
self.assertEqual(queryUtility(ITranslationDomain, 'erp5_ui'), None)
# Now simulate first access. Default behaviour from
# ObjectManager is to raise a ComponentLookupError here:
setSite(self.portal)
# This should have automatically reconstructed the i18n utility
# registrations:
self.assertEqual(queryUtility(ITranslationDomain, 'erp5_ui'),
erp5_ui_catalog)
self.assertEqual(queryUtility(ITranslationDomain, 'ui'), erp5_ui_catalog)
finally:
# clean everything up, we don't want to mess the test environment
transaction.abort()
setSite(old_site)
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestERP5Core)) suite.addTest(unittest.makeSuite(TestERP5Core))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment