From 0b62a6858f52a6d2e3edfaabdb64a71d2e0686fa Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Thu, 14 Mar 2013 15:59:49 +0530 Subject: [IMP] 1) Added code for opening the dialog box of edit followers, 2) Added an image in the mail.message.subtype template which is visible when the Technical Features menu is selected true . 3) On clicking on the edit pencil which is with the followers name gives the subtypes of the specific followers on which the user had clicked rather than the current form. bzr revid: psa@tinyerp.com-20130314102949-4v9l6xpz5u1jeq10 --- addons/mail/mail_thread.py | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 64b1410508d..2cec1557a55 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -138,9 +138,56 @@ class mail_thread(osv.AbstractModel): for subtype in fol.subtype_ids: thread_subtype_dict[subtype.name]['followed'] = True res[fol.res_id]['message_subtype_data'] = thread_subtype_dict + return res + + def edit_followers_subtype(self, cr, uid, ids, partner_id, context=None): + print "cr, uid, ids, partner_id, co",cr, uid, ids, partner_id + res = dict((id, dict(message_subtype_data='')) for id in ids) + subtype_obj = self.pool.get('mail.message.subtype') + subtype_ids = subtype_obj.search(cr, uid, ['|', ('res_model', '=', self._name), ('res_model', '=', False)], context=context) + subtype_dict = dict((subtype.name, dict(default=subtype.default, followed=False, id=subtype.id)) for subtype in subtype_obj.browse(cr, uid, subtype_ids, context=context)) + for id in ids: + res[id]['message_subtype_data'] = subtype_dict.copy() + fol_obj = self.pool.get('mail.followers') + fol_ids = fol_obj.search(cr, uid, [ + ('partner_id', '=', partner_id), + ('res_id', 'in', ids), + ('res_model', '=', self._name), + ], context=context) + print "\n\n fol _ids>>>>>>>>>>", fol_ids + for fol in fol_obj.browse(cr, uid, fol_ids, context=context): + thread_subtype_dict = res[fol.res_id]['message_subtype_data'] + for subtype in fol.subtype_ids: + thread_subtype_dict[subtype.name]['followed'] = True + res[fol.res_id]['message_subtype_data'] = thread_subtype_dict + print "\n<<<>>>",res return res + def apply_subtype(self, cr, uid, ids, partner_id, context=None): + print "\n\n uid, ids, subtype_id,", uid, ids, partner_id + res=[] + fol_obj = self.pool.get('mail.followers') + fol_ids = fol_obj.search(cr, uid, [ + ('partner_id', '=', partner_id), + ('res_id', 'in', ids), + ('res_model', '=', self._name), + ], context=context) + print "\n\n fol _ids>>>>>>>>>>", fol_ids + for fol in fol_obj.browse(cr, uid, fol_ids, context=context): + print "\fol.subtype::::>:>:>:>:>", fol.subtype_ids + for subtype in fol.subtype_ids: + res.append(subtype.id) + print "\nres::::>:>:>:>:>", res + if partner_id==True: + res.append(ids[0]) + else: + res.remove(ids[0]) + fol_obj.write(cr, uid, fol_ids, {'subtype_ids': [(6,0,res)]}, context=context) + print "\nsubtype_id......>>>", partner_id, res + return partner_id + + def _search_message_unread(self, cr, uid, obj=None, name=None, domain=None, context=None): return [('message_ids.to_read', '=', True)] -- cgit v1.2.3 From 90868a808903c8f5812a4243092a448752f25100 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Fri, 15 Mar 2013 14:22:45 +0530 Subject: [IMP] Add method for the apply button when the user click on the apply button of the dialog box the data will be updated Removed unwanted code and clean the code. bzr revid: psa@tinyerp.com-20130315085245-uhefj63na5z62of5 --- addons/mail/mail_thread.py | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 2cec1557a55..d85e91fa8ba 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -141,8 +141,8 @@ class mail_thread(osv.AbstractModel): return res def edit_followers_subtype(self, cr, uid, ids, partner_id, context=None): - print "cr, uid, ids, partner_id, co",cr, uid, ids, partner_id res = dict((id, dict(message_subtype_data='')) for id in ids) + subtype_obj = self.pool.get('mail.message.subtype') subtype_ids = subtype_obj.search(cr, uid, ['|', ('res_model', '=', self._name), ('res_model', '=', False)], context=context) subtype_dict = dict((subtype.name, dict(default=subtype.default, followed=False, id=subtype.id)) for subtype in subtype_obj.browse(cr, uid, subtype_ids, context=context)) @@ -155,38 +155,24 @@ class mail_thread(osv.AbstractModel): ('res_id', 'in', ids), ('res_model', '=', self._name), ], context=context) - print "\n\n fol _ids>>>>>>>>>>", fol_ids for fol in fol_obj.browse(cr, uid, fol_ids, context=context): thread_subtype_dict = res[fol.res_id]['message_subtype_data'] for subtype in fol.subtype_ids: thread_subtype_dict[subtype.name]['followed'] = True res[fol.res_id]['message_subtype_data'] = thread_subtype_dict - print "\n<<<>>>",res return res - def apply_subtype(self, cr, uid, ids, partner_id, context=None): - print "\n\n uid, ids, subtype_id,", uid, ids, partner_id - res=[] + def apply_edited_subtypes(self, cr, uid, ids, partner_id,check_list, context=None): + """ Apply the edited subtypes + of the user.""" fol_obj = self.pool.get('mail.followers') fol_ids = fol_obj.search(cr, uid, [ ('partner_id', '=', partner_id), ('res_id', 'in', ids), ('res_model', '=', self._name), ], context=context) - print "\n\n fol _ids>>>>>>>>>>", fol_ids - for fol in fol_obj.browse(cr, uid, fol_ids, context=context): - print "\fol.subtype::::>:>:>:>:>", fol.subtype_ids - for subtype in fol.subtype_ids: - res.append(subtype.id) - print "\nres::::>:>:>:>:>", res - if partner_id==True: - res.append(ids[0]) - else: - res.remove(ids[0]) - fol_obj.write(cr, uid, fol_ids, {'subtype_ids': [(6,0,res)]}, context=context) - print "\nsubtype_id......>>>", partner_id, res - return partner_id - + fol_obj.write(cr, uid, fol_ids, {'subtype_ids': [(6, 0, check_list)]}, context=context) + return True def _search_message_unread(self, cr, uid, obj=None, name=None, domain=None, context=None): return [('message_ids.to_read', '=', True)] -- cgit v1.2.3 From b5df63291a0de2cbcd42a348db5ffa925f8e4efc Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Fri, 15 Mar 2013 18:01:57 +0530 Subject: [IMP] Removed the dialog box on apply and close to open a new dialog box everytime. Removed unwanted code. bzr revid: psa@tinyerp.com-20130315123157-n0n3fdej014ysz7v --- addons/mail/mail_thread.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index d85e91fa8ba..ab4eead1a6e 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -162,7 +162,8 @@ class mail_thread(osv.AbstractModel): res[fol.res_id]['message_subtype_data'] = thread_subtype_dict return res - def apply_edited_subtypes(self, cr, uid, ids, partner_id,check_list, context=None): + def apply_edited_subtypes(self, cr, uid, ids, partner_id, check_list, context=None): + print "\n\n uid, ids, partner_id, check_list,,>", uid, ids, partner_id, check_list, """ Apply the edited subtypes of the user.""" fol_obj = self.pool.get('mail.followers') @@ -171,7 +172,8 @@ class mail_thread(osv.AbstractModel): ('res_id', 'in', ids), ('res_model', '=', self._name), ], context=context) - fol_obj.write(cr, uid, fol_ids, {'subtype_ids': [(6, 0, check_list)]}, context=context) + print "\n fol _ids>", fol_ids, check_list + fol_obj.write(cr, uid, fol_ids, {'subtype_ids': [(6,0, check_list)]}, context=context) return True def _search_message_unread(self, cr, uid, obj=None, name=None, domain=None, context=None): -- cgit v1.2.3 From 0abe605544641bb0788f6b84f8df76603dd90b93 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Fri, 15 Mar 2013 18:18:43 +0530 Subject: [IMP] Oops sorry forgot to remove the prints and improved code. bzr revid: psa@tinyerp.com-20130315124843-xtp19rbm2cvyfb67 --- addons/mail/mail_thread.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index ab4eead1a6e..720afd7fd8f 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -163,7 +163,6 @@ class mail_thread(osv.AbstractModel): return res def apply_edited_subtypes(self, cr, uid, ids, partner_id, check_list, context=None): - print "\n\n uid, ids, partner_id, check_list,,>", uid, ids, partner_id, check_list, """ Apply the edited subtypes of the user.""" fol_obj = self.pool.get('mail.followers') @@ -172,7 +171,6 @@ class mail_thread(osv.AbstractModel): ('res_id', 'in', ids), ('res_model', '=', self._name), ], context=context) - print "\n fol _ids>", fol_ids, check_list fol_obj.write(cr, uid, fol_ids, {'subtype_ids': [(6,0, check_list)]}, context=context) return True -- cgit v1.2.3 From cf3415f0877affc7f26ad16cd6a47ba671a9d601 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Tue, 19 Mar 2013 13:03:19 +0530 Subject: [IMP]Changed the position of methods and improved code. bzr revid: psa@tinyerp.com-20130319073319-8myj2hx5iaqmi5xj --- addons/mail/mail_thread.py | 71 ++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 34 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 6ead2c9202b..ddbbf8a689b 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -140,40 +140,6 @@ class mail_thread(osv.AbstractModel): res[fol.res_id]['message_subtype_data'] = thread_subtype_dict return res - def edit_followers_subtype(self, cr, uid, ids, partner_id, context=None): - res = dict((id, dict(message_subtype_data='')) for id in ids) - - subtype_obj = self.pool.get('mail.message.subtype') - subtype_ids = subtype_obj.search(cr, uid, ['|', ('res_model', '=', self._name), ('res_model', '=', False)], context=context) - subtype_dict = dict((subtype.name, dict(default=subtype.default, followed=False, id=subtype.id)) for subtype in subtype_obj.browse(cr, uid, subtype_ids, context=context)) - for id in ids: - res[id]['message_subtype_data'] = subtype_dict.copy() - - fol_obj = self.pool.get('mail.followers') - fol_ids = fol_obj.search(cr, uid, [ - ('partner_id', '=', partner_id), - ('res_id', 'in', ids), - ('res_model', '=', self._name), - ], context=context) - for fol in fol_obj.browse(cr, uid, fol_ids, context=context): - thread_subtype_dict = res[fol.res_id]['message_subtype_data'] - for subtype in fol.subtype_ids: - thread_subtype_dict[subtype.name]['followed'] = True - res[fol.res_id]['message_subtype_data'] = thread_subtype_dict - return res - - def apply_edited_subtypes(self, cr, uid, ids, partner_id, check_list, context=None): - """ Apply the edited subtypes - of the user.""" - fol_obj = self.pool.get('mail.followers') - fol_ids = fol_obj.search(cr, uid, [ - ('partner_id', '=', partner_id), - ('res_id', 'in', ids), - ('res_model', '=', self._name), - ], context=context) - fol_obj.write(cr, uid, fol_ids, {'subtype_ids': [(6,0, check_list)]}, context=context) - return True - def _search_message_unread(self, cr, uid, obj=None, name=None, domain=None, context=None): return [('message_ids.to_read', '=', True)] @@ -323,6 +289,43 @@ class mail_thread(osv.AbstractModel): default['message_follower_ids'] = [] return super(mail_thread, self).copy(cr, uid, id, default=default, context=context) + #------------------------------------------------------ + # Edit and apply followers subtypes. + #------------------------------------------------------ + def edit_followers_subtype(self, cr, uid, ids, partner_id, context=None): + res = dict((id, dict(message_subtype_data='')) for id in ids) + + subtype_obj = self.pool.get('mail.message.subtype') + subtype_ids = subtype_obj.search(cr, uid, ['|', ('res_model', '=', self._name), ('res_model', '=', False)], context=context) + subtype_dict = dict((subtype.name, dict(default=subtype.default, followed=False, id=subtype.id)) for subtype in subtype_obj.browse(cr, uid, subtype_ids, context=context)) + for id in ids: + res[id]['message_subtype_data'] = subtype_dict.copy() + + fol_obj = self.pool.get('mail.followers') + fol_ids = fol_obj.search(cr, uid, [ + ('partner_id', '=', partner_id), + ('res_id', 'in', ids), + ('res_model', '=', self._name), + ], context=context) + for fol in fol_obj.browse(cr, uid, fol_ids, context=context): + thread_subtype_dict = res[fol.res_id]['message_subtype_data'] + for subtype in fol.subtype_ids: + thread_subtype_dict[subtype.name]['followed'] = True + res[fol.res_id]['message_subtype_data'] = thread_subtype_dict + return res + + def apply_edited_subtypes(self, cr, uid, ids, partner_id, check_list, context=None): + """ Apply the edited subtypes + of the user.""" + fol_obj = self.pool.get('mail.followers') + fol_ids = fol_obj.search(cr, uid, [ + ('partner_id', '=', partner_id), + ('res_id', 'in', ids), + ('res_model', '=', self._name), + ], context=context) + fol_obj.write(cr, uid, fol_ids, {'subtype_ids': [(6,0, check_list)]}, context=context) + return True + #------------------------------------------------------ # Automatically log tracked fields #------------------------------------------------------ -- cgit v1.2.3 From e9065f77273a544c99b546bf58201ee9c08b4b73 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Thu, 21 Mar 2013 18:10:36 +0530 Subject: [IMP] Reduced code, deleted redundant code, deleted the edit template and used it in the existing by using 'mode' and improved code using the existing code and removed unwanted code. bzr revid: psa@tinyerp.com-20130321124036-0s4pv3oivzesmjh5 --- addons/mail/mail_thread.py | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index c901f6e64c2..2268e66ce36 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -126,6 +126,8 @@ class mail_thread(osv.AbstractModel): for id in ids: res[id]['message_subtype_data'] = subtype_dict.copy() + if context and 'partner_id' in context: + user_pid = context.get('partner_id') # find the document followers, update the data fol_obj = self.pool.get('mail.followers') fol_ids = fol_obj.search(cr, uid, [ @@ -138,6 +140,7 @@ class mail_thread(osv.AbstractModel): for subtype in fol.subtype_ids: thread_subtype_dict[subtype.name]['followed'] = True res[fol.res_id]['message_subtype_data'] = thread_subtype_dict + return res def _search_message_unread(self, cr, uid, obj=None, name=None, domain=None, context=None): @@ -289,34 +292,8 @@ class mail_thread(osv.AbstractModel): default['message_follower_ids'] = [] return super(mail_thread, self).copy(cr, uid, id, default=default, context=context) - #------------------------------------------------------ - # Edit and apply followers subtypes. - #------------------------------------------------------ - def edit_followers_subtype(self, cr, uid, ids, partner_id, context=None): - res = dict((id, dict(message_subtype_data='')) for id in ids) - - subtype_obj = self.pool.get('mail.message.subtype') - subtype_ids = subtype_obj.search(cr, uid, ['|', ('res_model', '=', self._name), ('res_model', '=', False)], context=context) - subtype_dict = dict((subtype.name, dict(default=subtype.default, followed=False, id=subtype.id)) for subtype in subtype_obj.browse(cr, uid, subtype_ids, context=context)) - for id in ids: - res[id]['message_subtype_data'] = subtype_dict.copy() - - fol_obj = self.pool.get('mail.followers') - fol_ids = fol_obj.search(cr, uid, [ - ('partner_id', '=', partner_id), - ('res_id', 'in', ids), - ('res_model', '=', self._name), - ], context=context) - for fol in fol_obj.browse(cr, uid, fol_ids, context=context): - thread_subtype_dict = res[fol.res_id]['message_subtype_data'] - for subtype in fol.subtype_ids: - thread_subtype_dict[subtype.name]['followed'] = True - res[fol.res_id]['message_subtype_data'] = thread_subtype_dict - return res - def apply_edited_subtypes(self, cr, uid, ids, partner_id, check_list, context=None): - """ Apply the edited subtypes - of the user.""" + """ Apply the edited subtypes of the user.""" fol_obj = self.pool.get('mail.followers') fol_ids = fol_obj.search(cr, uid, [ ('partner_id', '=', partner_id), -- cgit v1.2.3 From e627fce6b8a3b9db56967a7b8d93b24a9bdc45f5 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Thu, 21 Mar 2013 18:18:59 +0530 Subject: [IMP] Little improvement with context(context is None:). bzr revid: psa@tinyerp.com-20130321124859-281pcjosai1xtvaj --- addons/mail/mail_thread.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 2268e66ce36..c8086a8db76 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -116,6 +116,8 @@ class mail_thread(osv.AbstractModel): """ Computes: - message_subtype_data: data about document subtypes: which are available, which are followed if any """ + if context is None: + context = {} res = dict((id, dict(message_subtype_data='')) for id in ids) user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] @@ -126,7 +128,7 @@ class mail_thread(osv.AbstractModel): for id in ids: res[id]['message_subtype_data'] = subtype_dict.copy() - if context and 'partner_id' in context: + if 'partner_id' in context: user_pid = context.get('partner_id') # find the document followers, update the data fol_obj = self.pool.get('mail.followers') -- cgit v1.2.3 From f1db1ed7783b664ac3b6cceb085edfdddb7b8ee2 Mon Sep 17 00:00:00 2001 From: "Vishmita Jadeja (openerp)" Date: Fri, 22 Mar 2013 13:52:06 +0530 Subject: [IMP]Add method for checking the group technical features. bzr revid: vja@tinyerp.com-20130322082206-x2490850o8qbkmk0 --- addons/mail/mail_thread.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index c8086a8db76..f25d58c90e6 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -112,6 +112,13 @@ class mail_thread(osv.AbstractModel): res[id]['message_summary'] = "9 %d %s" % (title, res[id].pop('message_unread_count'), _("New")) return res + def check_access_right(self, cr, uid,ids , context=None ): + grp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_no_one') + user_pid = self.pool.get('res.groups').read(cr, uid, grp_id[1], ['users'], context=context)['users'] + if uid in user_pid: + return True + return False + def _get_subscription_data(self, cr, uid, ids, name, args, context=None): """ Computes: - message_subtype_data: data about document subtypes: which are -- cgit v1.2.3 From bd6a436bbb04b8121e58ad8b547ba8d7c67c3584 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Fri, 22 Mar 2013 14:40:26 +0530 Subject: [IMP] Added css for the ' Close(X)' icon of the dialog box when the title size increases than overlap the title. bzr revid: psa@tinyerp.com-20130322091026-m0eqoqnt1t2p184v --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index f25d58c90e6..14d13ab7094 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -112,7 +112,7 @@ class mail_thread(osv.AbstractModel): res[id]['message_summary'] = "9 %d %s" % (title, res[id].pop('message_unread_count'), _("New")) return res - def check_access_right(self, cr, uid,ids , context=None ): + def check_access_right(self, cr, uid, ids, context=None): grp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_no_one') user_pid = self.pool.get('res.groups').read(cr, uid, grp_id[1], ['users'], context=context)['users'] if uid in user_pid: -- cgit v1.2.3 From dbaeee703fc16027bf17552acc6bb3c409d21958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 22 Mar 2013 16:57:34 +0100 Subject: [IMP] mail: alias_contact on alias. However, not sure this will be usefull, to discuss. bzr revid: tde@openerp.com-20130322155734-9jfc7w8nw8oiytd4 --- addons/mail/mail_thread.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 7ca9fcb7b53..12e280594d4 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -553,9 +553,26 @@ class mail_thread(osv.AbstractModel): mail_alias = self.pool.get('mail.alias') alias_ids = mail_alias.search(cr, uid, [('alias_name', 'in', local_parts)]) if alias_ids: + # TDE note: at this stage, message parsing is not done yet - parse the from of the message + author_ids = self._message_find_partners(cr, uid, message, ['From'], context=context) routes = [] for alias in mail_alias.browse(cr, uid, alias_ids, context=context): user_id = alias.alias_user_id.id + + if alias.alias_contact == 'partners' and not author_ids: + # TDE TODO: bounce + _logger.info('Routing mail with Message-Id %s: alias %s does not accept unknown emails, skipping', message_id, alias.alias_name) + mail_id = self.pool.get('mail.mail').create(cr, uid, { + 'body_html': '

