[FIX] mail: message_process now handles replies to messages without model, thread_id. Based on in-reply-to, it finds the parent message. mail_thread.message_post_user_api is called to create a new mail.message, bypassing message_new / message_update in this case. Some improvements added to partner_ids when using the chatter or message processing.
bzr revid: tde@openerp.com-20121108152502-aow7vhu4erx7fb9l
This commit is contained in:
parent
72f218bd24
commit
d5d7dced4d
|
@ -319,10 +319,12 @@ class mail_thread(osv.AbstractModel):
|
||||||
"""
|
"""
|
||||||
assert isinstance(message, Message), 'message must be an email.message.Message at this point'
|
assert isinstance(message, Message), 'message must be an email.message.Message at this point'
|
||||||
message_id = message.get('Message-Id')
|
message_id = message.get('Message-Id')
|
||||||
|
references = decode_header(message, 'References')
|
||||||
|
in_reply_to = decode_header(message, 'In-Reply-To')
|
||||||
|
|
||||||
# 1. Verify if this is a reply to an existing thread
|
# 1. Verify if this is a reply to an existing thread
|
||||||
references = decode_header(message, 'References') or decode_header(message, 'In-Reply-To')
|
thread_references = references or in_reply_to
|
||||||
ref_match = references and tools.reference_re.search(references)
|
ref_match = thread_references and tools.reference_re.search(thread_references)
|
||||||
if ref_match:
|
if ref_match:
|
||||||
thread_id = int(ref_match.group(1))
|
thread_id = int(ref_match.group(1))
|
||||||
model = ref_match.group(2) or model
|
model = ref_match.group(2) or model
|
||||||
|
@ -333,6 +335,15 @@ class mail_thread(osv.AbstractModel):
|
||||||
message_id, model, thread_id, custom_values, uid)
|
message_id, model, thread_id, custom_values, uid)
|
||||||
return [(model, thread_id, custom_values, uid)]
|
return [(model, thread_id, custom_values, uid)]
|
||||||
|
|
||||||
|
# Verify this is a reply to a private message
|
||||||
|
message_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', 'ilike', in_reply_to)], limit=1, context=context)
|
||||||
|
if message_ids:
|
||||||
|
message = self.pool.get('mail.message').browse(cr, uid, message_ids[0], context=context)
|
||||||
|
_logger.debug('Routing mail with Message-Id %s: reply to a private message: %s, custom_values: %s, uid: %s',
|
||||||
|
message_id, message.id, custom_values, uid)
|
||||||
|
return [(False, 0, custom_values, uid)]
|
||||||
|
|
||||||
|
|
||||||
# 2. Look for a matching mail.alias entry
|
# 2. Look for a matching mail.alias entry
|
||||||
# Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values
|
# Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values
|
||||||
# for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value.
|
# for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value.
|
||||||
|
@ -376,14 +387,19 @@ class mail_thread(osv.AbstractModel):
|
||||||
def message_process(self, cr, uid, model, message, custom_values=None,
|
def message_process(self, cr, uid, model, message, custom_values=None,
|
||||||
save_original=False, strip_attachments=False,
|
save_original=False, strip_attachments=False,
|
||||||
thread_id=None, context=None):
|
thread_id=None, context=None):
|
||||||
"""Process an incoming RFC2822 email message, relying on
|
""" Process an incoming RFC2822 email message, relying on
|
||||||
``mail.message.parse()`` for the parsing operation,
|
``mail.message.parse()`` for the parsing operation,
|
||||||
and ``message_route()`` to figure out the target model.
|
and ``message_route()`` to figure out the target model.
|
||||||
|
|
||||||
Once the target model is known, its ``message_new`` method
|
Once the target model is known, its ``message_new`` method
|
||||||
is called with the new message (if the thread record did not exist)
|
is called with the new message (if the thread record did not exist)
|
||||||
or its ``message_update`` method (if it did).
|
or its ``message_update`` method (if it did).
|
||||||
|
|
||||||
|
There is a special case where the target model is False: a reply
|
||||||
|
to a private message. In this case, we skip the message_new /
|
||||||
|
message_update step, to just post a new message using mail_thread
|
||||||
|
message_post.
|
||||||
|
|
||||||
:param string model: the fallback model to use if the message
|
:param string model: the fallback model to use if the message
|
||||||
does not match any of the currently configured mail aliases
|
does not match any of the currently configured mail aliases
|
||||||
(may be None if a matching alias is supposed to be present)
|
(may be None if a matching alias is supposed to be present)
|
||||||
|
@ -425,15 +441,18 @@ class mail_thread(osv.AbstractModel):
|
||||||
for model, thread_id, custom_values, user_id in routes:
|
for model, thread_id, custom_values, user_id in routes:
|
||||||
if self._name != model:
|
if self._name != model:
|
||||||
context.update({'thread_model': model})
|
context.update({'thread_model': model})
|
||||||
model_pool = self.pool.get(model)
|
if model:
|
||||||
assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \
|
model_pool = self.pool.get(model)
|
||||||
"Undeliverable mail with Message-Id %s, model %s does not accept incoming emails" % \
|
assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \
|
||||||
(msg['message_id'], model)
|
"Undeliverable mail with Message-Id %s, model %s does not accept incoming emails" % \
|
||||||
if thread_id and hasattr(model_pool, 'message_update'):
|
(msg['message_id'], model)
|
||||||
model_pool.message_update(cr, user_id, [thread_id], msg, context=context)
|
if thread_id and hasattr(model_pool, 'message_update'):
|
||||||
|
model_pool.message_update(cr, user_id, [thread_id], msg, context=context)
|
||||||
|
else:
|
||||||
|
thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=context)
|
||||||
else:
|
else:
|
||||||
thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=context)
|
model_pool = self.pool.get('mail.thread')
|
||||||
model_pool.message_post(cr, uid, [thread_id], context=context, **msg)
|
model_pool.message_post_user_api(cr, uid, [thread_id], context=context, **msg)
|
||||||
return thread_id
|
return thread_id
|
||||||
|
|
||||||
def message_new(self, cr, uid, msg_dict, custom_values=None, context=None):
|
def message_new(self, cr, uid, msg_dict, custom_values=None, context=None):
|
||||||
|
@ -556,7 +575,6 @@ class mail_thread(osv.AbstractModel):
|
||||||
"""
|
"""
|
||||||
msg_dict = {
|
msg_dict = {
|
||||||
'type': 'email',
|
'type': 'email',
|
||||||
'subtype': 'mail.mt_comment',
|
|
||||||
'author_id': False,
|
'author_id': False,
|
||||||
}
|
}
|
||||||
if not isinstance(message, Message):
|
if not isinstance(message, Message):
|
||||||
|
@ -640,10 +658,13 @@ class mail_thread(osv.AbstractModel):
|
||||||
``(name,content)``, where content is NOT base64 encoded
|
``(name,content)``, where content is NOT base64 encoded
|
||||||
:return: ID of newly created mail.message
|
:return: ID of newly created mail.message
|
||||||
"""
|
"""
|
||||||
context = context or {}
|
if context is None:
|
||||||
attachments = attachments or []
|
context = {}
|
||||||
|
if attachments is None:
|
||||||
|
attachments = {}
|
||||||
|
|
||||||
assert (not thread_id) or isinstance(thread_id, (int, long)) or \
|
assert (not thread_id) or isinstance(thread_id, (int, long)) or \
|
||||||
(isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id"
|
(isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id; should be 0, False, an ID or a list with one ID"
|
||||||
if isinstance(thread_id, (list, tuple)):
|
if isinstance(thread_id, (list, tuple)):
|
||||||
thread_id = thread_id and thread_id[0]
|
thread_id = thread_id and thread_id[0]
|
||||||
mail_message = self.pool.get('mail.message')
|
mail_message = self.pool.get('mail.message')
|
||||||
|
@ -707,30 +728,45 @@ class mail_thread(osv.AbstractModel):
|
||||||
|
|
||||||
return mail_message.create(cr, uid, values, context=context)
|
return mail_message.create(cr, uid, values, context=context)
|
||||||
|
|
||||||
def message_post_api(self, cr, uid, thread_id, body='', subject=False, parent_id=False, attachment_ids=None, context=None):
|
def message_post_user_api(self, cr, uid, thread_id, body='', subject=False, parent_id=False,
|
||||||
""" Wrapper on message_post, used only in Chatter (JS). The purpose is
|
attachment_ids=None, context=None, content_subtype='plaintext', **kwargs):
|
||||||
to handle attachments.
|
""" Wrapper on message_post, used for user input :
|
||||||
- body is plaintext: convert it into html
|
- mail gateway
|
||||||
- handle reply to a previous message
|
- quick reply in Chatter (refer to mail.js), not
|
||||||
|
the mail.compose.message wizard
|
||||||
|
The purpose is to perform some pre- and post-processing:
|
||||||
|
- if body is plaintext: convert it into html
|
||||||
|
- if parent_id: handle reply to a previous message by adding the
|
||||||
|
parent partners to the message
|
||||||
|
- type and subtype: comment and mail.mt_comment by default
|
||||||
|
- attachment_ids: supposed not attached to any document; attach them
|
||||||
|
to the related document. Should only be set by Chatter.
|
||||||
"""
|
"""
|
||||||
# 1. handle body
|
ir_attachment = self.pool.get('ir.attachment')
|
||||||
body = tools.text2html(body)
|
mail_message = self.pool.get('mail.message')
|
||||||
|
|
||||||
# 2. handle message partner_ids
|
# 1. Pre-processing: body, partner_ids, type and subtype
|
||||||
|
if content_subtype == 'plaintext':
|
||||||
|
body = tools.text2html(body)
|
||||||
|
|
||||||
|
partner_ids = kwargs.pop('partner_ids', [])
|
||||||
if parent_id:
|
if parent_id:
|
||||||
parent_data = self.pool.get('mail.message').browse(cr, uid, parent_id, context=context)
|
parent_message = self.pool.get('mail.message').browse(cr, uid, parent_id, context=context)
|
||||||
partner_ids = [(4, partner.id) for partner in parent_data.partner_ids]
|
partner_ids += [(4, partner.id) for partner in parent_message.partner_ids]
|
||||||
else:
|
# TDE FIXME HACK: mail.thread -> private message
|
||||||
partner_ids = []
|
if self._name == 'mail.thread' and parent_message.author_id.id:
|
||||||
|
partner_ids.append((4, parent_message.author_id.id))
|
||||||
|
|
||||||
# 3. post message
|
message_type = kwargs.pop('type', 'comment')
|
||||||
new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type='comment',
|
message_subtype = kwargs.pop('type', 'mail.mt_comment')
|
||||||
subtype='mail.mt_comment', parent_id=parent_id, context=context, partner_ids=partner_ids)
|
|
||||||
|
|
||||||
# 4. HACK FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
|
# 2. Post message
|
||||||
|
new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=message_type,
|
||||||
|
subtype=message_subtype, parent_id=parent_id, context=context, partner_ids=partner_ids, **kwargs)
|
||||||
|
|
||||||
|
# 3. Post-processing
|
||||||
|
# HACK TDE FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
|
||||||
if attachment_ids:
|
if attachment_ids:
|
||||||
ir_attachment = self.pool.get('ir.attachment')
|
|
||||||
mail_message = self.pool.get('mail.message')
|
|
||||||
filtered_attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [
|
filtered_attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [
|
||||||
('res_model', '=', 'mail.compose.message'),
|
('res_model', '=', 'mail.compose.message'),
|
||||||
('res_id', '=', 0),
|
('res_id', '=', 0),
|
||||||
|
|
|
@ -350,7 +350,7 @@ openerp.mail = function (session) {
|
||||||
|
|
||||||
if (body.match(/\S+/)) {
|
if (body.match(/\S+/)) {
|
||||||
//session.web.blockUI();
|
//session.web.blockUI();
|
||||||
this.parent_thread.ds_thread.call('message_post_api', [
|
this.parent_thread.ds_thread.call('message_post_user_api', [
|
||||||
this.context.default_res_id,
|
this.context.default_res_id,
|
||||||
mail.ChatterUtils.get_text2html(body),
|
mail.ChatterUtils.get_text2html(body),
|
||||||
false,
|
false,
|
||||||
|
|
Loading…
Reference in New Issue