From 857db1f4f4c3e0144ecfb4a6e521791bc6892382 Mon Sep 17 00:00:00 2001 From: Samy Mostafa Shaawat Date: Sat, 17 Oct 2026 19:26:52 +0300 Subject: [PATCH] [FIX] fs_attachment: serve the thumbnail of an attachment, not its parent file _get_fs_attachment_for_field returned the attachment itself for any field, including the ones stored in their own attachment like the thumbnail. --- fs_attachment/models/ir_binary.py | 10 +++++-- fs_attachment/tests/test_fs_attachment.py | 33 +++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/fs_attachment/models/ir_binary.py b/fs_attachment/models/ir_binary.py index b2e187913d..8fd9e0bc17 100644 --- a/fs_attachment/models/ir_binary.py +++ b/fs_attachment/models/ir_binary.py @@ -19,9 +19,15 @@ class IrBinary(models.AbstractModel): _inherit = "ir.binary" def _get_fs_attachment_for_field(self, record, field_name): - if record._name == "ir.attachment" and record.fs_filename: - return record field_def = record._fields.get(field_name) + # a field stored in its own attachment (ex: thumbnail) is not the file of + # the attachment itself + if ( + record._name == "ir.attachment" + and record.fs_filename + and not (field_def and field_def.attachment) + ): + return record if field_def: record._check_field_access(field_def, "read") if field_def.attachment and field_def.store: diff --git a/fs_attachment/tests/test_fs_attachment.py b/fs_attachment/tests/test_fs_attachment.py index 42dd4cd734..45bd169829 100644 --- a/fs_attachment/tests/test_fs_attachment.py +++ b/fs_attachment/tests/test_fs_attachment.py @@ -1,5 +1,6 @@ # Copyright 2023 ACSONE SA/NV (http://acsone.eu). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +import copy import os from pathlib import Path from unittest import mock @@ -568,3 +569,35 @@ def test_store_in_db_instead_of_object_storage_domain(self): ] ), ) + + def test_get_fs_attachment_for_field_stored_in_attachment(self): + """A field stored in its own attachment (ex: the thumbnail added by mail) + must not be replaced by the file of the parent attachment""" + parent = ( + self.env["ir.attachment"] + .with_context(storage_location=self.temp_backend.code) + .create({"name": "doc.pdf", "raw": b"parent"}) + ) + thumbnail = ( + self.env["ir.attachment"] + .with_context(storage_location=self.temp_backend.code) + .create( + { + "name": "thumbnail", + "raw": b"thumbnail", + "res_model": "ir.attachment", + "res_id": parent.id, + "res_field": "thumbnail", + } + ) + ) + field = copy.copy(parent._fields["raw"]) + field.attachment = True + field.store = True + ir_binary = self.env["ir.binary"] + fields_with_thumbnail = {**parent._fields, "thumbnail": field} + with mock.patch.object(type(parent), "_fields", fields_with_thumbnail): + self.assertEqual( + ir_binary._get_fs_attachment_for_field(parent, "thumbnail"), thumbnail + ) + self.assertEqual(ir_binary._get_fs_attachment_for_field(parent, "raw"), parent)