diff --git a/.oca/oca-port/blacklist/storage_backend.json b/.oca/oca-port/blacklist/storage_backend.json new file mode 100644 index 0000000000..c34693e647 --- /dev/null +++ b/.oca/oca-port/blacklist/storage_backend.json @@ -0,0 +1,9 @@ +{ + "pull_requests": { + "orphaned_commits": "false-positive", + "78": "false-positive", + "97": "false-positive", + "106": "false-positive", + "298": "false-positive" + } +} diff --git a/storage_backend/components/filesystem_adapter.py b/storage_backend/components/filesystem_adapter.py index 42110a911a..101c3cc286 100644 --- a/storage_backend/components/filesystem_adapter.py +++ b/storage_backend/components/filesystem_adapter.py @@ -2,13 +2,17 @@ # @author Sébastien BEAU # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). +import logging import os +import shutil from odoo import _ from odoo.exceptions import AccessError from odoo.addons.component.core import Component +_logger = logging.getLogger(__name__) + def is_safe_path(basedir, path): return os.path.realpath(path).startswith(basedir) @@ -56,4 +60,17 @@ def list(self, relative_path=""): def delete(self, relative_path): full_path = self._fullpath(relative_path) - os.remove(full_path) + try: + os.remove(full_path) + except FileNotFoundError: + _logger.warning("File not found in %s", full_path) + + def move_files(self, files, destination_path): + result = [] + for file_path in files: + if not os.path.exists(destination_path): + os.makedirs(destination_path) + filename = os.path.basename(file_path) + destination_file = os.path.join(destination_path, filename) + result.append(shutil.move(file_path, destination_file)) + return result diff --git a/storage_backend/models/storage_backend.py b/storage_backend/models/storage_backend.py index b5ae680a6a..c678b94319 100644 --- a/storage_backend/models/storage_backend.py +++ b/storage_backend/models/storage_backend.py @@ -71,6 +71,13 @@ class StorageBackend(models.Model): def _compute_has_validation(self): for rec in self: + if not rec.backend_type: + # with server_env + # this code can be triggered + # before a backend_type has been set + # get_adapter() can't work without backend_type + rec.has_validation = False + continue adapter = rec._get_adapter() rec.has_validation = hasattr(adapter, "validate_config") diff --git a/storage_backend/tests/common.py b/storage_backend/tests/common.py index 2b81cc09d0..84f9167efc 100644 --- a/storage_backend/tests/common.py +++ b/storage_backend/tests/common.py @@ -52,6 +52,19 @@ def _test_find_files( res = backend.find_files(pattern) self.assertEqual(sorted(res), sorted(expected_filepaths)) + def _test_move_files( + self, + backend, + adapter_dotted_path, + filename, + destination_path, + expected_filepaths, + ): + with mock.patch(adapter_dotted_path + ".move_files") as mocked: + mocked.return_value = expected_filepaths + res = backend.move_files(filename, destination_path) + self.assertEqual(sorted(res), sorted(expected_filepaths)) + class CommonCase(TransactionComponentCase): @classmethod diff --git a/storage_backend/tests/test_filesystem.py b/storage_backend/tests/test_filesystem.py index 67d49cff84..a136401b28 100644 --- a/storage_backend/tests/test_filesystem.py +++ b/storage_backend/tests/test_filesystem.py @@ -1,6 +1,7 @@ # Copyright 2017 Akretion (http://www.akretion.com). # @author Sébastien BEAU # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). +import os from odoo.exceptions import AccessError @@ -29,6 +30,15 @@ def test_find_files(self): backend, ADAPTER_PATH, mocked_filepaths, r".*\.good$", expected ) + def test_move_files(self): + backend = self.backend.sudo() + base_dir = backend._get_adapter()._basedir() + expected = [base_dir + "/" + self.filename] + destination_path = os.path.join(base_dir, "destination") + self._test_move_files( + backend, ADAPTER_PATH, self.filename, destination_path, expected + ) + class FileSystemDemoUserAccessCase(CommonCase): @classmethod