summaryrefslogtreecommitdiff
path: root/addons/mail/models/mail_message.py
diff options
context:
space:
mode:
Diffstat (limited to 'addons/mail/models/mail_message.py')
-rw-r--r--addons/mail/models/mail_message.py127
1 files changed, 85 insertions, 42 deletions
diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py
index 95fc750066b..e1fc850d433 100644
--- a/addons/mail/models/mail_message.py
+++ b/addons/mail/models/mail_message.py
@@ -393,8 +393,8 @@ class Message(models.Model):
customer_email_data.append((partner_tree[notification.res_partner_id.id][0], partner_tree[notification.res_partner_id.id][1], notification.email_status))
has_access_to_model = message.model and self.env[message.model].check_access_rights('read', raise_exception=False)
- if message.attachment_ids:
- main_attachment = has_access_to_model and message.res_id and self.env[message.model].search([('id', '=', message.res_id)]) and getattr(self.env[message.model].browse(message.res_id), 'message_main_attachment_id')
+ if message.attachment_ids and message.res_id and issubclass(self.pool[message.model], self.pool['mail.thread']) and has_access_to_model:
+ main_attachment = self.env[message.model].browse(message.res_id).message_main_attachment_id
attachment_ids = []
for attachment in message.attachment_ids:
if attachment.id in attachments_tree:
@@ -860,6 +860,55 @@ class Message(models.Model):
author_ids = [mid for mid, message in message_values.items()
if not self.is_thread_message(message)]
+ # Moderator condition: allow to WRITE, UNLINK if moderator of a pending message
+ moderator_ids = []
+ if operation in ['write', 'unlink']:
+ moderator_ids = [mid for mid, message in message_values.items() if message.get('moderator_id')]
+ messages_to_check = self.ids
+ messages_to_check = set(messages_to_check).difference(set(author_ids), set(moderator_ids))
+ if not messages_to_check:
+ return
+
+ # Recipients condition, for read and write (partner_ids)
+ # keep on top, usefull for systray notifications
+ notified_ids = []
+ model_record_ids = _generate_model_record_ids(message_values, messages_to_check)
+ if operation in ['read', 'write']:
+ notified_ids = [mid for mid, message in message_values.items() if message.get('notified')]
+
+ messages_to_check = set(messages_to_check).difference(set(notified_ids))
+ if not messages_to_check:
+ return
+
+ # CRUD: Access rights related to the document
+ document_related_ids = []
+ document_related_candidate_ids = [mid for mid, message in message_values.items()
+ if (message.get('model') and message.get('res_id') and
+ message.get('message_type') != 'user_notification' and
+ (message.get('moderation_status') != 'pending_moderation' or operation not in ['write', 'unlink']))]
+ model_record_ids = _generate_model_record_ids(message_values, document_related_candidate_ids)
+ for model, doc_ids in model_record_ids.items():
+ DocumentModel = self.env[model]
+ if hasattr(DocumentModel, 'get_mail_message_access'):
+ check_operation = DocumentModel.get_mail_message_access(doc_ids, operation) ## why not giving model here?
+ else:
+ check_operation = self.env['mail.thread'].get_mail_message_access(doc_ids, operation, model_name=model)
+ records = DocumentModel.browse(doc_ids)
+ records.check_access_rights(check_operation)
+ mids = records.browse(doc_ids)._filter_access_rules(check_operation)
+ document_related_ids += [
+ mid for mid, message in message_values.items()
+ if (message.get('model') == model and
+ message.get('res_id') in mids.ids and
+ message.get('message_type') != 'user_notification' and
+ (message.get('moderation_status') != 'pending_moderation' or
+ operation not in ['write', 'unlink']))]
+
+ messages_to_check = messages_to_check.difference(set(document_related_ids))
+
+ if not messages_to_check:
+ return
+
# Parent condition, for create (check for received notifications for the created message parent)
notified_ids = []
if operation == 'create':
@@ -880,17 +929,12 @@ class Message(models.Model):
notified_ids += [mid for mid, message in message_values.items()
if message.get('parent_id') in not_parent_ids]
- # Moderator condition: allow to WRITE, UNLINK if moderator of a pending message
- moderator_ids = []
- if operation in ['write', 'unlink']:
- moderator_ids = [mid for mid, message in message_values.items() if message.get('moderator_id')]
+ messages_to_check = messages_to_check.difference(set(notified_ids))
+ if not messages_to_check:
+ return
- # Recipients condition, for read and write (partner_ids) and create (message_follower_ids)
- other_ids = set(self.ids).difference(set(author_ids), set(notified_ids), set(moderator_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.items() if message.get('notified')]
- elif operation == 'create':
+ # Recipients condition for create (message_follower_ids)
+ if operation == 'create':
for doc_model, doc_ids in model_record_ids.items():
followers = self.env['mail.followers'].sudo().search([
('res_model', '=', doc_model),
@@ -904,28 +948,11 @@ class Message(models.Model):
message.get('message_type') != 'user_notification'
]
- # CRUD: Access rights related to the document
- other_ids = other_ids.difference(set(notified_ids))
- model_record_ids = _generate_model_record_ids(message_values, other_ids)
- document_related_ids = []
- for model, doc_ids in model_record_ids.items():
- DocumentModel = self.env[model]
- mids = DocumentModel.browse(doc_ids).exists()
- if hasattr(DocumentModel, 'check_mail_message_access'):
- DocumentModel.check_mail_message_access(mids.ids, operation) # ?? mids ?
- else:
- self.env['mail.thread'].check_mail_message_access(mids.ids, operation, model_name=model)
- document_related_ids += [
- mid for mid, message in message_values.items()
- if (message.get('model') == model and
- message.get('res_id') in mids.ids and
- message.get('message_type') != 'user_notification' and
- (message.get('moderation_status') != 'pending_moderation' or
- operation not in ['write', 'unlink']))]
+ messages_to_check = messages_to_check.difference(set(notified_ids))
+ if not messages_to_check:
+ return
- # Calculate remaining ids: if not void, raise an error
- other_ids = other_ids.difference(set(document_related_ids))
- if not (other_ids and self.browse(other_ids).exists()):
+ if not self.browse(messages_to_check).exists():
return
raise AccessError(
_('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') %
@@ -966,17 +993,19 @@ class Message(models.Model):
return message_id
@api.multi
- def _invalidate_documents(self):
+ def _invalidate_documents(self, model=None, res_id=None):
""" Invalidate the cache of the documents followed by ``self``. """
for record in self:
- if record.is_thread_message() and 'message_ids' in self.env[record.model]:
- self.env[record.model].invalidate_cache(fnames=[
+ model = model or record.model
+ res_id = res_id or record.res_id
+ if 'message_ids' in self.env[model]:
+ self.env[model].invalidate_cache(fnames=[
'message_ids',
'message_unread',
'message_unread_counter',
'message_needaction',
'message_needaction_counter',
- ], ids=[record.res_id])
+ ], ids=[res_id])
@api.model
def create(self, values):
@@ -994,8 +1023,7 @@ class Message(models.Model):
values['record_name'] = self._get_record_name(values)
if 'attachment_ids' not in values:
- values.setdefault('attachment_ids', [])
-
+ values['attachment_ids'] = []
# extract base64 images
if 'body' in values:
Attachments = self.env['ir.attachment']
@@ -1021,8 +1049,21 @@ class Message(models.Model):
tracking_values_cmd = values.pop('tracking_value_ids', False)
message = super(Message, self).create(values)
+ # check attachement access
if values.get('attachment_ids'):
- message.attachment_ids.check(mode='read')
+ attachment_ids = []
+ if all(isinstance(command, int) or command[0] in (4, 6) for command in values.get('attachment_ids')):
+ attachment_ids = []
+ for command in values.get('attachment_ids'):
+ if isinstance(command, int):
+ attachment_ids += [command]
+ elif command[0] == 6:
+ attachment_ids += command[2]
+ else: # command[0] == 4:
+ attachment_ids += [command[1]]
+ else:
+ attachment_ids = message.mapped('attachment_ids').ids # fallback on read if any unknow command
+ self.env['ir.attachment'].browse(attachment_ids).check(mode='read')
if tracking_values_cmd:
vals_lst = [dict(cmd[2], mail_message_id=message.id) for cmd in tracking_values_cmd if len(cmd) == 3 and cmd[0] == 0]
@@ -1033,7 +1074,7 @@ class Message(models.Model):
message.sudo().write({'tracking_value_ids': tracking_values_cmd})
if message.is_thread_message(values):
- message._invalidate_documents()
+ message._invalidate_documents(values.get('model'), values.get('res_id'))
return message
@@ -1067,7 +1108,9 @@ class Message(models.Model):
self.mapped('attachment_ids').filtered(
lambda attach: attach.res_model == self._name and (attach.res_id in self.ids or attach.res_id == 0)
).unlink()
- self._invalidate_documents()
+ for elem in self:
+ if elem.is_thread_message():
+ elem._invalidate_documents()
return super(Message, self).unlink()
# --------------------------------------------------