Hello,

' + '

The following email sent to %s cannot be accepted because this address' + 'is private. Only known contacts are allowed to contact this address.

' + '
%s
' % (message.get('to'), message.get('body')), + 'subject': message.get('subject'), + 'email_to': message.get('from'), + 'auto_delete': True, + }, context=context) + self.pool.get('mail.mail').send(cr, uid, [mail_id], context=context) + continue if not user_id: # TDE note: this could cause crashes, because no clue that the user # that send the email has the right to create or modify a new document -- cgit v1.2.3 From 851e6c1f5a5d9a8b206e115760c7f2ae484341ce Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 3 Apr 2013 14:24:08 +0200 Subject: [REF] cleaning js code bzr revid: mat@openerp.com-20130403122408-fbbybeczf6xqwjvc --- addons/mail/mail_thread.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 778d7d53bd1..9ebd3fa218b 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -29,6 +29,8 @@ import re import time import xmlrpclib from email.message import Message +import operator + from openerp import tools from openerp import SUPERUSER_ID @@ -1245,4 +1247,20 @@ class mail_thread(osv.AbstractModel): ''', (ids, self._name, partner_id)) return True -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + #------------------------------------------------------ + # Thread suggestion + #------------------------------------------------------ + + def get_suggested_thread(self, cr, uid, removed_suggested_threads=None, context=None): + """Return a list of suggested threads, sorted by the numbers of followers""" + if context is None: + context = {} + threads = [] + if removed_suggested_threads is None: + removed_suggested_threads = [] + threads_ids = self.search(cr, uid, [('id', 'not in', removed_suggested_threads)], context=context) + for data in self.read(cr, uid, threads_ids, ['message_is_follower', 'message_ids', 'name', 'image_small'], context): + if not data['message_is_follower']: + data['popularity'] = len(data['message_ids']) + threads.append(data) + return sorted(threads, key=lambda x: x['popularity'], reverse=True)[:3] -- cgit v1.2.3 From 8d8eb553ceac3b3c4ca037c442c7f1714c0d9a12 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 3 Apr 2013 16:27:16 +0200 Subject: [ADD] suggestions for employees to follow bzr revid: mat@openerp.com-20130403142716-lmsz9hwkg7tathly --- addons/mail/mail_thread.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 9ebd3fa218b..40030613f23 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -29,7 +29,6 @@ import re import time import xmlrpclib from email.message import Message -import operator from openerp import tools @@ -1263,4 +1262,5 @@ class mail_thread(osv.AbstractModel): if not data['message_is_follower']: data['popularity'] = len(data['message_ids']) threads.append(data) - return sorted(threads, key=lambda x: x['popularity'], reverse=True)[:3] + sorted_threads = sorted(threads, key=lambda x: x['popularity'], reverse=True)[:3] + return sorted_threads -- cgit v1.2.3 From b32cc3b4427c6d59581da13d039bde931ce82a5c Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Thu, 4 Apr 2013 12:37:23 +0530 Subject: [IMP] Improved code 1) Edit Subscriptions of -> Edit Subscription (without 's') of 2) Instead of defining a new 'apply_edited_subtype', you can use 'message_subscribe' that has an optional 'subtype_ids' parameter that already allows to manage subtypes of a subscription. 3) In _get_subscription_data: do not use context when it is not necessary. Please add a parameter user_id=None that will be used instead of uid to find user_pid. 4) Instead of defining a new 'on_apply_subtype', can't you reuse 'do_update_subscription' with maybe some update to handle the classic use / edit widget ? The above changes has been done. bzr revid: psa@tinyerp.com-20130404070723-5v1v35fte6vl2b2j --- addons/mail/mail_thread.py | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index db177db7e8c..63f5b8316df 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -119,12 +119,10 @@ class mail_thread(osv.AbstractModel): return True return False - def _get_subscription_data(self, cr, uid, ids, name, args, context=None): + def _get_subscription_data(self, cr, uid, ids, user_id, name, args, context=None): """ Computes: - message_subtype_data: data about document subtypes: which are available, which are followed if any """ - if context is None: - context = {} res = dict((id, dict(message_subtype_data='')) for id in ids) user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] @@ -135,8 +133,8 @@ class mail_thread(osv.AbstractModel): for id in ids: res[id]['message_subtype_data'] = subtype_dict.copy() - if 'partner_id' in context: - user_pid = context.get('partner_id') + if user_id: + user_pid = user_id # find the document followers, update the data fol_obj = self.pool.get('mail.followers') fol_ids = fol_obj.search(cr, uid, [ @@ -301,17 +299,6 @@ class mail_thread(osv.AbstractModel): default['message_follower_ids'] = [] return super(mail_thread, self).copy(cr, uid, id, default=default, context=context) - def apply_edited_subtypes(self, cr, uid, ids, partner_id, check_list, context=None): - """ Apply the edited subtypes of the user.""" - fol_obj = self.pool.get('mail.followers') - fol_ids = fol_obj.search(cr, uid, [ - ('partner_id', '=', partner_id), - ('res_id', 'in', ids), - ('res_model', '=', self._name), - ], context=context) - fol_obj.write(cr, uid, fol_ids, {'subtype_ids': [(6,0, check_list)]}, context=context) - return True - #------------------------------------------------------ # Automatically log tracked fields #------------------------------------------------------ @@ -1102,21 +1089,23 @@ class mail_thread(osv.AbstractModel): # Followers API #------------------------------------------------------ - def message_get_subscription_data(self, cr, uid, ids, context=None): + def message_get_subscription_data(self, cr, uid, ids, user_id=None, context=None): """ Wrapper to get subtypes data. """ - return self._get_subscription_data(cr, uid, ids, None, None, context=context) + return self._get_subscription_data(cr, uid, ids, user_id, None, None, context=context) - def message_subscribe_users(self, cr, uid, ids, user_ids=None, subtype_ids=None, context=None): + def message_subscribe_users(self, cr, uid, ids, user_ids=None, partner_id=None, subtype_ids=None, context=None): """ Wrapper on message_subscribe, using users. If user_ids is not provided, subscribe uid instead. """ if user_ids is None: user_ids = [uid] partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)] - return self.message_subscribe(cr, uid, ids, partner_ids, subtype_ids=subtype_ids, context=context) + return self.message_subscribe(cr, uid, ids, partner_ids, partner_id, subtype_ids=subtype_ids, context=context) - def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None): + def message_subscribe(self, cr, uid, ids, partner_ids, user_id, subtype_ids=None, context=None): """ Add partners to the records followers. """ user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + if user_id: + partner_ids = [user_id] if set(partner_ids) == set([user_pid]): self.check_access_rights(cr, uid, 'read') else: -- cgit v1.2.3 From ee1c4c18c973a8f9982df16f84a9648b53c7dc34 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 4 Apr 2013 10:20:28 +0200 Subject: [IMP] sort on id bzr revid: mat@openerp.com-20130404082028-0klv136soo0oba73 --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 40030613f23..5088691084d 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1262,5 +1262,5 @@ class mail_thread(osv.AbstractModel): if not data['message_is_follower']: data['popularity'] = len(data['message_ids']) threads.append(data) - sorted_threads = sorted(threads, key=lambda x: x['popularity'], reverse=True)[:3] + sorted_threads = sorted(threads, key=lambda x: (x['popularity'], ẍ́['id']), reverse=True)[:3] return sorted_threads -- cgit v1.2.3 From 9a2a45c768b77fb829582f060221a90340445da1 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Thu, 4 Apr 2013 14:17:24 +0530 Subject: [IMP] Improved code and removed unwanted code. As suggested by tde in his comment >> **What's the purpose of defining a new 'check_access_right' ? Limiting to 'group_no_one' does not seems a viable solution. Instead, access rights on mail.followers entries should be correctly written (please check it is the case). I think having an asynchronous call just to check access rights is not necessary. In debug mode, always display the button.** bzr revid: psa@tinyerp.com-20130404084724-meqsx35jdvk56z2c --- addons/mail/mail_thread.py | 7 ------- 1 file changed, 7 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 63f5b8316df..528fd412e46 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -112,13 +112,6 @@ class mail_thread(osv.AbstractModel): res[id]['message_summary'] = "9 %d %s" % (title, res[id].pop('message_unread_count'), _("New")) return res - def check_access_right(self, cr, uid, ids, context=None): - grp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_no_one') - user_pid = self.pool.get('res.groups').read(cr, uid, grp_id[1], ['users'], context=context)['users'] - if uid in user_pid: - return True - return False - def _get_subscription_data(self, cr, uid, ids, user_id, name, args, context=None): """ Computes: - message_subtype_data: data about document subtypes: which are -- cgit v1.2.3 From 7e2e37b7c9ab314c5a45f99547b1a22be58eede8 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Thu, 4 Apr 2013 15:25:28 +0530 Subject: [IMP] Added *None* where message_subscribe is used. bzr revid: psa@tinyerp.com-20130404095528-l58jnpxiw8l5nuqf --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 528fd412e46..aff451a9935 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1206,7 +1206,7 @@ class mail_thread(osv.AbstractModel): for pid, subtypes in new_followers.items(): subtypes = list(subtypes) if subtypes is not None else None - self.message_subscribe(cr, uid, [record.id], [pid], subtypes, context=context) + self.message_subscribe(cr, uid, [record.id], [pid], None, subtypes, context=context) # find first email message, set it as unread for auto_subscribe fields for them to have a notification if user_id_partner_ids: -- cgit v1.2.3 From 87e3fe92bde0a6e5abfac213bc97149b5fc11bfb Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 5 Apr 2013 09:43:22 +0200 Subject: [FIX] remove strange unicode char bzr revid: mat@openerp.com-20130405074322-fiy3merl5kfuvlc2 --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 5088691084d..096481b1c55 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1262,5 +1262,5 @@ class mail_thread(osv.AbstractModel): if not data['message_is_follower']: data['popularity'] = len(data['message_ids']) threads.append(data) - sorted_threads = sorted(threads, key=lambda x: (x['popularity'], ẍ́['id']), reverse=True)[:3] + sorted_threads = sorted(threads, key=lambda x: (x['popularity'], x['id']), reverse=True)[:3] return sorted_threads -- cgit v1.2.3 From e61d6bae165444015ef37f71ae1e3c13f42ec253 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Fri, 5 Apr 2013 19:14:25 +0530 Subject: [IMP] Improved code and passed user_id=None as optional field. bzr revid: psa@tinyerp.com-20130405134425-3xfbbv3vapq1un68 --- addons/mail/mail_thread.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 2527b4cf035..aa929083374 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -112,7 +112,7 @@ class mail_thread(osv.AbstractModel): res[id]['message_summary'] = "9 %d %s" % (title, res[id].pop('message_unread_count'), _("New")) return res - def _get_subscription_data(self, cr, uid, ids, user_id, name, args, context=None): + def _get_subscription_data(self, cr, uid, ids, name, args, user_id=None, context=None): """ Computes: - message_subtype_data: data about document subtypes: which are available, which are followed if any """ @@ -1105,17 +1105,17 @@ class mail_thread(osv.AbstractModel): def message_get_subscription_data(self, cr, uid, ids, user_id=None, context=None): """ Wrapper to get subtypes data. """ - return self._get_subscription_data(cr, uid, ids, user_id, None, None, context=context) + return self._get_subscription_data(cr, uid, ids, None, None, user_id=user_id, context=context) - def message_subscribe_users(self, cr, uid, ids, user_ids=None, partner_id=None, subtype_ids=None, context=None): + def message_subscribe_users(self, cr, uid, ids, user_ids=None, subtype_ids=None, user_id=None, context=None): """ Wrapper on message_subscribe, using users. If user_ids is not provided, subscribe uid instead. """ if user_ids is None: user_ids = [uid] partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)] - return self.message_subscribe(cr, uid, ids, partner_ids, partner_id, subtype_ids=subtype_ids, context=context) + return self.message_subscribe(cr, uid, ids, partner_ids, subtype_ids=subtype_ids, user_id=user_id, context=context) - def message_subscribe(self, cr, uid, ids, partner_ids, user_id, subtype_ids=None, context=None): + def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, user_id=None, context=None): """ Add partners to the records followers. """ user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] if user_id: -- cgit v1.2.3 From c593c0cfe841793692ed82e0cf9b0f3f1ff3d96a Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 5 Apr 2013 16:16:18 +0200 Subject: [FIX] do not show suggestions for anonymous bzr revid: mat@openerp.com-20130405141618-zosargns9o355v7y --- addons/mail/mail_thread.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 096481b1c55..61c198014f6 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1254,6 +1254,21 @@ class mail_thread(osv.AbstractModel): """Return a list of suggested threads, sorted by the numbers of followers""" if context is None: context = {} + + # TOFIX : In case of user belonging to anonymous, do not show + # suggestions (doesn't make any sense). This should be done in + # portal_anonymous module. However done here because of static copy + # when using '_inherit'. Changes made in portal_anonymous wouldn't + # affect modules like mail_group. To move once the '_inherit' problem + # is solved + try: + anonymous_group = self.pool.get('ir.model.data').get_object(cr, SUPERUSER_ID, 'portal', 'group_anonymous') + if uid in [user.id for user in anonymous_group.users]: + return [] + except ValueError: + _logger.debug("Group portal.group_anonymous not existing, normal behavior") + + threads = [] if removed_suggested_threads is None: removed_suggested_threads = [] -- cgit v1.2.3 From 1769067ddd9b4b7b51ae4c0d430587e1287af22d Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Tue, 9 Apr 2013 10:09:32 +0530 Subject: [IMP] Improved code and removed unwanted 'None'. bzr revid: psa@tinyerp.com-20130409043932-z5c8hupbhrednwa0 --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index aa929083374..01fb561ebf3 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1227,7 +1227,7 @@ class mail_thread(osv.AbstractModel): for pid, subtypes in new_followers.items(): subtypes = list(subtypes) if subtypes is not None else None - self.message_subscribe(cr, uid, [record.id], [pid], None, subtypes, context=context) + self.message_subscribe(cr, uid, [record.id], [pid], subtypes, context=context) # find first email message, set it as unread for auto_subscribe fields for them to have a notification if user_id_partner_ids: -- cgit v1.2.3 From 5bbffbc39c899adb92d251a3c8ef7f06e39338a7 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Thu, 11 Apr 2013 18:05:37 +0530 Subject: [IMP] Improved code and made the EDIT followers visible when 'Technical Features' are given and it is in 'DEBUG mode'. bzr revid: psa@tinyerp.com-20130411123537-2wzb468o7o0dno8c --- addons/mail/mail_thread.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 603c77f6ede..879f991ddb3 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -152,6 +152,13 @@ class mail_thread(osv.AbstractModel): res[id]['message_summary'] = "9 %d %s" % (title, res[id].pop('message_unread_count'), _("New")) return res + def check_access_right(self, cr, uid, ids, context=None): + grp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_no_one') + user_pid = self.pool.get('res.groups').read(cr, uid, grp_id[1], ['users'], context=context)['users'] + if uid in user_pid: + return True + return False + def _get_subscription_data(self, cr, uid, ids, name, args, user_id=None, context=None): """ Computes: - message_subtype_data: data about document subtypes: which are -- cgit v1.2.3 From 7f6a47559094c57d2e858e1749b6c37237f96582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 16 Apr 2013 15:28:13 +0200 Subject: [IMP] [REF] mail_thread: refactored a bit message_parse, message_route and various find_partner methods. Now handles private aliases (alias_contact as partners or followers). message_route now works in 2 steps : 1/ finding all possible routes, as before 2/ checks and filtrates those routes, by finding the most relevant message author and using it to check alias contact settings. Also refactored the various partner finding method in one method that checks in res.partner, for: partners, partners that are users, partners that follow a given document. bzr revid: tde@openerp.com-20130416132813-zcm1r5kx0dwrfeic --- addons/mail/mail_thread.py | 380 ++++++++++++++++++++++++--------------------- 1 file changed, 205 insertions(+), 175 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 37336aeb6e7..e9b43d41f72 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -429,6 +429,9 @@ class mail_thread(osv.AbstractModel): return [('message_unread', '=', True)] return [] + # def _get_model(self, cr, uid, context=None): + # return if self._name == 'mail.thread' + def _garbage_collect_attachments(self, cr, uid, context=None): """ Garbage collect lost mail attachments. Those are attachments - linked to res_model 'mail.compose.message', the composer wizard @@ -449,11 +452,85 @@ class mail_thread(osv.AbstractModel): ir_attachment_obj.unlink(cr, uid, attach_ids, context=context) return True + def _find_partner_from_emails(self, cr, uid, id, emails, context=None, + check_followers=True, only_users=False, take_all=False, full_info=False): + """ Utility method to find partners + + :param boolean check_followers: TODO + :param boolean only_users: TODO + :param boolean take_all: TODO + """ + partner_obj = self.pool['res.partner'] + partner_ids = [] + obj = None + if id and self._name != 'mail.thread' and check_followers: + obj = self.browse(cr, uid, id, context=context) + for contact in emails: + partner_id = False + email_address = tools.email_split(contact) + if not email_address: + partner_ids.append(partner_id) + continue + email_address = email_address[0] + # first try: check in document's followers + if obj: + for follower in obj.message_follower_ids: + if follower.email == email_address: + partner_id = follower.id + # second try: check in partners that are also users + if not partner_id: + ids = partner_obj.search(cr, SUPERUSER_ID, [ + ('email', 'ilike', email_address), + ('user_ids', '!=', False) + ], limit=1, context=context) + if ids: + partner_id = ids[0] + # third try: check in partners + if not partner_id: + ids = partner_obj.search(cr, SUPERUSER_ID, [ + ('email', 'ilike', email_address) + ], limit=1, context=context) + if ids: + partner_id = ids[0] + partner_ids.append(partner_id) + return partner_ids + + def message_partner_info_from_emails(self, cr, uid, id, emails, link_mail=False, 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 + + TDE TODO: merge me with other partner finding methods in 8.0 """ + mail_message_obj = self.pool.get('mail.message') + partner_ids = self._find_partner_from_emails(cr, uid, id, emails, context=context) + result = list() + for idx in range(len(emails)): + email_address = emails[idx] + partner_id = partner_ids[idx] + partner_info = {'full_name': email_address, 'partner_id': partner_id} + result.append(partner_info) + + # link mail with this from mail to the new partner id + if link_mail and partner_info['partner_id']: + message_ids = mail_message_obj.search(cr, SUPERUSER_ID, [ + '|', + ('email_from', '=', email_address), + ('email_from', 'ilike', '<%s>' % email_address), + ('author_id', '=', False) + ], context=context) + if message_ids: + mail_message_obj.write(cr, SUPERUSER_ID, message_ids, {'author_id': partner_info['partner_id']}, context=context) + return result + #------------------------------------------------------ # Email specific #------------------------------------------------------ def message_get_reply_to(self, cr, uid, ids, context=None): + """ Returns the preferred reply-to email address that is basically + the alias of the document, if it exists. """ if not self._inherits.get('mail.alias'): return [False for id in ids] return ["%s@%s" % (record['alias_name'], record['alias_domain']) @@ -477,27 +554,11 @@ class mail_thread(osv.AbstractModel): def _message_find_partners(self, cr, uid, message, header_fields=['From'], context=None): """ Find partners related to some header fields of the message. - TDE TODO: merge me with other partner finding methods in 8.0 """ - partner_obj = self.pool.get('res.partner') - partner_ids = [] + :param string message: an email.message instance """ s = ', '.join([decode(message.get(h)) for h in header_fields if message.get(h)]) - for email_address in tools.email_split(s): - related_partners = partner_obj.search(cr, uid, [('email', 'ilike', email_address), ('user_ids', '!=', False)], limit=1, context=context) - if not related_partners: - related_partners = partner_obj.search(cr, uid, [('email', 'ilike', email_address)], limit=1, context=context) - partner_ids += related_partners - return partner_ids - - def _message_find_user_id(self, cr, uid, message, context=None): - """ TDE TODO: check and maybe merge me with other user finding methods in 8.0 """ - from_local_part = tools.email_split(decode(message.get('From')))[0] - # FP Note: canonification required, the minimu: .lower() - user_ids = self.pool.get('res.users').search(cr, uid, ['|', - ('login', '=', from_local_part), - ('email', '=', from_local_part)], context=context) - return user_ids[0] if user_ids else uid + return filter(lambda x: x, self._find_partner_from_emails(cr, uid, None, tools.email_split(s), context=context)) - def message_route(self, cr, uid, message, model=None, thread_id=None, + def message_route(self, cr, uid, message, message_dict, model=None, thread_id=None, custom_values=None, context=None): """Attempt to figure out the correct target model, thread_id, custom_values and user_id to use for an incoming message. @@ -516,6 +577,7 @@ class mail_thread(osv.AbstractModel): provided. 4. If all the above fails, raise an exception. + :param dict message_dict: dictionary holding message variables :param string message: an email.message instance :param string model: the fallback model to use if the message does not match any of the currently configured mail aliases @@ -530,28 +592,53 @@ class mail_thread(osv.AbstractModel): :return: list of [model, thread_id, custom_values, user_id] """ assert isinstance(message, Message), 'message must be an email.message.Message at this point' + found_routes = [] + DEFAULT_CONTACT_SETTINGS = 'everyone' + fallback_model = model + avoid_assert = False + + # Get email.message.Message variables for future processing message_id = message.get('Message-Id') email_from = decode_header(message, 'From') email_to = decode_header(message, 'To') 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 thread_references = references or in_reply_to + # 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. + rcpt_tos = ','.join([decode_header(message, 'Delivered-To'), + decode_header(message, 'To'), + decode_header(message, 'Cc'), + decode_header(message, 'Resent-To'), + decode_header(message, 'Resent-Cc')]) + + def create_bounce_email(): + mail_mail = self.pool.get('mail.mail') + mail_id = mail_mail.create(cr, uid, { + 'body_html': '

