From 9cd9aaaa174ae1f2a0af12143a34eb4682ea6f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 25 Jun 2015 13:30:49 +0200 Subject: [PATCH] [IMP] mail: new internal-only subtype feature. Starting from now, subtypes can be internal. This means that only employees (group_user members) can see the messages with this subtype. This feature replaces and enhances the 'log a note = no subtype = internal only' feature. Public and portal users cannot see internal messages. This allows to have subtypes and a follow mechanism that works for employees and is not visible for external people. Its first use will be for Crm Activities, allowing to have custom subtypes visible only for salesman and not send to the customer. --- addons/mail/data/mail_data.xml | 6 +++++ addons/mail/models/mail_message.py | 20 ++++++++++++----- addons/mail/models/mail_message_subtype.py | 7 +++++- addons/mail/models/mail_thread.py | 22 ++++++++++++++----- addons/mail/security/ir.model.access.csv | 2 +- addons/mail/security/mail_security.xml | 7 ++++++ addons/mail/static/src/js/mail.js | 15 +++++++++---- addons/mail/static/src/xml/mail.xml | 10 ++++++++- addons/mail/tests/test_mail_followers.py | 2 +- addons/mail/tests/test_message_track.py | 3 ++- .../mail/views/mail_message_subtype_views.xml | 1 + addons/portal/tests/test_portal.py | 2 +- 12 files changed, 77 insertions(+), 20 deletions(-) diff --git a/addons/mail/data/mail_data.xml b/addons/mail/data/mail_data.xml index 8b4c4ddcc65..8afde76abfd 100644 --- a/addons/mail/data/mail_data.xml +++ b/addons/mail/data/mail_data.xml @@ -68,5 +68,11 @@ Discussions + + Note + + + + diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index 7e191f9517d..44c0e254776 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -541,7 +541,7 @@ class Message(models.Model): count=count, access_rights_uid=access_rights_uid) # Non-employee see only messages with a subtype (aka, no internal logs) if not self.env['res.users'].has_group('base.group_user'): - args = ['&', ('subtype_id', '!=', False)] + list(args) + args = ['&', '&', ('subtype_id', '!=', False), ('subtype_id.internal', '=', False)] + list(args) # Perform a super with count as False, to have the ids, not a counter ids = super(Message, self)._search( args, offset=offset, limit=limit, order=order, @@ -620,7 +620,11 @@ class Message(models.Model): return # Non employees see only messages with a subtype (aka, not internal logs) if not self.env['res.users'].has_group('base.group_user'): - self._cr.execute('SELECT DISTINCT id FROM "%s" WHERE message_type = %%s AND subtype_id IS NULL AND id = ANY (%%s)' % (self._table), ('comment', self.ids,)) + self._cr.execute('''SELECT DISTINCT message.id, message.subtype_id, subtype.internal + FROM "%s" AS message + LEFT JOIN "mail_message_subtype" as subtype + ON message.subtype_id = subtype.id + WHERE message.message_type = %%s AND (message.subtype_id IS NULL OR subtype.internal IS TRUE) AND message.id = ANY (%%s)''' % (self._table), ('comment', self.ids,)) if self._cr.fetchall(): raise AccessError( _('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') % @@ -783,10 +787,16 @@ class Message(models.Model): self.ensure_one() # tde: not sure, just for testinh, will see partners_to_notify = self.env['res.partner'] - # all followers of the mail.message document have to be added as partners and notified if a subtype is defined (otherwise: log message) + # all followers of the mail.message document have to be added as partners and notified + # and filter to employees only if the subtype is internal if self.subtype_id and self.model and self.res_id: - followers = self.env['mail.followers'].sudo().search([('res_model', '=', self.model), ('res_id', '=', self.res_id)]) - partners_to_notify |= followers.filtered(lambda fol: self.subtype_id in fol.subtype_ids).mapped('partner_id') + followers = self.env['mail.followers'].sudo().search([ + ('res_model', '=', self.model), + ('res_id', '=', self.res_id) + ]).filtered(lambda fol: self.subtype_id in fol.subtype_ids) + if self.subtype_id.internal: + followers.filtered(lambda fol: fol.partner_id.user_ids and fol.partner_id.user_ids[0].has_group('base.group_user')) + partners_to_notify |= followers.mapped('partner_id') # remove me from notified partners, unless the message is written on my own wall if self.subtype_id and self.author_id and self.model == "res.partner" and self.res_id == self.author_id.id: diff --git a/addons/mail/models/mail_message_subtype.py b/addons/mail/models/mail_message_subtype.py index 26faa0a3e12..83d3f082159 100644 --- a/addons/mail/models/mail_message_subtype.py +++ b/addons/mail/models/mail_message_subtype.py @@ -22,9 +22,14 @@ class MailMessageSubtype(models.Model): 'Description', translate=True, help='Description that will be added in the message posted for this ' 'subtype. If void, the name will be added instead.') + internal = fields.Boolean( + 'Internal Only', + help='Messages with internal subtypes will be visible only by employees, aka members of base_user group') parent_id = fields.Many2one( 'mail.message.subtype', string='Parent', ondelete='set null', - help='Parent subtype, used for automatic subscription.') + help='Parent subtype, used for automatic subscription. This field is not' + 'correctly named. For example on a project, project subtypes have' + 'parent_id to task-related subtypes.') relation_field = fields.Char( 'Relation field', help='Field used to link the related model to the subtype model when ' diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 5b9755cafc8..a91b7c18768 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -336,8 +336,17 @@ class MailThread(models.AbstractModel): if view_type == 'form': doc = etree.XML(res['arch']) for node in doc.xpath("//field[@name='message_ids']"): + # the 'Log a note' button is employee only options = json.loads(node.get('options', '{}')) - options['display_log_button'] = self.env.user.sudo().has_group('base.group_user') + is_employee = self.env.user.has_group('base.group_user') + options['display_log_button'] = is_employee + if is_employee: + Subtype = self.env['mail.message.subtype'].sudo() + # fetch internal subtypes + internal_subtypes = Subtype.search_read([ + ('res_model', 'in', [False, self._name]), + ('internal', '=', True)], ['name', 'description', 'sequence']) + options['internal_subtypes'] = internal_subtypes node.set('options', json.dumps(options)) res['arch'] = etree.tostring(doc) return res @@ -1552,8 +1561,9 @@ class MailThread(models.AbstractModel): attachments, kwargs.pop('attachment_ids', []), model, self.ids and self.ids[0] or None) # 4: mail.message.subtype - subtype_id = False - if subtype: + subtype_id = kwargs.get('subtype_id', False) + if not subtype_id: + subtype = subtype or 'mt_note' if '.' not in subtype: subtype = 'mail.%s' % subtype subtype_id = self.env['ir.model.data'].xmlid_to_res_id(subtype) @@ -1607,8 +1617,10 @@ class MailThread(models.AbstractModel): # Post-process: subscribe author, update message_last_post if model and model != 'mail.thread' and self.ids and subtype_id: - # done with SUPERUSER_ID, because on some models users can post only with read access, not necessarily write access - self.sudo().write({'message_last_post': fields.datetime.now()}) + subtype_rec = self.env['mail.message.subtype'].sudo().browse(subtype_id) + if not subtype_rec.internal: + # done with SUPERUSER_ID, because on some models users can post only with read access, not necessarily write access + self.sudo().write({'message_last_post': fields.Datetime.now()}) if new_message.author_id and model and self.ids and message_type != 'notification' and not self._context.get('mail_create_nosubscribe'): self.message_subscribe([new_message.author_id.id]) return new_message diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv index c8f90dcaeac..c66045d6fe8 100644 --- a/addons/mail/security/ir.model.access.csv +++ b/addons/mail/security/ir.model.access.csv @@ -20,7 +20,7 @@ access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0 access_mail_alias_user,mail.alias.user,model_mail_alias,base.group_user,1,1,1,0 access_mail_alias_system,mail.alias.system,model_mail_alias,base.group_system,1,1,1,1 access_mail_message_subtype_all,mail.message.subtype.all,model_mail_message_subtype,,1,0,0,0 -access_mail_message_subtype_system,mail.message.subtype.system,model_mail_message_subtype,base.group_system,1,1,1,1 +access_mail_message_subtype_user,mail.message.subtype.user,model_mail_message_subtype,,1,1,1,1 access_mail_tracking_value_all,mail.tracking.value.all,model_mail_tracking_value,,1,0,0,0 access_mail_tracking_value_portal,mail.tracking.value.portal,model_mail_tracking_value,base.group_portal,1,1,1,1 access_mail_tracking_value_user,mail.tracking.value.user,model_mail_tracking_value,base.group_user,1,1,1,1 diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml index 5384e2aba95..2f07c659c95 100644 --- a/addons/mail/security/mail_security.xml +++ b/addons/mail/security/mail_security.xml @@ -38,6 +38,13 @@ + + mail.message.subtype: portal/public: read public subtypes + + [('internal', '=', False)] + + +