diff --git a/fs_attachment/tests/test_fs_storage.py b/fs_attachment/tests/test_fs_storage.py index 3947b1b647..79864ce496 100644 --- a/fs_attachment/tests/test_fs_storage.py +++ b/fs_attachment/tests/test_fs_storage.py @@ -299,6 +299,7 @@ def test_url_for_image_dir_optimized_and_not_obfuscated(self): { "name": "FS Product Image Backend", "code": "file", + "protocol": "odoofs", "base_url": "https://localhost/images", "optimizes_directory_path": True, "use_filename_obfuscation": False, diff --git a/fs_storage/README.rst b/fs_storage/README.rst index 8a9adacd62..48e9a128f4 100644 --- a/fs_storage/README.rst +++ b/fs_storage/README.rst @@ -129,9 +129,6 @@ When you create a new backend, you must specify the following: depend on the protocol used and are described in the fsspec documentation. -- Resolve env vars. This options resolves the protocol options values - starting with $ from environment variables - - Check Connection Method. If set, Odoo will always check the connection before using a storage and it will remove the fs connection from the cache if the check fails. @@ -166,35 +163,6 @@ follows: In this example, the SimpleCacheFileSystem protocol will be used as a wrapper around the odoofs protocol. -Server Environment ------------------- - -To ease the management of the filesystem storages configuration accross -the different environments, the configuration of the filesystem storages -can be defined in environment files or directly in the main -configuration file. For example, the configuration of a filesystem -storage with the code fsprod can be provided in the main configuration -file as follows: - -.. code:: ini - - [fs_storage.fsprod] - protocol=s3 - options={"endpoint_url": "https://my_s3_server/", "key": "KEY", "secret": "SECRET"} - directory_path=my_bucket - -To work, a storage.backend record must exist with the code fsprod into -the database. In your configuration section, you can specify the value -for the following fields: - -- protocol -- options -- directory_path - -When evaluating directory_path, ``{db_name}`` is replaced by the -database name. This is usefull in multi-tenant with a setup completly -controlled by configuration files. - Migration from storage_backend ------------------------------ diff --git a/fs_storage/__manifest__.py b/fs_storage/__manifest__.py index 40e44933f9..b1922892df 100644 --- a/fs_storage/__manifest__.py +++ b/fs_storage/__manifest__.py @@ -5,18 +5,18 @@ { "name": "Filesystem Storage Backend", "summary": "Implement the concept of Storage with amazon S3, sftp...", - "version": "19.0.1.1.1", + "version": "19.0.1.1.2", "category": "FS Storage", "website": "https://github.com/OCA/storage", "author": " ACSONE SA/NV, Odoo Community Association (OCA)", "license": "LGPL-3", "development_status": "Beta", - "depends": ["base", "base_sparse_field", "server_environment"], + "depends": ["base", "base_sparse_field"], "data": [ "views/fs_storage_view.xml", "security/ir.model.access.csv", "wizards/fs_test_connection.xml", ], - "external_dependencies": {"python": ["fsspec>=2024.5.0"]}, + "external_dependencies": {"python": ["fsspec>=2024.5.0", "openupgradelib>=3.6.0"]}, "installable": True, } diff --git a/fs_storage/migrations/19.0.1.1.2/post-migration.py b/fs_storage/migrations/19.0.1.1.2/post-migration.py new file mode 100644 index 0000000000..ca15759f71 --- /dev/null +++ b/fs_storage/migrations/19.0.1.1.2/post-migration.py @@ -0,0 +1,19 @@ +# Copyright 2026 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from openupgradelib import openupgrade + + +@openupgrade.migrate() +def migrate(env, version): + """Install the glue module once fs_storage upgrade succeeded.""" + module = env["ir.module.module"].search( + [ + ("name", "=", "fs_storage_environment"), + ("state", "=", "uninstalled"), + ], + limit=1, + ) + if not module: + return + module.button_install() diff --git a/fs_storage/migrations/19.0.1.1.2/pre-migration.py b/fs_storage/migrations/19.0.1.1.2/pre-migration.py new file mode 100644 index 0000000000..e8680ac883 --- /dev/null +++ b/fs_storage/migrations/19.0.1.1.2/pre-migration.py @@ -0,0 +1,94 @@ +# Copyright 2026 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from openupgradelib import openupgrade + +from odoo.tools import SQL + +from odoo.addons.base.models.ir_model import field_xmlid + + +def _get_server_env_mixin_fnames(cr, model: str) -> set[str]: + """Return the core mixin field names present on the model.""" + possible_fnames = ("server_env_defaults", "tech_name") + cr.execute( + SQL( + """ + SELECT name + FROM ir_model_fields + WHERE model = %(model)s + AND name IN %(possible_fnames)s + """, + model=model, + possible_fnames=possible_fnames, + ) + ) + return {row[0] for row in cr.fetchall()} + + +def _get_server_env_mixin_magic_fnames(cr, model): + """Return the dynamic server_environment helper fields for the model. + + These are the fields created on the fly by server.env.mixin: + - x__env_default + - x__env_is_editable + """ + cr.execute( + SQL( + """ + SELECT name + FROM ir_model_fields + WHERE model = %(model)s + AND ( + name LIKE 'x_%%_env_default' + OR name LIKE 'x_%%_env_is_editable' + ) + """, + model=model, + ) + ) + return {row[0] for row in cr.fetchall()} + + +@openupgrade.migrate() +def migrate(env, version): + """Move XMLIDs to the glue module. + + This keeps the server_environment ir.model.fields metadata attached to the + new module and preserves field values. + """ + cr = env.cr + if not version: + return + + model = "fs.storage" + old_module = "fs_storage" + new_module = "fs_storage_environment" + + mixin_fnames = _get_server_env_mixin_fnames(cr, model) + magic_fnames = _get_server_env_mixin_magic_fnames(cr, model) + to_move_fnames = mixin_fnames | magic_fnames + + rename_specs = [ + (field_xmlid(old_module, model, fname), field_xmlid(new_module, model, fname)) + for fname in to_move_fnames + ] + openupgrade.rename_xmlids(cr, rename_specs, allow_merge=True) + + # Add noupdate to the magic_fnames, to prevent Odoo from deleting them in upgrade + if magic_fnames: + openupgrade.logged_query( + cr, + """ + UPDATE ir_model_data SET noupdate = TRUE + WHERE module = %(module)s + AND name IN %(names)s + """, + dict( + module=new_module, + names=tuple( + field_xmlid(new_module, model, fname).split(".")[1] + for fname in magic_fnames + ), + ), + ) diff --git a/fs_storage/models/fs_storage.py b/fs_storage/models/fs_storage.py index 79c5109928..de7d7642a8 100644 --- a/fs_storage/models/fs_storage.py +++ b/fs_storage/models/fs_storage.py @@ -89,7 +89,6 @@ def wrapper(self, *args, **kwargs): class FSStorage(models.Model): _name = "fs.storage" - _inherit = "server.env.mixin" _description = "FS Storage" __slots__ = ("__fs", "__odoo_storage_path") @@ -231,8 +230,6 @@ def __init__(self, env, ids=(), prefetch_ids=()): "The code must be unique", ) - _server_env_section_name_field = "code" - @api.constrains("model_xmlids") def _check_model_xmlid_storage_unique(self): """ @@ -300,18 +297,6 @@ def _get_check_connection_method_selection(self): ("ls", self.env._("List File")), ] - @property - def _server_env_fields(self): - return { - "protocol": {}, - "options": {}, - "directory_path": {}, - "eval_options_from_env": {}, - "model_xmlids": {}, - "field_xmlids": {}, - "check_connection_method": {}, - } - @api.model_create_multi @prevent_call_from_safe_eval("create") def create(self, vals_list): diff --git a/fs_storage/readme/USAGE.md b/fs_storage/readme/USAGE.md index 82fc3553a9..580c63cc1f 100644 --- a/fs_storage/readme/USAGE.md +++ b/fs_storage/readme/USAGE.md @@ -16,8 +16,6 @@ When you create a new backend, you must specify the following: fsspec python package when creating the filesystem. These options depend on the protocol used and are described in the fsspec documentation. -- Resolve env vars. This options resolves the protocol options values - starting with \$ from environment variables - Check Connection Method. If set, Odoo will always check the connection before using a storage and it will remove the fs connection from the cache if the check fails. @@ -51,34 +49,6 @@ follows: In this example, the SimpleCacheFileSystem protocol will be used as a wrapper around the odoofs protocol. -## Server Environment - -To ease the management of the filesystem storages configuration accross -the different environments, the configuration of the filesystem storages -can be defined in environment files or directly in the main -configuration file. For example, the configuration of a filesystem -storage with the code fsprod can be provided in the main configuration -file as follows: - -``` ini -[fs_storage.fsprod] -protocol=s3 -options={"endpoint_url": "https://my_s3_server/", "key": "KEY", "secret": "SECRET"} -directory_path=my_bucket -``` - -To work, a storage.backend record must exist with the code fsprod into -the database. In your configuration section, you can specify the value -for the following fields: - -- protocol -- options -- directory_path - -When evaluating directory_path, `{db_name}` is replaced by the database name. -This is usefull in multi-tenant with a setup completly controlled by -configuration files. - ## Migration from storage_backend The fs_storage addon can be used to replace the storage_backend addon. diff --git a/fs_storage/static/description/index.html b/fs_storage/static/description/index.html index 0145e5797c..075412df28 100644 --- a/fs_storage/static/description/index.html +++ b/fs_storage/static/description/index.html @@ -441,38 +441,37 @@

Filesystem Storage Backend