Hello,

' + '

The following email sent to %s cannot be accepted because this address' + 'is private. Only known contacts are allowed to contact this address.

' + '
%s
' % (message.get('to'), message.get('body')), + 'subject': 'Re: %s' % message.get('subject'), + 'email_to': message.get('from'), + 'auto_delete': True, + }, context=context) + mail_mail.send(cr, uid, [mail_id], context=context) + + # 1. Reply to an existing thread ref_match = thread_references and tools.reference_re.search(thread_references) - if ref_match: thread_id = int(ref_match.group(1)) - model = ref_match.group(2) or model + model = ref_match.group(2) or fallback_model if thread_id and model in self.pool: model_obj = self.pool[model] if model_obj.exists(cr, uid, thread_id) and hasattr(model_obj, 'message_update'): _logger.info('Routing mail from %s to %s with Message-Id %s: direct reply to model: %s, thread_id: %s, custom_values: %s, uid: %s', email_from, email_to, message_id, model, thread_id, custom_values, uid) - return [(model, thread_id, custom_values, uid)] + found_routes = [(model, thread_id, DEFAULT_CONTACT_SETTINGS, custom_values, uid)] - # Verify whether this is a reply to a private message - if in_reply_to: + # 2. Reply to a private message + if not found_routes and in_reply_to: message_ids = self.pool.get('mail.message').search(cr, uid, [ ('message_id', '=', in_reply_to), '!', ('message_id', 'ilike', 'reply_to') @@ -560,77 +647,95 @@ class mail_thread(osv.AbstractModel): message = self.pool.get('mail.message').browse(cr, uid, message_ids[0], context=context) _logger.info('Routing mail from %s to %s with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s', email_from, email_to, message_id, message.id, custom_values, uid) - return [(message.model, message.res_id, custom_values, uid)] + found_routes = [(message.model, message.res_id, DEFAULT_CONTACT_SETTINGS, custom_values, uid)] - # 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 - # for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value. - rcpt_tos = \ - ','.join([decode_header(message, 'Delivered-To'), - decode_header(message, 'To'), - decode_header(message, 'Cc'), - decode_header(message, 'Resent-To'), - decode_header(message, 'Resent-Cc')]) + # 3. Look for a matching mail.alias entry local_parts = [e.split('@')[0] for e in tools.email_split(rcpt_tos)] - if local_parts: + if not found_routes and local_parts: mail_alias = self.pool.get('mail.alias') alias_ids = mail_alias.search(cr, uid, [('alias_name', 'in', local_parts)]) - if alias_ids: - # TDE note: at this stage, message parsing is not done yet - parse the from of the message - author_ids = self._message_find_partners(cr, uid, message, ['From'], context=context) - routes = [] - for alias in mail_alias.browse(cr, uid, alias_ids, context=context): - user_id = alias.alias_user_id.id - - if alias.alias_contact == 'partners' and not author_ids: - # TDE TODO: bounce - _logger.info('Routing mail with Message-Id %s: alias %s does not accept unknown emails, skipping', message_id, alias.alias_name) - mail_id = self.pool.get('mail.mail').create(cr, uid, { - 'body_html': '

Hello,

' - '

The following email sent to %s cannot be accepted because this address' - 'is private. Only known contacts are allowed to contact this address.

