From 3a8bc4122451ba7d3f65667434baca5581182b2d Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Thu, 21 May 2026 13:26:27 +0200 Subject: [PATCH 01/26] [IMP] storage_file: add search by public/private --- storage_file/models/storage_file.py | 21 +++++++++ storage_file/tests/__init__.py | 1 + storage_file/tests/test_is_public.py | 59 ++++++++++++++++++++++++ storage_file/views/storage_file_view.xml | 13 ++++++ 4 files changed, 94 insertions(+) create mode 100644 storage_file/tests/test_is_public.py diff --git a/storage_file/models/storage_file.py b/storage_file/models/storage_file.py index f7f23614ec..12d05469ea 100644 --- a/storage_file/models/storage_file.py +++ b/storage_file/models/storage_file.py @@ -65,6 +65,27 @@ class StorageFile(models.Model): "res.company", "Company", default=lambda self: self.env.user.company_id.id ) file_type = fields.Selection([]) + is_public = fields.Boolean( + compute="_compute_is_public", + compute_sudo=True, + search="_search_is_public", + # Not stored to avoid massive recomputes when the backend flag changes. + help="Reflects the `is_public` flag of the related backend.", + ) + + @api.depends("backend_id.is_public") + def _compute_is_public(self): + for rec in self: + rec.is_public = rec.backend_id.is_public + + def _search_is_public(self, operator, value): + # Look up matching backends with sudo so that users with limited ACL + # on `storage.backend` can still filter their accessible files by + # public flag. + backends = ( + self.env["storage.backend"].sudo().search([("is_public", operator, value)]) + ) + return [("backend_id", "in", backends.ids)] _sql_constraints = [ ( diff --git a/storage_file/tests/__init__.py b/storage_file/tests/__init__.py index cdf4f78fa1..3aa707d6d8 100644 --- a/storage_file/tests/__init__.py +++ b/storage_file/tests/__init__.py @@ -1,2 +1,3 @@ from . import test_storage_file from . import test_swap_backend +from . import test_is_public diff --git a/storage_file/tests/test_is_public.py b/storage_file/tests/test_is_public.py new file mode 100644 index 0000000000..7f93df7163 --- /dev/null +++ b/storage_file/tests/test_is_public.py @@ -0,0 +1,59 @@ +# Copyright 2026 Camptocamp SA +# @author Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo.addons.component.tests.common import TransactionComponentCase + + +class TestStorageFileIsPublic(TransactionComponentCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.backend = cls.env["storage.backend"].create( + {"name": "Test backend", "backend_type": "filesystem"} + ) + cls.storage_file = cls.env["storage.file"].create( + { + "name": "test-public.txt", + "backend_id": cls.backend.id, + "data": b"aGVsbG8=", # "hello" base64 + } + ) + + def test_reflects_backend_flag(self): + self.assertFalse(self.storage_file.is_public) + self.backend.is_public = True + self.assertTrue(self.storage_file.is_public) + + def test_search_true(self): + self.backend.is_public = True + result = self.env["storage.file"].search( + [("is_public", "=", True), ("id", "=", self.storage_file.id)] + ) + self.assertIn(self.storage_file, result) + + def test_search_false(self): + self.backend.is_public = False + result = self.env["storage.file"].search( + [("is_public", "=", False), ("id", "=", self.storage_file.id)] + ) + self.assertIn(self.storage_file, result) + + def test_search_with_two_backends(self): + public_backend = self.env["storage.backend"].create( + { + "name": "Public backend", + "backend_type": "filesystem", + "is_public": True, + } + ) + public_file = self.env["storage.file"].create( + { + "name": "public.txt", + "backend_id": public_backend.id, + "data": b"aGVsbG8=", + } + ) + result = self.env["storage.file"].search([("is_public", "=", True)]) + self.assertIn(public_file, result) + self.assertNotIn(self.storage_file, result) diff --git a/storage_file/views/storage_file_view.xml b/storage_file/views/storage_file_view.xml index 7405b367b8..200cbc9532 100644 --- a/storage_file/views/storage_file_view.xml +++ b/storage_file/views/storage_file_view.xml @@ -8,6 +8,7 @@ + @@ -29,6 +30,7 @@ + @@ -42,6 +44,17 @@ + + + From 363ad50b1fc2d273a47123b40ade09b8ced5774e Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Thu, 21 May 2026 13:27:15 +0200 Subject: [PATCH 02/26] [IMP] storage_image: add search by public/private --- .../models/storage_image_relation_abstract.py | 1 + storage_image/tests/__init__.py | 1 + storage_image/tests/test_is_public.py | 25 +++++++++++++++++++ storage_image/views/storage_image.xml | 12 +++++++++ 4 files changed, 39 insertions(+) create mode 100644 storage_image/tests/test_is_public.py diff --git a/storage_image/models/storage_image_relation_abstract.py b/storage_image/models/storage_image_relation_abstract.py index 0c6272227f..838f625130 100644 --- a/storage_image/models/storage_image_relation_abstract.py +++ b/storage_image/models/storage_image_relation_abstract.py @@ -23,3 +23,4 @@ class ImageRelationAbstract(models.AbstractModel): image_name = fields.Char(related="image_id.name") image_alt_name = fields.Char(related="image_id.alt_name") image_url = fields.Char(related="image_id.image_medium_url") + is_public = fields.Boolean(related="image_id.file_id.is_public", readonly=True) diff --git a/storage_image/tests/__init__.py b/storage_image/tests/__init__.py index cedd944b24..fbe7e719dc 100644 --- a/storage_image/tests/__init__.py +++ b/storage_image/tests/__init__.py @@ -2,3 +2,4 @@ from . import test_storage_image from . import test_storage_replace_file from . import test_swap_backend +from . import test_is_public diff --git a/storage_image/tests/test_is_public.py b/storage_image/tests/test_is_public.py new file mode 100644 index 0000000000..27938492d7 --- /dev/null +++ b/storage_image/tests/test_is_public.py @@ -0,0 +1,25 @@ +# Copyright 2026 Camptocamp SA +# @author Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from .common import StorageImageCommonCase + + +class TestStorageImageIsPublic(StorageImageCommonCase): + def setUp(self): + super().setUp() + self.storage_image = self._create_storage_image_from_file( + "static/akretion-logo.png" + ) + + def test_is_public_reflects_backend(self): + self.assertFalse(self.storage_image.is_public) + self.backend.sudo().is_public = True + self.assertTrue(self.storage_image.is_public) + + def test_is_public_search(self): + self.backend.sudo().is_public = True + result = self.env["storage.image"].search( + [("is_public", "=", True), ("id", "=", self.storage_image.id)] + ) + self.assertEqual(self.storage_image, result) diff --git a/storage_image/views/storage_image.xml b/storage_image/views/storage_image.xml index f05dda0e0b..da685998cc 100644 --- a/storage_image/views/storage_image.xml +++ b/storage_image/views/storage_image.xml @@ -8,6 +8,7 @@ + @@ -86,6 +87,17 @@ + + + From 588bafa278a50023b5c29e2744635dd0adf2c91a Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Thu, 21 May 2026 13:27:34 +0200 Subject: [PATCH 03/26] [IMP] storage_media: add search by public/private --- storage_media/tests/__init__.py | 1 + storage_media/tests/test_is_public.py | 28 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 storage_media/tests/test_is_public.py diff --git a/storage_media/tests/__init__.py b/storage_media/tests/__init__.py index 3a133375d2..1c48fb926f 100644 --- a/storage_media/tests/__init__.py +++ b/storage_media/tests/__init__.py @@ -1,3 +1,4 @@ from . import test_storage_media from . import test_storage_replace_file from . import test_swap_backend +from . import test_is_public diff --git a/storage_media/tests/test_is_public.py b/storage_media/tests/test_is_public.py new file mode 100644 index 0000000000..5a210f1c73 --- /dev/null +++ b/storage_media/tests/test_is_public.py @@ -0,0 +1,28 @@ +# Copyright 2026 Camptocamp SA +# @author Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo.addons.component.tests.common import TransactionComponentCase + + +class TestStorageMediaIsPublic(TransactionComponentCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.backend = cls.env.ref("storage_backend.default_storage_backend") + cls.media = cls.env["storage.media"].create( + {"name": "test-media.txt", "backend_id": cls.backend.id} + ) + + def test_is_public_reflects_backend(self): + self.backend.sudo().is_public = False + self.assertFalse(self.media.is_public) + self.backend.sudo().is_public = True + self.assertTrue(self.media.is_public) + + def test_is_public_search(self): + self.backend.sudo().is_public = True + result = self.env["storage.media"].search( + [("is_public", "=", True), ("id", "=", self.media.id)] + ) + self.assertEqual(self.media, result) From 12982785311007c4da4c195bb362304e0a6b6e03 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Sun, 24 May 2026 12:37:52 +0200 Subject: [PATCH 04/26] [IMP] storage_media_product: show is_public --- storage_media_product/models/product.py | 1 + storage_media_product/views/product.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/storage_media_product/models/product.py b/storage_media_product/models/product.py index 12832b70af..2b3ffb4e18 100644 --- a/storage_media_product/models/product.py +++ b/storage_media_product/models/product.py @@ -65,6 +65,7 @@ class ProductMediaRelation(models.Model): url = fields.Char(related="media_id.url", readonly=True) url_path = fields.Char(related="media_id.url_path", readonly=True) media_type_id = fields.Many2one(related="media_id.media_type_id", readonly=True) + is_public = fields.Boolean(related="media_id.file_id.is_public", readonly=True) @api.depends("media_id", "product_tmpl_id.attribute_line_ids.value_ids") def _compute_available_attribute(self): diff --git a/storage_media_product/views/product.xml b/storage_media_product/views/product.xml index 66095eb3ea..c76587a3eb 100644 --- a/storage_media_product/views/product.xml +++ b/storage_media_product/views/product.xml @@ -26,6 +26,7 @@ widget="many2many_tags" invisible="not available_attribute_value_ids" /> + From 9635392ad29070df666e807d0441da42268cab18 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Wed, 27 May 2026 16:13:24 +0200 Subject: [PATCH 05/26] [IMP] storage_file: make is_public visible all the times --- storage_file/views/storage_backend_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage_file/views/storage_backend_view.xml b/storage_file/views/storage_backend_view.xml index 219cd3fc84..f1d6f2e14e 100644 --- a/storage_file/views/storage_backend_view.xml +++ b/storage_file/views/storage_backend_view.xml @@ -15,7 +15,7 @@
Make sure this parameter is properly configured and accessible from everwhere you want to access the service. - + From a15e667b9cbdb9096636d2fbc5465f3a7f031744 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Thu, 28 May 2026 09:50:04 +0200 Subject: [PATCH 06/26] [IMP] storage_file: allow viewing external files via Odoo For the case of private files stored externally it might be necessary to view the file via Odoo directly because you can avoid to setup a private CDN with complex authentication (eg: token, vpn, etc). In this way, the files can be proxied by the controller. --- storage_file/controllers/main.py | 11 ++ storage_file/models/storage_backend.py | 5 +- storage_file/security/ir.model.access.csv | 1 + storage_file/security/storage_file.xml | 11 ++ storage_file/tests/__init__.py | 1 + storage_file/tests/test_controller.py | 156 ++++++++++++++++++++ storage_file/tests/test_storage_file.py | 11 ++ storage_file/views/storage_backend_view.xml | 10 ++ 8 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 storage_file/tests/test_controller.py diff --git a/storage_file/controllers/main.py b/storage_file/controllers/main.py index c2b29b44da..365b6b4682 100644 --- a/storage_file/controllers/main.py +++ b/storage_file/controllers/main.py @@ -1,7 +1,9 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from werkzeug.exceptions import NotFound from odoo import http +from odoo.exceptions import AccessError from odoo.http import request @@ -13,6 +15,15 @@ def content_common(self, slug_name_with_id, token=None, download=None, **kw): storage_file = request.env["storage.file"].get_from_slug_name_with_id( slug_name_with_id ) + if not storage_file.exists(): + raise NotFound() + try: + storage_file.check_access("read") + except AccessError as err: + # If you don't have access you should not know + # that the file exists (as anon user). + # You can inspect the traceback to see it's coming from an access error. + raise NotFound() from err stream = request.env["ir.binary"]._get_stream_from( storage_file, field_name="data" ) diff --git a/storage_file/models/storage_backend.py b/storage_file/models/storage_backend.py index c3a273a157..e011180b1b 100644 --- a/storage_file/models/storage_backend.py +++ b/storage_file/models/storage_backend.py @@ -145,7 +145,10 @@ def _get_base_url_from_param(self): def _get_url_for_file(self, storage_file, exclude_base_url=False): """Return final full URL for given file.""" backend = self.sudo() - if backend.served_by == "odoo": + # Make sure that no matter if you have a CDN URL or not, + # you can always access the file via Odoo. + force_serve_via_odoo = backend.served_by == "external" and not backend.base_url + if backend.served_by == "odoo" or force_serve_via_odoo: parts = [ self._get_base_url_from_param() if not exclude_base_url else "/", "storage.file", diff --git a/storage_file/security/ir.model.access.csv b/storage_file/security/ir.model.access.csv index 4532fee45a..dce3e6034e 100644 --- a/storage_file/security/ir.model.access.csv +++ b/storage_file/security/ir.model.access.csv @@ -1,5 +1,6 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_storage_file_edit,storage_file edit,model_storage_file,base.group_system,1,1,1,1 access_storage_file_read_public,storage_file public read,model_storage_file,base.group_user,1,0,0,0 +access_storage_file_read_portal,storage_file portal read,model_storage_file,base.group_public,1,0,0,0 access_storage_file_replace,storage_file_replace public,model_storage_file_replace,base.group_user,1,1,1,1 access_storage_file_swap_backend,storage_file_swap_backend admin,model_storage_file_swap_backend,base.group_system,1,1,1,1 diff --git a/storage_file/security/storage_file.xml b/storage_file/security/storage_file.xml index 2510d3defb..bb09998341 100644 --- a/storage_file/security/storage_file.xml +++ b/storage_file/security/storage_file.xml @@ -13,4 +13,15 @@ + + + Storage file internal read all + + + [(1, '=', 1)] + + + + + diff --git a/storage_file/tests/__init__.py b/storage_file/tests/__init__.py index 3aa707d6d8..e20c8f1eea 100644 --- a/storage_file/tests/__init__.py +++ b/storage_file/tests/__init__.py @@ -1,3 +1,4 @@ from . import test_storage_file from . import test_swap_backend from . import test_is_public +from . import test_controller diff --git a/storage_file/tests/test_controller.py b/storage_file/tests/test_controller.py new file mode 100644 index 0000000000..511d987f54 --- /dev/null +++ b/storage_file/tests/test_controller.py @@ -0,0 +1,156 @@ +# Copyright 2026 Camptocamp SA +# @author Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +import base64 + +from odoo.tests.common import HttpCase, tagged + + +@tagged("-at_install", "post_install") +class TestStorageFileController(HttpCase): + """Test the /storage.file/ controller with public/private and odoo/external.""" + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.data = b"Hello, storage!" + cls.filedata = base64.b64encode(cls.data) + cls.backend_odoo_public = cls.env["storage.backend"].create( + { + "name": "Odoo Public", + "backend_type": "filesystem", + "served_by": "odoo", + "is_public": True, + "filename_strategy": "name_with_id", + } + ) + cls.backend_odoo_private = cls.env["storage.backend"].create( + { + "name": "Odoo Private", + "backend_type": "filesystem", + "served_by": "odoo", + "is_public": False, + "filename_strategy": "name_with_id", + } + ) + cls.backend_ext_public = cls.env["storage.backend"].create( + { + "name": "Ext Public (no CDN)", + "backend_type": "filesystem", + "served_by": "external", + "base_url": "", + "is_public": True, + "filename_strategy": "name_with_id", + } + ) + cls.backend_ext_private = cls.env["storage.backend"].create( + { + "name": "Ext Private (no CDN)", + "backend_type": "filesystem", + "served_by": "external", + "base_url": "", + "is_public": False, + "filename_strategy": "name_with_id", + } + ) + cls.file_odoo_public = cls.env["storage.file"].create( + { + "name": "pub-odoo.txt", + "backend_id": cls.backend_odoo_public.id, + "data": cls.filedata, + } + ) + cls.file_odoo_private = cls.env["storage.file"].create( + { + "name": "priv-odoo.txt", + "backend_id": cls.backend_odoo_private.id, + "data": cls.filedata, + } + ) + cls.file_ext_public = cls.env["storage.file"].create( + { + "name": "pub-ext.txt", + "backend_id": cls.backend_ext_public.id, + "data": cls.filedata, + } + ) + cls.file_ext_private = cls.env["storage.file"].create( + { + "name": "priv-ext.txt", + "backend_id": cls.backend_ext_private.id, + "data": cls.filedata, + } + ) + cls.internal_user = ( + cls.env["res.users"] + .with_context(no_reset_password=True) + .create( + { + "name": "Storage Test User", + "login": "storage_test_user", + "password": "storage_test_user", + "groups_id": [ + (4, cls.env.ref("base.group_user").id), + ], + } + ) + ) + + def _url_for(self, storage_file): + return f"/storage.file/{storage_file.slug}" + + # ---- Public user (anonymous) ---- + + def test_public_user_odoo_public(self): + """Public user + public odoo backend -> 200.""" + resp = self.url_open(self._url_for(self.file_odoo_public)) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.content, self.data) + + def test_public_user_odoo_private(self): + """Public user + private odoo backend -> 404.""" + resp = self.url_open(self._url_for(self.file_odoo_private)) + self.assertEqual(resp.status_code, 404) + + def test_public_user_ext_public(self): + """Public user + public external backend (no CDN) -> 200.""" + resp = self.url_open(self._url_for(self.file_ext_public)) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.content, self.data) + + def test_public_user_ext_private(self): + """Public user + private external backend (no CDN) -> 404.""" + resp = self.url_open(self._url_for(self.file_ext_private)) + self.assertEqual(resp.status_code, 404) + + # ---- Internal (authenticated) user ---- + + def test_internal_user_odoo_public(self): + """Internal user + public odoo backend -> 200.""" + self.authenticate("storage_test_user", "storage_test_user") + resp = self.url_open(self._url_for(self.file_odoo_public)) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.content, self.data) + + def test_internal_user_odoo_private(self): + """Internal user + private odoo backend -> 200.""" + self.authenticate("storage_test_user", "storage_test_user") + resp = self.url_open(self._url_for(self.file_odoo_private)) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.content, self.data) + + def test_internal_user_ext_public(self): + """Internal user + public external backend (no CDN) -> 200.""" + self.authenticate("storage_test_user", "storage_test_user") + resp = self.url_open(self._url_for(self.file_ext_public)) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.content, self.data) + + def test_internal_user_ext_private(self): + """Internal user + private external backend (no CDN) -> 200.""" + self.authenticate("storage_test_user", "storage_test_user") + resp = self.url_open(self._url_for(self.file_ext_private)) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.content, self.data) diff --git a/storage_file/tests/test_storage_file.py b/storage_file/tests/test_storage_file.py index fa540cbcf9..919c817e42 100644 --- a/storage_file/tests/test_storage_file.py +++ b/storage_file/tests/test_storage_file.py @@ -110,6 +110,17 @@ def test_url(self): stfile.url, f"https://foo.com/baz/test-of-my_file-{stfile.id}.txt" ) + def test_url_external_no_base_url_falls_back_to_odoo(self): + """External backend w/o base_url uses the internal Odoo route.""" + stfile = self._create_storage_file() + params = self.env["ir.config_parameter"].sudo() + base_url = params.get_param("web.base.url") + stfile.backend_id.update({"served_by": "external", "base_url": ""}) + self.assertEqual( + stfile.url, + f"{base_url}/storage.file/test-of-my_file-{stfile.id}.txt", + ) + def test_url_without_base_url(self): stfile = self._create_storage_file() # served by odoo diff --git a/storage_file/views/storage_backend_view.xml b/storage_file/views/storage_backend_view.xml index f1d6f2e14e..31e4ceb56b 100644 --- a/storage_file/views/storage_backend_view.xml +++ b/storage_file/views/storage_backend_view.xml @@ -17,6 +17,16 @@ + From b29b20842c1c4135c984595e8ca1245d8ab1b104 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Thu, 28 May 2026 12:39:40 +0200 Subject: [PATCH 07/26] [IMP] storage_file: edit backend and pre-load default So far the backend was added only auto-magically on media or image creation. However, this is a partial behavior and since the backend is not editable you cannot decide where to put your file if not via global conf. This chance allows to edit the backend while still pre-loading the default one. --- storage_file/__manifest__.py | 1 + storage_file/data/ir_config_parameter.xml | 7 +++++++ storage_file/models/storage_file.py | 12 ++++++++++- storage_file/tests/test_storage_file.py | 21 +++++++++++++++++++ storage_image/tests/test_storage_image.py | 24 ++++++++++++++++++++++ storage_image/views/storage_image.xml | 1 + storage_media/tests/test_storage_media.py | 20 ++++++++++++++++++ storage_media/views/storage_media_view.xml | 1 + 8 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 storage_file/data/ir_config_parameter.xml diff --git a/storage_file/__manifest__.py b/storage_file/__manifest__.py index 91abd363a5..efdbea4fd9 100644 --- a/storage_file/__manifest__.py +++ b/storage_file/__manifest__.py @@ -23,5 +23,6 @@ "data/ir_cron.xml", "data/storage_backend.xml", "wizards/swap_backend.xml", + "data/ir_config_parameter.xml", ], } diff --git a/storage_file/data/ir_config_parameter.xml b/storage_file/data/ir_config_parameter.xml new file mode 100644 index 0000000000..68dafd61d1 --- /dev/null +++ b/storage_file/data/ir_config_parameter.xml @@ -0,0 +1,7 @@ + + + + storage.file.backend_id + + + diff --git a/storage_file/models/storage_file.py b/storage_file/models/storage_file.py index 12d05469ea..7816fc3122 100644 --- a/storage_file/models/storage_file.py +++ b/storage_file/models/storage_file.py @@ -30,7 +30,11 @@ class StorageFile(models.Model): name = fields.Char(required=True, index=True) backend_id = fields.Many2one( - "storage.backend", "Storage", index=True, required=True + "storage.backend", + "Storage", + index=True, + required=True, + default=lambda self: self._get_default_backend_id(), ) url = fields.Char(compute="_compute_url", help="HTTP accessible path to the file") url_path = fields.Char( @@ -78,6 +82,12 @@ def _compute_is_public(self): for rec in self: rec.is_public = rec.backend_id.is_public + @api.model + def _get_default_backend_id(self): + return self.env["storage.backend"]._get_backend_id_from_param( + self.env, "storage.file.backend_id" + ) + def _search_is_public(self, operator, value): # Look up matching backends with sudo so that users with limited ACL # on `storage.backend` can still filter their accessible files by diff --git a/storage_file/tests/test_storage_file.py b/storage_file/tests/test_storage_file.py index 919c817e42..46a3084d7e 100644 --- a/storage_file/tests/test_storage_file.py +++ b/storage_file/tests/test_storage_file.py @@ -7,6 +7,7 @@ from urllib import parse from odoo.exceptions import AccessError, UserError +from odoo.tests import Form from odoo.addons.component.tests.common import TransactionComponentCase @@ -317,3 +318,23 @@ def test_empty(self): # get_url is called on new records empty = self.env["storage.file"].new({})._get_url() self.assertEqual(empty, "") + + def test_default_backend_id_on_form(self): + """Form pre-fills the default backend for storage.file.""" + form = Form(self.env["storage.file"]) + self.assertEqual(form.backend_id, self.backend) + + def test_default_backend_id_from_param(self): + """storage.file.backend_id param overrides the form default.""" + other_backend = self.env["storage.backend"].create( + { + "name": "Other", + "backend_type": "filesystem", + "filename_strategy": "name_with_id", + } + ) + self.env["ir.config_parameter"].sudo().set_param( + "storage.file.backend_id", str(other_backend.id) + ) + form = Form(self.env["storage.file"]) + self.assertEqual(form.backend_id, other_backend) diff --git a/storage_image/tests/test_storage_image.py b/storage_image/tests/test_storage_image.py index de3f128065..bccce9c4ed 100644 --- a/storage_image/tests/test_storage_image.py +++ b/storage_image/tests/test_storage_image.py @@ -115,3 +115,27 @@ def test_create_thumbnail_pilbox(self): "&w=64&h=64&mode=fill&fmt=webp", urls, ) + + def test_default_backend_id_on_form(self): + """Creating an image without backend_id uses the configured default.""" + image = self._create_storage_image(self.filename, self.filedata) + self.assertEqual(image.backend_id, self.backend) + + def test_default_backend_id_from_param(self): + """storage.image.backend_id param overrides backend on create.""" + other_backend = ( + self.env["storage.backend"] + .sudo() + .create( + { + "name": "Image Backend", + "backend_type": "filesystem", + "filename_strategy": "name_with_id", + } + ) + ) + self.env["ir.config_parameter"].sudo().set_param( + "storage.image.backend_id", str(other_backend.id) + ) + image = self._create_storage_image(self.filename, self.filedata) + self.assertEqual(image.backend_id.id, other_backend.id) diff --git a/storage_image/views/storage_image.xml b/storage_image/views/storage_image.xml index da685998cc..500215d0d3 100644 --- a/storage_image/views/storage_image.xml +++ b/storage_image/views/storage_image.xml @@ -40,6 +40,7 @@ + diff --git a/storage_media/tests/test_storage_media.py b/storage_media/tests/test_storage_media.py index 5d1dc4a123..ccb1e91601 100644 --- a/storage_media/tests/test_storage_media.py +++ b/storage_media/tests/test_storage_media.py @@ -34,3 +34,23 @@ def test_unlink(self): media.unlink() self.assertEqual(stfile.to_delete, True) self.assertEqual(stfile.active, False) + + def test_default_backend_id_on_form(self): + """Creating a media without backend_id uses the configured default.""" + media = self.env["storage.media"].create({"name": "default-test.txt"}) + self.assertEqual(media.backend_id, self.backend) + + def test_default_backend_id_from_param(self): + """storage.media.backend_id param overrides backend on create.""" + other_backend = self.env["storage.backend"].create( + { + "name": "Media Backend", + "backend_type": "filesystem", + "filename_strategy": "name_with_id", + } + ) + self.env["ir.config_parameter"].sudo().set_param( + "storage.media.backend_id", str(other_backend.id) + ) + media = self.env["storage.media"].create({"name": "test.txt"}) + self.assertEqual(media.backend_id.id, other_backend.id) diff --git a/storage_media/views/storage_media_view.xml b/storage_media/views/storage_media_view.xml index 4e47ac99c3..2cfa3d57e6 100644 --- a/storage_media/views/storage_media_view.xml +++ b/storage_media/views/storage_media_view.xml @@ -34,6 +34,7 @@ + From d4959cc89cf9320ddd3951743eddff0e8df09581 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Thu, 28 May 2026 12:40:30 +0200 Subject: [PATCH 08/26] [FIX] storage_file: _get_url returns nothing if no backend is set --- storage_file/models/storage_file.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/storage_file/models/storage_file.py b/storage_file/models/storage_file.py index 7816fc3122..b76c0d05e5 100644 --- a/storage_file/models/storage_file.py +++ b/storage_file/models/storage_file.py @@ -206,6 +206,8 @@ def _get_url(self, exclude_base_url=False): :param exclude_base_url: skip base_url """ + if not self.backend_id or not self.relative_path: + return "" return self.backend_id._get_url_for_file( self, exclude_base_url=exclude_base_url ) From 7b339a53f9e8337eafd3b3afbd2aca333b8322cd Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Thu, 28 May 2026 13:45:22 +0200 Subject: [PATCH 09/26] [FIX] storage_thumbnail: test data Provide data so that the URL is generated properly. --- storage_thumbnail/tests/test_thumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage_thumbnail/tests/test_thumbnail.py b/storage_thumbnail/tests/test_thumbnail.py index 29e17bc3fc..384c3f2a1d 100644 --- a/storage_thumbnail/tests/test_thumbnail.py +++ b/storage_thumbnail/tests/test_thumbnail.py @@ -33,7 +33,7 @@ def check_attrs(self): def _create_thumbnail(self): # create thumbnail - vals = {"name": "TEST THUMB"} + vals = {"name": "TEST THUMB", "data": self.filedata} return self.env["storage.thumbnail"].create(vals) def _create_image(self, resize=False, **kw): From 71ccf1b16c3343ea7e05764db59ed0cf7aea1dee Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Wed, 10 Jun 2026 12:24:00 +0200 Subject: [PATCH 10/26] [IMP] storage_file: allow to group by backend --- storage_file/views/storage_file_view.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/storage_file/views/storage_file_view.xml b/storage_file/views/storage_file_view.xml index 200cbc9532..a922416d1d 100644 --- a/storage_file/views/storage_file_view.xml +++ b/storage_file/views/storage_file_view.xml @@ -55,6 +55,13 @@ name="private" domain="[('is_public', '=', False)]" /> + + + From 5675d61553d2405d7c626175ee08e2169ddc6767 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Wed, 10 Jun 2026 12:25:30 +0200 Subject: [PATCH 11/26] [IMP] storage_image*: improve views * group by backend * search by public/private --- .../models/storage_image_relation_abstract.py | 1 + storage_image/views/storage_image.xml | 8 ++++++++ storage_image_product/views/storage_image.xml | 16 ++++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/storage_image/models/storage_image_relation_abstract.py b/storage_image/models/storage_image_relation_abstract.py index 838f625130..4f0723a5a4 100644 --- a/storage_image/models/storage_image_relation_abstract.py +++ b/storage_image/models/storage_image_relation_abstract.py @@ -24,3 +24,4 @@ class ImageRelationAbstract(models.AbstractModel): image_alt_name = fields.Char(related="image_id.alt_name") image_url = fields.Char(related="image_id.image_medium_url") is_public = fields.Boolean(related="image_id.file_id.is_public", readonly=True) + active = fields.Boolean(related="image_id.active", readonly=True) diff --git a/storage_image/views/storage_image.xml b/storage_image/views/storage_image.xml index 500215d0d3..42338506e2 100644 --- a/storage_image/views/storage_image.xml +++ b/storage_image/views/storage_image.xml @@ -88,6 +88,7 @@ + + + + diff --git a/storage_image_product/views/storage_image.xml b/storage_image_product/views/storage_image.xml index c93cd0fdb2..c3a4cd140f 100644 --- a/storage_image_product/views/storage_image.xml +++ b/storage_image_product/views/storage_image.xml @@ -7,11 +7,17 @@ - + + +
@@ -27,9 +33,15 @@ - + + + From 1c9ae67550a5b74780f93afcf4ebc0690f6e1c4d Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Wed, 10 Jun 2026 12:26:10 +0200 Subject: [PATCH 12/26] [IMP] storage_media*: improve views * group by backend * search by public/privte --- storage_media/views/storage_media_view.xml | 20 ++++++++++++++++++++ storage_media_product/models/product.py | 1 + storage_media_product/views/product.xml | 8 +++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/storage_media/views/storage_media_view.xml b/storage_media/views/storage_media_view.xml index 2cfa3d57e6..20ba7494c6 100644 --- a/storage_media/views/storage_media_view.xml +++ b/storage_media/views/storage_media_view.xml @@ -6,6 +6,7 @@ + @@ -46,8 +47,20 @@ + + + + + + + diff --git a/storage_media_product/models/product.py b/storage_media_product/models/product.py index 2b3ffb4e18..a885f7f80d 100644 --- a/storage_media_product/models/product.py +++ b/storage_media_product/models/product.py @@ -66,6 +66,7 @@ class ProductMediaRelation(models.Model): url_path = fields.Char(related="media_id.url_path", readonly=True) media_type_id = fields.Many2one(related="media_id.media_type_id", readonly=True) is_public = fields.Boolean(related="media_id.file_id.is_public", readonly=True) + active = fields.Boolean(related="media_id.active", readonly=True) @api.depends("media_id", "product_tmpl_id.attribute_line_ids.value_ids") def _compute_available_attribute(self): diff --git a/storage_media_product/views/product.xml b/storage_media_product/views/product.xml index c76587a3eb..d03831bbfa 100644 --- a/storage_media_product/views/product.xml +++ b/storage_media_product/views/product.xml @@ -35,9 +35,15 @@ product.media.relation - + + + From fcb16d8896965b25ed41300d66337585f2a52830 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Wed, 10 Jun 2026 12:47:09 +0200 Subject: [PATCH 13/26] checklog-odoo: ignore warning from assets generation --- checklog-odoo.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/checklog-odoo.cfg b/checklog-odoo.cfg index 0b55b7bf66..ce6fa8d678 100644 --- a/checklog-odoo.cfg +++ b/checklog-odoo.cfg @@ -1,3 +1,4 @@ [checklog-odoo] ignore= WARNING.* 0 failed, 0 error\(s\).* + WARNING.*DeprecationWarning: PyUnicode_FromUnicode\(NULL, size\) is deprecated; use PyUnicode_New\(\) instead From dc54dce02bf20fe10b6ea72ed4eff9392897a6db Mon Sep 17 00:00:00 2001 From: oca-ci Date: Fri, 12 Jun 2026 07:02:28 +0000 Subject: [PATCH 14/26] [UPD] Update storage_file.pot --- storage_file/i18n/storage_file.pot | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/storage_file/i18n/storage_file.pot b/storage_file/i18n/storage_file.pot index 4274550bc2..5078abea17 100644 --- a/storage_file/i18n/storage_file.pot +++ b/storage_file/i18n/storage_file.pot @@ -13,6 +13,15 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" +#. module: storage_file +#: model_terms:ir.ui.view,arch_db:storage_file.storage_backend_view_form +msgid "" +"Note: Without a CDN base URL, files will be proxied\n" +" through Odoo. This is acceptable for internal use with low traffic\n" +" but suboptimal for high-volume public access as every request loads\n" +" the file from the storage backend into memory." +msgstr "" + #. module: storage_file #. odoo-python #: code:addons/storage_file/models/storage_file.py:0 @@ -37,6 +46,11 @@ msgid "" "%s" msgstr "" +#. module: storage_file +#: model_terms:ir.ui.view,arch_db:storage_file.storage_file_view_search +msgid "Backend" +msgstr "" + #. module: storage_file #: model:ir.model.fields,field_description:storage_file.field_storage_backend__backend_view_use_internal_url msgid "Backend View Use Internal Url" @@ -192,6 +206,11 @@ msgstr "" msgid "Files to swap" msgstr "" +#. module: storage_file +#: model_terms:ir.ui.view,arch_db:storage_file.storage_file_view_search +msgid "Group By" +msgstr "" + #. module: storage_file #: model:ir.model.fields,help:storage_file.field_storage_file__internal_url msgid "HTTP URL to load the file directly from storage." @@ -228,6 +247,7 @@ msgstr "" #. module: storage_file #: model:ir.model.fields,field_description:storage_file.field_storage_backend__is_public +#: model:ir.model.fields,field_description:storage_file.field_storage_file__is_public msgid "Is Public" msgstr "" @@ -284,11 +304,26 @@ msgstr "" msgid "Please select at least one file." msgstr "" +#. module: storage_file +#: model_terms:ir.ui.view,arch_db:storage_file.storage_file_view_search +msgid "Private" +msgstr "" + +#. module: storage_file +#: model_terms:ir.ui.view,arch_db:storage_file.storage_file_view_search +msgid "Public" +msgstr "" + #. module: storage_file #: model_terms:ir.ui.view,arch_db:storage_file.storage_backend_view_form msgid "Recompute base URL for files" msgstr "" +#. module: storage_file +#: model:ir.model.fields,help:storage_file.field_storage_file__is_public +msgid "Reflects the `is_public` flag of the related backend." +msgstr "" + #. module: storage_file #: model:ir.model.fields,field_description:storage_file.field_storage_file__relative_path msgid "Relative Path" From ff40a6da1322f1f7e76795fe97d60fe946b0f18b Mon Sep 17 00:00:00 2001 From: oca-ci Date: Fri, 12 Jun 2026 07:02:29 +0000 Subject: [PATCH 15/26] [UPD] Update storage_image.pot --- storage_image/i18n/storage_image.pot | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/storage_image/i18n/storage_image.pot b/storage_image/i18n/storage_image.pot index 8fdd8cf1fe..c8dc2ae4e6 100644 --- a/storage_image/i18n/storage_image.pot +++ b/storage_image/i18n/storage_image.pot @@ -29,6 +29,7 @@ msgid "Accessible path, no base URL" msgstr "" #. module: storage_image +#: model:ir.model.fields,field_description:storage_image.field_image_relation_abstract__active #: model:ir.model.fields,field_description:storage_image.field_storage_image__active msgid "Active" msgstr "" @@ -39,6 +40,11 @@ msgstr "" msgid "Alt Image name" msgstr "" +#. module: storage_image +#: model_terms:ir.ui.view,arch_db:storage_image.storage_image_view_search +msgid "Backend" +msgstr "" + #. module: storage_image #: model_terms:ir.ui.view,arch_db:storage_image.storage_file_replace_view_form msgid "Cancel" @@ -112,6 +118,11 @@ msgstr "" msgid "Filename without extension" msgstr "" +#. module: storage_image +#: model_terms:ir.ui.view,arch_db:storage_image.storage_image_view_search +msgid "Group By" +msgstr "" + #. module: storage_image #: model:ir.model.fields,help:storage_image.field_storage_image__internal_url msgid "HTTP URL to load the file directly from storage." @@ -159,6 +170,12 @@ msgstr "" msgid "Internal Url" msgstr "" +#. module: storage_image +#: model:ir.model.fields,field_description:storage_image.field_image_relation_abstract__is_public +#: model:ir.model.fields,field_description:storage_image.field_storage_image__is_public +msgid "Is Public" +msgstr "" + #. module: storage_image #: model:ir.model.fields,field_description:storage_image.field_storage_image__write_uid msgid "Last Updated by" @@ -188,12 +205,28 @@ msgstr "" msgid "Name" msgstr "" +#. module: storage_image +#: model_terms:ir.ui.view,arch_db:storage_image.storage_image_view_search +msgid "Private" +msgstr "" + +#. module: storage_image +#: model_terms:ir.ui.view,arch_db:storage_image.storage_image_view_search +msgid "Public" +msgstr "" + #. module: storage_image #. odoo-javascript #: code:addons/storage_image/static/src/js/StorageImageHandle.esm.js:0 msgid "Records have been successfully rearranged." msgstr "" +#. module: storage_image +#: model:ir.model.fields,help:storage_image.field_image_relation_abstract__is_public +#: model:ir.model.fields,help:storage_image.field_storage_image__is_public +msgid "Reflects the `is_public` flag of the related backend." +msgstr "" + #. module: storage_image #: model:ir.model.fields,field_description:storage_image.field_storage_image__relative_path msgid "Relative Path" From 4d3ea78c6ae9105f9ada349842094878278329c6 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Fri, 12 Jun 2026 07:02:30 +0000 Subject: [PATCH 16/26] [UPD] Update storage_image_product.pot --- .../i18n/storage_image_product.pot | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/storage_image_product/i18n/storage_image_product.pot b/storage_image_product/i18n/storage_image_product.pot index bf1bc5c21f..25a837a4b2 100644 --- a/storage_image_product/i18n/storage_image_product.pot +++ b/storage_image_product/i18n/storage_image_product.pot @@ -23,6 +23,12 @@ msgstr "" msgid "# of Products" msgstr "" +#. module: storage_image_product +#: model:ir.model.fields,field_description:storage_image_product.field_category_image_relation__active +#: model:ir.model.fields,field_description:storage_image_product.field_product_image_relation__active +msgid "Active" +msgstr "" + #. module: storage_image_product #: model:ir.model.fields,field_description:storage_image_product.field_category_image_relation__image_alt_name #: model:ir.model.fields,field_description:storage_image_product.field_product_image_relation__image_alt_name @@ -132,6 +138,12 @@ msgstr "" msgid "Images" msgstr "" +#. module: storage_image_product +#: model:ir.model.fields,field_description:storage_image_product.field_category_image_relation__is_public +#: model:ir.model.fields,field_description:storage_image_product.field_product_image_relation__is_public +msgid "Is Public" +msgstr "" + #. module: storage_image_product #: model:ir.model.fields,field_description:storage_image_product.field_category_image_relation__write_uid #: model:ir.model.fields,field_description:storage_image_product.field_image_tag__write_uid @@ -228,6 +240,12 @@ msgstr "" msgid "Products" msgstr "" +#. module: storage_image_product +#: model:ir.model.fields,help:storage_image_product.field_category_image_relation__is_public +#: model:ir.model.fields,help:storage_image_product.field_product_image_relation__is_public +msgid "Reflects the `is_public` flag of the related backend." +msgstr "" + #. module: storage_image_product #: model:ir.model.fields,field_description:storage_image_product.field_category_image_relation__sequence #: model:ir.model.fields,field_description:storage_image_product.field_product_image_relation__sequence From a6dbf76e94a95ad52903739443b6ee595fc976b8 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Fri, 12 Jun 2026 07:02:30 +0000 Subject: [PATCH 17/26] [UPD] Update storage_media.pot --- storage_media/i18n/storage_media.pot | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/storage_media/i18n/storage_media.pot b/storage_media/i18n/storage_media.pot index dac136a245..7203d9caea 100644 --- a/storage_media/i18n/storage_media.pot +++ b/storage_media/i18n/storage_media.pot @@ -34,6 +34,11 @@ msgstr "" msgid "Archived" msgstr "" +#. module: storage_media +#: model_terms:ir.ui.view,arch_db:storage_media.storage_media_view_search +msgid "Backend" +msgstr "" + #. module: storage_media #: model_terms:ir.ui.view,arch_db:storage_media.storage_file_replace_view_form msgid "Cancel" @@ -111,6 +116,11 @@ msgstr "" msgid "Filename without extension" msgstr "" +#. module: storage_media +#: model_terms:ir.ui.view,arch_db:storage_media.storage_media_view_search +msgid "Group By" +msgstr "" + #. module: storage_media #: model:ir.model.fields,help:storage_media.field_storage_media__internal_url msgid "HTTP URL to load the file directly from storage." @@ -137,6 +147,11 @@ msgstr "" msgid "Internal Url" msgstr "" +#. module: storage_media +#: model:ir.model.fields,field_description:storage_media.field_storage_media__is_public +msgid "Is Public" +msgstr "" + #. module: storage_media #: model:ir.model.fields,field_description:storage_media.field_storage_media__write_uid #: model:ir.model.fields,field_description:storage_media.field_storage_media_type__write_uid @@ -173,6 +188,21 @@ msgstr "" msgid "Name" msgstr "" +#. module: storage_media +#: model_terms:ir.ui.view,arch_db:storage_media.storage_media_view_search +msgid "Private" +msgstr "" + +#. module: storage_media +#: model_terms:ir.ui.view,arch_db:storage_media.storage_media_view_search +msgid "Public" +msgstr "" + +#. module: storage_media +#: model:ir.model.fields,help:storage_media.field_storage_media__is_public +msgid "Reflects the `is_public` flag of the related backend." +msgstr "" + #. module: storage_media #: model:ir.model.fields,field_description:storage_media.field_storage_media__relative_path msgid "Relative Path" From 1657e969cf05a25bdfb31ff16d213164981af8f8 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Fri, 12 Jun 2026 07:02:31 +0000 Subject: [PATCH 18/26] [UPD] Update storage_media_product.pot --- .../i18n/storage_media_product.pot | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/storage_media_product/i18n/storage_media_product.pot b/storage_media_product/i18n/storage_media_product.pot index 975eef8bd7..796bc54628 100644 --- a/storage_media_product/i18n/storage_media_product.pot +++ b/storage_media_product/i18n/storage_media_product.pot @@ -18,6 +18,11 @@ msgstr "" msgid "Accessible path, no base URL" msgstr "" +#. module: storage_media_product +#: model:ir.model.fields,field_description:storage_media_product.field_product_media_relation__active +msgid "Active" +msgstr "" + #. module: storage_media_product #: model_terms:ir.ui.view,arch_db:storage_media_product.product_media_relation_form msgid "Association" @@ -63,6 +68,11 @@ msgstr "" msgid "ID" msgstr "" +#. module: storage_media_product +#: model:ir.model.fields,field_description:storage_media_product.field_product_media_relation__is_public +msgid "Is Public" +msgstr "" + #. module: storage_media_product #: model:ir.model.fields,field_description:storage_media_product.field_product_media_relation__write_uid msgid "Last Updated by" @@ -119,6 +129,11 @@ msgstr "" msgid "Products and storage media relation" msgstr "" +#. module: storage_media_product +#: model:ir.model.fields,help:storage_media_product.field_product_media_relation__is_public +msgid "Reflects the `is_public` flag of the related backend." +msgstr "" + #. module: storage_media_product #: model:ir.model.fields,field_description:storage_media_product.field_product_media_relation__sequence msgid "Sequence" From 10f070c4837c2c8e6c05b3ce71aa8ff70c3e3107 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Fri, 12 Jun 2026 07:02:31 +0000 Subject: [PATCH 19/26] [UPD] Update storage_thumbnail.pot --- storage_thumbnail/i18n/storage_thumbnail.pot | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/storage_thumbnail/i18n/storage_thumbnail.pot b/storage_thumbnail/i18n/storage_thumbnail.pot index e11335dcf2..adc4158782 100644 --- a/storage_thumbnail/i18n/storage_thumbnail.pot +++ b/storage_thumbnail/i18n/storage_thumbnail.pot @@ -105,6 +105,11 @@ msgstr "" msgid "Internal Url" msgstr "" +#. module: storage_thumbnail +#: model:ir.model.fields,field_description:storage_thumbnail.field_storage_thumbnail__is_public +msgid "Is Public" +msgstr "" + #. module: storage_thumbnail #: model:ir.model.fields,field_description:storage_thumbnail.field_storage_thumbnail__write_uid msgid "Last Updated by" @@ -130,6 +135,11 @@ msgstr "" msgid "Name" msgstr "" +#. module: storage_thumbnail +#: model:ir.model.fields,help:storage_thumbnail.field_storage_thumbnail__is_public +msgid "Reflects the `is_public` flag of the related backend." +msgstr "" + #. module: storage_thumbnail #: model:ir.model.fields,field_description:storage_thumbnail.field_storage_thumbnail__relative_path msgid "Relative Path" From 3ebaef28beeee080bd2521b0aff58b58e1fd1069 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 12 Jun 2026 07:06:42 +0000 Subject: [PATCH 20/26] [BOT] post-merge updates --- README.md | 12 ++++---- storage_file/README.rst | 2 +- storage_file/__manifest__.py | 2 +- storage_file/static/description/index.html | 2 +- storage_image/README.rst | 2 +- storage_image/__manifest__.py | 2 +- storage_image/static/description/index.html | 2 +- storage_image_product/README.rst | 2 +- storage_image_product/__manifest__.py | 2 +- .../static/description/index.html | 2 +- storage_media/__manifest__.py | 2 +- storage_media_product/README.rst | 2 +- storage_media_product/__manifest__.py | 2 +- .../static/description/index.html | 2 +- storage_thumbnail/README.rst | 8 ++++-- storage_thumbnail/__manifest__.py | 2 +- .../static/description/index.html | 28 +++++++++++-------- 17 files changed, 43 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 28b94bf101..ab1b5426e3 100644 --- a/README.md +++ b/README.md @@ -38,13 +38,13 @@ addon | version | maintainers | summary [storage_backend_ftp](storage_backend_ftp/) | 18.0.1.0.0 | | Implement FTP Storage [storage_backend_s3](storage_backend_s3/) | 18.0.1.1.0 | | Implement amazon S3 Storage [storage_backend_sftp](storage_backend_sftp/) | 18.0.1.0.0 | | Implement SFTP Storage -[storage_file](storage_file/) | 18.0.1.1.0 | | Storage file in storage backend +[storage_file](storage_file/) | 18.0.1.2.0 | | Storage file in storage backend [storage_file_swap_backend_queue](storage_file_swap_backend_queue/) | 18.0.1.1.0 | simahawk | Delegate storage file backend swap to queue jobs -[storage_image](storage_image/) | 18.0.1.1.0 | | Store image and resized image in a storage backend -[storage_image_product](storage_image_product/) | 18.0.1.0.2 | | Link images to products and categories -[storage_media](storage_media/) | 18.0.1.2.0 | | Give the posibility to store media data in Odoo -[storage_media_product](storage_media_product/) | 18.0.1.0.1 | | Link media to products and categories -[storage_thumbnail](storage_thumbnail/) | 18.0.1.0.0 | | Abstract module that add the possibility to have thumbnail +[storage_image](storage_image/) | 18.0.1.2.0 | | Store image and resized image in a storage backend +[storage_image_product](storage_image_product/) | 18.0.1.1.0 | | Link images to products and categories +[storage_media](storage_media/) | 18.0.1.3.0 | | Give the posibility to store media data in Odoo +[storage_media_product](storage_media_product/) | 18.0.1.1.0 | | Link media to products and categories +[storage_thumbnail](storage_thumbnail/) | 18.0.1.1.0 | | Abstract module that add the possibility to have thumbnail [//]: # (end addons) diff --git a/storage_file/README.rst b/storage_file/README.rst index d17d2cc992..eb7a8e63af 100644 --- a/storage_file/README.rst +++ b/storage_file/README.rst @@ -11,7 +11,7 @@ Storage File !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:14eff9ac3e34f90b55e98e5f1d8e938390db9e5d7c2f421d370143c3a26f5e1b + !! source digest: sha256:c7ccd99c8428f973c93fbbdde0021b61a5db3077bc2d7722a2f929611f8ac415 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png diff --git a/storage_file/__manifest__.py b/storage_file/__manifest__.py index efdbea4fd9..87c22813d0 100644 --- a/storage_file/__manifest__.py +++ b/storage_file/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Storage File", "summary": "Storage file in storage backend", - "version": "18.0.1.1.0", + "version": "18.0.1.2.0", "category": "Storage", "website": "https://github.com/OCA/storage", "author": " Akretion, Odoo Community Association (OCA)", diff --git a/storage_file/static/description/index.html b/storage_file/static/description/index.html index 50e1156ab5..8f336fd518 100644 --- a/storage_file/static/description/index.html +++ b/storage_file/static/description/index.html @@ -372,7 +372,7 @@

Storage File

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:14eff9ac3e34f90b55e98e5f1d8e938390db9e5d7c2f421d370143c3a26f5e1b +!! source digest: sha256:c7ccd99c8428f973c93fbbdde0021b61a5db3077bc2d7722a2f929611f8ac415 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Production/Stable License: LGPL-3 OCA/storage Translate me on Weblate Try me on Runboat

External file management depending on Storage Backend module.

diff --git a/storage_image/README.rst b/storage_image/README.rst index b11178c3c2..b119ddd1e8 100644 --- a/storage_image/README.rst +++ b/storage_image/README.rst @@ -11,7 +11,7 @@ Storage Image !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:288cb6384d178a0baa57c73bf92d5ab94f325c0ff7e347bd72c79da2d67e18fa + !! source digest: sha256:5d665efc3d0b5c44f7dec44b33a76b1f1d53557ca28803cdaf1613f2814bb73b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png diff --git a/storage_image/__manifest__.py b/storage_image/__manifest__.py index 39063806b7..e91a2d1dd4 100644 --- a/storage_image/__manifest__.py +++ b/storage_image/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Storage Image", "summary": "Store image and resized image in a storage backend", - "version": "18.0.1.1.0", + "version": "18.0.1.2.0", "category": "Storage", "website": "https://github.com/OCA/storage", "author": " Akretion, Odoo Community Association (OCA)", diff --git a/storage_image/static/description/index.html b/storage_image/static/description/index.html index 32df5a2856..da1d4dfef7 100644 --- a/storage_image/static/description/index.html +++ b/storage_image/static/description/index.html @@ -372,7 +372,7 @@

Storage Image

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:288cb6384d178a0baa57c73bf92d5ab94f325c0ff7e347bd72c79da2d67e18fa +!! source digest: sha256:5d665efc3d0b5c44f7dec44b33a76b1f1d53557ca28803cdaf1613f2814bb73b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Production/Stable License: LGPL-3 OCA/storage Translate me on Weblate Try me on Runboat

External image management depending on Storage File module.

diff --git a/storage_image_product/README.rst b/storage_image_product/README.rst index f32d81c587..f0743f2f44 100644 --- a/storage_image_product/README.rst +++ b/storage_image_product/README.rst @@ -11,7 +11,7 @@ Storage Image Product !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:da4b914be20e01a01cfa782549a9aeab2ac2a946a96895fce85de92e6f2b454c + !! source digest: sha256:9771b16b89fdd6826cf5a52c8acd51d7e53786b76a566f42d8662e7a140a9d9d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png diff --git a/storage_image_product/__manifest__.py b/storage_image_product/__manifest__.py index 7eaac02f1e..cea1e84d99 100644 --- a/storage_image_product/__manifest__.py +++ b/storage_image_product/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Storage Image Product", "summary": "Link images to products and categories", - "version": "18.0.1.0.2", + "version": "18.0.1.1.0", "category": "Storage", "website": "https://github.com/OCA/storage", "author": " Akretion, Odoo Community Association (OCA)", diff --git a/storage_image_product/static/description/index.html b/storage_image_product/static/description/index.html index e5e73410d7..c970f5b821 100644 --- a/storage_image_product/static/description/index.html +++ b/storage_image_product/static/description/index.html @@ -372,7 +372,7 @@

Storage Image Product

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:da4b914be20e01a01cfa782549a9aeab2ac2a946a96895fce85de92e6f2b454c +!! source digest: sha256:9771b16b89fdd6826cf5a52c8acd51d7e53786b76a566f42d8662e7a140a9d9d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Production/Stable License: LGPL-3 OCA/storage Translate me on Weblate Try me on Runboat

Attach images to products and categories

diff --git a/storage_media/__manifest__.py b/storage_media/__manifest__.py index 482e6edda7..abc65c1a52 100644 --- a/storage_media/__manifest__.py +++ b/storage_media/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Storage Media", "summary": "Give the posibility to store media data in Odoo", - "version": "18.0.1.2.0", + "version": "18.0.1.3.0", "category": "Uncategorized", "website": "https://github.com/OCA/storage", "author": " Akretion, Odoo Community Association (OCA)", diff --git a/storage_media_product/README.rst b/storage_media_product/README.rst index a59bde9257..3b64bd8b60 100644 --- a/storage_media_product/README.rst +++ b/storage_media_product/README.rst @@ -11,7 +11,7 @@ Storage Media Product !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:1ebaac1a52437a2cde37c3583656a9c9185ac8e24068cf876aee4e93b654460d + !! source digest: sha256:3a5eabb371a6add760b7a4453df1247677c0efb1fab103fc5ae07e651a4bb499 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/storage_media_product/__manifest__.py b/storage_media_product/__manifest__.py index 43642eb1d2..52919ec988 100644 --- a/storage_media_product/__manifest__.py +++ b/storage_media_product/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Storage Media Product", "summary": "Link media to products and categories", - "version": "18.0.1.0.1", + "version": "18.0.1.1.0", "category": "Storage", "website": "https://github.com/OCA/storage", "author": " Akretion, Odoo Community Association (OCA)", diff --git a/storage_media_product/static/description/index.html b/storage_media_product/static/description/index.html index ee918351b4..8947d3bcc1 100644 --- a/storage_media_product/static/description/index.html +++ b/storage_media_product/static/description/index.html @@ -372,7 +372,7 @@

Storage Media Product

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:1ebaac1a52437a2cde37c3583656a9c9185ac8e24068cf876aee4e93b654460d +!! source digest: sha256:3a5eabb371a6add760b7a4453df1247677c0efb1fab103fc5ae07e651a4bb499 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: LGPL-3 OCA/storage Translate me on Weblate Try me on Runboat

Attach images to products and categories

diff --git a/storage_thumbnail/README.rst b/storage_thumbnail/README.rst index a2c5d9cde4..cf6bd62305 100644 --- a/storage_thumbnail/README.rst +++ b/storage_thumbnail/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ================= Storage Thumbnail ================= @@ -7,13 +11,13 @@ Storage Thumbnail !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:3321f6180032d0f285bf859786259d133e995f1bf60c2d1250df0805789fc83f + !! source digest: sha256:7e31e0b9d9261fe9d529753f5d57dfaafffbf51dbdd6fffdccb52382e26bcc63 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png :target: https://odoo-community.org/page/development-status :alt: Production/Stable -.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html :alt: License: LGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstorage-lightgray.png?logo=github diff --git a/storage_thumbnail/__manifest__.py b/storage_thumbnail/__manifest__.py index 14570c6693..8cabd67fe5 100644 --- a/storage_thumbnail/__manifest__.py +++ b/storage_thumbnail/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Storage Thumbnail", "summary": "Abstract module that add the possibility to have thumbnail", - "version": "18.0.1.0.0", + "version": "18.0.1.1.0", "category": "Storage", "website": "https://github.com/OCA/storage", "author": " Akretion, Odoo Community Association (OCA)", diff --git a/storage_thumbnail/static/description/index.html b/storage_thumbnail/static/description/index.html index 70de439c32..8b7167ce3b 100644 --- a/storage_thumbnail/static/description/index.html +++ b/storage_thumbnail/static/description/index.html @@ -3,7 +3,7 @@ -Storage Thumbnail +README.rst -
-

Storage Thumbnail

+
+ + +Odoo Community Association + +
+

Storage Thumbnail

-

Production/Stable License: LGPL-3 OCA/storage Translate me on Weblate Try me on Runboat

+

Production/Stable License: LGPL-3 OCA/storage Translate me on Weblate Try me on Runboat

External image thumbnail management depending on Storage File module.

Table of contents

@@ -385,7 +390,7 @@

Storage Thumbnail

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -393,15 +398,15 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Akretion
-

Contributors

+

Contributors

-

Other credits

+

Other credits

The migration of this module from 15.0 to 18.0 was financially supported by Camptocamp

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -428,5 +433,6 @@

Maintainers

+
From 46c71889b57ddf0bafc2e20fef745d3e94cdfba0 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 12 Jun 2026 07:07:01 +0000 Subject: [PATCH 21/26] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: storage-18.0/storage-18.0-storage_media_product Translate-URL: https://translation.odoo-community.org/projects/storage-18-0/storage-18-0-storage_media_product/ --- storage_media_product/i18n/it.po | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/storage_media_product/i18n/it.po b/storage_media_product/i18n/it.po index b60968ce71..493abaed27 100644 --- a/storage_media_product/i18n/it.po +++ b/storage_media_product/i18n/it.po @@ -21,6 +21,11 @@ msgstr "" msgid "Accessible path, no base URL" msgstr "Percorso accessibile, non URL base" +#. module: storage_media_product +#: model:ir.model.fields,field_description:storage_media_product.field_product_media_relation__active +msgid "Active" +msgstr "" + #. module: storage_media_product #: model_terms:ir.ui.view,arch_db:storage_media_product.product_media_relation_form msgid "Association" @@ -66,6 +71,11 @@ msgstr "Percorso HTTP al file accessibile" msgid "ID" msgstr "ID" +#. module: storage_media_product +#: model:ir.model.fields,field_description:storage_media_product.field_product_media_relation__is_public +msgid "Is Public" +msgstr "" + #. module: storage_media_product #: model:ir.model.fields,field_description:storage_media_product.field_product_media_relation__write_uid msgid "Last Updated by" @@ -122,6 +132,11 @@ msgstr "Variante prodotto" msgid "Products and storage media relation" msgstr "Relazione prodotti e media deposito" +#. module: storage_media_product +#: model:ir.model.fields,help:storage_media_product.field_product_media_relation__is_public +msgid "Reflects the `is_public` flag of the related backend." +msgstr "" + #. module: storage_media_product #: model:ir.model.fields,field_description:storage_media_product.field_product_media_relation__sequence msgid "Sequence" From 4b1c7396b805de567794d30448aa15accbe63573 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 12 Jun 2026 07:07:02 +0000 Subject: [PATCH 22/26] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: storage-18.0/storage-18.0-storage_thumbnail Translate-URL: https://translation.odoo-community.org/projects/storage-18-0/storage-18-0-storage_thumbnail/ --- storage_thumbnail/i18n/it.po | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/storage_thumbnail/i18n/it.po b/storage_thumbnail/i18n/it.po index 596b0b9776..5403a71050 100644 --- a/storage_thumbnail/i18n/it.po +++ b/storage_thumbnail/i18n/it.po @@ -108,6 +108,11 @@ msgstr "ID" msgid "Internal Url" msgstr "URL interno" +#. module: storage_thumbnail +#: model:ir.model.fields,field_description:storage_thumbnail.field_storage_thumbnail__is_public +msgid "Is Public" +msgstr "" + #. module: storage_thumbnail #: model:ir.model.fields,field_description:storage_thumbnail.field_storage_thumbnail__write_uid msgid "Last Updated by" @@ -133,6 +138,11 @@ msgstr "Tipo MIME" msgid "Name" msgstr "Nome" +#. module: storage_thumbnail +#: model:ir.model.fields,help:storage_thumbnail.field_storage_thumbnail__is_public +msgid "Reflects the `is_public` flag of the related backend." +msgstr "" + #. module: storage_thumbnail #: model:ir.model.fields,field_description:storage_thumbnail.field_storage_thumbnail__relative_path msgid "Relative Path" From 04adccfdece3c043fb3b6480f4ce5bbf3ef40167 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 12 Jun 2026 07:07:02 +0000 Subject: [PATCH 23/26] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: storage-18.0/storage-18.0-storage_image Translate-URL: https://translation.odoo-community.org/projects/storage-18-0/storage-18-0-storage_image/ --- storage_image/i18n/it.po | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/storage_image/i18n/it.po b/storage_image/i18n/it.po index 8c6e824569..d779ad2cf3 100644 --- a/storage_image/i18n/it.po +++ b/storage_image/i18n/it.po @@ -32,6 +32,7 @@ msgid "Accessible path, no base URL" msgstr "Percorso accessibile, non URL base" #. module: storage_image +#: model:ir.model.fields,field_description:storage_image.field_image_relation_abstract__active #: model:ir.model.fields,field_description:storage_image.field_storage_image__active msgid "Active" msgstr "Attiva" @@ -42,6 +43,11 @@ msgstr "Attiva" msgid "Alt Image name" msgstr "Nome alternativo immagine" +#. module: storage_image +#: model_terms:ir.ui.view,arch_db:storage_image.storage_image_view_search +msgid "Backend" +msgstr "" + #. module: storage_image #: model_terms:ir.ui.view,arch_db:storage_image.storage_file_replace_view_form msgid "Cancel" @@ -115,6 +121,11 @@ msgstr "Tipo file" msgid "Filename without extension" msgstr "Nome file senza estensione" +#. module: storage_image +#: model_terms:ir.ui.view,arch_db:storage_image.storage_image_view_search +msgid "Group By" +msgstr "" + #. module: storage_image #: model:ir.model.fields,help:storage_image.field_storage_image__internal_url msgid "HTTP URL to load the file directly from storage." @@ -162,6 +173,12 @@ msgstr "Sintesi relazione immagine" msgid "Internal Url" msgstr "URL interno" +#. module: storage_image +#: model:ir.model.fields,field_description:storage_image.field_image_relation_abstract__is_public +#: model:ir.model.fields,field_description:storage_image.field_storage_image__is_public +msgid "Is Public" +msgstr "" + #. module: storage_image #: model:ir.model.fields,field_description:storage_image.field_storage_image__write_uid msgid "Last Updated by" @@ -191,12 +208,28 @@ msgstr "Tipo MIME" msgid "Name" msgstr "Nome" +#. module: storage_image +#: model_terms:ir.ui.view,arch_db:storage_image.storage_image_view_search +msgid "Private" +msgstr "" + +#. module: storage_image +#: model_terms:ir.ui.view,arch_db:storage_image.storage_image_view_search +msgid "Public" +msgstr "" + #. module: storage_image #. odoo-javascript #: code:addons/storage_image/static/src/js/StorageImageHandle.esm.js:0 msgid "Records have been successfully rearranged." msgstr "I record sono stati riorganizzati con successo." +#. module: storage_image +#: model:ir.model.fields,help:storage_image.field_image_relation_abstract__is_public +#: model:ir.model.fields,help:storage_image.field_storage_image__is_public +msgid "Reflects the `is_public` flag of the related backend." +msgstr "" + #. module: storage_image #: model:ir.model.fields,field_description:storage_image.field_storage_image__relative_path msgid "Relative Path" From c0a43c3211289b55dc0fd17e2be0d8cd110f706b Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 12 Jun 2026 07:07:02 +0000 Subject: [PATCH 24/26] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: storage-18.0/storage-18.0-storage_image_product Translate-URL: https://translation.odoo-community.org/projects/storage-18-0/storage-18-0-storage_image_product/ --- storage_image_product/i18n/it.po | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/storage_image_product/i18n/it.po b/storage_image_product/i18n/it.po index 11a28e5947..38a0411361 100644 --- a/storage_image_product/i18n/it.po +++ b/storage_image_product/i18n/it.po @@ -26,6 +26,12 @@ msgstr "N° di categorie" msgid "# of Products" msgstr "N° di prodotti" +#. module: storage_image_product +#: model:ir.model.fields,field_description:storage_image_product.field_category_image_relation__active +#: model:ir.model.fields,field_description:storage_image_product.field_product_image_relation__active +msgid "Active" +msgstr "" + #. module: storage_image_product #: model:ir.model.fields,field_description:storage_image_product.field_category_image_relation__image_alt_name #: model:ir.model.fields,field_description:storage_image_product.field_product_image_relation__image_alt_name @@ -135,6 +141,12 @@ msgstr "Etichetta immagine" msgid "Images" msgstr "Immagini" +#. module: storage_image_product +#: model:ir.model.fields,field_description:storage_image_product.field_category_image_relation__is_public +#: model:ir.model.fields,field_description:storage_image_product.field_product_image_relation__is_public +msgid "Is Public" +msgstr "" + #. module: storage_image_product #: model:ir.model.fields,field_description:storage_image_product.field_category_image_relation__write_uid #: model:ir.model.fields,field_description:storage_image_product.field_image_tag__write_uid @@ -231,6 +243,12 @@ msgstr "Variante prodotto" msgid "Products" msgstr "Prodotti" +#. module: storage_image_product +#: model:ir.model.fields,help:storage_image_product.field_category_image_relation__is_public +#: model:ir.model.fields,help:storage_image_product.field_product_image_relation__is_public +msgid "Reflects the `is_public` flag of the related backend." +msgstr "" + #. module: storage_image_product #: model:ir.model.fields,field_description:storage_image_product.field_category_image_relation__sequence #: model:ir.model.fields,field_description:storage_image_product.field_product_image_relation__sequence From 42af5de9f202a995308f367acb7116b1b445691b Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 12 Jun 2026 07:07:02 +0000 Subject: [PATCH 25/26] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: storage-18.0/storage-18.0-storage_media Translate-URL: https://translation.odoo-community.org/projects/storage-18-0/storage-18-0-storage_media/ --- storage_media/i18n/it.po | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/storage_media/i18n/it.po b/storage_media/i18n/it.po index f1485757cb..35fdc13e77 100644 --- a/storage_media/i18n/it.po +++ b/storage_media/i18n/it.po @@ -37,6 +37,11 @@ msgstr "Tutti" msgid "Archived" msgstr "In archivio" +#. module: storage_media +#: model_terms:ir.ui.view,arch_db:storage_media.storage_media_view_search +msgid "Backend" +msgstr "" + #. module: storage_media #: model_terms:ir.ui.view,arch_db:storage_media.storage_file_replace_view_form msgid "Cancel" @@ -114,6 +119,11 @@ msgstr "Tipo file" msgid "Filename without extension" msgstr "Nome file senza estensione" +#. module: storage_media +#: model_terms:ir.ui.view,arch_db:storage_media.storage_media_view_search +msgid "Group By" +msgstr "" + #. module: storage_media #: model:ir.model.fields,help:storage_media.field_storage_media__internal_url msgid "HTTP URL to load the file directly from storage." @@ -140,6 +150,11 @@ msgstr "ID" msgid "Internal Url" msgstr "URL interno" +#. module: storage_media +#: model:ir.model.fields,field_description:storage_media.field_storage_media__is_public +msgid "Is Public" +msgstr "" + #. module: storage_media #: model:ir.model.fields,field_description:storage_media.field_storage_media__write_uid #: model:ir.model.fields,field_description:storage_media.field_storage_media_type__write_uid @@ -176,6 +191,21 @@ msgstr "Tipo MIME" msgid "Name" msgstr "Nome" +#. module: storage_media +#: model_terms:ir.ui.view,arch_db:storage_media.storage_media_view_search +msgid "Private" +msgstr "" + +#. module: storage_media +#: model_terms:ir.ui.view,arch_db:storage_media.storage_media_view_search +msgid "Public" +msgstr "" + +#. module: storage_media +#: model:ir.model.fields,help:storage_media.field_storage_media__is_public +msgid "Reflects the `is_public` flag of the related backend." +msgstr "" + #. module: storage_media #: model:ir.model.fields,field_description:storage_media.field_storage_media__relative_path msgid "Relative Path" From 97cf807225f9ef62e97beeec7062230e35a8bcd7 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 12 Jun 2026 07:07:03 +0000 Subject: [PATCH 26/26] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: storage-18.0/storage-18.0-storage_file Translate-URL: https://translation.odoo-community.org/projects/storage-18-0/storage-18-0-storage_file/ --- storage_file/i18n/it.po | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/storage_file/i18n/it.po b/storage_file/i18n/it.po index 31b90b9997..fc633a1c24 100644 --- a/storage_file/i18n/it.po +++ b/storage_file/i18n/it.po @@ -16,6 +16,17 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.6.2\n" +#. module: storage_file +#: model_terms:ir.ui.view,arch_db:storage_file.storage_backend_view_form +msgid "" +"Note: Without a CDN base URL, files will be proxied\n" +" through Odoo. This is acceptable for internal use with " +"low traffic\n" +" but suboptimal for high-volume public access as every " +"request loads\n" +" the file from the storage backend into memory." +msgstr "" + #. module: storage_file #. odoo-python #: code:addons/storage_file/models/storage_file.py:0 @@ -40,6 +51,11 @@ msgid "" "%s" msgstr "" +#. module: storage_file +#: model_terms:ir.ui.view,arch_db:storage_file.storage_file_view_search +msgid "Backend" +msgstr "" + #. module: storage_file #: model:ir.model.fields,field_description:storage_file.field_storage_backend__backend_view_use_internal_url msgid "Backend View Use Internal Url" @@ -206,6 +222,11 @@ msgstr "" msgid "Files to swap" msgstr "" +#. module: storage_file +#: model_terms:ir.ui.view,arch_db:storage_file.storage_file_view_search +msgid "Group By" +msgstr "" + #. module: storage_file #: model:ir.model.fields,help:storage_file.field_storage_file__internal_url msgid "HTTP URL to load the file directly from storage." @@ -244,6 +265,7 @@ msgstr "URL interno" #. module: storage_file #: model:ir.model.fields,field_description:storage_file.field_storage_backend__is_public +#: model:ir.model.fields,field_description:storage_file.field_storage_file__is_public msgid "Is Public" msgstr "È pubblico" @@ -302,11 +324,26 @@ msgstr "" msgid "Please select at least one file." msgstr "" +#. module: storage_file +#: model_terms:ir.ui.view,arch_db:storage_file.storage_file_view_search +msgid "Private" +msgstr "" + +#. module: storage_file +#: model_terms:ir.ui.view,arch_db:storage_file.storage_file_view_search +msgid "Public" +msgstr "" + #. module: storage_file #: model_terms:ir.ui.view,arch_db:storage_file.storage_backend_view_form msgid "Recompute base URL for files" msgstr "Ricalcola l'URL base per i file" +#. module: storage_file +#: model:ir.model.fields,help:storage_file.field_storage_file__is_public +msgid "Reflects the `is_public` flag of the related backend." +msgstr "" + #. module: storage_file #: model:ir.model.fields,field_description:storage_file.field_storage_file__relative_path msgid "Relative Path"