Commit e7fd1555 authored by Julien Muchembled's avatar Julien Muchembled

New Base.skinSuper method to reuse code from lower-priority skins

Purpose is to reduce code duplication.
parent 4e66566f
......@@ -59,6 +59,7 @@ from Products.ERP5Type import _dtmldir
from Products.ERP5Type import PropertySheet
from Products.ERP5Type import interfaces
from Products.ERP5Type import Permissions
from Products.ERP5Type.patches.CMFCoreSkinnable import SKINDATA, skinResolve
from Products.ERP5Type.Utils import UpperCase
from Products.ERP5Type.Utils import convertToUpperCase, convertToMixedCase
from Products.ERP5Type.Utils import createExpressionContext, simple_decorator
......@@ -2976,6 +2977,17 @@ class Base( CopyContainer,
if fallback_script_id is not None:
return getattr(self, fallback_script_id)
security.declareProtected(Permissions.AccessContentsInformation, 'skinSuper')
def skinSuper(self, skin, id):
self.pdb()
if id[:1] != '_' and id[:3] != 'aq_':
skin_info = SKINDATA.get(thread.get_ident())
if skin_info is not None:
object = skinResolve(self.getPortalObject(), (skin_info[0], skin), id)
if object is not None:
return object.__of__(self)
raise AttributeError(id)
# Predicate handling
security.declareProtected(Permissions.AccessContentsInformation, 'asPredicate')
def asPredicate(self, script_id=None):
......
......@@ -30,6 +30,18 @@ from Acquisition import aq_base
during the same request.
"""
def _initializeCache(skin_tool, skin_folder_id_list):
skin_list = {}
for skin_folder_id in skin_folder_id_list[::-1]:
try:
skin_folder = getattr(skin_tool, skin_folder_id)
except AttributeError:
LOG(__name__, WARNING, 'Skin folder %s is in selection list'
' but does not exist.' % skin_folder_id)
else:
skin_list.update(dict.fromkeys(skin_folder.objectIds(), skin_folder_id))
return skin_list
def CMFCoreSkinnableSkinnableObjectManager_initializeCache(self):
'''
Initialize the cache on portal skins.
......@@ -40,23 +52,50 @@ def CMFCoreSkinnableSkinnableObjectManager_initializeCache(self):
portal_skins = portal_skins.aq_base
skin_selection_mapping = {}
for selection_name, skin_folder_id_string in portal_skins._getSelections().iteritems():
skin_list = {}
skin_folder_id_list = skin_folder_id_string.split(',')
skin_folder_id_list.reverse()
for skin_folder_id in skin_folder_id_list:
skin_folder = getattr(portal_skins, skin_folder_id, None)
if skin_folder is not None:
for skin_id in skin_folder.objectIds():
skin_list[skin_id] = skin_folder_id
else:
LOG('__getattr__', WARNING, 'Skin folder %s is in selection list '\
'but does not exist.' % (skin_folder_id, ))
skin_selection_mapping[selection_name] = skin_list
skin_selection_mapping[selection_name] = _initializeCache(portal_skins,
skin_folder_id_string.split(','))
portal_skins._v_skin_location_list = skin_selection_mapping
return skin_selection_mapping
Skinnable.SkinnableObjectManager.initializeCache = CMFCoreSkinnableSkinnableObjectManager_initializeCache
def skinResolve(self, selection, name):
try:
portal_skins = aq_base(self.portal_skins)
except AttributeError:
raise AttributeError, name
try:
skin_selection_mapping = portal_skins._v_skin_location_list
reset = False
except AttributeError:
LOG(__name__, DEBUG, 'Initial skin cache fill.'
' This should not happen often. Current thread id:%X' % get_ident())
skin_selection_mapping = self.initializeCache()
reset = True
while True:
try:
skin_folder_id = skin_selection_mapping[selection][name]
except KeyError:
if selection in skin_selection_mapping or \
isinstance(selection, basestring):
return
skin_list = portal_skins._getSelections()[selection[0]].split(',')
skin_selection_mapping[selection] = skin_list = _initializeCache(
portal_skins, skin_list[1+skin_list.index(selection[1]):])
try:
skin_folder_id = skin_list[name]
except KeyError:
return
reset = True
try:
return aq_base(getattr(getattr(portal_skins, skin_folder_id), name))
except AttributeError:
if reset:
return
# We cannot find a document referenced in the cache, so reset it.
skin_selection_mapping = self.initializeCache()
reset = True
def CMFCoreSkinnableSkinnableObjectManager___getattr__(self, name):
'''
Looks for the name in an object with wrappers that only reach
......@@ -71,46 +110,10 @@ def CMFCoreSkinnableSkinnableObjectManager___getattr__(self, name):
return resolve[name]
except KeyError:
if name not in ignore:
try:
portal_skins = aq_base(self.portal_skins)
except AttributeError:
raise AttributeError, name
try:
skin_selection_mapping = portal_skins._v_skin_location_list
except AttributeError:
LOG('Skinnable Monkeypatch __getattr__', DEBUG, 'Initial skin cache fill. This should not happen often. Current thread id:%X' % (get_ident(), ))
skin_selection_mapping = self.initializeCache()
try:
skin_folder_id = skin_selection_mapping[skin_selection_name][name]
except KeyError:
pass
else:
object = getattr(getattr(portal_skins, skin_folder_id), name, None)
if object is not None:
resolve[name] = object.aq_base
return resolve[name]
else:
# We cannot find a document referenced in the cache.
# Try to find if there is any other candidate in another
# skin folder of lower priority.
selection_dict = portal_skins._getSelections()
candidate_folder_id_list = selection_dict[skin_selection_name].split(',')
previous_skin_folder_id = skin_selection_mapping[skin_selection_name][name]
del skin_selection_mapping[skin_selection_name][name]
if previous_skin_folder_id in candidate_folder_id_list:
previous_skin_index = candidate_folder_id_list.index(previous_skin_folder_id)
candidate_folder_id_list = candidate_folder_id_list[previous_skin_index + 1:]
for candidate_folder_id in candidate_folder_id_list:
candidate_folder = getattr(portal_skins, candidate_folder_id, None)
if candidate_folder is not None:
object = getattr(candidate_folder, name, None)
if object is not None:
skin_selection_mapping[skin_selection_name][name] = candidate_folder_id
resolve[name] = object.aq_base
return resolve[name]
else:
LOG('__getattr__', WARNING, 'Skin folder %s is in selection list '\
'but does not exist.' % (candidate_folder_id, ))
object = skinResolve(self, skin_selection_name, name)
if object is not None:
resolve[name] = object
return object
ignore[name] = None
raise AttributeError(name)
......
......@@ -55,6 +55,9 @@ def CMFCoreSkinsTool__updateCacheEntry(self, container_id, object_id):
skin_location_list = getattr(self, '_v_skin_location_list', None)
if skin_location_list is not None:
self._p_changed = 1
for selection_name in skin_location_list.keys():
if not isinstance(selection_name, basestring):
del skin_location_list[selection_name]
for selection_name, skin_folder_id_string in self._getSelections().iteritems():
skin_folder_id_list = skin_folder_id_string.split(',')
if container_id in skin_folder_id_list:
......
......@@ -30,6 +30,7 @@ import unittest
import transaction
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.tests.utils import createZODBPythonScript
from AccessControl.SecurityManagement import newSecurityManager
TESTED_SKIN_FOLDER_ID = 'custom'
......@@ -131,5 +132,23 @@ class TestCachedSkinsTool(ERP5TypeTestCase):
self.assertTrue(getattr(skinnable_object, searched_object_other_id, None) is not None)
self.assertTrue(getattr(tested_skin_folder, searched_object_other_id, None) is not None)
def test_05_skinSuper(self):
tested_skin_folder = self.getTestedSkinFolder()
script_id = 'Base_getOwnerId'
ob = self.portal.portal_activities
orig = getattr(ob, script_id)()
self.assertEqual(orig, 'ERP5TypeTestCase')
try:
script = createZODBPythonScript(tested_skin_folder, script_id, '',
'return not %r' % orig)
self.assertEqual(getattr(ob, script_id)(), not orig)
script.ZPythonScript_edit('', 'return context.skinSuper(%r, %r)()'
% (TESTED_SKIN_FOLDER_ID, script_id))
self.assertEqual(getattr(ob, script_id)(), orig)
self.getSkinsTool().erp5_core._delObject(script_id)
self.assertRaises(AttributeError, getattr(ob, script_id))
finally:
transaction.abort()
if __name__ == '__main__':
unittest.main()
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