' - '
%s
' % (message.get('to'), message.get('body')), - 'subject': message.get('subject'), - 'email_to': message.get('from'), - 'auto_delete': True, - }, context=context) - self.pool.get('mail.mail').send(cr, uid, [mail_id], context=context) - continue - if not user_id: - # TDE note: this could cause crashes, because no clue that the user - # that send the email has the right to create or modify a new document - # Fallback on user_id = uid - # Note: recognized partners will be added as followers anyway - # user_id = self._message_find_user_id(cr, uid, message, context=context) - user_id = uid - _logger.info('No matching user_id for the alias %s', alias.alias_name) - routes.append((alias.alias_model_id.model, alias.alias_force_thread_id, \ - eval(alias.alias_defaults), user_id)) + for alias in mail_alias.browse(cr, uid, alias_ids, context=context): + user_id = alias.alias_user_id.id + if not user_id: + # TDE note: this could cause crashes, because no clue that the user + # that send the email has the right to create or modify a new document + # Fallback on user_id = uid + # Note: recognized partners will be added as followers anyway + # user_id = self._message_find_user_id(cr, uid, message, context=context) + user_id = uid + _logger.info('No matching user_id for the alias %s', alias.alias_name) + found_routes.append((alias.alias_model_id.model, alias.alias_force_thread_id, \ + alias.alias_contact, eval(alias.alias_defaults), user_id)) + if found_routes: _logger.info('Routing mail from %s to %s with Message-Id %s: direct alias match: %r', - email_from, email_to, message_id, routes) - return routes - - # 3. Fallback to the provided parameters, if they work - model_pool = self.pool.get(model) - if not thread_id: - # Legacy: fallback to matching [ID] in the Subject - match = tools.res_re.search(decode_header(message, 'Subject')) - thread_id = match and match.group(1) - # Convert into int (bug spotted in 7.0 because of str) - try: - thread_id = int(thread_id) - except: - thread_id = False - assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \ - "No possible route found for incoming message from %s to %s (Message-Id %s:)." \ - "Create an appropriate mail.alias or force the destination model." % (email_from, email_to, message_id) - if thread_id and not model_pool.exists(cr, uid, thread_id): - _logger.warning('Received mail reply to missing document %s! Ignoring and creating new document instead for Message-Id %s', - thread_id, message_id) - thread_id = None - _logger.info('Routing mail from %s to %s with Message-Id %s: fallback to model:%s, thread_id:%s, custom_values:%s, uid:%s', - email_from, email_to, message_id, model, thread_id, custom_values, uid) - return [(model, thread_id, custom_values, uid)] + email_from, email_to, message_id, found_routes) + + # 4. Fallback to the provided parameters, if they work + if not found_routes: + if not thread_id: + # Legacy: fallback to matching [ID] in the Subject + match = tools.res_re.search(decode_header(message, 'Subject')) + thread_id = match and match.group(1) + # Convert into int (bug spotted in 7.0 because of str) + try: + thread_id = int(thread_id) + except: + thread_id = False + found_routes = [(fallback_model, thread_id, DEFAULT_CONTACT_SETTINGS, custom_values, uid)] + _logger.info('Routing mail from %s to %s with Message-Id %s: fallback to model:%s, thread_id:%s, custom_values:%s, uid:%s', + email_from, email_to, message_id, fallback_model, thread_id, custom_values, uid) + + # Post-process routes + valid_routes = [] + author_id = False + for route in found_routes: + model, thread_id, contact = route[0], route[1], route[2] + model_pool = self.pool.get(model) + + # check related document effectively exists + if thread_id and not model_pool.exists(cr, uid, thread_id): + _logger.warning('Routing mail with Message-Id %s: route %s: reply to missing document %s, ignoring and creating new document instead', + message_id, route, thread_id) + thread_id = None + # check model accepts the mailgateway + if not (thread_id and hasattr(model_pool, 'message_update')) and not (hasattr(model_pool, 'message_new')): + _logger.warning('Routing mail with Message-Id %s: route %s: model %s does not accept unknown emails, skipping', + message_id, route, model) + continue + + # check for author + if not author_id: + email_from = decode(message.get('From')) + author_ids = model_pool._find_partner_from_emails(cr, uid, thread_id, [email_from], context=context) + if author_ids: + author_id = author_ids[0] + message_dict['author_id'] = author_id + + # route contact settings + if contact == 'followers' and thread_id: + obj = self.browse(cr, uid, id, context=context) + if not author_id or not author_id in obj.message_follower_ids: + _logger.warning('Routing mail with Message-Id %s: route %s: alias %s restricted to internal followers, skipping', + message_id, route, alias.alias_name) + create_bounce_email() + avoid_assert = True + continue + elif (contact == 'followers' or contact == 'partners') and not author_id: + _logger.warning('Routing mail with Message-Id %s: route %s: alias %s does not accept unknown sender, skipping', + message_id, route, alias.alias_name) + create_bounce_email() + avoid_assert = True + continue + + # update route + valid_routes.append((model, thread_id, route[3], route[4])) + + # AssertionError if no routes found and if no bounce occured + assert valid_routes or avoid_assert, \ + "Routing mail from %s to %s with Message-Id %s: no possible route found. " \ + "Create an appropriate mail.alias or force the destination model." % \ + (email_from, email_to, message_id) + return valid_routes def message_process(self, cr, uid, model, message, custom_values=None, save_original=False, strip_attachments=False, @@ -684,24 +789,20 @@ class mail_thread(osv.AbstractModel): msg = self.message_parse(cr, uid, msg_txt, save_original=save_original, context=context) if strip_attachments: msg.pop('attachments', None) + # postpone setting msg.partner_ids after message_post, to avoid double notifications + partner_ids = msg.pop('partner_ids', []) if msg.get('message_id'): # should always be True as message_parse generate one if missing existing_msg_ids = self.pool.get('mail.message').search(cr, SUPERUSER_ID, [ ('message_id', '=', msg.get('message_id')), ], context=context) if existing_msg_ids: - _logger.info('Ignored mail from %s to %s with Message-Id %s:: found duplicated Message-Id during processing', + _logger.info('Ignored mail from %s to %s with Message-Id %s: found duplicated Message-Id during processing', msg.get('from'), msg.get('to'), msg.get('message_id')) return False # find possible routes for the message - routes = self.message_route(cr, uid, msg_txt, model, - thread_id, custom_values, - context=context) - - # postpone setting msg.partner_ids after message_post, to avoid double notifications - partner_ids = msg.pop('partner_ids', []) - thread_id = False + routes = self.message_route(cr, uid, msg_txt, msg, model, thread_id, custom_values, context=context) for model, thread_id, custom_values, user_id in routes: if self._name == 'mail.thread': context.update({'thread_model': model}) @@ -713,11 +814,10 @@ class mail_thread(osv.AbstractModel): # disabled subscriptions during message_new/update to avoid having the system user running the # email gateway become a follower of all inbound messages - nosub_ctx = dict(context, mail_create_nosubscribe=True) + nosub_ctx = dict(context, mail_create_nosubscribe=True, mail_create_nolog=True) if thread_id and hasattr(model_pool, 'message_update'): model_pool.message_update(cr, user_id, [thread_id], msg, context=nosub_ctx) else: - nosub_ctx = dict(nosub_ctx, mail_create_nolog=True) thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=nosub_ctx) else: assert thread_id == 0, "Posting a message without model should be with a null res_id, to create a private message." @@ -851,7 +951,6 @@ class mail_thread(osv.AbstractModel): """ msg_dict = { 'type': 'email', - 'author_id': False, } if not isinstance(message, Message): if isinstance(message, unicode): @@ -874,12 +973,7 @@ class mail_thread(osv.AbstractModel): msg_dict['from'] = decode(message.get('from')) msg_dict['to'] = decode(message.get('to')) msg_dict['cc'] = decode(message.get('cc')) - - if message.get('From'): - author_ids = self._message_find_partners(cr, uid, message, ['From'], context=context) - if author_ids: - msg_dict['author_id'] = author_ids[0] - msg_dict['email_from'] = decode(message.get('from')) + msg_dict['email_from'] = decode(message.get('from')) partner_ids = self._message_find_partners(cr, uid, message, ['To', 'Cc'], context=context) msg_dict['partner_ids'] = [(4, partner_id) for partner_id in partner_ids] @@ -933,7 +1027,7 @@ class mail_thread(osv.AbstractModel): partner_id, partner_name or partner_name, reason """ if email and not partner: # get partner info from email - partner_info = self.message_get_partner_info_from_emails(cr, uid, [email], context=context, res_id=obj.id)[0] + partner_info = self.message_partner_info_from_emails(cr, uid, obj.id, [email], context=context)[0] if partner_info.get('partner_id'): partner = self.pool.get('res.partner').browse(cr, SUPERUSER_ID, [partner_info.get('partner_id')], context=context)[0] if email and email in [val[1] for val in result[obj.id]]: # already existing email -> skip @@ -961,59 +1055,6 @@ class mail_thread(osv.AbstractModel): self._message_add_suggested_recipient(cr, uid, result, obj, partner=obj.user_id.partner_id, reason=self._all_columns['user_id'].column.string, context=context) return result - def message_get_partner_info_from_emails(self, cr, uid, emails, link_mail=False, context=None, res_id=None): - """ Wrapper with weird order parameter because of 7.0 fix. - - TDE TODO: remove me in 8.0 """ - return self.message_find_partner_from_emails(cr, uid, res_id, emails, link_mail=link_mail, context=context) - - def message_find_partner_from_emails(self, cr, uid, id, emails, link_mail=False, 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 - - TDE TODO: merge me with other partner finding methods in 8.0 """ - mail_message_obj = self.pool.get('mail.message') - partner_obj = self.pool.get('res.partner') - result = list() - if id and self._name != 'mail.thread': - obj = self.browse(cr, SUPERUSER_ID, id, context=context) - else: - obj = None - for email in emails: - partner_info = {'full_name': email, 'partner_id': False} - m = re.search(r"((.+?)\s*<)?([^<>]+@[^<>]+)>?", email, re.IGNORECASE | re.DOTALL) - if not m: - continue - email_address = m.group(3) - # first try: check in document's followers - if obj: - for follower in obj.message_follower_ids: - if follower.email == email_address: - partner_info['partner_id'] = follower.id - # second try: check in partners - if not partner_info.get('partner_id'): - ids = partner_obj.search(cr, SUPERUSER_ID, [('email', 'ilike', email_address), ('user_ids', '!=', False)], limit=1, context=context) - if not ids: - ids = partner_obj.search(cr, SUPERUSER_ID, [('email', 'ilike', email_address)], limit=1, context=context) - if ids: - partner_info['partner_id'] = ids[0] - result.append(partner_info) - - # link mail with this from mail to the new partner id - if link_mail and partner_info['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, {'author_id': partner_info['partner_id']}, context=context) - return result - def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification', subtype=None, parent_id=False, attachments=None, context=None, content_subtype='html', **kwargs): @@ -1060,18 +1101,7 @@ class mail_thread(osv.AbstractModel): del context['thread_model'] return self.pool[model].message_post(cr, uid, thread_id, body=body, subject=subject, type=type, subtype=subtype, parent_id=parent_id, attachments=attachments, context=context, content_subtype=content_subtype, **kwargs) - # 0: Parse email-from, try to find a better author_id based on document's followers for incoming emails - email_from = kwargs.get('email_from') - if email_from and thread_id and type == 'email' and kwargs.get('author_id'): - email_list = tools.email_split(email_from) - doc = self.browse(cr, uid, thread_id, context=context) - if email_list and doc: - author_ids = self.pool.get('res.partner').search(cr, uid, [ - ('email', 'ilike', email_list[0]), - ('id', 'in', [f.id for f in doc.message_follower_ids]) - ], limit=1, context=context) - if author_ids: - kwargs['author_id'] = author_ids[0] + #0: Find the message's author, because we need it for private discussion author_id = kwargs.get('author_id') if author_id is None: # keep False values author_id = self.pool.get('mail.message')._get_default_author(cr, uid, context=context) -- cgit v1.2.3 From c1a04891566456e18d869a9e0c55759f84d02d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 16 Apr 2013 15:44:05 +0200 Subject: [FIX] Chatter: fixed calls to refactored methos. bzr revid: tde@openerp.com-20130416134405-nxtwbvxbz77pxufx --- addons/mail/mail_thread.py | 1 - 1 file changed, 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index e9b43d41f72..f143b71dd83 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -705,7 +705,6 @@ class mail_thread(osv.AbstractModel): # check for author if not author_id: - email_from = decode(message.get('From')) author_ids = model_pool._find_partner_from_emails(cr, uid, thread_id, [email_from], context=context) if author_ids: author_id = author_ids[0] -- cgit v1.2.3 From a68e7fe9eb236bdc604ac7f7dfc2b9651ebf2a15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 16 Apr 2013 17:38:09 +0200 Subject: [FIX] mail_thread: message_process: fixed body of bounced emails. bzr revid: tde@openerp.com-20130416153809-d5xbjqw6i7l7x4av --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index f143b71dd83..05354287284 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -618,7 +618,7 @@ class mail_thread(osv.AbstractModel): 'body_html': '

Hello,

' '

The following email sent to %s cannot be accepted because this address' 'is private. Only known contacts are allowed to contact this address.

' - '
%s
' % (message.get('to'), message.get('body')), + '
%s
' % (message.get('to'), message_dict.get('body')), 'subject': 'Re: %s' % message.get('subject'), 'email_to': message.get('from'), 'auto_delete': True, -- cgit v1.2.3 From cadddbdf818b83f25acf51adb748bda871753532 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 17 Apr 2013 12:45:04 +0200 Subject: [IMP] overwrite get_suggested_thread for anonymous bzr revid: mat@openerp.com-20130417104504-k0us58cta22goblj --- addons/mail/mail_thread.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 105fd1ae84f..8b624655104 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1359,19 +1359,8 @@ class mail_thread(osv.AbstractModel): if context is None: context = {} - # TOFIX : In case of user belonging to anonymous, do not show - # suggestions (doesn't make any sense). This should be done in - # portal_anonymous module. However done here because of static copy - # when using '_inherit'. Changes made in portal_anonymous wouldn't - # affect modules like mail_group. To move once the '_inherit' problem - # is solved - try: - anonymous_group = self.pool.get('ir.model.data').get_object(cr, SUPERUSER_ID, 'portal', 'group_anonymous') - if uid in [user.id for user in anonymous_group.users]: - return [] - except ValueError: - _logger.debug("Group portal.group_anonymous not existing, normal behavior") - + _logger.info("Normal behavior") + print(self.__class__.mro()) threads = [] if removed_suggested_threads is None: -- cgit v1.2.3 From 67bffc62c4d443b2b4315b10c1872d136e3a18ef Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 17 Apr 2013 17:17:21 +0200 Subject: [IMP] clean code bzr revid: mat@openerp.com-20130417151721-fmwd143gazkldvu3 --- addons/mail/mail_thread.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 8b624655104..de960d02aec 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1359,9 +1359,6 @@ class mail_thread(osv.AbstractModel): if context is None: context = {} - _logger.info("Normal behavior") - print(self.__class__.mro()) - threads = [] if removed_suggested_threads is None: removed_suggested_threads = [] -- cgit v1.2.3 From 1fdf64b309eaf33c7e0a2219db8224b5093ebdf2 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 2 May 2013 14:39:45 +0200 Subject: [IMP] search on field message_is_follower bzr revid: mat@openerp.com-20130502123945-z3sg64sotgd5q98n --- addons/mail/mail_thread.py | 49 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 11 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index de960d02aec..573e0cffd1a 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -237,21 +237,42 @@ class mail_thread(osv.AbstractModel): fol_obj.create(cr, SUPERUSER_ID, {'res_model': self._name, 'res_id': id, 'partner_id': partner_id}) def _search_followers(self, cr, uid, obj, name, args, context): + """Search function for message_follower_ids + + Do not use with operator 'not in'. Use instead message_is_followers + """ fol_obj = self.pool.get('mail.followers') res = [] for field, operator, value in args: assert field == name + # TOFIX make it work with not in + assert operator != "not in", "Do not search message_follower_ids with 'not in'" fol_ids = fol_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('partner_id', operator, value)]) res_ids = [fol.res_id for fol in fol_obj.browse(cr, SUPERUSER_ID, fol_ids)] res.append(('id', 'in', res_ids)) return res + def _search_is_follower(self, cr, uid, obj, name, args, context): + """Search function for message_is_follower""" + fol_obj = self.pool.get('mail.followers') + res = [] + for field, operator, value in args: + assert field == name + partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id + if (operator == '=' and value) or (operator == '!=' and not value): # is a follower + res_ids = self.search(cr, uid, [('message_follower_ids', 'in', [partner_id])], context=context) + else: # is not a follower or unknown domain + mail_ids = self.search(cr, uid, [('message_follower_ids', 'in', [partner_id])], context=context) + res_ids = self.search(cr, uid, [('id', 'not in', mail_ids)], context=context) + res.append(('id', 'in', res_ids)) + return res + _columns = { - 'message_is_follower': fields.function(_get_followers, - type='boolean', string='Is a Follower', multi='_get_followers,'), + 'message_is_follower': fields.function(_get_followers, type='boolean', + fnct_search=_search_is_follower, string='Is a Follower', multi='_get_followers,'), 'message_follower_ids': fields.function(_get_followers, fnct_inv=_set_followers, - fnct_search=_search_followers, type='many2many', - obj='res.partner', string='Followers', multi='_get_followers'), + fnct_search=_search_followers, type='many2many', + obj='res.partner', string='Followers', multi='_get_followers'), 'message_ids': fields.one2many('mail.message', 'res_id', domain=lambda self: [('model', '=', self._name)], auto_join=True, @@ -1362,10 +1383,16 @@ class mail_thread(osv.AbstractModel): threads = [] if removed_suggested_threads is None: removed_suggested_threads = [] - threads_ids = self.search(cr, uid, [('id', 'not in', removed_suggested_threads)], context=context) - for data in self.read(cr, uid, threads_ids, ['message_is_follower', 'message_ids', 'name', 'image_small'], context): - if not data['message_is_follower']: - data['popularity'] = len(data['message_ids']) - threads.append(data) - sorted_threads = sorted(threads, key=lambda x: (x['popularity'], x['id']), reverse=True)[:3] - return sorted_threads + + thread_ids = self.search(cr, uid, [('id', 'not in', removed_suggested_threads), ('message_is_follower', '=', False)], context=context) + print(thread_ids) + for thread in self.browse(cr, uid, thread_ids, context=context): + data = { + 'id': thread.id, + 'popularity': len(thread.message_follower_ids), + 'name': thread.name, + 'image_small': thread.image_small + } + print(data['id'], data['name'], data['popularity']) + threads.append(data) + return sorted(threads, key=lambda x: (x['popularity'], x['id']), reverse=True)[:3] \ No newline at end of file -- cgit v1.2.3 From a576c23043bdb8fee8bdeed250d9126dcf9b3495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 7 May 2013 15:01:49 +0200 Subject: [FIX] empty list menu tip: do not display 'False' aliases. bzr revid: tde@openerp.com-20130507130149-qd1rjfrphin6ds59 --- addons/mail/mail_thread.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 05354287284..547d2d4336b 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -101,18 +101,19 @@ class mail_thread(osv.AbstractModel): if catchall_domain and model and res_id: # specific res_id -> find its alias (i.e. section_id specified) object_id = self.pool.get(model).browse(cr, uid, res_id, context=context) - alias = object_id.alias_id + if object_id.alias_id and object_id.alias_id.alias_name: # avoid void aliases + alias = object_id.alias_id elif catchall_domain and model: # no specific res_id given -> generic help message, take an example alias (i.e. alias of some section_id) model_id = self.pool.get('ir.model').search(cr, uid, [("model", "=", self._name)], context=context)[0] alias_obj = self.pool.get('mail.alias') - alias_ids = alias_obj.search(cr, uid, [("alias_model_id", "=", model_id)], context=context, limit=1, order='id ASC') + alias_ids = alias_obj.search(cr, uid, [("alias_model_id", "=", model_id), ("alias_name", "!=", False)], context=context, limit=1, order='id ASC') if alias_ids: alias = alias_obj.browse(cr, uid, alias_ids[0], context=context) if alias: alias_email = alias.name_get()[0][1] return _("""

