Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fs_attachment/tests/test_fs_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
32 changes: 0 additions & 32 deletions fs_storage/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
------------------------------

Expand Down
6 changes: 3 additions & 3 deletions fs_storage/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]},
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had several times an issue with openupgradelib no available. I don't get why.

"installable": True,
}
19 changes: 19 additions & 0 deletions fs_storage/migrations/19.0.1.1.2/post-migration.py
Original file line number Diff line number Diff line change
@@ -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()
94 changes: 94 additions & 0 deletions fs_storage/migrations/19.0.1.1.2/pre-migration.py
Original file line number Diff line number Diff line change
@@ -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_<field_name>_env_default
- x_<field_name>_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
),
),
)
15 changes: 0 additions & 15 deletions fs_storage/models/fs_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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):
"""
Expand Down Expand Up @@ -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):
Expand Down
30 changes: 0 additions & 30 deletions fs_storage/readme/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
Loading
Loading