Commit 06aee0c2 authored by Vincent Pelletier's avatar Vincent Pelletier

CMFActivity.ActivityTool: Use uid for identity check instead of oid.

uids are a way one can signal that different objects (from a ZODB point of
view, and hence an oid point of view) are actually to be considered as the
same objet (from a higher abstration point of view). For example, another
variant of the same object, as imported over an older variant.
In turn, this allows extending the protection to activities spawned from
brains, and not just from live objects.
parent 4c981a55
......@@ -194,13 +194,13 @@ class Message(BaseMessage):
exc_type = None
is_executed = MESSAGE_NOT_EXECUTED
traceback = None
oid = None
document_uid = None
is_registered = False
def __init__(
self,
url,
oid,
document_uid,
active_process,
active_process_uid,
activity_kw,
......@@ -210,7 +210,7 @@ class Message(BaseMessage):
portal_activities=None,
):
self.object_path = url
self.oid = oid
self.document_uid = document_uid
self.active_process = active_process
self.active_process_uid = active_process_uid
self.activity_kw = activity_kw
......@@ -266,10 +266,8 @@ class Message(BaseMessage):
% (self.object_path,), error=True)
self.setExecutionState(MESSAGE_NOT_EXECUTABLE)
else:
if (self.oid and self.oid != getattr(aq_base(obj), '_p_oid', None) and
# XXX: BusinessTemplate must be fixed to preserve OID
'portal_workflow' not in self.object_path):
raise ValueError("OID mismatch for %r" % obj)
if self.document_uid and self.document_uid != getattr(aq_base(obj), 'uid', None):
raise ValueError("UID mismatch for %r" % obj)
return obj
def getObjectList(self, activity_tool):
......@@ -506,7 +504,7 @@ class Method(object):
__slots__ = (
'_portal_activities',
'_passive_url',
'_passive_oid',
'_passive_uid',
'_activity',
'_active_process',
'_active_process_uid',
......@@ -515,11 +513,11 @@ class Method(object):
'_request',
)
def __init__(self, portal_activities, passive_url, passive_oid, activity,
def __init__(self, portal_activities, passive_url, passive_uid, activity,
active_process, active_process_uid, kw, method_id, request):
self._portal_activities = portal_activities
self._passive_url = passive_url
self._passive_oid = passive_oid
self._passive_uid = passive_uid
self._activity = activity
self._active_process = active_process
self._active_process_uid = active_process_uid
......@@ -531,7 +529,7 @@ class Method(object):
portal_activities = self._portal_activities
m = Message(
url=self._passive_url,
oid=self._passive_oid,
document_uid=self._passive_uid,
active_process=self._active_process,
active_process_uid=self._active_process_uid,
activity_kw=self._kw,
......@@ -552,7 +550,7 @@ class ActiveWrapper(object):
__slots__ = (
'__portal_activities',
'__passive_url',
'__passive_oid',
'__passive_uid',
'__activity',
'__active_process',
'__active_process_uid',
......@@ -562,12 +560,12 @@ class ActiveWrapper(object):
# Shortcut security lookup (avoid calling __getattr__)
__parent__ = None
def __init__(self, portal_activities, url, oid, activity, active_process,
def __init__(self, portal_activities, url, uid, activity, active_process,
active_process_uid, kw, request):
# second parameter can be an object or an object's path
self.__portal_activities = portal_activities
self.__passive_url = url
self.__passive_oid = oid
self.__passive_uid = uid
self.__activity = activity
self.__active_process = active_process
self.__active_process_uid = active_process_uid
......@@ -578,7 +576,7 @@ class ActiveWrapper(object):
return Method(
self.__portal_activities,
self.__passive_url,
self.__passive_oid,
self.__passive_uid,
self.__activity,
self.__active_process,
self.__active_process_uid,
......@@ -1396,7 +1394,7 @@ class ActivityTool (BaseTool):
def activateObject(self, object, activity=DEFAULT_ACTIVITY,
active_process=None, serialization_tag=None,
node=None, **kw):
node=None, uid=None, **kw):
if active_process is None:
active_process_uid = None
elif isinstance(active_process, str):
......@@ -1406,15 +1404,11 @@ class ActivityTool (BaseTool):
active_process_uid = active_process.getUid()
active_process = active_process.getPhysicalPath()
if isinstance(object, str):
oid = None
url = tuple(object.split('/'))
else:
try:
oid = aq_base(object)._p_oid
# Note that it's too early to get the OID of a newly created object,
# so at this point, self.oid may still be None.
except AttributeError:
pass
if uid is not None:
raise ValueError
uid = getattr(aq_base(object), 'uid', None)
url = object.getPhysicalPath()
if serialization_tag is not None:
kw['serialization_tag'] = serialization_tag
......@@ -1438,7 +1432,7 @@ class ActivityTool (BaseTool):
except ValueError:
pass
break
return ActiveWrapper(self, url, oid, activity,
return ActiveWrapper(self, url, uid, activity,
active_process, active_process_uid, kw,
getattr(self, 'REQUEST', None))
......
......@@ -2342,7 +2342,7 @@ class TestCMFActivity(ERP5TypeTestCase, LogInterceptor):
self.assertEqual(1, activity_tool.countMessage())
self.flushAllActivities()
sender, recipients, mail = message_list.pop()
self.assertIn('OID mismatch', mail)
self.assertIn('UID mismatch', mail)
m, = activity_tool.getMessageList()
self.assertEqual(m.processing_node, INVOKE_ERROR_STATE)
obj.flushActivity()
......
......@@ -498,6 +498,20 @@ class CopyContainer:
new_ob.setDefaultReindexParameterDict(reindex_kw)
if is_indexable is not None and not is_indexable:
new_ob._setNonIndexable()
if is_clone:
# Clear uids before spawning indexation activities, so the activity does
# not do an uid check (as the uid is still the old one, and a new one
# will be allocated by _postDuplicate, which must run after object gets
# a parent).
# Note: do not use __recurse as it only iterates over immediate content,
# and then stop instead of calling itself into them. It relies on called
# methods to call it back, and we do not want that for _setUid .
todo_list = [new_ob]
while todo_list:
document = todo_list.pop()
todo_list.extend(document.objectValues())
todo_list.extend(document.opaqueValues())
document._setUid(None)
self._setObject(new_id, new_ob, set_owner=set_owner)
new_ob = self._getOb(new_id)
new_ob._postCopy(self, op=op)
......
......@@ -137,7 +137,7 @@ class ZSQLBrain(Acquisition.Implicit):
# a queue can be provided as well as extra parameters
# which can be used for example to define deferred tasks
return activity_tool.activateObject(
self.getPath(), activity, active_process, **new_kw)
self.getPath(), activity, active_process, uid=self.getUid(), **new_kw)
allow_class(ZSQLBrain)
......
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