- Click here to add a new %(document)s or send an email to: %(email)s + Click here to add new %(document)s or send an email to: %(email)s

%(static_help)s""" ) % { @@ -122,7 +123,7 @@ class mail_thread(osv.AbstractModel): } if document_name != 'document' and help and help.find("oe_view_nocontent_create") == -1: - return _("

Click here to add a new %(document)s

%(static_help)s") % { + return _("

Click here to add new %(document)s

%(static_help)s") % { 'document': document_name, 'static_help': help or '', } -- cgit v1.2.3 From 0c5bd1acd653be00442fa4beb3c8e4dbf5731c72 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 8 May 2013 15:32:24 +0200 Subject: [IMP] mail: clean code bzr revid: mat@openerp.com-20130508133224-y0mtl3421yfoka2p --- addons/mail/mail_thread.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 573e0cffd1a..ab7fb4afeb4 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1385,7 +1385,6 @@ class mail_thread(osv.AbstractModel): removed_suggested_threads = [] thread_ids = self.search(cr, uid, [('id', 'not in', removed_suggested_threads), ('message_is_follower', '=', False)], context=context) - print(thread_ids) for thread in self.browse(cr, uid, thread_ids, context=context): data = { 'id': thread.id, @@ -1393,6 +1392,5 @@ class mail_thread(osv.AbstractModel): 'name': thread.name, 'image_small': thread.image_small } - print(data['id'], data['name'], data['popularity']) threads.append(data) return sorted(threads, key=lambda x: (x['popularity'], x['id']), reverse=True)[:3] \ No newline at end of file -- cgit v1.2.3 From 88e3505554038350ae0274e9359bbffff342b9d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 May 2013 18:42:07 +0200 Subject: [IMP] mail_alias: added reference to the parent record. The parent record is the record that holds the alias. It is different from the record updated or created using the alias. For example projects have aliases whose parent is the given projet, and that creates new task inside the project. Updated alias creation and management accordingly. This ownership concept is used to compute the 'followers' contact settings of aliases. bzr revid: tde@openerp.com-20130516164207-1zr0q6abw6a34ndf --- addons/mail/mail_thread.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 547d2d4336b..3151846bc04 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -594,7 +594,6 @@ class mail_thread(osv.AbstractModel): """ assert isinstance(message, Message), 'message must be an email.message.Message at this point' found_routes = [] - DEFAULT_CONTACT_SETTINGS = 'everyone' fallback_model = model avoid_assert = False @@ -636,7 +635,7 @@ class mail_thread(osv.AbstractModel): if model_obj.exists(cr, uid, thread_id) and hasattr(model_obj, 'message_update'): _logger.info('Routing mail from %s to %s with Message-Id %s: direct reply to model: %s, thread_id: %s, custom_values: %s, uid: %s', email_from, email_to, message_id, model, thread_id, custom_values, uid) - found_routes = [(model, thread_id, DEFAULT_CONTACT_SETTINGS, custom_values, uid)] + found_routes = [(model, thread_id, custom_values, uid, None)] # 2. Reply to a private message if not found_routes and in_reply_to: @@ -648,7 +647,7 @@ class mail_thread(osv.AbstractModel): message = self.pool.get('mail.message').browse(cr, uid, message_ids[0], context=context) _logger.info('Routing mail from %s to %s with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s', email_from, email_to, message_id, message.id, custom_values, uid) - found_routes = [(message.model, message.res_id, DEFAULT_CONTACT_SETTINGS, custom_values, uid)] + found_routes = [(message.model, message.res_id, custom_values, uid, None)] # 3. Look for a matching mail.alias entry local_parts = [e.split('@')[0] for e in tools.email_split(rcpt_tos)] @@ -665,8 +664,7 @@ class mail_thread(osv.AbstractModel): # user_id = self._message_find_user_id(cr, uid, message, context=context) user_id = uid _logger.info('No matching user_id for the alias %s', alias.alias_name) - found_routes.append((alias.alias_model_id.model, alias.alias_force_thread_id, \ - alias.alias_contact, eval(alias.alias_defaults), user_id)) + found_routes.append((alias.alias_model_id.model, alias.alias_force_thread_id, eval(alias.alias_defaults), user_id, alias)) if found_routes: _logger.info('Routing mail from %s to %s with Message-Id %s: direct alias match: %r', email_from, email_to, message_id, found_routes) @@ -682,7 +680,7 @@ class mail_thread(osv.AbstractModel): thread_id = int(thread_id) except: thread_id = False - found_routes = [(fallback_model, thread_id, DEFAULT_CONTACT_SETTINGS, custom_values, uid)] + found_routes = [(fallback_model, thread_id, custom_values, uid, None)] _logger.info('Routing mail from %s to %s with Message-Id %s: fallback to model:%s, thread_id:%s, custom_values:%s, uid:%s', email_from, email_to, message_id, fallback_model, thread_id, custom_values, uid) @@ -690,7 +688,7 @@ class mail_thread(osv.AbstractModel): valid_routes = [] author_id = False for route in found_routes: - model, thread_id, contact = route[0], route[1], route[2] + model, thread_id, alias = route[0], route[1], route[4] model_pool = self.pool.get(model) # check related document effectively exists @@ -712,15 +710,19 @@ class mail_thread(osv.AbstractModel): message_dict['author_id'] = author_id # route contact settings - if contact == 'followers' and thread_id: - obj = self.browse(cr, uid, id, context=context) + if alias and alias.alias_contact == 'followers' and (thread_id or alias.alias_parent_thread_id): + print alias, alias.alias_contact + if thread_id: + obj = self.pool[model].browse(cr, uid, thread_id, context=context) + else: + obj = self.pool[alias.alias_parent_model_id.model].browse(cr, uid, alias.alias_parent_thread_id, context=context) if not author_id or not author_id in obj.message_follower_ids: _logger.warning('Routing mail with Message-Id %s: route %s: alias %s restricted to internal followers, skipping', message_id, route, alias.alias_name) create_bounce_email() avoid_assert = True continue - elif (contact == 'followers' or contact == 'partners') and not author_id: + elif alias and alias.alias_contact == 'partners' and not author_id: _logger.warning('Routing mail with Message-Id %s: route %s: alias %s does not accept unknown sender, skipping', message_id, route, alias.alias_name) create_bounce_email() @@ -728,7 +730,7 @@ class mail_thread(osv.AbstractModel): continue # update route - valid_routes.append((model, thread_id, route[3], route[4])) + valid_routes.append((model, thread_id, route[2], route[3])) # AssertionError if no routes found and if no bounce occured assert valid_routes or avoid_assert, \ -- cgit v1.2.3 From ac3f8a7615e5c7664319cd57c4f832f63517a542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 17 May 2013 17:13:09 +0200 Subject: [FIX] mail_thread: fixed bug in contact check, comparing int to list of browse is not a good idea. bzr revid: tde@openerp.com-20130517151309-v0x32829dpwr0dw6 --- addons/mail/mail_thread.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 3151846bc04..b29dd1cbad6 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -616,8 +616,8 @@ class mail_thread(osv.AbstractModel): mail_mail = self.pool.get('mail.mail') mail_id = mail_mail.create(cr, uid, { 'body_html': '

Hello,

' - '

The following email sent to %s cannot be accepted because this address' - 'is private. Only known contacts are allowed to contact this address.

' + '

The following email sent to %s cannot be accepted because this is ' + 'a private email address. Only allowed people can contact us at this address.

