Commit d7356d5a authored by Kazuhiko Shiozaki's avatar Kazuhiko Shiozaki

support unique selection for unique anonymous user using a different storage...

support unique selection for unique anonymous user using a different storage that should be volatile one like memcached. this feature is disabled by default.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@38249 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 579bc9c9
...@@ -43,6 +43,8 @@ from Products.ERP5Form.Selection import Selection, DomainSelection ...@@ -43,6 +43,8 @@ from Products.ERP5Form.Selection import Selection, DomainSelection
from ZPublisher.HTTPRequest import FileUpload from ZPublisher.HTTPRequest import FileUpload
import md5 import md5
import string, re import string, re
from time import time
from random import random
from urlparse import urlsplit, urlunsplit from urlparse import urlsplit, urlunsplit
from zLOG import LOG, INFO from zLOG import LOG, INFO
from Acquisition import aq_base from Acquisition import aq_base
...@@ -139,14 +141,19 @@ class SelectionTool( BaseTool, SimpleItem ): ...@@ -139,14 +141,19 @@ class SelectionTool( BaseTool, SimpleItem ):
return storage_item_list return storage_item_list
security.declareProtected( ERP5Permissions.ManagePortal, 'setStorage') security.declareProtected( ERP5Permissions.ManagePortal, 'setStorage')
def setStorage(self, value, RESPONSE=None): def setStorage(self, storage, anonymous_storage=None, RESPONSE=None):
""" """
Set the storage of Selection Tool. Set the storage of Selection Tool.
""" """
if value in [item[1] for item in self.getStorageItemList()]: if storage in [item[1] for item in self.getStorageItemList()]:
self.storage = value self.storage = storage
else: else:
raise ValueError, 'Given storage type (%s) is now supported.' % (value,) raise ValueError, 'Given storage type (%s) is now supported.' % (storage,)
anonymous_storage = anonymous_storage or None
if anonymous_storage in [item[1] for item in self.getStorageItemList()] + [None]:
self.anonymous_storage = anonymous_storage
else:
raise ValueError, 'Given storage type (%s) is now supported.' % (anonymous_storage,)
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('%s/manage_configure' % (self.absolute_url())) RESPONSE.redirect('%s/manage_configure' % (self.absolute_url()))
...@@ -167,6 +174,12 @@ class SelectionTool( BaseTool, SimpleItem ): ...@@ -167,6 +174,12 @@ class SelectionTool( BaseTool, SimpleItem ):
storage = 'selection_data' storage = 'selection_data'
return storage return storage
security.declareProtected( ERP5Permissions.ManagePortal, 'getAnonymousStorage')
def getAnonymousStorage(self, default=None):
"""return the selected storage
"""
return getattr(aq_base(self), 'anonymous_storage', default)
def _redirectToOriginalForm(self, REQUEST=None, form_id=None, dialog_id=None, def _redirectToOriginalForm(self, REQUEST=None, form_id=None, dialog_id=None,
query_string=None, query_string=None,
no_reset=False, no_report_depth=False): no_reset=False, no_report_depth=False):
...@@ -267,6 +280,9 @@ class SelectionTool( BaseTool, SimpleItem ): ...@@ -267,6 +280,9 @@ class SelectionTool( BaseTool, SimpleItem ):
""" """
if not selection_name: if not selection_name:
return return
if self._isAnonymous():
self.REQUEST.response.setCookie('anonymous_uid',
self.REQUEST.get('anonymous_uid'))
if selection_object != None: if selection_object != None:
# 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)
...@@ -1365,9 +1381,19 @@ class SelectionTool( BaseTool, SimpleItem ): ...@@ -1365,9 +1381,19 @@ class SelectionTool( BaseTool, SimpleItem ):
return SelectionTool.inheritedAttribute('_aq_dynamic')(self, name) return SelectionTool.inheritedAttribute('_aq_dynamic')(self, name)
def _getUserId(self): def _getUserId(self):
return self.portal_membership.getAuthenticatedMember().getUserName() tv = getTransactionalVariable(self)
# XXX It would be good to add somthing here user_id = tv.get('_user_id', None)
# So that 2 anonymous users do not share the same selection if user_id is not None:
return user_id
user_id = self.portal_membership.getAuthenticatedMember().getUserName()
if user_id == 'Anonymous User' and self.getAnonymousStorage() is not None:
anonymous_uid = self.REQUEST.get('anonymous_uid', None)
if anonymous_uid is None:
anonymous_uid = md5.new('%s.%s' % (time(), random())).hexdigest()
self.REQUEST['anonymous_uid'] = anonymous_uid
user_id = 'Anonymous:%s' % anonymous_uid
tv['_user_id'] = user_id
return user_id
def getTemporarySelectionDict(self): def getTemporarySelectionDict(self):
""" Temporary selections are used in push/pop nested scope, """ Temporary selections are used in push/pop nested scope,
...@@ -1432,7 +1458,14 @@ class SelectionTool( BaseTool, SimpleItem ): ...@@ -1432,7 +1458,14 @@ class SelectionTool( BaseTool, SimpleItem ):
return list(set(self._getContainer().getSelectionNameList(user_id) + \ return list(set(self._getContainer().getSelectionNameList(user_id) + \
self.getTemporarySelectionDict().keys())) self.getTemporarySelectionDict().keys()))
def _isAnonymous(self):
return self.portal_membership.isAnonymousUser()
def _getContainer(self): def _getContainer(self):
if self._isAnonymous():
container_id = '_v_anonymous_selection_container'
storage = self.getAnonymousStorage()
else:
container_id = '_v_selection_container' container_id = '_v_selection_container'
storage = self.getStorage() storage = self.getStorage()
container = getattr(aq_base(self), container_id, None) container = getattr(aq_base(self), container_id, None)
......
...@@ -5,33 +5,43 @@ ...@@ -5,33 +5,43 @@
<p> <p>
Selection Tool supports Memcached Tool and Persistent Mapping for its storage. Selection Tool supports Memcached Tool and Persistent Mapping for its storage.
</p> </p>
<div>
<form action="setStorage" method="post">
<h4>
Storage for logged-in users' Selection objects.
</h4>
<select name="storage">
<dtml-let storage_item_list="getStorageItemList()"> <dtml-let storage_item_list="getStorageItemList()">
<dtml-in prefix="store" name="storage_item_list"> <dtml-in prefix="store" name="storage_item_list">
<dtml-let storage="store_item[1]" <dtml-let storage="store_item[1]"
storage_title="store_item[0]" storage_title="store_item[0]"
selected="storage == getStorage()"> selected="storage == getStorage() and 'selected' or ''">
<dtml-if selected> <option value="&dtml-storage;" &dtml-selected;>&dtml-storage_title;</option>
Current setting: <dtml-var storage_title html_quote>
</dtml-if>
</dtml-let> </dtml-let>
</dtml-in> </dtml-in>
</dtml-let> </dtml-let>
</div> </select>
<h4>
<form action="setStorage" method="post"> Storage for anonymous users' Selection objects.
<select name="value"> </h4>
<p>
You can specify another storage to store unique Selection objects for each anonymous user. If you select nothing here, the same Selection object will be shared for all anonymous users and will be stored in the storage selected above. Using a volatile storage (like memcached) is highly recommended.
</p>
<select name="anonymous_storage">
<option value="">&nbsp;</option>
<dtml-let storage_item_list="getStorageItemList()"> <dtml-let storage_item_list="getStorageItemList()">
<dtml-in prefix="store" name="storage_item_list"> <dtml-in prefix="store" name="storage_item_list">
<dtml-let storage="store_item[1]" <dtml-let storage="store_item[1]"
storage_title="store_item[0]" storage_title="store_item[0]"
selected="storage == getStorage() and 'selected' or ''"> selected="storage == getAnonymousStorage() and 'selected' or ''">
<option value="&dtml-storage;" &dtml-selected;>&dtml-storage_title;</option> <option value="&dtml-storage;" &dtml-selected;>&dtml-storage_title;</option>
</dtml-let> </dtml-let>
</dtml-in> </dtml-in>
</dtml-let> </dtml-let>
</select> </select>
<p>
<input type="submit" value="Change"/> <input type="submit" value="Change"/>
</p>
</form> </form>
<dtml-var manage_page_footer> <dtml-var manage_page_footer>
...@@ -246,6 +246,7 @@ class TestSelectionPersistence(unittest.TestCase): ...@@ -246,6 +246,7 @@ class TestSelectionPersistence(unittest.TestCase):
# find the current user name # find the current user name
SelectionTool._getUserId_saved = SelectionTool._getUserId SelectionTool._getUserId_saved = SelectionTool._getUserId
SelectionTool._getUserId = lambda self: 'user' SelectionTool._getUserId = lambda self: 'user'
SelectionTool._isAnonymous = lambda self: 0
self.db = ZODButil.makeDB() self.db = ZODButil.makeDB()
self.cnx = self.db.open() self.cnx = self.db.open()
......
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