From 20536e1bbeb641539c0de44364f8376e7cef651b Mon Sep 17 00:00:00 2001 From: "Anh Thao Pham (pta)" <pta@odoo.com> Date: Thu, 11 Feb 2021 09:40:00 +0000 Subject: [PATCH] [FIX] mail: prevent use of private addresses for followers, recipients,... - Connect with Admin - Go to Contacts, edit himself by adding a Private Address - Create an Internal User without "Access to Private Addresses" right (i.e. User X) - Go to any app implementing chatter (i.e. Sales) - Create a SO - Add the created Private Address as follower - Make sure User X can access the record (i.e. Sales: Administrator) - Connect with User X and open the SO An Access Error is raised while trying to fetch data about the followers. This commit prevents to: - add a private address as follower of a record - add a private address as Recipient in full composer - propose private addresses when adding a mention to a partner opw-2428936 closes odoo/odoo#65933 Task-id: 2463622 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com> --- addons/mail/models/mail_followers.py | 2 +- addons/mail/models/mail_thread.py | 4 ++-- addons/mail/models/res_partner.py | 2 +- addons/mail/wizard/invite.py | 3 ++- addons/mail/wizard/mail_compose_message.py | 3 ++- addons/test_mail/tests/test_mail_followers.py | 15 +++++++++++++++ 6 files changed, 23 insertions(+), 6 deletions(-) diff --git a/addons/mail/models/mail_followers.py b/addons/mail/models/mail_followers.py index 8995de70acf8..e584b87dd109 100644 --- a/addons/mail/models/mail_followers.py +++ b/addons/mail/models/mail_followers.py @@ -29,7 +29,7 @@ class Followers(models.Model): res_id = fields.Many2oneReference( 'Related Document ID', index=True, help='Id of the followed resource', model_field='res_model') partner_id = fields.Many2one( - 'res.partner', string='Related Partner', ondelete='cascade', index=True) + 'res.partner', string='Related Partner', ondelete='cascade', index=True, domain=[('type', '!=', 'private')]) channel_id = fields.Many2one( 'mail.channel', string='Listener', ondelete='cascade', index=True) subtype_ids = fields.Many2many( diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 8c27eed77034..4c85ef530441 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -2666,9 +2666,9 @@ class MailThread(models.AbstractModel): self.check_access_rights('write') self.check_access_rule('write') - # filter inactive + # filter inactive and private addresses if partner_ids and not adding_current: - partner_ids = self.env['res.partner'].sudo().search([('id', 'in', partner_ids), ('active', '=', True)]).ids + partner_ids = self.env['res.partner'].sudo().search([('id', 'in', partner_ids), ('active', '=', True), ('type', '!=', 'private')]).ids return self._message_subscribe(partner_ids, channel_ids, subtype_ids, customer_ids=customer_ids) diff --git a/addons/mail/models/res_partner.py b/addons/mail/models/res_partner.py index ce1fcb35a239..08b948059d4e 100644 --- a/addons/mail/models/res_partner.py +++ b/addons/mail/models/res_partner.py @@ -130,7 +130,7 @@ class Partner(models.Model): If channel_id is given, only members of this channel are returned. """ search_dom = expression.OR([[('name', 'ilike', search)], [('email', 'ilike', search)]]) - search_dom = expression.AND([[('active', '=', True)], search_dom]) + search_dom = expression.AND([[('active', '=', True), ('type', '!=', 'private')], search_dom]) if channel_id: search_dom = expression.AND([[('channel_ids', 'in', channel_id)], search_dom]) diff --git a/addons/mail/wizard/invite.py b/addons/mail/wizard/invite.py index 610b1a0dd3e5..8b6a2de8342d 100644 --- a/addons/mail/wizard/invite.py +++ b/addons/mail/wizard/invite.py @@ -41,7 +41,8 @@ class Invite(models.TransientModel): res_model = fields.Char('Related Document Model', required=True, index=True, help='Model of the followed resource') res_id = fields.Integer('Related Document ID', index=True, help='Id of the followed resource') - partner_ids = fields.Many2many('res.partner', string='Recipients', help="List of partners that will be added as follower of the current document.") + partner_ids = fields.Many2many('res.partner', string='Recipients', help="List of partners that will be added as follower of the current document.", + domain=[('type', '!=', 'private')]) channel_ids = fields.Many2many('mail.channel', string='Channels', help='List of channels that will be added as listeners of the current document.', domain=[('channel_type', '=', 'channel')]) message = fields.Html('Message') diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index a75cc2a1367c..b71a6fe8a74b 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -131,7 +131,8 @@ class MailComposer(models.TransientModel): help='Whether the message is an internal note (comment mode only)') partner_ids = fields.Many2many( 'res.partner', 'mail_compose_message_res_partner_rel', - 'wizard_id', 'partner_id', 'Additional Contacts') + 'wizard_id', 'partner_id', 'Additional Contacts', + domain=[('type', '!=', 'private')]) # mass mode options notify = fields.Boolean('Notify followers', help='Notify followers of the document (mass post only)') auto_delete = fields.Boolean('Delete Emails', diff --git a/addons/test_mail/tests/test_mail_followers.py b/addons/test_mail/tests/test_mail_followers.py index 739c210d3e36..9246073aa976 100644 --- a/addons/test_mail/tests/test_mail_followers.py +++ b/addons/test_mail/tests/test_mail_followers.py @@ -174,6 +174,21 @@ class BaseFollowersTest(TestMailCommon): self.assertEqual(document.message_partner_ids, self.partner_portal, 'No active test: customer not visible') self.assertEqual(document.message_follower_ids.partner_id, self.partner_portal | customer) + @users('employee') + def test_followers_private_address(self): + """ Test standard API does not subscribe private addresses """ + private_address = self.env['res.partner'].sudo().create({ + 'name': 'Private Address', + 'type': 'private', + }) + document = self.env['mail.test.simple'].browse(self.test_record.id) + document.message_subscribe(partner_ids=(self.partner_portal | private_address).ids) + self.assertEqual(document.message_follower_ids.partner_id, self.partner_portal) + + # works through low-level API + document._message_subscribe(partner_ids=(self.partner_portal | private_address).ids) + self.assertEqual(document.message_follower_ids.partner_id, self.partner_portal | private_address) + @tagged('mail_followers') class AdvancedFollowersTest(TestMailCommon): -- GitLab