' '
%s
' % (message.get('to'), message_dict.get('body')), 'subject': 'Re: %s' % message.get('subject'), 'email_to': message.get('from'), @@ -711,12 +711,11 @@ class mail_thread(osv.AbstractModel): # route contact settings if alias and alias.alias_contact == 'followers' and (thread_id or alias.alias_parent_thread_id): - print alias, alias.alias_contact if thread_id: obj = self.pool[model].browse(cr, uid, thread_id, context=context) else: obj = self.pool[alias.alias_parent_model_id.model].browse(cr, uid, alias.alias_parent_thread_id, context=context) - if not author_id or not author_id in obj.message_follower_ids: + if not author_id or not author_id in [fol.id for fol in obj.message_follower_ids]: _logger.warning('Routing mail with Message-Id %s: route %s: alias %s restricted to internal followers, skipping', message_id, route, alias.alias_name) create_bounce_email() -- cgit v1.2.3 From 388a3e14a15c9d18cc179cee0779a07e45424b82 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Tue, 4 Jun 2013 15:17:22 +0530 Subject: [ImP] method name change and removed the access call which is not needed bcz the system is calling it self. bzr revid: psa@tinyerp.com-20130604094722-2b8i6ba7blz1g2rc --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index b248247202b..cf8f5828650 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -152,7 +152,7 @@ class mail_thread(osv.AbstractModel): res[id]['message_summary'] = "9 %d %s" % (title, res[id].pop('message_unread_count'), _("New")) return res - def check_access_right(self, cr, uid, ids, context=None): + def check_technical_rights(self, cr, uid, ids, context=None): grp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_no_one') user_pid = self.pool.get('res.groups').read(cr, uid, grp_id[1], ['users'], context=context)['users'] if uid in user_pid: -- cgit v1.2.3 From 52b02c879b0e2b23194f6c08fc30e38a22b42c4a Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Wed, 5 Jun 2013 18:40:31 +0530 Subject: [IMP] Improved code without disturbing the others methods and solved the issue of unfollowing the specific user by specific id. bzr revid: psa@tinyerp.com-20130605131031-bppkpzdwmi8sp4f7 --- addons/mail/mail_thread.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index cf8f5828650..778419968e2 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -159,12 +159,13 @@ class mail_thread(osv.AbstractModel): return True return False - def _get_subscription_data(self, cr, uid, ids, name, args, user_id=None, context=None): + def _get_subscription_data(self, cr, uid, ids, name, args, user_pid=None, context=None): """ Computes: - message_subtype_data: data about document subtypes: which are available, which are followed if any """ res = dict((id, dict(message_subtype_data='')) for id in ids) - user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + if user_pid is None: + user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] # find current model subtypes, add them to a dictionary subtype_obj = self.pool.get('mail.message.subtype') @@ -173,8 +174,6 @@ class mail_thread(osv.AbstractModel): for id in ids: res[id]['message_subtype_data'] = subtype_dict.copy() - if user_id: - user_pid = user_id # find the document followers, update the data fol_obj = self.pool.get('mail.followers') fol_ids = fol_obj.search(cr, uid, [ @@ -1257,23 +1256,21 @@ class mail_thread(osv.AbstractModel): # Followers API #------------------------------------------------------ - def message_get_subscription_data(self, cr, uid, ids, user_id=None, context=None): + def message_get_subscription_data(self, cr, uid, ids, user_pid=None, context=None): """ Wrapper to get subtypes data. """ - return self._get_subscription_data(cr, uid, ids, None, None, user_id=user_id, context=context) + return self._get_subscription_data(cr, uid, ids, None, None, user_pid=user_pid, context=context) - def message_subscribe_users(self, cr, uid, ids, user_ids=None, subtype_ids=None, user_id=None, context=None): + def message_subscribe_users(self, cr, uid, ids, user_ids=None, subtype_ids=None, context=None): """ Wrapper on message_subscribe, using users. If user_ids is not provided, subscribe uid instead. """ if user_ids is None: user_ids = [uid] partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)] - return self.message_subscribe(cr, uid, ids, partner_ids, subtype_ids=subtype_ids, user_id=user_id, context=context) + return self.message_subscribe(cr, uid, ids, partner_ids, subtype_ids=subtype_ids, context=context) - def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, user_id=None, context=None): + def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None): """ Add partners to the records followers. """ user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] - if user_id: - partner_ids = [user_id] if set(partner_ids) == set([user_pid]): try: self.check_access_rights(cr, uid, 'read') -- cgit v1.2.3 From a216e70e8513d1b9cad807b738023d8a92d8c8aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 6 Jun 2013 14:32:30 +0200 Subject: [FIX] [IMP] mail: allow to use message_post on models not having message_post method defined. mail.compose.message wizard and messaage_process now check that the active model has message_post defined. Otherwise using thread_model context key that is better managed in message_post, it is possible to use mail_thread.message_post() with a thread_model and thread_id that should not allow message_post otherwise. Hint: look for backport into 7.0 bzr revid: tde@openerp.com-20130606123230-d7ql14yydzfrlc7h --- addons/mail/mail_thread.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 6a32ed3bb52..e676e69552d 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -730,6 +730,9 @@ class mail_thread(osv.AbstractModel): else: assert thread_id == 0, "Posting a message without model should be with a null res_id, to create a private message." model_pool = self.pool.get('mail.thread') + if not hasattr(hasattr, 'message_post'): + context['thread_model'] = model + model_pool = self.pool['mail.thread'] new_msg_id = model_pool.message_post(cr, uid, [thread_id], context=context, subtype='mail.mt_comment', **msg) if partner_ids: @@ -1064,7 +1067,7 @@ class mail_thread(osv.AbstractModel): model = False if thread_id: model = context.get('thread_model', self._name) if self._name == 'mail.thread' else self._name - if model != self._name: + if model != self._name and hasattr(self.pool[model], 'message_post'): del context['thread_model'] return self.pool[model].message_post(cr, uid, thread_id, body=body, subject=subject, type=type, subtype=subtype, parent_id=parent_id, attachments=attachments, context=context, content_subtype=content_subtype, **kwargs) -- cgit v1.2.3 From dff9e6f8d84ed2258928794b7209c2b7ce2d4a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 10 Jun 2013 17:48:09 +0200 Subject: [FIX] mail: fixed hasattr on hasattr. bzr revid: tde@openerp.com-20130610154809-uro1vnbpe90ip1d4 --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index e676e69552d..8695f772dde 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -730,7 +730,7 @@ class mail_thread(osv.AbstractModel): else: assert thread_id == 0, "Posting a message without model should be with a null res_id, to create a private message." model_pool = self.pool.get('mail.thread') - if not hasattr(hasattr, 'message_post'): + if not hasattr(model_pool, 'message_post'): context['thread_model'] = model model_pool = self.pool['mail.thread'] new_msg_id = model_pool.message_post(cr, uid, [thread_id], context=context, subtype='mail.mt_comment', **msg) -- cgit v1.2.3 From 75ed151ad937d423fdceb61a41c3464bb2a4b908 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 11 Jun 2013 15:33:14 +0200 Subject: [FIX]mail: mail_thread, method message_capable_models was not returning all message capable models bzr revid: dle@openerp.com-20130611133314-pq9bmj7af61k7swe --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index ef9eac65451..9ebd67f0eb5 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -436,7 +436,7 @@ class mail_thread(osv.AbstractModel): ret_dict = {} for model_name in self.pool.obj_list(): model = self.pool.get(model_name) - if 'mail.thread' in getattr(model, '_inherit', []): + if hasattr(model, "message_process") and hasattr(model, "message_post"): ret_dict[model_name] = model._description return ret_dict -- cgit v1.2.3 From 99dd06cfd0f87e0bdd6be402f85328f1006667aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 12 Jun 2013 13:36:30 +0200 Subject: [FIX] [HACK] Delocate code about mail_thread inheritance from portal to mail_thread, because of the inheritance graph bug in trunk to sovle that makes this code not visible for hr.employee. bzr revid: tde@openerp.com-20130612113630-ao1dxpv0ax5n4xje --- addons/mail/mail_thread.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 927e01e7406..41fcaf5adb7 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1485,6 +1485,13 @@ class mail_thread(osv.AbstractModel): if context is None: context = {} + # TDE HACK: originally by MAT from portal/mail_mail.py but not working until the inheritance graph bug is not solved in trunk + # TDE FIXME: relocate in portal when it won't be necessary to reload the hr.employee model in an additional bridge module + if self.pool['res.groups']._all_columns.get('is_portal'): + user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context) + if any(group.is_portal for group in user.groups_id): + return [] + threads = [] if removed_suggested_threads is None: removed_suggested_threads = [] @@ -1498,4 +1505,4 @@ class mail_thread(osv.AbstractModel): 'image_small': thread.image_small } threads.append(data) - return sorted(threads, key=lambda x: (x['popularity'], x['id']), reverse=True)[:3] \ No newline at end of file + return sorted(threads, key=lambda x: (x['popularity'], x['id']), reverse=True)[:3] -- cgit v1.2.3 From 2652bd586d4ff38c0c1a0c2fe82bc25900e50ae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 13 Jun 2013 10:20:29 +0200 Subject: [FIX] mail: message_subscribe_users: refactoring of the algorithm to achieve better computation time. Previous implementation did a search on mail.followers with subtype_ids=False, leading to a very bad computation time. This search is now avoided. bzr revid: tde@openerp.com-20130613082029-lmd63s3mqwxasy4j --- addons/mail/mail_thread.py | 55 +++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 22 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 9ebd67f0eb5..51eed7c7f8f 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1160,7 +1160,10 @@ class mail_thread(osv.AbstractModel): def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None): """ Add partners to the records followers. """ - user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + mail_followers_obj = self.pool.get('mail.followers') + subtype_obj = self.pool.get('mail.message.subtype') + + user_pid = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id if set(partner_ids) == set([user_pid]): try: self.check_access_rights(cr, uid, 'read') @@ -1169,27 +1172,35 @@ class mail_thread(osv.AbstractModel): else: self.check_access_rights(cr, uid, 'write') - # subscribe partners - self.write(cr, SUPERUSER_ID, ids, {'message_follower_ids': [(4, pid) for pid in partner_ids]}, context=context) - - # subtype specified: update the subscriptions - fol_obj = self.pool.get('mail.followers') - if subtype_ids is not None: - fol_ids = fol_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('res_id', 'in', ids), ('partner_id', 'in', partner_ids)], context=context) - fol_obj.write(cr, SUPERUSER_ID, fol_ids, {'subtype_ids': [(6, 0, subtype_ids)]}, context=context) - # no subtypes: default ones for new subscription, do not update existing subscriptions - else: - # search new subscriptions: subtype_ids is False - fol_ids = fol_obj.search(cr, SUPERUSER_ID, [ - ('res_model', '=', self._name), - ('res_id', 'in', ids), - ('partner_id', 'in', partner_ids), - ('subtype_ids', '=', False) - ], context=context) - if fol_ids: - subtype_obj = self.pool.get('mail.message.subtype') - subtype_ids = subtype_obj.search(cr, uid, [('default', '=', True), '|', ('res_model', '=', self._name), ('res_model', '=', False)], context=context) - fol_obj.write(cr, SUPERUSER_ID, fol_ids, {'subtype_ids': [(6, 0, subtype_ids)]}, context=context) + for record in self.browse(cr, SUPERUSER_ID, ids, context=context): + existing_pids = set([f.id for f in record.message_follower_ids + if f.id in partner_ids]) + new_pids = set(partner_ids) - existing_pids + + # subtype_ids specified: update already subscribed partners + if subtype_ids and existing_pids: + fol_ids = mail_followers_obj.search(cr, SUPERUSER_ID, [ + ('res_model', '=', self._name), + ('res_id', 'in', ids), + ('partner_id', 'in', list(existing_pids)), + ], context=context) + mail_followers_obj.write(cr, SUPERUSER_ID, fol_ids, {'subtype_ids': [(6, 0, subtype_ids)]}, context=context) + # subtype_ids not specified: do not update already subscribed partner, fetch default subtypes for new partners + else: + subtype_ids = subtype_obj.search(cr, uid, [ + ('default', '=', True), + '|', + ('res_model', '=', self._name), + ('res_model', '=', False) + ], context=context) + # subscribe new followers + for new_pid in new_pids: + mail_followers_obj.create(cr, SUPERUSER_ID, { + 'res_model': self._name, + 'res_id': record.id, + 'partner_id': new_pid, + 'subtype_ids': [(6, 0, subtype_ids)], + }, context=context) return True -- cgit v1.2.3 From 41311b9f33cb6e904a95be8b1d72c499b3fa1743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 13 Jun 2013 11:52:28 +0200 Subject: [FIX] mail: fixed id of record in a loop (record.id, not all ids). bzr revid: tde@openerp.com-20130613095228-b4r8kca7hkjd6ppa --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 51eed7c7f8f..349122e5942 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1181,7 +1181,7 @@ class mail_thread(osv.AbstractModel): if subtype_ids and existing_pids: fol_ids = mail_followers_obj.search(cr, SUPERUSER_ID, [ ('res_model', '=', self._name), - ('res_id', 'in', ids), + ('res_id', '=', record.id), ('partner_id', 'in', list(existing_pids)), ], context=context) mail_followers_obj.write(cr, SUPERUSER_ID, fol_ids, {'subtype_ids': [(6, 0, subtype_ids)]}, context=context) -- cgit v1.2.3 From cd9efe1f994e5012e509ca3cda106d08a0ce9195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 19 Jun 2013 14:38:29 +0200 Subject: [FIX] mail: take into account default_ context values for auto subscribe bzr revid: tde@openerp.com-20130619123829-gr1rkgp490bdci9u --- addons/mail/mail_thread.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 349122e5942..6de308a1bfa 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -248,7 +248,12 @@ class mail_thread(osv.AbstractModel): # subscribe uid unless asked not to if not context.get('mail_create_nosubscribe'): self.message_subscribe_users(cr, uid, [thread_id], [uid], context=context) - self.message_auto_subscribe(cr, uid, [thread_id], values.keys(), context=context) + # auto_subscribe: take values and defaults into account + create_values = set(values.keys()) + for key, val in context.iteritems(): + if key.startswith('default_'): + create_values.add(key[8:]) + self.message_auto_subscribe(cr, uid, [thread_id], list(create_values), context=context) # track values tracked_fields = self._get_tracked_fields(cr, uid, values.keys(), context=context) -- cgit v1.2.3 From ff00a84d33881ef8ca8965a688a8ce05421528d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 20 Jun 2013 15:57:18 +0200 Subject: [FIX] mail: fixed a glitch in message_subscribe sometimes overriding specified subtypes bzr revid: tde@openerp.com-20130620135718-qi0d8fpqvombq3v1 --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 349122e5942..a138aa230db 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1186,7 +1186,7 @@ class mail_thread(osv.AbstractModel): ], context=context) mail_followers_obj.write(cr, SUPERUSER_ID, fol_ids, {'subtype_ids': [(6, 0, subtype_ids)]}, context=context) # subtype_ids not specified: do not update already subscribed partner, fetch default subtypes for new partners - else: + elif subtype_ids is None: subtype_ids = subtype_obj.search(cr, uid, [ ('default', '=', True), '|', -- cgit v1.2.3 From fd90140d7bd05820aeac7bd7e22539893f87319d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 24 Jun 2013 17:18:27 +0200 Subject: [REF] mail_thread: refactored message_route improvement, to be closer to the original code + call to a new method that checks the route, instead of doing everything in one method. bzr revid: tde@openerp.com-20130624151827-hxwaelefs540pvca --- addons/mail/mail_thread.py | 310 ++++++++++++++++++++++++++------------------- 1 file changed, 177 insertions(+), 133 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index b4ce06812a9..409f0ad12f7 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -25,7 +25,6 @@ import dateutil import email import logging import pytz -import re import time import xmlrpclib from email.message import Message @@ -258,7 +257,6 @@ class mail_thread(osv.AbstractModel): def _search_is_follower(self, cr, uid, obj, name, args, context): """Search function for message_is_follower""" - fol_obj = self.pool.get('mail.followers') res = [] for field, operator, value in args: assert field == name @@ -462,9 +460,6 @@ class mail_thread(osv.AbstractModel): return [('message_unread', '=', True)] return [] - # def _get_model(self, cr, uid, context=None): - # return if self._name == 'mail.thread' - def _garbage_collect_attachments(self, cr, uid, context=None): """ Garbage collect lost mail attachments. Those are attachments - linked to res_model 'mail.compose.message', the composer wizard @@ -597,6 +592,118 @@ class mail_thread(osv.AbstractModel): s = ', '.join([decode(message.get(h)) for h in header_fields if message.get(h)]) return filter(lambda x: x, self._find_partner_from_emails(cr, uid, None, tools.email_split(s), context=context)) + def message_route_verify(self, cr, uid, message, message_dict, route, update_author=True, assert_model=True, create_fallback=True, context=None): + """ Verify route validity. Check and rules: + 1 - if thread_id -> check that document effectively exists; otherwise + fallback on a message_new by resetting thread_id + 2 - check that message_update exists if thread_id is set; or at least + that message_new exist + [ - find author_id if udpate_author is set] + 3 - if there is an alias, check alias_contact: + 'followers' and thread_id: + check on target document that the author is in the followers + 'followers' and alias_parent_thread_id: + check on alias parent document that the author is in the + followers + 'partners': check that author_id id set + """ + + assert isinstance(route, (list, tuple)), 'A route should be a list or a tuple' + assert len(route) == 5, 'A route should contain 5 elements: model, thread_id, custom_values, uid, alias record' + + message_id = message.get('Message-Id') + email_from = decode_header(message, 'From') + author_id = message_dict.get('author_id') + model, thread_id, alias = route[0], route[1], route[4] + model_pool = None + + def _create_bounce_email(): + mail_mail = self.pool.get('mail.mail') + mail_id = mail_mail.create(cr, uid, { + 'body_html': '

Hello,

' + '

The following email sent to %s cannot be accepted because this is ' + 'a private email address. Only allowed people can contact us at this address.

' + '
%s
' % (message.get('to'), message_dict.get('body')), + 'subject': 'Re: %s' % message.get('subject'), + 'email_to': message.get('from'), + 'auto_delete': True, + }, context=context) + mail_mail.send(cr, uid, [mail_id], context=context) + + def _warn(message): + _logger.warning('Routing mail with Message-Id %s: route %s: %s', + message_id, route, message) + + # Wrong model + if model and not model in self.pool: + if assert_model: + assert model in self.pool, 'Routing: unknown target model %s' % model + _warn('unknown target model %s' % model) + return () + elif model: + model_pool = self.pool[model] + + # Private message: should not contain any thread_id + if not model and thread_id: + if assert_model: + assert thread_id == 0, 'Routing: posting a message without model should be with a null res_id (private message).' + _warn('posting a message without model should be with a null res_id (private message), resetting thread_id') + thread_id = 0 + + # Existing Document: check if exists; if not, fallback on create if allowed + if thread_id and not model_pool.exists(cr, uid, thread_id): + if create_fallback: + _warn('reply to missing document (%s,%s), fall back on new document creation' % (model, thread_id)) + thread_id = None + elif assert_model: + assert model_pool.exists(cr, uid, thread_id), 'Routing: reply to missing document (%s,%s)' % (model, thread_id) + else: + _warn('reply to missing document (%s,%s), skipping' % (model, thread_id)) + return () + + # Existing Document: check model accepts the mailgateway + if thread_id and not hasattr(model_pool, 'message_update'): + if create_fallback: + _warn('model %s does not accept document update, fall back on document creation' % model) + thread_id = None + elif assert_model: + assert hasattr(model_pool, 'message_update'), 'Routing: model %s does not accept document update, crashing' % model + else: + _warn('model %s does not accept document update, skipping' % model) + return () + + # New Document: check model accepts the mailgateway + if not thread_id and not hasattr(model_pool, 'message_new'): + if assert_model: + assert hasattr(model_pool, 'message_new'), 'Model %s does not accept document creation, crashing' % model + _warn('model %s does not accept document creation, skipping' % model) + return () + + # Update message author if asked + # We do it now because we need it for aliases (contact settings) + if not author_id and update_author: + author_ids = self._find_partner_from_emails(cr, uid, thread_id, [email_from], model=model, context=context) + if author_ids: + author_id = author_ids[0] + message_dict['author_id'] = author_id + + # Alias: check alias_contact settings + if alias and alias.alias_contact == 'followers' and (thread_id or alias.alias_parent_thread_id): + if thread_id: + obj = self.pool[model].browse(cr, uid, thread_id, context=context) + else: + obj = self.pool[alias.alias_parent_model_id.model].browse(cr, uid, alias.alias_parent_thread_id, context=context) + if not author_id or not author_id in [fol.id for fol in obj.message_follower_ids]: + _warn('alias %s restricted to internal followers, skipping' % alias.alias_name) + _create_bounce_email() + return () + elif alias and alias.alias_contact == 'partners' and not author_id: + _warn('alias %s does not accept unknown author, skipping' % alias.alias_name) + _create_bounce_email() + return () + + return (model, thread_id, route[2], route[3], route[4]) + def message_route(self, cr, uid, message, message_dict, model=None, thread_id=None, custom_values=None, context=None): """Attempt to figure out the correct target model, thread_id, @@ -616,8 +723,8 @@ class mail_thread(osv.AbstractModel): provided. 4. If all the above fails, raise an exception. - :param dict message_dict: dictionary holding message variables :param string message: an email.message instance + :param dict message_dict: dictionary holding message variables :param string model: the fallback model to use if the message does not match any of the currently configured mail aliases (may be None if a matching alias is supposed to be present) @@ -628,12 +735,10 @@ class mail_thread(osv.AbstractModel): :param int thread_id: optional ID of the record/thread from ``model`` to which this mail should be attached. Only used if the message does not reply to an existing thread and does not match any mail alias. - :return: list of [model, thread_id, custom_values, user_id] + :return: list of [model, thread_id, custom_values, user_id, alias] """ assert isinstance(message, Message), 'message must be an email.message.Message at this point' - found_routes = [] fallback_model = model - avoid_assert = False # Get email.message.Message variables for future processing message_id = message.get('Message-Id') @@ -642,26 +747,6 @@ class mail_thread(osv.AbstractModel): references = decode_header(message, 'References') in_reply_to = decode_header(message, 'In-Reply-To') thread_references = references or in_reply_to - # 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. - rcpt_tos = ','.join([decode_header(message, 'Delivered-To'), - decode_header(message, 'To'), - decode_header(message, 'Cc'), - decode_header(message, 'Resent-To'), - decode_header(message, 'Resent-Cc')]) - - def create_bounce_email(): - mail_mail = self.pool.get('mail.mail') - mail_id = mail_mail.create(cr, uid, { - 'body_html': '

