diff options
| author | Christophe Simonis <chs@odoo.com> | 2017-11-09 19:16:05 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2017-11-09 19:16:05 +0100 |
| commit | de93645fe3c85883d2f08677afad51456815fa6e (patch) | |
| tree | 618ad9d3144a272e082aee1fc4b824f97a13a59f /addons/mail | |
| parent | acd26691eef2930b03c2d3fb228110a1a6cc5f12 (diff) | |
| parent | 82add438f21085a799f1d2d86a44d523c4fd2690 (diff) | |
[MERGE] forward port branch saas-16 up to 82add438f21
Diffstat (limited to 'addons/mail')
| -rw-r--r-- | addons/mail/controllers/bus.py | 10 | ||||
| -rw-r--r-- | addons/mail/models/mail_activity.py | 53 | ||||
| -rw-r--r-- | addons/mail/models/mail_alias.py | 21 | ||||
| -rw-r--r-- | addons/mail/models/mail_message.py | 37 | ||||
| -rw-r--r-- | addons/mail/models/mail_thread.py | 7 | ||||
| -rw-r--r-- | addons/mail/models/res_partner.py | 2 | ||||
| -rw-r--r-- | addons/mail/security/ir.model.access.csv | 12 | ||||
| -rw-r--r-- | addons/mail/security/mail_security.xml | 11 |
8 files changed, 112 insertions, 41 deletions
diff --git a/addons/mail/controllers/bus.py b/addons/mail/controllers/bus.py index 2c6d4b835b2..50f08d8d8de 100644 --- a/addons/mail/controllers/bus.py +++ b/addons/mail/controllers/bus.py @@ -36,21 +36,19 @@ class MailChatController(BusController): # -------------------------- @route('/mail/chat_post', type="json", auth="none") def mail_chat_post(self, uuid, message_content, **kwargs): - request_uid = self._default_request_uid() # find the author from the user session, which can be None author_id = False # message_post accept 'False' author_id, but not 'None' if request.session.uid: author_id = request.env['res.users'].sudo().browse(request.session.uid).partner_id.id # post a message without adding followers to the channel. email_from=False avoid to get author from email data - mail_channel = request.env["mail.channel"].sudo(request_uid).search([('uuid', '=', uuid)], limit=1) - message = mail_channel.sudo(request_uid).with_context(mail_create_nosubscribe=True).message_post(author_id=author_id, email_from=False, body=message_content, message_type='comment', subtype='mail.mt_comment', content_subtype='plaintext', **kwargs) + mail_channel = request.env["mail.channel"].sudo().search([('uuid', '=', uuid)], limit=1) + message = mail_channel.sudo().with_context(mail_create_nosubscribe=True).message_post(author_id=author_id, email_from=False, body=message_content, message_type='comment', subtype='mail.mt_comment', content_subtype='plaintext') return message and message.id or False @route(['/mail/chat_history'], type="json", auth="none") def mail_chat_history(self, uuid, last_id=False, limit=20): - request_uid = self._default_request_uid() - channel = request.env["mail.channel"].sudo(request_uid).search([('uuid', '=', uuid)], limit=1) + channel = request.env["mail.channel"].sudo().search([('uuid', '=', uuid)], limit=1) if not channel: return [] else: - return channel.sudo(request_uid).channel_fetch_message(last_id, limit) + return channel.channel_fetch_message(last_id, limit) diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py index 1e7c0729ba4..6ed049833d5 100644 --- a/addons/mail/models/mail_activity.py +++ b/addons/mail/models/mail_activity.py @@ -3,7 +3,7 @@ from datetime import date, datetime, timedelta -from odoo import api, fields, models +from odoo import api, exceptions, fields, models, _ class MailActivityType(models.Model): @@ -134,21 +134,61 @@ class MailActivity(models.Model): def _onchange_recommended_activity_type_id(self): self.activity_type_id = self.recommended_activity_type_id + @api.multi + def _check_access(self, operation): + """ Rule to access activities + + * create: check write rights on related document; + * write: rule OR write rights on document; + * unlink: rule OR write rights on document; + """ + self.check_access_rights(operation, raise_exception=True) # will raise an AccessError + + if operation in ('write', 'unlink'): + try: + self.check_access_rule(operation) + except exceptions.AccessError: + pass + else: + return + + doc_operation = 'read' if operation == 'read' else 'write' + activity_to_documents = dict() + for activity in self.sudo(): + activity_to_documents.setdefault(activity.res_model, list()).append(activity.res_id) + for model, res_ids in activity_to_documents.items(): + self.env[model].check_access_rights(doc_operation, raise_exception=True) + try: + self.env[model].browse(res_ids).check_access_rule(doc_operation) + except exceptions.AccessError: + raise exceptions.AccessError( + _('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') % + (self._description, operation)) + @api.model def create(self, values): - activity = super(MailActivity, self).create(values) - self.env[activity.res_model].browse(activity.res_id).message_subscribe(partner_ids=[activity.user_id.partner_id.id]) + # already compute default values to be sure those are computed using the current user + values_w_defaults = self.default_get(self._fields.keys()) + values_w_defaults.update(values) + + # continue as sudo because activities are somewhat protected + activity = super(MailActivity, self.sudo()).create(values_w_defaults) + activity_user = activity.sudo(self.env.user) + activity_user._check_access('create') + self.env[activity_user.res_model].browse(activity_user.res_id).message_subscribe(partner_ids=[activity_user.user_id.partner_id.id]) if activity.date_deadline <= fields.Date.today(): self.env['bus.bus'].sendone( (self._cr.dbname, 'res.partner', activity.user_id.partner_id.id), {'type': 'activity_updated', 'activity_created': True}) - return activity + return activity_user @api.multi def write(self, values): + self._check_access('write') if values.get('user_id'): pre_responsibles = self.mapped('user_id.partner_id') - res = super(MailActivity, self).write(values) + res = super(MailActivity, self.sudo()).write(values) + if values.get('user_id'): for activity in self: self.env[activity.res_model].browse(activity.res_id).message_subscribe(partner_ids=[activity.user_id.partner_id.id]) @@ -166,12 +206,13 @@ class MailActivity(models.Model): @api.multi def unlink(self): + self._check_access('unlink') for activity in self: if activity.date_deadline <= fields.Date.today(): self.env['bus.bus'].sendone( (self._cr.dbname, 'res.partner', activity.user_id.partner_id.id), {'type': 'activity_updated', 'activity_deleted': True}) - return super(MailActivity, self).unlink() + return super(MailActivity, self.sudo()).unlink() @api.multi def action_done(self): diff --git a/addons/mail/models/mail_alias.py b/addons/mail/models/mail_alias.py index 8bd0b8f19c9..dc09f3be13b 100644 --- a/addons/mail/models/mail_alias.py +++ b/addons/mail/models/mail_alias.py @@ -264,16 +264,27 @@ class AliasMixin(models.AbstractModel): record._name, record.display_name, record.id) def _alias_check_contact(self, message, message_dict, alias): + """ Main mixin method that inheriting models may inherit in order + to implement a specifc behavior. """ + return self._alias_check_contact_on_record(self, message, message_dict, alias) + + def _alias_check_contact_on_record(self, record, message, message_dict, alias): + """ Generic method that takes a record not necessarily inheriting from + mail.alias.mixin. """ author = self.env['res.partner'].browse(message_dict.get('author_id', False)) - if alias.alias_contact == 'followers' and self.ids: - if not hasattr(self, "message_partner_ids") or not hasattr(self, "message_channel_ids"): + if alias.alias_contact == 'followers': + if not record.ids: + return { + 'error_message': _('incorrectly configured alias (unknown reference record)'), + } + if not hasattr(record, "message_partner_ids") or not hasattr(record, "message_channel_ids"): return { - 'error_mesage': _('incorrectly configured alias'), + 'error_message': _('incorrectly configured alias'), } - accepted_partner_ids = self.message_partner_ids | self.message_channel_ids.mapped('channel_partner_ids') + accepted_partner_ids = record.message_partner_ids | record.message_channel_ids.mapped('channel_partner_ids') if not author or author not in accepted_partner_ids: return { - 'error_mesage': _('restricted to followers'), + 'error_message': _('restricted to followers'), } elif alias.alias_contact == 'partners' and not author: return { diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index 47918de4966..86168bf6049 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -97,6 +97,7 @@ class Message(models.Model): tracking_value_ids = fields.One2many( 'mail.tracking.value', 'mail_message_id', string='Tracking values', + groups="base.group_no_one", help='Tracked values are stored in a separate model. This field allow to reconstruct ' 'the tracking and to generate statistics on the model.') # mail gateway @@ -280,8 +281,8 @@ class Message(models.Model): # 1. Aggregate partners (author_id and partner_ids), attachments and tracking values partners = self.env['res.partner'].sudo() attachments = self.env['ir.attachment'] - trackings = self.env['mail.tracking.value'] - for key, message in message_tree.items(): + message_ids = list(message_tree.keys()) + for message in message_tree.values(): if message.author_id: partners |= message.author_id if message.subtype_id and message.partner_ids: # take notified people of message with a subtype @@ -292,8 +293,6 @@ class Message(models.Model): partners |= message.needaction_partner_ids if message.attachment_ids: attachments |= message.attachment_ids - if message.tracking_value_ids: - trackings |= message.tracking_value_ids # Read partners as SUPERUSER -> message being browsed as SUPERUSER it is already the case partners_names = partners.name_get() partner_tree = dict((partner[0], partner) for partner in partners_names) @@ -308,13 +307,18 @@ class Message(models.Model): }) for attachment in attachments_data) # 3. Tracking values - tracking_tree = dict((tracking.id, { - 'id': tracking.id, - 'changed_field': tracking.field_desc, - 'old_value': tracking.get_old_display_value()[0], - 'new_value': tracking.get_new_display_value()[0], - 'field_type': tracking.field_type, - }) for tracking in trackings) + tracking_values = self.env['mail.tracking.value'].sudo().search([('mail_message_id', 'in', message_ids)]) + message_to_tracking = dict() + tracking_tree = dict.fromkeys(tracking_values.ids, False) + for tracking in tracking_values: + message_to_tracking.setdefault(tracking.mail_message_id.id, list()).append(tracking.id) + tracking_tree[tracking.id] = { + 'id': tracking.id, + 'changed_field': tracking.field_desc, + 'old_value': tracking.get_old_display_value()[0], + 'new_value': tracking.get_new_display_value()[0], + 'field_type': tracking.field_type, + } # 4. Update message dictionaries for message_dict in messages: @@ -341,9 +345,9 @@ class Message(models.Model): if attachment.id in attachments_tree: attachment_ids.append(attachments_tree[attachment.id]) tracking_value_ids = [] - for tracking_value in message.tracking_value_ids: - if tracking_value.id in tracking_tree: - tracking_value_ids.append(tracking_tree[tracking_value.id]) + for tracking_value_id in message_to_tracking.get(message_id, list()): + if tracking_value_id in tracking_tree: + tracking_value_ids.append(tracking_tree[tracking_value_id]) message_dict.update({ 'author_id': author, @@ -746,7 +750,12 @@ class Message(models.Model): return '%s%s alt="%s"' % (data_to_url[key], match.group(3), name) values['body'] = _image_dataurl.sub(base64_to_boundary, tools.ustr(values['body'])) + # delegate creation of tracking after the create as sudo to avoid access rights issues + tracking_values_cmd = values.pop('tracking_value_ids', False) message = super(Message, self).create(values) + if tracking_values_cmd: + message.sudo().write({'tracking_value_ids': tracking_values_cmd}) + message._invalidate_documents() if not self.env.context.get('message_create_from_mail_mail'): diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 1d7d9681ea1..b681e18d284 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -958,9 +958,10 @@ class MailThread(models.AbstractModel): obj = self.env[alias.alias_parent_model_id.model].browse(alias.alias_parent_thread_id) elif model: obj = self.env[model] - if not hasattr(obj, '_alias_check_contact'): - obj = self.env['mail.alias.mixin'] - check_result = obj._alias_check_contact(message, message_dict, alias) + if hasattr(obj, '_alias_check_contact'): + check_result = obj._alias_check_contact(message, message_dict, alias) + else: + check_result = self.env['mail.alias.mixin']._alias_check_contact_on_record(obj, message, message_dict, alias) if check_result is not True: self._routing_warn(_('alias %s: %s') % (alias.alias_name, check_result.get('error_message', _('unknown error'))), _('skipping'), message_id, route, False) self._routing_create_bounce_email(email_from, check_result.get('error_template', _generic_bounce_body_html), message) diff --git a/addons/mail/models/res_partner.py b/addons/mail/models/res_partner.py index 3a81423a9b2..6114adcce7b 100644 --- a/addons/mail/models/res_partner.py +++ b/addons/mail/models/res_partner.py @@ -62,7 +62,7 @@ class Partner(models.Model): record_name = message.record_name tracking = [] - for tracking_value in message.tracking_value_ids: + for tracking_value in self.env['mail.tracking.value'].sudo().search([('mail_message_id', '=', message.id)]): tracking.append((tracking_value.field_desc, tracking_value.get_old_display_value()[0], tracking_value.get_new_display_value()[0])) diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv index 99f811a3634..0a2e9713c4f 100644 --- a/addons/mail/security/ir.model.access.csv +++ b/addons/mail/security/ir.model.access.csv @@ -23,9 +23,9 @@ access_mail_alias_user,mail.alias.user,model_mail_alias,base.group_user,1,1,1,1 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_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
+access_mail_tracking_value_all,mail.tracking.value.all,model_mail_tracking_value,,0,0,0,0
+access_mail_tracking_value_portal,mail.tracking.value.portal,model_mail_tracking_value,base.group_portal,0,0,0,0
+access_mail_tracking_value_user,mail.tracking.value.user,model_mail_tracking_value,base.group_user,0,0,0,0
access_mail_tracking_value_system,mail.tracking.value.system,model_mail_tracking_value,base.group_system,1,1,1,1
access_mail_thread_all,mail.thread.all,model_mail_thread,,1,1,1,1
access_publisher_warranty_contract_all,publisher.warranty.contract.all,model_publisher_warranty_contract,,1,1,1,1
@@ -36,7 +36,7 @@ access_mail_shortcode_portal,mail.shortcode.portal,model_mail_shortcode,base.gro access_mail_test_user,mail.test.all,model_mail_test,base.group_user,1,1,1,1
access_mail_test_portal,mail.test.all,model_mail_test,base.group_portal,1,1,0,0
access_mail_test_simple,mail.test.simple.all,model_mail_test_simple,base.group_user,1,1,1,1
-access_mail_activity_all,mail.activity.all,model_mail_activity,,1,0,0,0
+access_mail_activity_all,mail.activity.all,model_mail_activity,,0,0,0,0
access_mail_activity_user,mail.activity.user,model_mail_activity,base.group_user,1,1,1,1
-access_mail_activity_type_all,mail.activity.type.all,model_mail_activity_type,,1,0,0,0
-access_mail_activity_type_user,mail.activity.type.user,model_mail_activity_type,base.group_user,1,1,1,1
\ No newline at end of file +access_mail_activity_type_all,mail.activity.type.all,model_mail_activity_type,,0,0,0,0
+access_mail_activity_type_user,mail.activity.type.user,model_mail_activity_type,base.group_user,1,1,1,1
diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml index d5a5b5422c9..b9b13d9de3b 100644 --- a/addons/mail/security/mail_security.xml +++ b/addons/mail/security/mail_security.xml @@ -40,5 +40,16 @@ <field name="groups" eval="[(4, ref('base.group_portal')), (4, ref('base.group_public'))]"/> </record> + <record id="mail_activity_rule_user" model="ir.rule"> + <field name="name">mail.activity: user: own only</field> + <field name="model_id" ref="model_mail_activity"/> + <field name="domain_force">[('user_id', '=', user.id)]</field> + <field name="groups" eval="[(4, ref('base.group_user'))]"/> + <field name="perm_create" eval="False"/> + <field name="perm_read" eval="False"/> + <field name="perm_write" eval="True"/> + <field name="perm_unlink" eval="True"/> + </record> + </data> </odoo> |
