92 lines
4.3 KiB
Python
92 lines
4.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import contextlib
|
|
|
|
from odoo import _, api, models, SUPERUSER_ID
|
|
from odoo.exceptions import AccessError, MissingError, UserError
|
|
from odoo.http import request
|
|
from odoo.tools import consteq
|
|
|
|
|
|
class IrAttachment(models.Model):
|
|
_inherit = 'ir.attachment'
|
|
|
|
def _check_attachments_access(self, attachment_tokens):
|
|
"""This method relies on access rules/rights and therefore it should not be called from a sudo env."""
|
|
self = self.sudo(False)
|
|
attachment_tokens = attachment_tokens or ([None] * len(self))
|
|
if len(attachment_tokens) != len(self):
|
|
raise UserError(_("An access token must be provided for each attachment."))
|
|
for attachment, access_token in zip(self, attachment_tokens):
|
|
try:
|
|
attachment_sudo = attachment.with_user(SUPERUSER_ID).exists()
|
|
if not attachment_sudo:
|
|
raise MissingError(_("The attachment %s does not exist.", attachment.id))
|
|
try:
|
|
attachment.check('write')
|
|
except AccessError:
|
|
if not access_token or not attachment_sudo.access_token or not consteq(attachment_sudo.access_token, access_token):
|
|
message_sudo = self.env['mail.message'].sudo().search([('attachment_ids', 'in', attachment_sudo.ids)], limit=1)
|
|
if not message_sudo or not message_sudo.is_current_user_or_guest_author:
|
|
raise
|
|
except (AccessError, MissingError):
|
|
raise UserError(_("The attachment %s does not exist or you do not have the rights to access it.", attachment.id))
|
|
|
|
def _post_add_create(self, **kwargs):
|
|
""" Overrides behaviour when the attachment is created through the controller
|
|
"""
|
|
super(IrAttachment, self)._post_add_create(**kwargs)
|
|
for record in self:
|
|
record.register_as_main_attachment(force=False)
|
|
|
|
def register_as_main_attachment(self, force=True):
|
|
""" Registers this attachment as the main one of the model it is
|
|
attached to.
|
|
|
|
:param bool force: if set, the method always updates the existing main attachment
|
|
otherwise it only sets the main attachment if there is none.
|
|
"""
|
|
self.ensure_one()
|
|
if not self.res_model or not self.res_id:
|
|
return
|
|
related_record = self.env[self.res_model].browse(self.res_id)
|
|
if not related_record or \
|
|
not related_record.check_access_rights('write', raise_exception=False) or \
|
|
not hasattr(related_record, 'message_main_attachment_id'):
|
|
return
|
|
|
|
if force or not related_record.message_main_attachment_id:
|
|
with contextlib.suppress(AccessError):
|
|
related_record.message_main_attachment_id = self
|
|
|
|
def _delete_and_notify(self, message=None):
|
|
if message:
|
|
# sudo: mail.message - safe write just updating the date, because guests don't have the rights
|
|
message.sudo().write({}) # to make sure write_date on the message is updated
|
|
self.env['bus.bus']._sendmany((attachment._bus_notification_target(), 'ir.attachment/delete', {
|
|
'id': attachment.id, 'message': {'id': message.id, 'write_date': message.write_date} if message else None
|
|
}) for attachment in self)
|
|
self.unlink()
|
|
|
|
def _bus_notification_target(self):
|
|
self.ensure_one()
|
|
return self.env.user.partner_id
|
|
|
|
def _attachment_format(self):
|
|
safari = request and request.httprequest.user_agent and request.httprequest.user_agent.browser == 'safari'
|
|
return [{
|
|
'checksum': attachment.checksum,
|
|
'create_date': attachment.create_date,
|
|
'id': attachment.id,
|
|
'filename': attachment.name,
|
|
'name': attachment.name,
|
|
"size": attachment.file_size,
|
|
'res_name': attachment.res_name,
|
|
'mimetype': 'application/octet-stream' if safari and attachment.mimetype and 'video' in attachment.mimetype else attachment.mimetype,
|
|
'originThread': [('ADD', {
|
|
'id': attachment.res_id,
|
|
'model': attachment.res_model,
|
|
})],
|
|
} for attachment in self]
|