Hello,

' - '

The following email sent to %s cannot be accepted because this is ' - 'a private email address. Only allowed people can contact us at this address.

' - '
%s
' % (message.get('to'), message_dict.get('body')), - 'subject': 'Re: %s' % message.get('subject'), - 'email_to': message.get('from'), - 'auto_delete': True, - }, context=context) - mail_mail.send(cr, uid, [mail_id], context=context) # 1. Reply to an existing thread ref_match = thread_references and tools.reference_re.search(thread_references) @@ -673,10 +758,13 @@ class mail_thread(osv.AbstractModel): if model_obj.exists(cr, uid, thread_id) and hasattr(model_obj, 'message_update'): _logger.info('Routing mail from %s to %s with Message-Id %s: direct reply to model: %s, thread_id: %s, custom_values: %s, uid: %s', email_from, email_to, message_id, model, thread_id, custom_values, uid) - found_routes = [(model, thread_id, custom_values, uid, None)] + route = self.message_route_verify(cr, uid, message, message_dict, + (model, thread_id, custom_values, uid, None), + update_author=True, assert_model=True, create_fallback=True, context=context) + return route and [route] or [] # 2. Reply to a private message - if not found_routes and in_reply_to: + if in_reply_to: message_ids = self.pool.get('mail.message').search(cr, uid, [ ('message_id', '=', in_reply_to), '!', ('message_id', 'ilike', 'reply_to') @@ -685,96 +773,67 @@ class mail_thread(osv.AbstractModel): message = self.pool.get('mail.message').browse(cr, uid, message_ids[0], context=context) _logger.info('Routing mail from %s to %s with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s', email_from, email_to, message_id, message.id, custom_values, uid) - found_routes = [(message.model, message.res_id, custom_values, uid, None)] + route = self.message_route_verify(cr, uid, message, message_dict, + (message.model, message.res_id, custom_values, uid, None), + update_author=True, assert_model=True, create_fallback=True, context=context) + return route and [route] or [] # 3. 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 + # for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value. + rcpt_tos = ','.join([decode_header(message, 'Delivered-To'), + decode_header(message, 'To'), + decode_header(message, 'Cc'), + decode_header(message, 'Resent-To'), + decode_header(message, 'Resent-Cc')]) local_parts = [e.split('@')[0] for e in tools.email_split(rcpt_tos)] - if not found_routes and local_parts: + if local_parts: mail_alias = self.pool.get('mail.alias') alias_ids = mail_alias.search(cr, uid, [('alias_name', 'in', local_parts)]) - for alias in mail_alias.browse(cr, uid, alias_ids, context=context): - user_id = alias.alias_user_id.id - if not user_id: - # TDE note: this could cause crashes, because no clue that the user - # that send the email has the right to create or modify a new document - # Fallback on user_id = uid - # Note: recognized partners will be added as followers anyway - # user_id = self._message_find_user_id(cr, uid, message, context=context) - user_id = uid - _logger.info('No matching user_id for the alias %s', alias.alias_name) - found_routes.append((alias.alias_model_id.model, alias.alias_force_thread_id, eval(alias.alias_defaults), user_id, alias)) - if found_routes: - _logger.info('Routing mail from %s to %s with Message-Id %s: direct alias match: %r', - email_from, email_to, message_id, found_routes) + if alias_ids: + routes = [] + for alias in mail_alias.browse(cr, uid, alias_ids, context=context): + user_id = alias.alias_user_id.id + if not user_id: + # TDE note: this could cause crashes, because no clue that the user + # that send the email has the right to create or modify a new document + # Fallback on user_id = uid + # Note: recognized partners will be added as followers anyway + # user_id = self._message_find_user_id(cr, uid, message, context=context) + user_id = uid + _logger.info('No matching user_id for the alias %s', alias.alias_name) + route = (alias.alias_model_id.model, alias.alias_force_thread_id, eval(alias.alias_defaults), user_id, alias) + _logger.info('Routing mail from %s to %s with Message-Id %s: direct alias match: %r', + email_from, email_to, message_id, route) + route = self.message_route_verify(cr, uid, message, message_dict, route, + update_author=True, assert_model=True, create_fallback=True, context=context) + if route: + routes.append(route) + return routes # 4. Fallback to the provided parameters, if they work - if not found_routes: - if not thread_id: - # Legacy: fallback to matching [ID] in the Subject - match = tools.res_re.search(decode_header(message, 'Subject')) - thread_id = match and match.group(1) - # Convert into int (bug spotted in 7.0 because of str) - try: - thread_id = int(thread_id) - except: - thread_id = False - found_routes = [(fallback_model, thread_id, custom_values, uid, None)] - _logger.info('Routing mail from %s to %s with Message-Id %s: fallback to model:%s, thread_id:%s, custom_values:%s, uid:%s', - email_from, email_to, message_id, fallback_model, thread_id, custom_values, uid) - - # Post-process routes - valid_routes = [] - author_id = False - for route in found_routes: - model, thread_id, alias = route[0], route[1], route[4] - model_pool = self.pool.get(model) - - # check related document effectively exists - if thread_id and not model_pool.exists(cr, uid, thread_id): - _logger.warning('Routing mail with Message-Id %s: route %s: reply to missing document %s, ignoring and creating new document instead', - message_id, route, thread_id) - thread_id = None - # check model accepts the mailgateway - if not (thread_id and hasattr(model_pool, 'message_update')) and not (hasattr(model_pool, 'message_new')): - _logger.warning('Routing mail with Message-Id %s: route %s: model %s does not accept unknown emails, skipping', - message_id, route, model) - continue - - # check for author - if not author_id: - author_ids = model_pool._find_partner_from_emails(cr, uid, thread_id, [email_from], context=context) - if author_ids: - author_id = author_ids[0] - message_dict['author_id'] = author_id - - # route contact settings - if alias and alias.alias_contact == 'followers' and (thread_id or alias.alias_parent_thread_id): - if thread_id: - obj = self.pool[model].browse(cr, uid, thread_id, context=context) - else: - obj = self.pool[alias.alias_parent_model_id.model].browse(cr, uid, alias.alias_parent_thread_id, context=context) - if not author_id or not author_id in [fol.id for fol in obj.message_follower_ids]: - _logger.warning('Routing mail with Message-Id %s: route %s: alias %s restricted to internal followers, skipping', - message_id, route, alias.alias_name) - create_bounce_email() - avoid_assert = True - continue - elif alias and alias.alias_contact == 'partners' and not author_id: - _logger.warning('Routing mail with Message-Id %s: route %s: alias %s does not accept unknown sender, skipping', - message_id, route, alias.alias_name) - create_bounce_email() - avoid_assert = True - continue - - # update route - valid_routes.append((model, thread_id, route[2], route[3])) + if not thread_id: + # Legacy: fallback to matching [ID] in the Subject + match = tools.res_re.search(decode_header(message, 'Subject')) + thread_id = match and match.group(1) + # Convert into int (bug spotted in 7.0 because of str) + try: + thread_id = int(thread_id) + except: + thread_id = False + _logger.info('Routing mail from %s to %s with Message-Id %s: fallback to model:%s, thread_id:%s, custom_values:%s, uid:%s', + email_from, email_to, message_id, fallback_model, thread_id, custom_values, uid) + route = self.message_route_verify(cr, uid, message, message_dict, + (fallback_model, thread_id, custom_values, uid, None), + update_author=True, assert_model=True, context=context) + if route: + return [route] # AssertionError if no routes found and if no bounce occured - assert valid_routes or avoid_assert, \ + assert False, \ "Routing mail from %s to %s with Message-Id %s: no possible route found. " \ "Create an appropriate mail.alias or force the destination model." % \ (email_from, email_to, message_id) - return valid_routes def message_process(self, cr, uid, model, message, custom_values=None, save_original=False, strip_attachments=False, @@ -840,9 +899,9 @@ class mail_thread(osv.AbstractModel): return False # find possible routes for the message - thread_id = False routes = self.message_route(cr, uid, msg_txt, msg, model, thread_id, custom_values, context=context) - for model, thread_id, custom_values, user_id in routes: + thread_id = False + for model, thread_id, custom_values, user_id, alias in routes: if self._name == 'mail.thread': context.update({'thread_model': model}) if model: @@ -1097,8 +1156,7 @@ class mail_thread(osv.AbstractModel): self._message_add_suggested_recipient(cr, uid, result, obj, partner=obj.user_id.partner_id, reason=self._all_columns['user_id'].column.string, context=context) return result - def _find_partner_from_emails(self, cr, uid, id, emails, context=None, - check_followers=True, only_users=False, take_all=False, full_info=False): + def _find_partner_from_emails(self, cr, uid, id, emails, model=None, context=None, check_followers=True): """ Utility method to find partners :param boolean check_followers: TODO @@ -1108,8 +1166,11 @@ class mail_thread(osv.AbstractModel): partner_obj = self.pool['res.partner'] partner_ids = [] obj = None - if id and self._name != 'mail.thread' and check_followers: - obj = self.browse(cr, uid, id, context=context) + if id and (model or self._name != 'mail.thread') and check_followers: + if model: + obj = self.pool[model].browse(cr, uid, id, context=context) + else: + obj = self.browse(cr, uid, id, context=context) for contact in emails: partner_id = False email_address = tools.email_split(contact) @@ -1145,9 +1206,7 @@ class mail_thread(osv.AbstractModel): 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 - - TDE TODO: merge me with other partner finding methods in 8.0 """ + :return dict: partner_ids and new_partner_ids """ mail_message_obj = self.pool.get('mail.message') partner_ids = self._find_partner_from_emails(cr, uid, id, emails, context=context) result = list() @@ -1326,21 +1385,6 @@ class mail_thread(osv.AbstractModel): self.message_subscribe(cr, uid, [thread_id], [message.author_id.id], context=context) return msg_id - #------------------------------------------------------ - # Compatibility methods: do not use - # TDE TODO: remove me in 8.0 - #------------------------------------------------------ - - def message_create_partners_from_emails(self, cr, uid, emails, context=None): - return {'partner_ids': [], 'new_partner_ids': []} - - def message_post_user_api(self, cr, uid, thread_id, body='', parent_id=False, - attachment_ids=None, content_subtype='plaintext', - context=None, **kwargs): - return self.message_post(cr, uid, thread_id, body=body, parent_id=parent_id, - attachment_ids=attachment_ids, content_subtype=content_subtype, - context=context, **kwargs) - #------------------------------------------------------ # Followers API #------------------------------------------------------ -- cgit v1.2.3 From e6ee1d315e21a377c104aa0bf05cd9a15b0ce844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 24 Jun 2013 18:24:57 +0200 Subject: [CLEAN] Misc cleaning before merging bzr revid: tde@openerp.com-20130624162457-8y8eqwebwolvcdc6 --- addons/mail/mail_thread.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 409f0ad12f7..6e01ea1069d 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -781,11 +781,12 @@ class mail_thread(osv.AbstractModel): # 3. 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 # for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value. - rcpt_tos = ','.join([decode_header(message, 'Delivered-To'), - decode_header(message, 'To'), - decode_header(message, 'Cc'), - decode_header(message, 'Resent-To'), - decode_header(message, 'Resent-Cc')]) + rcpt_tos = \ + ','.join([decode_header(message, 'Delivered-To'), + decode_header(message, 'To'), + decode_header(message, 'Cc'), + decode_header(message, 'Resent-To'), + decode_header(message, 'Resent-Cc')]) local_parts = [e.split('@')[0] for e in tools.email_split(rcpt_tos)] if local_parts: mail_alias = self.pool.get('mail.alias') @@ -831,9 +832,8 @@ class mail_thread(osv.AbstractModel): # AssertionError if no routes found and if no bounce occured assert False, \ - "Routing mail from %s to %s with Message-Id %s: no possible route found. " \ - "Create an appropriate mail.alias or force the destination model." % \ - (email_from, email_to, message_id) + "No possible route found for incoming message from %s to %s (Message-Id %s:)." \ + "Create an appropriate mail.alias or force the destination model." % (email_from, email_to, message_id) def message_process(self, cr, uid, model, message, custom_values=None, save_original=False, strip_attachments=False, -- cgit v1.2.3 From 3994ea12e9ca32604736db34f89faf777f6a18e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 25 Jun 2013 11:26:06 +0200 Subject: [CLEAN] Misc cleaning before merging (some code cleaning, added comments). bzr revid: tde@openerp.com-20130625092606-l8bqt3ce2xz4zm9t --- addons/mail/mail_thread.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 6e01ea1069d..403cfab7d61 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -746,9 +746,9 @@ class mail_thread(osv.AbstractModel): email_to = decode_header(message, 'To') references = decode_header(message, 'References') in_reply_to = decode_header(message, 'In-Reply-To') - thread_references = references or in_reply_to - # 1. Reply to an existing thread + # 1. Verify if this is a reply to an existing thread + thread_references = references or in_reply_to ref_match = thread_references and tools.reference_re.search(thread_references) if ref_match: thread_id = int(ref_match.group(1)) @@ -1157,11 +1157,15 @@ class mail_thread(osv.AbstractModel): return result def _find_partner_from_emails(self, cr, uid, id, emails, model=None, context=None, check_followers=True): - """ Utility method to find partners - - :param boolean check_followers: TODO - :param boolean only_users: TODO - :param boolean take_all: TODO + """ Utility method to find partners from email addresses. The rules are : + 1 - check in document (model | self, id) followers + 2 - try to find a matching partner that is also an user + 3 - try to find a matching partner + + :param list emails: list of email addresses + :param string model: model to fetch related record; by default self + is used. + :param boolean check_followers: check in document followers """ partner_obj = self.pool['res.partner'] partner_ids = [] -- cgit v1.2.3 From bf4ada34b4e6bc9793f4870786d579d9dce4c799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 27 Jun 2013 16:46:47 +0200 Subject: [REF] mail_thread: message_track now uses browse records instead of read results. Updated addons accordingly. Updated tests to test corner cases using False / null browse records. bzr revid: tde@openerp.com-20130627144647-swbj77i84vo9ii0v --- addons/mail/mail_thread.py | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 403cfab7d61..23196925b63 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -328,8 +328,8 @@ class mail_thread(osv.AbstractModel): # Track initial values of tracked fields tracked_fields = self._get_tracked_fields(cr, uid, values.keys(), context=context) if tracked_fields: - initial = self.read(cr, uid, ids, tracked_fields.keys(), context=context) - initial_values = dict((item['id'], item) for item in initial) + records = self.browse(cr, uid, ids, context=context) + initial_values = dict((this.id, dict((key, getattr(this, key)) for key in tracked_fields.keys())) for this in records) # Perform write, update followers result = super(mail_thread, self).write(cr, uid, ids, values, context=context) @@ -388,7 +388,7 @@ class mail_thread(osv.AbstractModel): if not value: return '' if col_info['type'] == 'many2one': - return value[1] + return value.name_get()[0][1] if col_info['type'] == 'selection': return dict(col_info['selection'])[value] return value @@ -407,23 +407,28 @@ class mail_thread(osv.AbstractModel): if not tracked_fields: return True - for record in self.read(cr, uid, ids, tracked_fields.keys(), context=context): - initial = initial_values[record['id']] - changes = [] + for browse_record in self.browse(cr, uid, ids, context=context): + initial = initial_values[browse_record.id] + changes = set() tracked_values = {} # generate tracked_values data structure: {'col_name': {col_info, new_value, old_value}} for col_name, col_info in tracked_fields.items(): - if record[col_name] == initial[col_name] and getattr(self._all_columns[col_name].column, 'track_visibility', None) == 'always': + initial_value = initial[col_name] + record_value = getattr(browse_record, col_name) + + if record_value == initial_value and getattr(self._all_columns[col_name].column, 'track_visibility', None) == 'always': tracked_values[col_name] = dict(col_info=col_info['string'], - new_value=convert_for_display(record[col_name], col_info)) - elif record[col_name] != initial[col_name]: + new_value=convert_for_display(record_value, col_info)) + elif record_value != initial_value: + if col_info['type'] == 'many2one' and not (record_value or initial_value): + continue if getattr(self._all_columns[col_name].column, 'track_visibility', None) in ['always', 'onchange']: tracked_values[col_name] = dict(col_info=col_info['string'], - old_value=convert_for_display(initial[col_name], col_info), - new_value=convert_for_display(record[col_name], col_info)) + old_value=convert_for_display(initial_value, col_info), + new_value=convert_for_display(record_value, col_info)) if col_name in tracked_fields: - changes.append(col_name) + changes.add(col_name) if not changes: continue @@ -433,7 +438,7 @@ class mail_thread(osv.AbstractModel): if field not in changes: continue for subtype, method in track_info.items(): - if method(self, cr, uid, record, context): + if method(self, cr, uid, browse_record, context): subtypes.append(subtype) posted = False @@ -444,11 +449,11 @@ class mail_thread(osv.AbstractModel): _logger.debug('subtype %s not found, giving error "%s"' % (subtype, e)) continue message = format_message(subtype_rec.description if subtype_rec.description else subtype_rec.name, tracked_values) - self.message_post(cr, uid, record['id'], body=message, subtype=subtype, context=context) + self.message_post(cr, uid, browse_record.id, body=message, subtype=subtype, context=context) posted = True if not posted: message = format_message('', tracked_values) - self.message_post(cr, uid, record['id'], body=message, context=context) + self.message_post(cr, uid, browse_record.id, body=message, context=context) return True #------------------------------------------------------ -- cgit v1.2.3 From e3c729e1a65a1e23f874525bf154c7b3a721392b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 27 Jun 2013 16:55:19 +0200 Subject: [CLEAN] Cleaned last commit. bzr revid: tde@openerp.com-20130627145519-533br1ho1da3d4f0 --- addons/mail/mail_thread.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 23196925b63..1b5d520cd42 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -420,9 +420,7 @@ class mail_thread(osv.AbstractModel): if record_value == initial_value and getattr(self._all_columns[col_name].column, 'track_visibility', None) == 'always': tracked_values[col_name] = dict(col_info=col_info['string'], new_value=convert_for_display(record_value, col_info)) - elif record_value != initial_value: - if col_info['type'] == 'many2one' and not (record_value or initial_value): - continue + elif record_value != initial_value and (record_value or initial_value): # because browse null != False if getattr(self._all_columns[col_name].column, 'track_visibility', None) in ['always', 'onchange']: tracked_values[col_name] = dict(col_info=col_info['string'], old_value=convert_for_display(initial_value, col_info), -- cgit v1.2.3 From 6694183dcb7b95947eea4931bc76cc3e2e1dcee8 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Fri, 12 Jul 2013 19:09:20 +0530 Subject: [IMP] Improved code and added {'is_editable': True/False, 'is_uid': True/False} -- where is_editable will be True if uid is in technical group -- where is_uid will be True if uid is in partner.user_ids. bzr revid: psa@tinyerp.com-20130712133920-96l6axns7yynyz9e --- addons/mail/mail_thread.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 59f2817d016..ebd143e1be8 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -156,12 +156,21 @@ class mail_thread(osv.AbstractModel): res[id]['message_summary'] = "9 %d %s" % (title, res[id].pop('message_unread_count'), _("New")) return res - def check_technical_rights(self, cr, uid, ids, context=None): - grp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_no_one') - user_pid = self.pool.get('res.groups').read(cr, uid, grp_id[1], ['users'], context=context)['users'] - if uid in user_pid: - return True - return False + def read_followers_data(self, cr, uid, ids, context=None): + data = self.pool.get('res.partner').read(cr, uid, ids, ['name', 'user_ids'], context=context) + + grp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_no_one') + tech_user = self.pool.get('res.groups').read(cr, uid, grp_id[1], ['users'], context=context)['users'] + user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + + if uid in tech_user: + for dict in data: + if dict['id'] in [user_pid]: + dict.update({'is_editable': True}) + if uid in dict['user_ids']: + dict.update({'is_uid': True}) + + return data def _get_subscription_data(self, cr, uid, ids, name, args, user_pid=None, context=None): """ Computes: -- cgit v1.2.3 From 670710b88eb596ab9f6e8587de3d43ac133c0e18 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Mon, 15 Jul 2013 13:31:06 +0530 Subject: [IMP] Improved code and passed the data according to the format as suggest (partner_id, partner_name, {'is_editable': True/False, 'is_uid': True/False}) and done changes according this changes. bzr revid: psa@tinyerp.com-20130715080106-63dbeh3mhgiqppzv --- addons/mail/mail_thread.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index ebd143e1be8..949ed60ba82 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -156,21 +156,20 @@ class mail_thread(osv.AbstractModel): res[id]['message_summary'] = "9 %d %s" % (title, res[id].pop('message_unread_count'), _("New")) return res - def read_followers_data(self, cr, uid, ids, context=None): - data = self.pool.get('res.partner').read(cr, uid, ids, ['name', 'user_ids'], context=context) - - grp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_no_one') - tech_user = self.pool.get('res.groups').read(cr, uid, grp_id[1], ['users'], context=context)['users'] - user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] - - if uid in tech_user: - for dict in data: - if dict['id'] in [user_pid]: - dict.update({'is_editable': True}) - if uid in dict['user_ids']: - dict.update({'is_uid': True}) - - return data + def read_followers_data(self, cr, uid, follower_ids, context=None): + datas = [] + partner_pool = self.pool.get('res.partner') + technical_group = self.pool.get('ir.model.data').get_object(cr, uid, 'base', 'group_no_one') + for follower in partner_pool.browse(cr, uid, follower_ids, context=context): + is_editable = uid in map(lambda x:x.id, technical_group.users) + is_uid = uid in map(lambda x:x.id, follower.user_ids) + data = ( + follower.id, + follower.name, + {'is_editable': is_editable, 'is_uid': is_uid}, + ) + datas.append(data) + return datas def _get_subscription_data(self, cr, uid, ids, name, args, user_pid=None, context=None): """ Computes: -- cgit v1.2.3 From 54837802acf9520e4971192f2a5eb3574bf89174 Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Mon, 15 Jul 2013 17:07:36 +0530 Subject: Improved code. bzr revid: psa@tinyerp.com-20130715113736-ww4wffkajnwkk961 --- addons/mail/mail_thread.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 949ed60ba82..b4e8ddee439 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -158,9 +158,8 @@ class mail_thread(osv.AbstractModel): def read_followers_data(self, cr, uid, follower_ids, context=None): datas = [] - partner_pool = self.pool.get('res.partner') technical_group = self.pool.get('ir.model.data').get_object(cr, uid, 'base', 'group_no_one') - for follower in partner_pool.browse(cr, uid, follower_ids, context=context): + for follower in self.pool.get('res.partner').browse(cr, uid, follower_ids, context=context): is_editable = uid in map(lambda x:x.id, technical_group.users) is_uid = uid in map(lambda x:x.id, follower.user_ids) data = ( -- cgit v1.2.3 From 68d1c2928fc1d0307726ed4d32555d68c4f330c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 23 Jul 2013 11:55:09 +0200 Subject: [CLEAN] Cleaning befor merging No need to use an image for edition -> use webtypo font instead Small code cleaning in js / python bzr revid: tde@openerp.com-20130723095509-knp45uvmlfmr27v9 --- addons/mail/mail_thread.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index b4e8ddee439..b61477ec7ca 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -157,18 +157,17 @@ class mail_thread(osv.AbstractModel): return res def read_followers_data(self, cr, uid, follower_ids, context=None): - datas = [] + result = [] technical_group = self.pool.get('ir.model.data').get_object(cr, uid, 'base', 'group_no_one') for follower in self.pool.get('res.partner').browse(cr, uid, follower_ids, context=context): - is_editable = uid in map(lambda x:x.id, technical_group.users) - is_uid = uid in map(lambda x:x.id, follower.user_ids) - data = ( - follower.id, - follower.name, - {'is_editable': is_editable, 'is_uid': is_uid}, - ) - datas.append(data) - return datas + is_editable = uid in map(lambda x: x.id, technical_group.users) + is_uid = uid in map(lambda x: x.id, follower.user_ids) + data = (follower.id, + follower.name, + {'is_editable': is_editable, 'is_uid': is_uid}, + ) + result.append(data) + return result def _get_subscription_data(self, cr, uid, ids, name, args, user_pid=None, context=None): """ Computes: -- cgit v1.2.3 From e0e3d985573e0b21c1e5affa57c89d75eb6ef351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 23 Jul 2013 16:45:07 +0200 Subject: [IMP] mail: refactored check_mail_message_access bzr revid: tde@openerp.com-20130723144507-bwwegheqofs7x1ox --- addons/mail/mail_thread.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index b61477ec7ca..306e5fd5905 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -70,6 +70,7 @@ class mail_thread(osv.AbstractModel): _name = 'mail.thread' _description = 'Email Thread' _mail_flat_thread = True + _mail_post_access = 'write' # Automatic logging system if mail installed # _track = { @@ -509,12 +510,22 @@ class mail_thread(osv.AbstractModel): access rule on the document, for portal document such as issues. """ if not model_obj: model_obj = self - if operation in ['create', 'write', 'unlink']: - model_obj.check_access_rights(cr, uid, 'write') - model_obj.check_access_rule(cr, uid, mids, 'write', context=context) + if hasattr(self, '_mail_post_access'): + create_allow = self._mail_post_access else: - model_obj.check_access_rights(cr, uid, operation) - model_obj.check_access_rule(cr, uid, mids, operation, context=context) + create_allow = 'write' + + if operation in ['write', 'unlink']: + check_operation = 'write' + elif operation == 'create' and create_allow in ['create', 'read', 'write', 'unlink']: + check_operation = create_allow + elif operation == 'create': + check_operation = 'write' + else: + check_operation = operation + + model_obj.check_access_rights(cr, uid, check_operation) + model_obj.check_access_rule(cr, uid, mids, check_operation, context=context) def _get_formview_action(self, cr, uid, id, model=None, context=None): """ Return an action to open the document. This method is meant to be -- cgit v1.2.3 From 2eece10cd4631763b1ca2cc00b2d8f84280f6d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 7 Aug 2013 16:24:18 +0200 Subject: [FIX] mail_mail: computation of reply_to after create to avoid interfering with automatic message_id creation of mail_message [FIX] mail_thread: fixed issues with private messages through mailgateway (wrong route checking, variable erasing) [TEST] mail: added test for the second bug bzr revid: tde@openerp.com-20130807142418-3h5qxdt3ekosj9x6 --- addons/mail/mail_thread.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'addons/mail/mail_thread.py') diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 306e5fd5905..94e9126f020 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -682,6 +682,12 @@ class mail_thread(osv.AbstractModel): assert thread_id == 0, 'Routing: posting a message without model should be with a null res_id (private message).' _warn('posting a message without model should be with a null res_id (private message), resetting thread_id') thread_id = 0 + # Private message: should have a parent_id (only answers) + if not model and not message_dict.get('parent_id'): + if assert_model: + assert message_dict.get('parent_id'), 'Routing: posting a message without model should be with a parent_id (private mesage).' + _warn('posting a message without model should be with a parent_id (private mesage), skipping') + return () # Existing Document: check if exists; if not, fallback on create if allowed if thread_id and not model_pool.exists(cr, uid, thread_id): @@ -695,7 +701,7 @@ class mail_thread(osv.AbstractModel): return () # Existing Document: check model accepts the mailgateway - if thread_id and not hasattr(model_pool, 'message_update'): + if thread_id and model and not hasattr(model_pool, 'message_update'): if create_fallback: _warn('model %s does not accept document update, fall back on document creation' % model) thread_id = None @@ -706,7 +712,7 @@ class mail_thread(osv.AbstractModel): return () # New Document: check model accepts the mailgateway - if not thread_id and not hasattr(model_pool, 'message_new'): + if not thread_id and model and not hasattr(model_pool, 'message_new'): if assert_model: assert hasattr(model_pool, 'message_new'), 'Model %s does not accept document creation, crashing' % model _warn('model %s does not accept document creation, skipping' % model) @@ -798,16 +804,16 @@ class mail_thread(osv.AbstractModel): # 2. Reply to a private message if in_reply_to: - message_ids = self.pool.get('mail.message').search(cr, uid, [ + mail_message_ids = self.pool.get('mail.message').search(cr, uid, [ ('message_id', '=', in_reply_to), '!', ('message_id', 'ilike', 'reply_to') ], limit=1, context=context) - if message_ids: - message = self.pool.get('mail.message').browse(cr, uid, message_ids[0], context=context) + if mail_message_ids: + mail_message = self.pool.get('mail.message').browse(cr, uid, mail_message_ids[0], context=context) _logger.info('Routing mail from %s to %s with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s', - email_from, email_to, message_id, message.id, custom_values, uid) + email_from, email_to, message_id, mail_message.id, custom_values, uid) route = self.message_route_verify(cr, uid, message, message_dict, - (message.model, message.res_id, custom_values, uid, None), + (mail_message.model, mail_message.res_id, custom_values, uid, None), update_author=True, assert_model=True, create_fallback=True, context=context) return route and [route] or [] -- cgit v1.2.3