mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-20 19:12:06 +02:00
19.0 vanilla
This commit is contained in:
parent
d1963a3c3a
commit
2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions
|
|
@ -1,94 +1,121 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import _, models, SUPERUSER_ID
|
||||
from odoo.exceptions import AccessError, MissingError, UserError
|
||||
from odoo.tools import consteq
|
||||
import contextlib
|
||||
|
||||
from odoo import _, models, fields, api
|
||||
from odoo.exceptions import AccessError, UserError
|
||||
from odoo.tools.misc import limited_field_access_token, verify_limited_field_access_token
|
||||
from odoo.addons.mail.tools.discuss import Store
|
||||
|
||||
|
||||
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)
|
||||
thumbnail = fields.Image()
|
||||
has_thumbnail = fields.Boolean(compute="_compute_has_thumbnail")
|
||||
|
||||
@api.depends("thumbnail")
|
||||
def _compute_has_thumbnail(self):
|
||||
for attachment in self.with_context(bin_size=True):
|
||||
attachment.has_thumbnail = bool(attachment.thumbnail)
|
||||
|
||||
def _has_attachments_ownership(self, attachment_tokens):
|
||||
""" Checks if the current user has ownership of all attachments in the recordset.
|
||||
Ownership is defined as either:
|
||||
- Having 'write' access to the attachment.
|
||||
- Providing a valid, scoped 'attachment_ownership' access token.
|
||||
|
||||
:param list attachment_tokens: A list of access tokens
|
||||
"""
|
||||
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):
|
||||
def is_owned(attachment, token):
|
||||
if not attachment.exists():
|
||||
return False
|
||||
if attachment.sudo(False).has_access("write"):
|
||||
return True
|
||||
return token and verify_limited_field_access_token(
|
||||
attachment, "id", token, scope="attachment_ownership"
|
||||
)
|
||||
|
||||
return all(is_owned(att, tok) for att, tok in zip(self, attachment_tokens, strict=True))
|
||||
|
||||
def _post_add_create(self, **kwargs):
|
||||
""" Overrides behaviour when the attachment is created through the controller
|
||||
"""
|
||||
super(IrAttachment, self)._post_add_create()
|
||||
for record in self:
|
||||
record.register_as_main_attachment(force=False)
|
||||
super()._post_add_create(**kwargs)
|
||||
self.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.
|
||||
"""
|
||||
self.ensure_one()
|
||||
if not self.res_model:
|
||||
return
|
||||
related_record = self.env[self.res_model].browse(self.res_id)
|
||||
if not related_record.check_access_rights('write', raise_exception=False):
|
||||
return
|
||||
# message_main_attachment_id field can be empty, that's why we compare to False;
|
||||
# we are just checking that it exists on the model before writing it
|
||||
if related_record and hasattr(related_record, 'message_main_attachment_id'):
|
||||
if force or not related_record.message_main_attachment_id:
|
||||
#Ignore AccessError, if you don't have access to modify the document
|
||||
#Just don't set the value
|
||||
try:
|
||||
related_record.message_main_attachment_id = self
|
||||
except AccessError:
|
||||
pass
|
||||
|
||||
def _delete_and_notify(self):
|
||||
:param bool force: if set, the method always updates the existing main attachment
|
||||
otherwise it only sets the main attachment if there is none.
|
||||
"""
|
||||
todo = self.filtered(lambda a: a.res_model and a.res_id)
|
||||
if not todo:
|
||||
return
|
||||
|
||||
for model, attachments in todo.grouped("res_model").items():
|
||||
related_records = self.env[model].browse(attachments.mapped("res_id"))
|
||||
if not hasattr(related_records, '_message_set_main_attachment_id'):
|
||||
return
|
||||
|
||||
# this action is generic; if user cannot update record do not crash
|
||||
# just skip update
|
||||
for related_record, attachment in zip(related_records, attachments):
|
||||
with contextlib.suppress(AccessError):
|
||||
related_record._message_set_main_attachment_id(attachment, force=force)
|
||||
|
||||
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
|
||||
for attachment in self:
|
||||
if attachment.res_model == 'mail.channel' and attachment.res_id:
|
||||
target = self.env['mail.channel'].browse(attachment.res_id)
|
||||
else:
|
||||
target = self.env.user.partner_id
|
||||
self.env['bus.bus']._sendone(target, 'ir.attachment/delete', {
|
||||
'id': attachment.id,
|
||||
})
|
||||
attachment._bus_send(
|
||||
"ir.attachment/delete",
|
||||
{
|
||||
"id": attachment.id,
|
||||
"message": (
|
||||
{"id": message.id, "write_date": message.write_date} if message else None
|
||||
),
|
||||
},
|
||||
)
|
||||
self.unlink()
|
||||
|
||||
def _attachment_format(self, legacy=False):
|
||||
res_list = []
|
||||
for attachment in self:
|
||||
res = {
|
||||
'checksum': attachment.checksum,
|
||||
'id': attachment.id,
|
||||
'filename': attachment.name,
|
||||
'name': attachment.name,
|
||||
'mimetype': attachment.mimetype,
|
||||
'type': attachment.type,
|
||||
'url': attachment.url,
|
||||
}
|
||||
if not legacy:
|
||||
res['originThread'] = [('insert', {
|
||||
'id': attachment.res_id,
|
||||
'model': attachment.res_model,
|
||||
})]
|
||||
else:
|
||||
res.update({
|
||||
'res_id': attachment.res_id,
|
||||
'res_model': attachment.res_model,
|
||||
})
|
||||
res_list.append(res)
|
||||
return res_list
|
||||
def _get_store_ownership_fields(self):
|
||||
return [Store.Attr("ownership_token", lambda a: a._get_ownership_token())]
|
||||
|
||||
def _to_store_defaults(self, target):
|
||||
return [
|
||||
"checksum",
|
||||
"create_date",
|
||||
"file_size",
|
||||
"has_thumbnail",
|
||||
"mimetype",
|
||||
"name",
|
||||
Store.Attr("raw_access_token", lambda a: a._get_raw_access_token()),
|
||||
"res_name",
|
||||
"res_model",
|
||||
Store.One("thread", [], as_thread=True),
|
||||
Store.Attr("thumbnail_access_token", lambda a: a._get_thumbnail_token()),
|
||||
"type",
|
||||
"url",
|
||||
]
|
||||
|
||||
def _get_ownership_token(self):
|
||||
""" Returns a scoped limited access token that indicates ownership of the attachment when
|
||||
using _has_attachments_ownership. If verified by verify_limited_field_access_token,
|
||||
accessing the attachment bypasses the ACLs.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
self.ensure_one()
|
||||
return limited_field_access_token(self, field_name="id", scope="attachment_ownership")
|
||||
|
||||
def _get_thumbnail_token(self):
|
||||
self.ensure_one()
|
||||
return limited_field_access_token(self, "thumbnail", scope="binary")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue