X-Git-Url: http://git.inspyration.org/?a=blobdiff_plain;ds=sidebyside;f=addons%2Fmail%2Fmail_message.py;h=a2d38287062b0a6bad6dfb1ea48523341c6c4b8f;hb=1d9bdb43bf2adc7b6b55b616d65f0a5db44b67dc;hp=d545f3782b4c534a2d808db540d3da0536d0561b;hpb=6fd2f14e3b368359aa630d730fdb37829e3fa9ef;p=odoo%2Fodoo.git diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index d545f37..a2d3828 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -20,13 +20,17 @@ ############################################################################## import logging +import re + from openerp import tools from email.header import decode_header +from email.utils import formataddr from openerp import SUPERUSER_ID from openerp.osv import osv, orm, fields from openerp.tools import html_email_clean from openerp.tools.translate import _ +from HTMLParser import HTMLParser _logger = logging.getLogger(__name__) @@ -43,6 +47,19 @@ def decode(text): text = decode_header(text.replace('\r', '')) return ''.join([tools.ustr(x[0], x[1]) for x in text]) +class MLStripper(HTMLParser): + def __init__(self): + self.reset() + self.fed = [] + def handle_data(self, d): + self.fed.append(d) + def get_data(self): + return ''.join(self.fed) + +def strip_tags(html): + s = MLStripper() + s.feed(html) + return s.get_data() class mail_message(osv.Model): """ Messages model: system notification (replacing res.log notifications), @@ -61,7 +78,8 @@ class mail_message(osv.Model): def default_get(self, cr, uid, fields, context=None): # protection for `default_type` values leaking from menu action context (e.g. for invoices) - if context and context.get('default_type') and context.get('default_type') not in self._columns['type'].selection: + if context and context.get('default_type') and context.get('default_type') not in [ + val[0] for val in self._columns['type'].selection]: context = dict(context, default_type=None) return super(mail_message, self).default_get(cr, uid, fields, context=context) @@ -76,15 +94,15 @@ class mail_message(osv.Model): # TDE note: regroup by model/ids, to have less queries to perform result = dict.fromkeys(ids, False) for message in self.read(cr, uid, ids, ['model', 'res_id'], context=context): - if not message.get('model') or not message.get('res_id') or not self.pool.get(message['model']): + if not message.get('model') or not message.get('res_id') or message['model'] not in self.pool: continue - result[message['id']] = self._shorten_name(self.pool.get(message['model']).name_get(cr, SUPERUSER_ID, [message['res_id']], context=context)[0][1]) + result[message['id']] = self.pool[message['model']].name_get(cr, SUPERUSER_ID, [message['res_id']], context=context)[0][1] return result def _get_to_read(self, cr, uid, ids, name, arg, context=None): """ Compute if the message is unread by the current user. """ res = dict((id, False) for id in ids) - partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + partner_id = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context).partner_id.id notif_obj = self.pool.get('mail.notification') notif_ids = notif_obj.search(cr, uid, [ ('partner_id', 'in', [partner_id]), @@ -103,7 +121,7 @@ class mail_message(osv.Model): def _get_starred(self, cr, uid, ids, name, arg, context=None): """ Compute if the message is unread by the current user. """ res = dict((id, False) for id in ids) - partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + partner_id = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context).partner_id.id notif_obj = self.pool.get('mail.notification') notif_ids = notif_obj.search(cr, uid, [ ('partner_id', 'in', [partner_id]), @@ -125,7 +143,7 @@ class mail_message(osv.Model): ids = [ids] res = [] for message in self.browse(cr, uid, ids, context=context): - name = '%s: %s' % (message.subject or '', message.body or '') + name = '%s: %s' % (message.subject or '', strip_tags(message.body or '') or '') res.append((message.id, self._shorten_name(name.lstrip(' :')))) return res @@ -139,9 +157,12 @@ class mail_message(osv.Model): "message, comment for other messages such as user replies"), 'email_from': fields.char('From', help="Email address of the sender. This field is set when no matching partner is found for incoming emails."), + 'reply_to': fields.char('Reply-To', + help='Reply email address. Setting the reply_to bypasses the automatic thread creation.'), 'author_id': fields.many2one('res.partner', 'Author', select=1, ondelete='set null', help="Author of the message. If not set, email_from may hold an email address that did not match any partner."), + 'author_avatar': fields.related('author_id', 'image_small', type="binary", string="Author's Avatar"), 'partner_ids': fields.many2many('res.partner', string='Recipients'), 'notified_partner_ids': fields.many2many('res.partner', 'mail_notification', 'message_id', 'partner_id', 'Notified partners', @@ -174,19 +195,29 @@ class mail_message(osv.Model): 'vote_user_ids': fields.many2many('res.users', 'mail_vote', 'message_id', 'user_id', string='Votes', help='Users that voted for this message'), + 'mail_server_id': fields.many2one('ir.mail_server', 'Outgoing mail server', readonly=1), } def _needaction_domain_get(self, cr, uid, context=None): return [('to_read', '=', True)] + def _get_default_from(self, cr, uid, context=None): + this = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context) + if this.alias_name and this.alias_domain: + return formataddr((this.name, '%s@%s' % (this.alias_name, this.alias_domain))) + elif this.email: + return formataddr((this.name, this.email)) + raise osv.except_osv(_('Invalid Action!'), _("Unable to send email, please configure the sender's email address or alias.")) + def _get_default_author(self, cr, uid, context=None): - return self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + return self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context).partner_id.id _defaults = { 'type': 'email', - 'date': lambda *a: fields.datetime.now(), - 'author_id': lambda self, cr, uid, ctx={}: self._get_default_author(cr, uid, ctx), + 'date': fields.datetime.now, + 'author_id': lambda self, cr, uid, ctx=None: self._get_default_author(cr, uid, ctx), 'body': '', + 'email_from': lambda self, cr, uid, ctx=None: self._get_default_from(cr, uid, ctx), } #------------------------------------------------------ @@ -224,58 +255,70 @@ class mail_message(osv.Model): # Notification API #------------------------------------------------------ - def set_message_read(self, cr, uid, msg_ids, read, context=None): + def set_message_read(self, cr, uid, msg_ids, read, create_missing=True, context=None): """ Set messages as (un)read. Technically, the notifications related to uid are set to (un)read. If for some msg_ids there are missing notifications (i.e. due to load more or thread parent fetching), they are created. :param bool read: set notification as (un)read + :param bool create_missing: create notifications for missing entries + (i.e. when acting on displayed messages not notified) + + :return number of message mark as read """ notification_obj = self.pool.get('mail.notification') - user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] - notif_ids = notification_obj.search(cr, uid, [ - ('partner_id', '=', user_pid), - ('message_id', 'in', msg_ids) - ], context=context) + user_pid = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context).partner_id.id + domain = [('partner_id', '=', user_pid), ('message_id', 'in', msg_ids)] + if not create_missing: + domain += [('read', '=', not read)] + notif_ids = notification_obj.search(cr, uid, domain, context=context) # all message have notifications: already set them as (un)read - if len(notif_ids) == len(msg_ids): - return notification_obj.write(cr, uid, notif_ids, {'read': read}, context=context) + if len(notif_ids) == len(msg_ids) or not create_missing: + notification_obj.write(cr, uid, notif_ids, {'read': read}, context=context) + return len(notif_ids) # some messages do not have notifications: find which one, create notification, update read status notified_msg_ids = [notification.message_id.id for notification in notification_obj.browse(cr, uid, notif_ids, context=context)] to_create_msg_ids = list(set(msg_ids) - set(notified_msg_ids)) for msg_id in to_create_msg_ids: notification_obj.create(cr, uid, {'partner_id': user_pid, 'read': read, 'message_id': msg_id}, context=context) - return notification_obj.write(cr, uid, notif_ids, {'read': read}, context=context) + notification_obj.write(cr, uid, notif_ids, {'read': read}, context=context) + return len(notif_ids) - def set_message_starred(self, cr, uid, msg_ids, starred, context=None): + def set_message_starred(self, cr, uid, msg_ids, starred, create_missing=True, context=None): """ Set messages as (un)starred. Technically, the notifications related - to uid are set to (un)starred. If for some msg_ids there are missing - notifications (i.e. due to load more or thread parent fetching), - they are created. + to uid are set to (un)starred. :param bool starred: set notification as (un)starred + :param bool create_missing: create notifications for missing entries + (i.e. when acting on displayed messages not notified) """ notification_obj = self.pool.get('mail.notification') - user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] - notif_ids = notification_obj.search(cr, uid, [ - ('partner_id', '=', user_pid), - ('message_id', 'in', msg_ids) - ], context=context) + user_pid = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context).partner_id.id + domain = [('partner_id', '=', user_pid), ('message_id', 'in', msg_ids)] + if not create_missing: + domain += [('starred', '=', not starred)] + values = { + 'starred': starred + } + if starred: + values['read'] = False + + notif_ids = notification_obj.search(cr, uid, domain, context=context) # all message have notifications: already set them as (un)starred - if len(notif_ids) == len(msg_ids): - notification_obj.write(cr, uid, notif_ids, {'starred': starred}, context=context) + if len(notif_ids) == len(msg_ids) or not create_missing: + notification_obj.write(cr, uid, notif_ids, values, context=context) return starred # some messages do not have notifications: find which one, create notification, update starred status notified_msg_ids = [notification.message_id.id for notification in notification_obj.browse(cr, uid, notif_ids, context=context)] to_create_msg_ids = list(set(msg_ids) - set(notified_msg_ids)) for msg_id in to_create_msg_ids: - notification_obj.create(cr, uid, {'partner_id': user_pid, 'starred': starred, 'message_id': msg_id}, context=context) - notification_obj.write(cr, uid, notif_ids, {'starred': starred}, context=context) + notification_obj.create(cr, uid, dict(values, partner_id=user_pid, message_id=msg_id), context=context) + notification_obj.write(cr, uid, notif_ids, values, context=context) return starred #------------------------------------------------------ @@ -291,7 +334,7 @@ class mail_message(osv.Model): """ res_partner_obj = self.pool.get('res.partner') ir_attachment_obj = self.pool.get('ir.attachment') - pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=None)['partner_id'][0] + pid = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context).partner_id.id # 1. Aggregate partners (author_id and partner_ids) and attachments partner_ids = set() @@ -299,7 +342,9 @@ class mail_message(osv.Model): for key, message in message_tree.iteritems(): if message.author_id: partner_ids |= set([message.author_id.id]) - if message.partner_ids: + if message.subtype_id and message.notified_partner_ids: # take notified people of message with a subtype + partner_ids |= set([partner.id for partner in message.notified_partner_ids]) + elif not message.subtype_id and message.partner_ids: # take specified people of message without a subtype (log) partner_ids |= set([partner.id for partner in message.partner_ids]) if message.attachment_ids: attachment_ids |= set([attachment.id for attachment in message.attachment_ids]) @@ -308,8 +353,13 @@ class mail_message(osv.Model): partner_tree = dict((partner[0], partner) for partner in partners) # 2. Attachments as SUPERUSER, because could receive msg and attachments for doc uid cannot see - attachments = ir_attachment_obj.read(cr, SUPERUSER_ID, list(attachment_ids), ['id', 'datas_fname'], context=context) - attachments_tree = dict((attachment['id'], {'id': attachment['id'], 'filename': attachment['datas_fname']}) for attachment in attachments) + attachments = ir_attachment_obj.read(cr, SUPERUSER_ID, list(attachment_ids), ['id', 'datas_fname', 'name', 'file_type_icon'], context=context) + attachments_tree = dict((attachment['id'], { + 'id': attachment['id'], + 'filename': attachment['datas_fname'], + 'name': attachment['name'], + 'file_type_icon': attachment['file_type_icon'], + }) for attachment in attachments) # 3. Update message dictionaries for message_dict in messages: @@ -320,9 +370,12 @@ class mail_message(osv.Model): else: author = (0, message.email_from) partner_ids = [] - for partner in message.partner_ids: - if partner.id in partner_tree: - partner_ids.append(partner_tree[partner.id]) + if message.subtype_id: + partner_ids = [partner_tree[partner.id] for partner in message.notified_partner_ids + if partner.id in partner_tree] + else: + partner_ids = [partner_tree[partner.id] for partner in message.partner_ids + if partner.id in partner_tree] attachment_ids = [] for attachment in message.attachment_ids: if attachment.id in attachments_tree: @@ -332,6 +385,7 @@ class mail_message(osv.Model): 'author_id': author, 'partner_ids': partner_ids, 'attachment_ids': attachment_ids, + 'user_pid': pid }) return True @@ -350,9 +404,22 @@ class mail_message(osv.Model): vote_nb = len(message.vote_user_ids) has_voted = uid in [user.id for user in message.vote_user_ids] + try: + if parent_id: + max_length = 300 + else: + max_length = 100 + body_short = html_email_clean(message.body, remove=False, shorten=True, max_length=max_length) + + except Exception: + body_short = '
Encoding Error :
Unable to convert this message (id: %s).