[REF] mail.message.common model: renamed subtype to content_subtype. Purpose: make a distinction between content and message model. Type and subtype will be used to distinguish messages, content_subtype to distinguish the content itself.

bzr revid: tde@openerp.com-20120420093645-tt78zzrmq2nxomvb
This commit is contained in:
Thibault Delavallée 2012-04-20 11:36:45 +02:00
parent 7a4ca1338c
commit 318ef517ab
7 changed files with 65 additions and 59 deletions

View File

@ -515,7 +515,7 @@ property or property parameter."),
sub,
body,
attachments=attach and {'invitation.ics': attach} or None,
subtype='html',
content_subtype='html',
reply_to=email_from,
context=context
)

View File

@ -54,7 +54,7 @@ class mail_compose_message(osv.osv_memory):
'email_cc' : tools.ustr(data.email_cc or ''),
'model': model,
'res_id': res_id,
'subtype': 'plain',
'content_subtype': 'plain',
})
if hasattr(data, 'section_id'):
result.update({'reply_to' : data.section_id and data.section_id.reply_to or False})

View File

@ -310,7 +310,7 @@ class email_template(osv.osv):
'attachment_ids': False,
'message_id': False,
'state': 'outgoing',
'subtype': 'plain',
'content_subtype': 'plain',
}
if not template_id:
return values
@ -326,7 +326,7 @@ class email_template(osv.osv):
or False
if values['body_html']:
values.update(subtype='html')
values.update(content_subtype='html')
if template.user_signature:
signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature

View File

