diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml index c8246a187f5..5e072c3d258 100644 --- a/addons/account/account_view.xml +++ b/addons/account/account_view.xml @@ -97,7 +97,7 @@
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index af18abb67e5..f2cea9b4538 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -25,6 +25,7 @@ import dateutil import email import logging import pytz +import re import time import xmlrpclib from email.message import Message @@ -647,14 +648,14 @@ class mail_thread(osv.AbstractModel): """ if context is None: context = {} + data = {} + if isinstance(custom_values, dict): + data = custom_values.copy() model = context.get('thread_model') or self._name model_pool = self.pool.get(model) fields = model_pool.fields_get(cr, uid, context=context) - data = model_pool.default_get(cr, uid, fields, context=context) if 'name' in fields and not data.get('name'): data['name'] = msg_dict.get('subject', '') - if custom_values and isinstance(custom_values, dict): - data.update(custom_values) res_id = model_pool.create(cr, uid, data, context=context) return res_id @@ -819,6 +820,41 @@ class mail_thread(osv.AbstractModel): "now deprecated res.log.") self.message_post(cr, uid, [id], message, context=context) + def message_create_partners_from_emails(self, cr, uid, emails, context=None): + """ Convert a list of emails into a list partner_ids and a list + new_partner_ids. The return value is non conventional because + it is meant to be used by the mail widget. + + :return dict: partner_ids and new_partner_ids + """ + partner_obj = self.pool.get('res.partner') + mail_message_obj = self.pool.get('mail.message') + + partner_ids = [] + new_partner_ids = [] + for email in emails: + m = re.search(r"((.+?)\s*<)?([^<>]+@[^<>]+)>?", email, re.IGNORECASE | re.DOTALL) + name = m.group(2) or m.group(0) + email = m.group(3) + ids = partner_obj.search(cr, SUPERUSER_ID, [('email', '=', email)], context=context) + if ids: + partner_ids.append(ids[0]) + else: + partner_id = partner_obj.create(cr, uid, { + 'name': name or email, + 'email': email, + }, context=context) + new_partner_ids.append(partner_id) + + # link mail with this from mail to the new partner id + message_ids = mail_message_obj.search(cr, SUPERUSER_ID, ['|', ('email_from', '=', email), ('email_from', 'ilike', '<%s>' % email), ('author_id', '=', False)], context=context) + if message_ids: + mail_message_obj.write(cr, SUPERUSER_ID, message_ids, {'email_from': None, 'author_id': partner_id}, context=context) + return { + 'partner_ids': partner_ids, + 'new_partner_ids': new_partner_ids, + } + def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification', subtype=None, parent_id=False, attachments=None, context=None, **kwargs): """ Post a new message in an existing thread, returning the new @@ -907,7 +943,7 @@ class mail_thread(osv.AbstractModel): return mail_message.create(cr, uid, values, context=context) def message_post_user_api(self, cr, uid, thread_id, body='', parent_id=False, - attachment_ids=None, extra_emails=None, content_subtype='plaintext', + attachment_ids=None, content_subtype='plaintext', context=None, **kwargs): """ Wrapper on message_post, used for user input : - mail gateway @@ -920,26 +956,12 @@ class mail_thread(osv.AbstractModel): - 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. - - extra_email: [ 'Fabien ', 'al@openerp.com' ] """ - partner_obj = self.pool.get('res.partner') mail_message_obj = self.pool.get('mail.message') ir_attachment = self.pool.get('ir.attachment') - extra_emails = extra_emails or [] - # 1.A.1: pre-process partners and incoming extra_emails + # 1.A.1: add recipients of parent message partner_ids = set([]) - for email in extra_emails: - partner_id = partner_obj.find_or_create(cr, uid, email, context=context) - # link mail with this from mail to the new partner id - partner_msg_ids = mail_message_obj.search(cr, SUPERUSER_ID, [('email_from', '=', email), ('author_id', '=', False)], context=context) - if partner_id and partner_msg_ids: - mail_message_obj.write(cr, SUPERUSER_ID, partner_msg_ids, {'email_from': None, 'author_id': partner_id}, context=context) - partner_ids.add((4, partner_id)) - if partner_ids: - self.message_subscribe(cr, uid, [thread_id], [item[1] for item in partner_ids], context=context) - - # 1.A.2: add recipients of parent message if parent_id: parent_message = mail_message_obj.browse(cr, uid, parent_id, context=context) partner_ids |= set([(4, partner.id) for partner in parent_message.partner_ids]) @@ -947,8 +969,21 @@ class mail_thread(osv.AbstractModel): if self._name == 'mail.thread' and parent_message.author_id.id: partner_ids.add((4, parent_message.author_id.id)) - # 1.A.3: add specified recipients - partner_ids |= set(kwargs.pop('partner_ids', [])) + # 1.A.2: add specified recipients + param_partner_ids = set() + for item in kwargs.pop('partner_ids', []): + if isinstance(item, (list)): + param_partner_ids.add((item[0], item[1])) + elif isinstance(item, (int, long)): + param_partner_ids.add((4, item)) + else: + param_partner_ids.add(item) + partner_ids |= param_partner_ids + + # 1.A.3: add parameters recipients as follower + # TDE FIXME in 7.1: should check whether this comes from email_list or partner_ids + if param_partner_ids and self._name != 'mail.thread': + self.message_subscribe(cr, uid, [thread_id], [pid[1] for pid in param_partner_ids], context=context) # 1.B: handle body, message_type and message_subtype if content_subtype == 'plaintext': diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index f8643e94bb3..e08afdad217 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -253,7 +253,14 @@ openerp.mail = function (session) { } else { this.avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid); } - + if (this.author_id) { + var email = this.author_id[1].match(/(.*)<(.*@.*)>/); + if (!email) { + this.author_id.push(_.str.escapeHTML(this.author_id[1]), '', this.author_id[1]); + } else { + this.author_id.push(_.str.escapeHTML(email[0]), _.str.trim(email[1]), email[2]); + } + } }, @@ -370,6 +377,7 @@ openerp.mail = function (session) { this.show_compact_message = false; this.show_delete_attachment = true; this.emails_from = []; + this.partners_from = []; }, start: function () { @@ -494,43 +502,43 @@ openerp.mail = function (session) { this.$(".oe_msg_attachment_list").on('click', '.oe_delete', this.on_attachment_delete); this.$(".oe_emails_from").on('change', 'input', this.on_checked_email_from); + this.$(".oe_partners_from").on('change', 'input', this.on_checked_partner_from); }, on_compose_fullmail: function (default_composition_mode) { - + var self = this; if(!this.do_check_attachment_upload()) { return false; } - if (default_composition_mode == 'reply') { + // create list of new partners + this.check_recipient_partners().done(function (partner_ids) { var context = { 'default_composition_mode': default_composition_mode, - 'default_parent_id': this.id, - 'default_body': mail.ChatterUtils.get_text2html(this.$el ? (this.$el.find('textarea:not(.oe_compact)').val() || '') : ''), - 'default_attachment_ids': this.attachment_ids, + 'default_parent_id': self.id, + 'default_body': mail.ChatterUtils.get_text2html(self.$el ? (self.$el.find('textarea:not(.oe_compact)').val() || '') : ''), + 'default_attachment_ids': self.attachment_ids, + 'default_partner_ids': partner_ids, }; - } else { - var context = { - 'default_model': this.context.default_model, - 'default_res_id': this.context.default_res_id, - 'default_composition_mode': default_composition_mode, - 'default_parent_id': this.id, - 'default_body': mail.ChatterUtils.get_text2html(this.$el ? (this.$el.find('textarea:not(.oe_compact)').val() || '') : ''), - 'default_attachment_ids': this.attachment_ids, - }; - } - var action = { - type: 'ir.actions.act_window', - res_model: 'mail.compose.message', - view_mode: 'form', - view_type: 'form', - views: [[false, 'form']], - target: 'new', - context: context, - }; + if (default_composition_mode != 'reply' && self.context.default_model && self.context.default_res_id) { + context.default_model = self.context.default_model; + context.default_res_id = self.context.default_res_id; + } + + var action = { + type: 'ir.actions.act_window', + res_model: 'mail.compose.message', + view_mode: 'form', + view_type: 'form', + views: [[false, 'form']], + target: 'new', + context: context, + }; + + self.do_action(action); + self.on_cancel(); + }); - this.do_action(action); - this.on_cancel(); }, reinit: function() { @@ -562,63 +570,65 @@ openerp.mail = function (session) { } }, - check_recipient_partners: function (emails) { + check_recipient_partners: function () { var self = this; - var deferreds = []; - for (var i = 0; i < emails.length; i++) { - deferreds.push($.Deferred()); - } - var ds_partner = new session.web.DataSetSearch(this, 'res.partner'); - _.each(emails, function (email) { - ds_partner.call('search', [[['email', 'ilike', email]]]).then(function (partner_ids) { - var deferred = deferreds[_.indexOf(emails, email)]; - if (!partner_ids.length) { - var pop = new session.web.form.FormOpenPopup(this); - pop.show_element( - 'res.partner', - 0, - { - 'default_email': email, - 'force_email': true, - 'ref': "compound_context", - }, - { - title: _t("Please complete partner's informations"), - } - ); - pop.on('write_completed, closed', self, function () { - deferred.resolve(); - }); - } - else { + var partners_from = []; + var emails = []; + _.each(this.emails_from, function (email_from) { + if (email_from[1] && !_.find(emails, function (email) {return email == email_from[0][4];})) { + emails.push(email_from[0][1]); + } + }); + var deferred_check = $.Deferred(); + self.parent_thread.ds_thread._model.call('message_create_partners_from_emails', [emails]).then(function (partners) { + partners_from = _.clone(partners.partner_ids); + var deferreds = []; + _.each(partners.new_partner_ids, function (id) { + var deferred = $.Deferred() + deferreds.push(deferred); + var pop = new session.web.form.FormOpenPopup(this); + pop.show_element( + 'res.partner', + id, + { + 'force_email': true, + 'ref': "compound_context", + }, + { + title: _t("Please complete partner's informations"), + } + ); + pop.on('closed', self, function () { deferred.resolve(); - } - return deferred; + }); + partners_from.push(id); + }); + $.when.apply( $, deferreds ).then(function () { + deferred_check.resolve(partners_from); }); }); - return $.when.apply( $, deferreds ).done(); + return deferred_check; }, on_message_post: function (event) { var self = this; if (this.do_check_attachment_upload() && (this.attachment_ids.length || this.$('textarea').val().match(/\S+/))) { // create list of new partners - var extra_email = _.map(_.filter(this.emails_from, function (f) {return f[1]}), function (f) {return f[0]}); - this.check_recipient_partners(extra_email).done(function () { - self.do_send_message_post(); + this.check_recipient_partners().done(function (partner_ids) { + self.do_send_message_post(partner_ids); }); } }, /*do post a message and fetch the message*/ - do_send_message_post: function () { + do_send_message_post: function (partner_ids) { var self = this; this.parent_thread.ds_thread._model.call('message_post_user_api', [this.context.default_res_id], { 'body': this.$('textarea').val(), 'subject': false, 'parent_id': this.context.default_parent_id, 'attachment_ids': _.map(this.attachment_ids, function (file) {return file.id;}), - 'extra_emails': _.map(_.filter(this.emails_from, function (f) {return f[1]}), function (f) {return f[0]}), + 'partner_ids': partner_ids, 'context': this.parent_thread.context, }).done(function (message_id) { var thread = self.parent_thread; @@ -678,26 +688,24 @@ openerp.mail = function (session) { _.each(this.options.root_thread.messages, function (msg) {messages.push(msg); messages.concat(msg.get_childs());}); } - var emails_from = _.map(_.filter(messages, - function (thread) {return thread.author_id && !thread.author_id[0];}), - function (thread) {return thread.author_id[1];}); - - return _.each(emails_from, function (email_from) { - if (!_.find(self.emails_from, function (from) {return from[0] == email_from;})) { - self.emails_from.push([email_from, true]); + _.each(messages, function (thread) { + if (thread.author_id && !thread.author_id[0] && + !_.find(self.emails_from, function (from) {return from[0][4] == thread.author_id[4];})) { + self.emails_from.push([thread.author_id, true]); } }); + return self.emails_from; }, on_checked_email_from: function (event) { var $input = $(event.target); var email = $input.attr("data"); _.each(this.emails_from, function (email_from) { - if (email_from[0] == email) { + if (email_from[0][4] == email) { email_from[1] = $input.is(":checked"); } }); - } + }, }); /** @@ -1690,7 +1698,6 @@ openerp.mail = function (session) { this.defaults[key.replace(/^search_default_/, '')] = this.context[key]; } } - this.action.params = _.extend({ 'display_indented_thread': 1, 'show_reply_button': true, diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index 1fc93781039..9f88116acc7 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -221,11 +221,14 @@ openerp_mail_followers = function(session, mail) { var nb_subtype = 0; _(records).each(function (record) {nb_subtype++;}); if (nb_subtype > 1) { + this.$('hr').show(); _(records).each(function (record, record_name) { record.name = record_name; record.followed = record.followed || undefined; $(session.web.qweb.render('mail.followers.subtype', {'record': record})).appendTo( self.$('.oe_subtype_list') ); }); + } else { + this.$('hr').hide(); } }, diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index c1a32a2fe89..63f8a10658f 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -132,8 +132,8 @@
@@ -243,8 +243,8 @@
- - + + • • diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index 0062b5e01bd..ec0c2a8de06 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -168,6 +168,7 @@ class mail_compose_message(osv.TransientModel): reply_subject = "%s %s" % (re_prefix, reply_subject) # get partner_ids from original message partner_ids = [partner.id for partner in message_data.partner_ids] if message_data.partner_ids else [] + partner_ids += context.get('default_partner_ids', []) # update the result result = {