Commit 4e744350 authored by Julien Muchembled's avatar Julien Muchembled

CMFActivity: revamp notification mail

parent 2e2b366c
...@@ -160,6 +160,11 @@ class Message(BaseMessage): ...@@ -160,6 +160,11 @@ class Message(BaseMessage):
active_process = None active_process = None
active_process_uid = None active_process_uid = None
call_traceback = None
is_executed = MESSAGE_NOT_EXECUTED
processing = None
traceback = None
exc_type = None
def __init__(self, obj, active_process, activity_kw, method_id, args, kw): def __init__(self, obj, active_process, activity_kw, method_id, args, kw):
if isinstance(obj, str): if isinstance(obj, str):
...@@ -178,18 +183,11 @@ class Message(BaseMessage): ...@@ -178,18 +183,11 @@ class Message(BaseMessage):
self.method_id = method_id self.method_id = method_id
self.args = args self.args = args
self.kw = kw self.kw = kw
self.is_executed = MESSAGE_NOT_EXECUTED
self.exc_type = None
self.exc_value = None
self.traceback = None
if activity_creation_trace and format_list is not None: if activity_creation_trace and format_list is not None:
# Save current traceback, to make it possible to tell where a message # Save current traceback, to make it possible to tell where a message
# was generated. # was generated.
# Strip last stack entry, since it will always be the same. # Strip last stack entry, since it will always be the same.
self.call_traceback = ''.join(format_list(extract_stack()[:-1])) self.call_traceback = ''.join(format_list(extract_stack()[:-1]))
else:
self.call_traceback = None
self.processing = None
self.user_name = str(_getAuthenticatedUser(self)) self.user_name = str(_getAuthenticatedUser(self))
# Store REQUEST Info # Store REQUEST Info
self.request_info = {} self.request_info = {}
...@@ -263,11 +261,12 @@ class Message(BaseMessage): ...@@ -263,11 +261,12 @@ class Message(BaseMessage):
try: try:
obj = self.getObject(activity_tool) obj = self.getObject(activity_tool)
except KeyError: except KeyError:
exc_info = sys.exc_info()
LOG('CMFActivity', ERROR, LOG('CMFActivity', ERROR,
'Message failed in getting an object from the path %r' % \ 'Message failed in getting an object from the path %r'
(self.object_path,), % (self.object_path,), error=exc_info)
error=sys.exc_info()) self.setExecutionState(MESSAGE_NOT_EXECUTABLE, exc_info,
self.setExecutionState(MESSAGE_NOT_EXECUTABLE, context=activity_tool) context=activity_tool)
else: else:
try: try:
old_security_manager = getSecurityManager() old_security_manager = getSecurityManager()
...@@ -279,13 +278,14 @@ class Message(BaseMessage): ...@@ -279,13 +278,14 @@ class Message(BaseMessage):
# XXX: There is no check to see if user is allowed to access # XXX: There is no check to see if user is allowed to access
# that method ! # that method !
method = getattr(obj, self.method_id) method = getattr(obj, self.method_id)
except: except Exception:
exc_info = sys.exc_info()
LOG('CMFActivity', ERROR, LOG('CMFActivity', ERROR,
'Message failed in getting a method %r from an object %r' % \ 'Message failed in getting a method %r from an object %r'
(self.method_id, obj,), % (self.method_id, obj), error=exc_info)
error=sys.exc_info())
method = None method = None
self.setExecutionState(MESSAGE_NOT_EXECUTABLE, context=activity_tool) self.setExecutionState(MESSAGE_NOT_EXECUTABLE, exc_info,
context=activity_tool)
else: else:
if activity_tool.activity_timing_log: if activity_tool.activity_timing_log:
result = activity_timing_method(method, self.args, self.kw) result = activity_timing_method(method, self.args, self.kw)
...@@ -316,13 +316,8 @@ class Message(BaseMessage): ...@@ -316,13 +316,8 @@ class Message(BaseMessage):
portal = activity_tool.getPortalObject() portal = activity_tool.getPortalObject()
user_email = portal.getProperty('email_to_address', user_email = portal.getProperty('email_to_address',
portal.getProperty('email_from_address')) portal.getProperty('email_from_address'))
email_from_name = portal.getProperty('email_from_name', email_from_name = portal.getProperty('email_from_name',
portal.getProperty('email_from_address')) portal.getProperty('email_from_address'))
call_traceback = ''
if self.call_traceback:
call_traceback = 'Created at:\n%s' % self.call_traceback
fail_count = self.line.retry + 1 fail_count = self.line.retry + 1
if self.getExecutionState() == MESSAGE_NOT_EXECUTABLE: if self.getExecutionState() == MESSAGE_NOT_EXECUTABLE:
message = "Not executable activity" message = "Not executable activity"
...@@ -342,21 +337,18 @@ Document: %s ...@@ -342,21 +337,18 @@ Document: %s
Method: %s Method: %s
Arguments: %r Arguments: %r
Named Parameters: %r Named Parameters: %r
%s """ % (email_from_name, activity_tool.email_from_address, user_email, message,
path, self.method_id, activity_tool.getCurrentNode(), fail_count,
Exception: %s %s self.user_name, path, self.method_id, self.args, self.kw)
if self.traceback:
%s mail_text += '\nException:\n' + self.traceback
""" % (email_from_name, activity_tool.email_from_address, user_email, if self.call_traceback:
message, path, self.method_id, mail_text += '\nCreated at:\n' + self.call_traceback
activity_tool.getCurrentNode(), fail_count,
self.user_name, path, self.method_id, self.args, self.kw,
call_traceback, self.exc_type, self.exc_value, self.traceback)
try: try:
activity_tool.MailHost.send( mail_text ) portal.MailHost.send(mail_text)
except (socket.error, MailHostError), message: except (socket.error, MailHostError), message:
LOG('ActivityTool.notifyUser', WARNING, 'Mail containing failure information failed to be sent: %s. Exception was: %s %s\n%s' % (message, self.exc_type, self.exc_value, self.traceback)) LOG('ActivityTool.notifyUser', WARNING,
'Mail containing failure information failed to be sent: %s' % message)
def reactivate(self, activity_tool, activity=DEFAULT_ACTIVITY): def reactivate(self, activity_tool, activity=DEFAULT_ACTIVITY):
# Reactivate the original object. # Reactivate the original object.
...@@ -400,24 +392,22 @@ Exception: %s %s ...@@ -400,24 +392,22 @@ Exception: %s %s
assert is_executed in (MESSAGE_NOT_EXECUTED, MESSAGE_EXECUTED, MESSAGE_NOT_EXECUTABLE) assert is_executed in (MESSAGE_NOT_EXECUTED, MESSAGE_EXECUTED, MESSAGE_NOT_EXECUTABLE)
self.is_executed = is_executed self.is_executed = is_executed
if is_executed != MESSAGE_EXECUTED: if is_executed != MESSAGE_EXECUTED:
if exc_info is None: if not exc_info:
exc_info = sys.exc_info() exc_info = sys.exc_info()
if exc_info == (None, None, None): self.exc_type = exc_info[0]
if exc_info[0] is None:
# Raise a dummy exception, ignore it, fetch it and use it as if it was the error causing message non-execution. This will help identifyting the cause of this misbehaviour. # Raise a dummy exception, ignore it, fetch it and use it as if it was the error causing message non-execution. This will help identifyting the cause of this misbehaviour.
try: try:
raise Exception, 'Message execution failed, but there is no exception to explain it. This is a dummy exception so that one can track down why we end up here outside of an exception handling code path.' raise Exception, 'Message execution failed, but there is no exception to explain it. This is a dummy exception so that one can track down why we end up here outside of an exception handling code path.'
except: except Exception:
pass exc_info = sys.exc_info()
exc_info = sys.exc_info()
if log: if log:
LOG('ActivityTool', WARNING, 'Could not call method %s on object %s. Activity created at:\n%s' % (self.method_id, self.object_path, self.call_traceback), error=exc_info) LOG('ActivityTool', WARNING, 'Could not call method %s on object %s. Activity created at:\n%s' % (self.method_id, self.object_path, self.call_traceback), error=exc_info)
# push the error in ZODB error_log # push the error in ZODB error_log
error_log = getattr(context, 'error_log', None) error_log = getattr(context, 'error_log', None)
if error_log is not None: if error_log is not None:
error_log.raising(exc_info) error_log.raising(exc_info)
self.exc_type = exc_info[0] self.traceback = ''.join(ExceptionFormatter.format_exception(*exc_info)[1:])
self.exc_value = str(exc_info[1])
self.traceback = ''.join(ExceptionFormatter.format_exception(*exc_info))
def getExecutionState(self): def getExecutionState(self):
return self.is_executed return self.is_executed
...@@ -432,8 +422,9 @@ class Method: ...@@ -432,8 +422,9 @@ class Method:
self.__method_id = method_id self.__method_id = method_id
def __call__(self, *args, **kw): def __call__(self, *args, **kw):
m = Message(self.__passive_self, self.__active_process, self.__kw, self.__method_id, args, kw) passive_self = self.__passive_self
portal_activities = self.__passive_self.getPortalObject().portal_activities m = Message(passive_self, self.__active_process, self.__kw, self.__method_id, args, kw)
portal_activities = passive_self.getPortalObject().portal_activities
if portal_activities.activity_tracking: if portal_activities.activity_tracking:
activity_tracking_logger.info('queuing message: activity=%s, object_path=%s, method_id=%s, args=%s, kw=%s, activity_kw=%s, user_name=%s' % (self.__activity, '/'.join(m.object_path), m.method_id, m.args, m.kw, m.activity_kw, m.user_name)) activity_tracking_logger.info('queuing message: activity=%s, object_path=%s, method_id=%s, args=%s, kw=%s, activity_kw=%s, user_name=%s' % (self.__activity, '/'.join(m.object_path), m.method_id, m.args, m.kw, m.activity_kw, m.user_name))
activity_dict[self.__activity].queueMessage(portal_activities, m) activity_dict[self.__activity].queueMessage(portal_activities, m)
...@@ -1200,11 +1191,11 @@ class ActivityTool (Folder, UniqueObject): ...@@ -1200,11 +1191,11 @@ class ActivityTool (Folder, UniqueObject):
try: try:
obj = m.getObject(self) obj = m.getObject(self)
except KeyError: except KeyError:
exc_info = sys.exc_info()
LOG('CMFActivity', ERROR, LOG('CMFActivity', ERROR,
'Message failed in getting an object from the path %r' % \ 'Message failed in getting an object from the path %r'
(m.object_path,), % (m.object_path,), error=exc_info)
error=sys.exc_info()) m.setExecutionState(MESSAGE_NOT_EXECUTABLE, exc_info, context=self)
m.setExecutionState(MESSAGE_NOT_EXECUTABLE, context=self)
continue continue
try: try:
if m.hasExpandMethod(): if m.hasExpandMethod():
......
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