Commit b3a221d4 authored by Jérome Perrin's avatar Jérome Perrin

This is Kazuhiko's patch to restore 2 level selections (1 level of mapping per

user, then 1 level per selection_name), this also adds conflict resolution
for Persistent Mapping storage in portal_selections. This conflict resolution
is just to prevent restarting transactions.



git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@14543 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent bf89211c
...@@ -176,6 +176,15 @@ class Selection(Acquisition.Implicit, Traversable, Persistent): ...@@ -176,6 +176,15 @@ class Selection(Acquisition.Implicit, Traversable, Persistent):
v = v.encode('ascii') v = v.encode('ascii')
setattr(self, k, v) setattr(self, k, v)
def _p_independent(self) :
return 1
def _p_resolveConflict(self, oldState, savedState, newState) :
"""Selection are edited by listboxs, so many conflicts can happen,
this is a workaround, so that no unnecessary transaction is
restarted."""
return newState
def __call__(self, method = None, context=None, REQUEST=None): def __call__(self, method = None, context=None, REQUEST=None):
#LOG("Selection", 0, str((self.__dict__))) #LOG("Selection", 0, str((self.__dict__)))
#LOG("Selection", 0, str(method)) #LOG("Selection", 0, str(method))
......
...@@ -160,11 +160,7 @@ class SelectionTool( BaseTool, UniqueObject, SimpleItem ): ...@@ -160,11 +160,7 @@ class SelectionTool( BaseTool, UniqueObject, SimpleItem ):
""" """
if self.isMemcachedUsed(): if self.isMemcachedUsed():
return [] return []
user_id = self.portal_membership.getAuthenticatedMember().getUserName() return self._getSelectionNameListFromContainer()
if user_id is not None:
prefix = '%s-' % user_id
return [x.replace(prefix, '', 1) for x in self.getSelectionContainer().keys() if x.startswith(prefix)]
return []
# backward compatibility # backward compatibility
security.declareProtected(ERP5Permissions.View, 'getSelectionNames') security.declareProtected(ERP5Permissions.View, 'getSelectionNames')
...@@ -182,34 +178,16 @@ class SelectionTool( BaseTool, UniqueObject, SimpleItem ): ...@@ -182,34 +178,16 @@ class SelectionTool( BaseTool, UniqueObject, SimpleItem ):
return None return None
return selection(context=context) return selection(context=context)
def getSelectionContainer(self):
"""
Return the selection container.
"""
if self.isMemcachedUsed():
value = getattr(self, '_v_selection_data', None)
if value is None:
value = self.getPortalObject().portal_memcached.getMemcachedDict(key_prefix='selection_tool')
setattr(self, '_v_selection_data', value)
else:
value = getattr(self, '_selection_data', None)
if value is None:
value = PersistentMapping()
setattr(self, '_selection_data', value)
return value
security.declareProtected(ERP5Permissions.View, 'getSelectionFor') security.declareProtected(ERP5Permissions.View, 'getSelectionFor')
def getSelectionFor(self, selection_name, REQUEST=None): def getSelectionFor(self, selection_name, REQUEST=None):
""" """
Returns the selection instance for a given selection_name Returns the selection instance for a given selection_name
""" """
user_id = self.portal_membership.getAuthenticatedMember().getUserName() if isinstance(selection_name, (tuple, list)):
if user_id is not None: selection_name = selection_name[0]
if isinstance(selection_name, (tuple, list)): selection = self._getSelectionFromContainer(selection_name)
selection_name = selection_name[0] if selection is not None:
selection = self.getSelectionContainer().get('%s-%s' % (user_id, selection_name)) return selection.__of__(self)
if selection is not None:
return selection.__of__(self)
security.declareProtected(ERP5Permissions.View, 'setSelectionFor') security.declareProtected(ERP5Permissions.View, 'setSelectionFor')
def setSelectionFor(self, selection_name, selection_object, REQUEST=None): def setSelectionFor(self, selection_name, selection_object, REQUEST=None):
...@@ -220,10 +198,7 @@ class SelectionTool( BaseTool, UniqueObject, SimpleItem ): ...@@ -220,10 +198,7 @@ class SelectionTool( BaseTool, UniqueObject, SimpleItem ):
# Set the name so that this selection itself can get its own name. # Set the name so that this selection itself can get its own name.
selection_object.edit(name = selection_name) selection_object.edit(name = selection_name)
user_id = self.portal_membership.getAuthenticatedMember().getUserName() self._setSelectionToContainer(selection_name, selection_object)
if user_id is not None:
self.getSelectionContainer()['%s-%s' % (user_id, selection_name)] = aq_base(selection_object)
return
security.declareProtected(ERP5Permissions.View, 'getSelectionParamsFor') security.declareProtected(ERP5Permissions.View, 'getSelectionParamsFor')
def getSelectionParamsFor(self, selection_name, params=None, REQUEST=None): def getSelectionParamsFor(self, selection_name, params=None, REQUEST=None):
...@@ -1314,8 +1289,73 @@ class SelectionTool( BaseTool, UniqueObject, SimpleItem ): ...@@ -1314,8 +1289,73 @@ class SelectionTool( BaseTool, UniqueObject, SimpleItem ):
return aq_base_name return aq_base_name
return aq_base_name return aq_base_name
def _getUserId(self):
return self.portal_membership.getAuthenticatedMember().getUserName()
def _getSelectionFromContainer(self, selection_name):
user_id = self._getUserId()
if user_id is None: return None
if self.isMemcachedUsed():
return self._getMemcachedContainer().get('%s-%s' %
(user_id, selection_name))
else:
return self._getPersistentContainer(user_id).get(selection_name,
None)
def _setSelectionToContainer(self, selection_name, selection):
user_id = self._getUserId()
if user_id is None: return
if self.isMemcachedUsed():
self._getMemcachedContainer().set('%s-%s' % (user_id, selection_name), aq_base(selection))
else:
self._getPersistentContainer(user_id)[selection_name] = aq_base(selection)
def _getSelectionNameListFromContainer(self):
if self.isMemcachedUsed():
return []
else:
user_id = self._getUserId()
if user_id is None: return []
return self._getPersistentContainer(user_id).keys()
def _getMemcachedContainer(self):
value = getattr(self, '_v_selection_data', None)
if value is None:
value = self.getPortalObject().portal_memcached.getMemcachedDict(key_prefix='selection_tool')
setattr(self, '_v_selection_data', value)
return value
def _getPersistentContainer(self, user_id):
if getattr(self, 'selection_data', None) is None:
self.selection_data = PersistentMapping()
if not self.selection_data.has_key(user_id):
self.selection_data[user_id] = SelectionPersistentMapping()
return self.selection_data[user_id]
InitializeClass( SelectionTool ) InitializeClass( SelectionTool )
class SelectionPersistentMapping(PersistentMapping):
"""A conflict-free PersistentMapping.
Like selection objects, the purpose is to only prevent restarting
transactions.
"""
def _p_independent(self) :
return 1
def _p_resolveConflict(self, oldState, savedState, newState):
# update keys that only savedState has
oldState = newState
# dict returned by PersistentMapping.__getstate__ contains the data
# under _container key, so only compare this key (this is coupled with
# PersistentMapping implementation, but this implementation is lot likely
# to change, because it would break existing pickles).
oldState['_container'].update(savedState['_container'])
return oldState
class TreeListLine: class TreeListLine:
def __init__(self,object,is_pure_summary,depth, is_open,select_domain_dict,exception_uid_list): def __init__(self,object,is_pure_summary,depth, is_open,select_domain_dict,exception_uid_list):
self.object=object self.object=object
...@@ -1529,4 +1569,4 @@ def createFolderMixInPageSelectionMethod(listbox_id): ...@@ -1529,4 +1569,4 @@ def createFolderMixInPageSelectionMethod(listbox_id):
security_property = getattr(SelectionTool, security_property_id, None) security_property = getattr(SelectionTool, security_property_id, None)
if security_property is not None: if security_property is not None:
new_security_property_id = '%s__roles__' % (new_property_id, ) new_security_property_id = '%s__roles__' % (new_property_id, )
setattr(FolderMixIn, new_security_property_id, security_property) setattr(FolderMixIn, new_security_property_id, security_property)
\ No newline at end of file
...@@ -68,8 +68,9 @@ class TestSelectionTool(ERP5TypeTestCase): ...@@ -68,8 +68,9 @@ class TestSelectionTool(ERP5TypeTestCase):
self.portal_selections.getSelectionNameList()) self.portal_selections.getSelectionNameList())
self.assertEquals(['test_selection'], self.assertEquals(['test_selection'],
self.portal_selections.getSelectionNames()) self.portal_selections.getSelectionNames())
self.assert_(self.portal_selections.getSelectionContainer() is not None) self.assert_(self.portal_selections._getPersistentContainer('manager')
self.assert_(getattr(self.portal_selections, '_selection_data', None) is not None)
self.assert_(getattr(self.portal_selections, 'selection_data', None)
is not None) is not None)
# use memcached tool # use memcached tool
self.portal_selections.setStorage('Memcached Tool') self.portal_selections.setStorage('Memcached Tool')
...@@ -77,7 +78,7 @@ class TestSelectionTool(ERP5TypeTestCase): ...@@ -77,7 +78,7 @@ class TestSelectionTool(ERP5TypeTestCase):
self.portal_selections.getSelectionNameList()) self.portal_selections.getSelectionNameList())
self.assertEquals([], self.assertEquals([],
self.portal_selections.getSelectionNames()) self.portal_selections.getSelectionNames())
self.assert_(self.portal_selections.getSelectionContainer() is not None) self.assert_(self.portal_selections._getMemcachedContainer() is not None)
self.assert_(getattr(self.portal_selections, '_v_selection_data', None) self.assert_(getattr(self.portal_selections, '_v_selection_data', None)
is not None) is not None)
......
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