From e1ed2c6ddc6750a2090ee37badfaeccadd765b9b Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 25 Apr 2016 14:01:01 +0200 Subject: [PATCH] [FIX] mail: visibility rules for channel notifications Avoid raising an access denied error for messages that the user has indeed be notified about. The issue arose when a message posted on a document inaccessible to the user was notified to one of the channels the user is subscribed to. The access control logic on messages relies on 2 heuristics to grant read access to a message: a. either the user was notified about the messages, by being a follower of the document, or a subscriber of a channel following the document (in that case the user can see the message but not the document) b. or the user has read access to the document on which the message is posted (in that case the user can see both the message and the document) Case `a.` sometimes fail to match when a message got notified to several channels including one the user was not subscribed to. Depending on the order of the returned rows in the SQL query, the "foreign" channels could shadow the channels of the user, making `a.` a non-match. If case `b.` did not match either, the user would have the `read` access denied, even though the message was visible by the `search()` method. The fix explicitly makes case `a.` match if the user was notified in *at least* one channel. This was not done through a change of the SQL query ORDER, for readability reasons. --- addons/mail/models/mail_message.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index fe7d6d88448..f86ba64ce7e 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -741,7 +741,13 @@ class Message(models.Model): ON channel_partner.channel_id = channel.id AND channel_partner.partner_id = (%%s) WHERE m.id = ANY (%%s)""" % self._table, (self.env.user.partner_id.id, self.env.user.partner_id.id, self.ids,)) for mid, rmod, rid, author_id, parent_id, partner_id, channel_id in self._cr.fetchall(): - message_values[mid] = {'model': rmod, 'res_id': rid, 'author_id': author_id, 'parent_id': parent_id, 'partner_id': partner_id, 'channel_id': channel_id} + message_values[mid] = { + 'model': rmod, + 'res_id': rid, + 'author_id': author_id, + 'parent_id': parent_id, + 'notified': any((message_values[mid].get('notified'), partner_id, channel_id)) + } else: self._cr.execute("""SELECT DISTINCT id, model, res_id, author_id, parent_id FROM "%s" WHERE id = ANY (%%s)""" % self._table, (self.ids,)) for mid, rmod, rid, author_id, parent_id in self._cr.fetchall(): @@ -780,7 +786,7 @@ class Message(models.Model): other_ids = set(self.ids).difference(set(author_ids), set(notified_ids)) model_record_ids = _generate_model_record_ids(message_values, other_ids) if operation in ['read', 'write']: - notified_ids = [mid for mid, message in message_values.iteritems() if message.get('partner_id') or message.get('channel_id')] + notified_ids = [mid for mid, message in message_values.iteritems() if message.get('notified')] elif operation == 'create': for doc_model, doc_ids in model_record_ids.items(): followers = self.env['mail.followers'].sudo().search([