@ -63,18 +63,21 @@ def to_email(text):
if not text: return []
return re.findall(r'([^ ,<@]+@[^> ,]+)', text)
class mail_message_common(osv.osv_memory):
class mail_message_common(osv.TransientModel):
"""Common abstract class for holding the main attributes of a
message object. It could be reused as parent model for any
database model or wizard screen that needs to hold a kind of
message"""
message.
All internal logic should be in a database-based model. For example,
a wizard for writing emails should inherit from this class and not
from mail.message."""
def get_body(self, cr, uid, ids, name, arg, context=None):
if context is None:
context = {}
result = dict.fromkeys(ids, '')
for message in self.browse(cr, uid, ids, context=context):
if message.subtype == 'html':
if message.content_subtype == 'html':
result[message.id] = message.body_html
else:
result[message.id] = message.body_text
@ -85,7 +88,7 @@ class mail_message_common(osv.osv_memory):
- obj: mail.message object
- name: 'body'
- args: [('body', 'ilike', 'blah')]"""
return ['|', '&', ('subtype', '=', 'html'), ('body_html', args[0][1], args[0][2]), ('body_text', args[0][1], args[0][2])]
return ['|', '&', ('content_subtype', '=', 'html'), ('body_html', args[0][1], args[0][2]), ('body_text', args[0][1], args[0][2])]
def get_record_name(self, cr, uid, ids, name, arg, context=None):
if context is None:
@ -115,19 +118,20 @@ class mail_message_common(osv.osv_memory):
help="Full message headers, e.g. SMTP session headers (usually available on inbound messages only)"),
'message_id': fields.char('Message-Id', size=256, help='Message unique identifier', select=1, readonly=1),
'references': fields.text('References', help='Message references, such as identifiers of previous messages', readonly=1),
'subtype': fields.char('Message type', size=32, help="Type of message, usually 'html' or 'plain', used to "
"select plaintext or rich text contents accordingly", readonly=1),
'content_subtype': fields.char('Message content subtype', size=32,
help="Type of message, usually 'html' or 'plain', used to "
"select plain-text or rich-text contents accordingly", readonly=1),
'body_text': fields.text('Text contents', help="Plain-text version of the message"),
'body_html': fields.text('Rich-text contents', help="Rich-text/HTML version of the message"),
'body': fields.function(get_body, fnct_search = search_body, string='Message content', type='text',
help="Content of the message. This content equals the body_text field for plain-test messages, and body_html for rich-text/HTML messages. This allows having one field if we want to access the content matching the message subtype."),
help="Content of the message. This content equals the body_text field for plain-test messages, and body_html for rich-text/HTML messages. This allows having one field if we want to access the content matching the message content_subtype."),
'parent_id': fields.many2one('mail.message', 'Parent message', help="Parent message, used for displaying as threads with hierarchy",
select=True, ondelete='set null',),
'child_ids': fields.one2many('mail.message', 'parent_id', 'Child messages'),
}
_defaults = {
'subtype': 'plain',
'content_subtype': 'plain',
'date': (lambda *a: fields.datetime.now()),
}
@ -206,12 +210,12 @@ class mail_message(osv.osv):
('comment', 'Comment'),
('notification', 'System notification'),
], 'Type', help="Message type: e-mail for e-mail message, notification for system message, comment for other messages such as user replies"),
'message_subtype': fields.selection([
'message_tmptype': fields.selection([
('email', 'e-mail'),
('comment', 'Comment'),
('create', 'Create'),
('cancel', 'Cancel'),
], 'Type', help="Message subtype, such as create or cancel. May be overriden by addons."),
], 'Type', help="Message temptype, such as create or cancel. May be overriden by addons."),
'partner_id': fields.many2one('res.partner', 'Related partner'),
'user_id': fields.many2one('res.users', 'Related user', readonly=1),
'attachment_ids': fields.many2many('ir.attachment', 'message_attachment_rel', 'message_id', 'attachment_id', 'Attachments'),
@ -230,7 +234,7 @@ class mail_message(osv.osv):
_defaults = {
'type': 'email',
'message_subtype': 'email',
'message_tmptype': 'email',
'state': 'received',
}
@ -250,18 +254,18 @@ class mail_message(osv.osv):
default.update(message_id=False,original=False,headers=False)
return super(mail_message,self).copy(cr, uid, id, default=default, context=context)
def schedule_with_attach(self, cr, uid, email_from, email_to, subject, body, model=False, email_cc=None,
email_bcc=None, reply_to=False, attachments=None, message_id=False, references=False,
res_id=False, subtype='plain', headers=None, mail_server_id=False, auto_delete=False,
context=None):
def schedule_with_attach(self, cr, uid, email_from, email_to, subject, body, model=False,
email_cc=None, email_bcc=None, reply_to=False, attachments=None,
message_id=False, references=False, res_id=False, content_subtype='plain',
headers=None, mail_server_id=False, auto_delete=False, context=None):
"""Schedule sending a new email message, to be sent the next time the mail scheduler runs, or
the next time :meth:`process_email_queue` is called explicitly.
:param string email_from: sender email address
:param list email_to: list of recipient addresses (to be joined with commas)
:param string subject: email subject (no pre-encoding/quoting necessary)
:param string body: email body, according to the ``subtype`` (by default, plaintext).
If html subtype is used, the message will be automatically converted
:param string body: email body, according to the ``content_subtype``
(by default, plaintext). If html content_subtype is used, the message will be automatically converted
to plaintext and wrapped in multipart/alternative.
:param list email_cc: optional list of string values for CC header (to be joined with commas)
:param list email_bcc: optional list of string values for BCC header (to be joined with commas)
@ -272,9 +276,9 @@ class mail_message(osv.osv):
be used to generate a tracking id, used to match any response related to the
same document)
:param string reply_to: optional value of Reply-To header
:param string subtype: optional mime subtype for the text body (usually 'plain' or 'html'),
must match the format of the ``body`` parameter. Default is 'plain',
making the content part of the mail "text/plain".
:param string content_subtype: optional mime content_subtype for the text body (usually 'plain' or 'html'),
must match the format of the ``body`` parameter. Default is 'plain',
making the content part of the mail "text/plain".
:param dict attachments: map of filename to filecontents, where filecontents is a string
containing the bytes of the attachment
:param dict headers: optional map of headers to set on the outgoing mail (may override the
@ -299,8 +303,8 @@ class mail_message(osv.osv):
'model': model,
'res_id': res_id,
'type': 'email',
'body_text': body if subtype != 'html' else False,
'body_html': body if subtype == 'html' else False,
'body_text': body if content_subtype != 'html' else False,
'body_html': body if content_subtype == 'html' else False,
'email_from': email_from,
'email_to': email_to and ','.join(email_to) or '',
'email_cc': email_cc and ','.join(email_cc) or '',
@ -308,7 +312,7 @@ class mail_message(osv.osv):
'reply_to': reply_to,
'message_id': message_id,
'references': references,
'subtype': subtype,
'content_subtype': content_subtype,
'headers': headers, # serialize the dict on the fly
'mail_server_id': mail_server_id,
'state': 'outgoing',
@ -388,7 +392,7 @@ class mail_message(osv.osv):
'headers' : { 'X-Mailer': mailer,
#.. all X- headers...
},
'subtype': msg_mime_subtype,
'content_subtype': msg_mime_subtype,
'body_text': plaintext_body
'body_html': html_body,
'attachments': [('file1', 'bytes'),
@ -464,7 +468,7 @@ class mail_message(osv.osv):
msg['in-reply-to'] = msg_txt.get('In-Reply-To')
msg['headers'] = {}
msg['subtype'] = 'plain'
msg['content_subtype'] = 'plain'
for item in msg_txt.items():
if item[0].startswith('X-'):
msg['headers'].update({item[0]: item[1]})
@ -473,7 +477,7 @@ class mail_message(osv.osv):
body = msg_txt.get_payload(decode=True)
if 'text/html' in msg.get('content-type', ''):
msg['body_html'] = body
msg['subtype'] = 'html'
msg['content_subtype'] = 'html'
if body:
body = tools.html2plaintext(body)
msg['body_text'] = tools.ustr(body, encoding)
@ -482,9 +486,9 @@ class mail_message(osv.osv):
if msg_txt.is_multipart() or 'multipart/alternative' in msg.get('content-type', ''):
body = ""
if 'multipart/alternative' in msg.get('content-type', ''):
msg['subtype'] = 'alternative'
msg['content_subtype'] = 'alternative'
else:
msg['subtype'] = 'mixed'
msg['content_subtype'] = 'mixed'
for part in msg_txt.walk():
if part.get_content_maintype() == 'multipart':
continue
@ -498,7 +502,7 @@ class mail_message(osv.osv):
content = tools.ustr(content, encoding)
if part.get_content_subtype() == 'html':
msg['body_html'] = content
msg['subtype'] = 'html' # html version prevails
msg['content_subtype'] = 'html' # html version prevails
body = tools.ustr(tools.html2plaintext(content))
body = body.replace('&#13;', '')
elif part.get_content_subtype() == 'plain':
@ -515,7 +519,7 @@ class mail_message(osv.osv):
# for backwards compatibility:
msg['body'] = msg['body_text']
msg['sub_type'] = msg['subtype'] or 'plain'
msg['sub_type'] = msg['content_subtype'] or 'plain'
return msg
def _postprocess_sent_message(self, cr, uid, message, context=None):
@ -561,15 +565,17 @@ class mail_message(osv.osv):
for attach in message.attachment_ids:
attachments.append((attach.datas_fname, base64.b64decode(attach.datas)))
body = message.body_html if message.subtype == 'html' else message.body_text
body = message.body_html if message.content_subtype == 'html' else message.body_text
body_alternative = None
subtype_alternative = None
if message.subtype == 'html' and message.body_text:
content_subtype_alternative = None
if message.content_subtype == 'html' and message.body_text:
# we have a plain text alternative prepared, pass it to
# build_message instead of letting it build one
body_alternative = message.body_text
subtype_alternative = 'plain'
content_subtype_alternative = 'plain'
# build an RFC2822 email.message.Message object adn send it
# without queuing
msg = ir_mail_server.build_email(
email_from=message.email_from,
email_to=to_email(message.email_to),
@ -582,8 +588,8 @@ class mail_message(osv.osv):
attachments=attachments, message_id=message.message_id,
references = message.references,
object_id=message.res_id and ('%s-%s' % (message.res_id,message.model)),
subtype=message.subtype,
subtype_alternative=subtype_alternative,
subtype=message.content_subtype,
subtype_alternative=content_subtype_alternative,
headers=message.headers and ast.literal_eval(message.headers))
res = ir_mail_server.send_email(cr, uid, msg,
mail_server_id=message.mail_server_id.id,

View File

@ -103,7 +103,7 @@
<field name="references" colspan="4" widget="char" size="512" groups="base.group_extended" attrs="{'invisible':[('references', '=', False)]}"/>
</group>
<notebook colspan="4">
<page string="Body (Rich)" attrs="{'invisible':[('subtype','=','plain')]}">
<page string="Body (Rich)" attrs="{'invisible':[('content_subtype','=','plain')]}">
<field name="body_html" widget="text_html" nolabel="1" colspan="4"/>
</page>
<page string="Body (Plain)">
@ -113,7 +113,7 @@
<separator string="" colspan="4"/>
<group col="6" colspan="6">
<field name="state" colspan="2"/>
<field name="subtype" attrs="{'invisible':[('subtype', '=', False)]}"/>
<field name="content_subtype" attrs="{'invisible':[('content_subtype', '=', False)]}"/>
<group colspan="2">
<button name="%(action_email_compose_message_wizard)d" string="Reply" type="action" icon="terp-mail-replied"
context="{'mail.compose.message.mode':'reply', 'message_id':active_id}" states='received,sent,exception,cancel'/>

View File

@ -130,7 +130,7 @@ class mail_thread(osv.osv):
subscription_obj = self.pool.get('mail.subscription')
notification_obj = self.pool.get('mail.notification')
res_users_obj = self.pool.get('res.users')
body = vals.get('body_html', '') if vals.get('subtype', 'plain') == 'html' else vals.get('body_text', '')
body = vals.get('body_html', '') if vals.get('content_subtype') == 'html' else vals.get('body_text', '')
# automatically subscribe the writer of the message
if vals['user_id']:
@ -178,7 +178,7 @@ class mail_thread(osv.osv):
context = {}
notif_user_ids = []
body = new_msg_vals.get('body_html', '') if new_msg_vals.get('subtype', 'plain') == 'html' else new_msg_vals.get('body_text', '')
body = new_msg_vals.get('body_html', '') if new_msg_vals.get('content_subtype') == 'html' else new_msg_vals.get('body_text', '')
for thread_id in thread_ids:
# add subscribers
notif_user_ids += [user['id'] for user in self.message_get_subscribers(cr, uid, [thread_id], context=context)]
@ -218,7 +218,7 @@ class mail_thread(osv.osv):
return ret_dict
def message_append(self, cr, uid, threads, subject, body_text=None, body_html=None,
parent_id=False, type='email', subtype='plain', state='received',
parent_id=False, type='email', content_subtype='plain', state='received',
email_to=False, email_from=False, email_cc=None, email_bcc=None,
reply_to=None, email_date=None, message_id=False, references=None,
attachments=None, headers=None, original=None, context=None):
@ -240,7 +240,7 @@ class mail_thread(osv.osv):
:param body_html: html contents of the mail or log message
:param parent_id: id of the parent message (threaded messaging model)
:param type: optional type of message: 'email', 'comment', 'notification'
:param subtype: optional subtype of message: 'plain' or 'html', corresponding to the main
:param content_subtype: optional content_subtype of message: 'plain' or 'html', corresponding to the main
body contents (body_text or body_html).
:param state: optional state of message; 'received' by default
:param email_to: Email-To / Recipient address
@ -304,7 +304,7 @@ class mail_thread(osv.osv):
'parent_id': parent_id,
'date': email_date or fields.datetime.now(),
'type': type,
'subtype': subtype,
'content_subtype': content_subtype,
'state': state,
'message_id': message_id,
'attachment_ids': [(6, 0, to_attach)],
@ -355,7 +355,7 @@ class mail_thread(osv.osv):
body_html= msg_dict.get('body_html'),
parent_id = msg_dict.get('parent_id', False),
type = msg_dict.get('type', 'email'),
subtype = msg_dict.get('subtype', 'plain'),
content_subtype = msg_dict.get('content_subtype', 'plain'),
state = msg_dict.get('state', 'received'),
email_from = msg_dict.get('from', msg_dict.get('email_from')),
email_to = msg_dict.get('to', msg_dict.get('email_to')),
@ -686,12 +686,12 @@ class mail_thread(osv.osv):
# Note specific
#------------------------------------------------------
def message_broadcast(self, cr, uid, ids, subject=None, body=None, parent_id=False, type='notification', subtype='html', context=None):
def message_broadcast(self, cr, uid, ids, subject=None, body=None, parent_id=False, type='notification', content_subtype='html', context=None):
if context is None:
context = {}
notification_obj = self.pool.get('mail.notification')
# write message
msg_ids = self.message_append_note(cr, uid, ids, subject=subject, body=body, parent_id=parent_id, type=type, subtype=subtype, context=context)
msg_ids = self.message_append_note(cr, uid, ids, subject=subject, body=body, parent_id=parent_id, type=type, content_subtype=content_subtype, context=context)
# escape if in install mode or note writing was not successfull
if 'install_mode' in context:
return True
@ -715,7 +715,7 @@ class mail_thread(osv.osv):
_logger.warning("log() is deprecated. Please use OpenChatter notification system instead of the res.log mechanism.")
self.message_append_note(cr, uid, [id], 'res.log', message, context=context)
def message_append_note(self, cr, uid, ids, subject=None, body=None, parent_id=False, type='notification', subtype='html', context=None):
def message_append_note(self, cr, uid, ids, subject=None, body=None, parent_id=False, type='notification', content_subtype='html', context=None):
if subject is None:
if type == 'notification':
subject = _('System notification')
@ -723,13 +723,13 @@ class mail_thread(osv.osv):
subject = _('Comment')
elif type == 'comment' and parent_id:
subject = _('Reply')
if subtype == 'html':
if content_subtype == 'html':
body_html = body
body_text = body
else:
body_html = body
body_text = body
return self.message_append(cr, uid, ids, subject, body_html=body_html, body_text=body_text, parent_id=parent_id, type=type, subtype=subtype, context=context)
return self.message_append(cr, uid, ids, subject, body_html=body_html, body_text=body_text, parent_id=parent_id, type=type, content_subtype=content_subtype, context=context)
#------------------------------------------------------
# Subscription mechanism

View File

@ -158,7 +158,7 @@ class mail_compose_message(osv.osv_memory):
if not (subject.startswith('Re:') or subject.startswith(re_prefix)):
subject = "%s %s" % (re_prefix, subject)
result.update({
'subtype' : 'plain', # default to the text version due to quoting
'content_subtype' : 'plain', # default to the text version due to quoting
'body_text' : body,
'subject' : subject,
'attachment_ids' : [],
@ -198,7 +198,7 @@ class mail_compose_message(osv.osv_memory):
references = None
headers = {}
body = mail.body_html if mail.subtype == 'html' else mail.body_text
body = mail.body_html if mail.content_subtype == 'html' else mail.body_text
# Get model, and check whether it is OpenChatter enabled, aka inherit from mail.thread
if context.get('mail.compose.message.mode') == 'mass_mail':
@ -238,26 +238,26 @@ class mail_compose_message(osv.osv_memory):
# processed as soon as the mail scheduler runs.
if mail_thread_enabled:
active_model_pool.message_append(cr, uid, [active_id],
subject, body_text=mail.body_text, body_html=mail.body_html, subtype=mail.subtype, state='outgoing',
subject, body_text=mail.body_text, body_html=mail.body_html, content_subtype=mail.content_subtype, state='outgoing',
email_to=email_to, email_from=email_from, email_cc=email_cc, email_bcc=email_bcc,
reply_to=reply_to, references=references, attachments=attachment, headers=headers, context=context)
else:
mail_message.schedule_with_attach(cr, uid, email_from, to_email(email_to), subject, rendered_body,
model=mail.model, email_cc=to_email(email_cc), email_bcc=to_email(email_bcc), reply_to=reply_to,
attachments=attachment, references=references, res_id=active_id,
subtype=mail.subtype, headers=headers, context=context)
content_subtype=mail.content_subtype, headers=headers, context=context)
else:
# normal mode - no mass-mailing
if mail_thread_enabled:
msg_ids = active_model_pool.message_append(cr, uid, active_ids,
mail.subject, body_text=mail.body_text, body_html=mail.body_html, subtype=mail.subtype, state='outgoing',
mail.subject, body_text=mail.body_text, body_html=mail.body_html, content_subtype=mail.content_subtype, state='outgoing',
email_to=mail.email_to, email_from=mail.email_from, email_cc=mail.email_cc, email_bcc=mail.email_bcc,
reply_to=mail.reply_to, references=references, attachments=attachment, headers=headers, context=context)
else:
msg_ids = [mail_message.schedule_with_attach(cr, uid, mail.email_from, to_email(mail.email_to), mail.subject, body,
model=mail.model, email_cc=to_email(mail.email_cc), email_bcc=to_email(mail.email_bcc), reply_to=mail.reply_to,
attachments=attachment, references=references, res_id=int(mail.res_id),
subtype=mail.subtype, headers=headers, context=context)]
content_subtype=mail.content_subtype, headers=headers, context=context)]
# in normal mode, we send the email immediately, as the user expects us to (delay should be sufficiently small)
mail_message.send(cr, uid, msg_ids, context=context)