diff --git a/server_environment/models/server_env_mixin.py b/server_environment/models/server_env_mixin.py index b49c35974..bc2adc490 100644 --- a/server_environment/models/server_env_mixin.py +++ b/server_environment/models/server_env_mixin.py @@ -2,6 +2,7 @@ # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) import logging +from ast import literal_eval from functools import partialmethod from lxml import etree @@ -424,3 +425,40 @@ def _setup_base(self): self._server_env_transform_field_to_read_from_env(field) self._server_env_add_is_editable_field(field) return + + def _register_hook(self): + super()._register_hook() + for model_name in self.env: + model = self.env[model_name] + if hasattr(model, "_server_env_global_section_name"): + global_section_name = model._server_env_global_section_name() + for section in serv_config: + if section.startswith(f"{global_section_name}."): + if serv_config[section].get("__autocreate", None): + name_value = section[len(global_section_name) + 1 :] + domain = [ + (model._server_env_section_name_field, "=", name_value) + ] + count = model.with_context(active_test=False).search_count( + domain + ) + if count == 0: + _logger.debug("Automatic creation of %s", section) + values = literal_eval( + serv_config[section].get("__autocreate") + ) + values[ + model._server_env_section_name_field + ] = name_value + records = model.create([values]) + self.env["ir.model.data"].create( + [ + { + "name": section, + "model": model_name, + "module": "__server_environment__", + "res_id": record.id, + } + for record in records + ] + ) diff --git a/server_environment/readme/CONFIGURE.md b/server_environment/readme/CONFIGURE.md index 225be2d0b..9cadcc9cf 100644 --- a/server_environment/readme/CONFIGURE.md +++ b/server_environment/readme/CONFIGURE.md @@ -98,3 +98,20 @@ Note: empty environment keys always take precedence over default fields Read the documentation of the class [models/server_env_mixin.py](models/server_env_mixin.py). + +## Auto creation of records + +It is possible to indicate that records must be created automatically if not found in the database. + +When specifying a section in the configuration file or environment variable, also define ``__autocreate = {}``. +The value is a dictionary that will be passed when the record is created. This allows setting some non environment variables that are required. +For example, when using fs_storage module, the name of the storage is required so the configuration would look like: + +```ini +[fs_storage.my_sftp] +__autocreate = {"name": "My SFTP"} +protocol=sftp +options={"host": "10.10.10.10", "username": "foo", "password": "xxxxxxxxx"} +``` + +When the module creates such a record, it will add an xml id in the form `__server_enironment__.
`. diff --git a/server_environment/readme/CONTRIBUTORS.md b/server_environment/readme/CONTRIBUTORS.md index 2ad99dcca..d340a3527 100644 --- a/server_environment/readme/CONTRIBUTORS.md +++ b/server_environment/readme/CONTRIBUTORS.md @@ -10,3 +10,4 @@ - Thomas Binfeld \<\> - Stéphane Bidoul \<\> - Simone Orsi \<\> +- Vincent Hatakeyama \<\> diff --git a/server_environment/readme/ROADMAP.md b/server_environment/readme/ROADMAP.md index 463bd0374..1d6b1eef4 100644 --- a/server_environment/readme/ROADMAP.md +++ b/server_environment/readme/ROADMAP.md @@ -1,5 +1,5 @@ - it is not possible to set the environment from the command line. A - configuration file must be used. + configuration file or environment variables must be used. - the module does not allow to set low level attributes such as database server, etc. - server.env.techname.mixin's tech_name field could leverage the new diff --git a/server_environment/tests/__init__.py b/server_environment/tests/__init__.py index 73093474f..a8ebba378 100644 --- a/server_environment/tests/__init__.py +++ b/server_environment/tests/__init__.py @@ -1,2 +1,3 @@ +from . import test_server_environment_autocreate from . import test_server_environment from . import test_environment_variable diff --git a/server_environment/tests/models.py b/server_environment/tests/models.py new file mode 100644 index 000000000..0c7ee4ca8 --- /dev/null +++ b/server_environment/tests/models.py @@ -0,0 +1,24 @@ +# Copyright 2024 XCG Consulting +# @author Vincent Hatakeyama +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class ExternalService(models.Model): + _name = "external_service" + _description = "External Service" + _inherit = "server.env.mixin" + + name = fields.Char(required=True) + description = fields.Char(required=True) + host = fields.Char() + user = fields.Char() + password = fields.Char() + + @property + def _server_env_fields(self): + return { + "host": {}, + "user": {}, + "password": {}, + } diff --git a/server_environment/tests/test_environment_variable.py b/server_environment/tests/test_environment_variable.py index 42047904f..f04d3847a 100644 --- a/server_environment/tests/test_environment_variable.py +++ b/server_environment/tests/test_environment_variable.py @@ -6,8 +6,7 @@ from odoo.tools.config import config as odoo_config -from odoo.addons.server_environment import server_env - +from .. import server_env from .common import ServerEnvironmentCase diff --git a/server_environment/tests/test_server_environment_autocreate.py b/server_environment/tests/test_server_environment_autocreate.py new file mode 100644 index 000000000..7995581a8 --- /dev/null +++ b/server_environment/tests/test_server_environment_autocreate.py @@ -0,0 +1,69 @@ +# Copyright 2018 Camptocamp (https://www.camptocamp.com). +# Copyright 2024 XCG Consulting (https://xcg-consulting.fr). +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) +from unittest.mock import patch + +from odoo_test_helper import FakeModelLoader + +from odoo.tests import tagged +from odoo.tools.config import config as odoo_config + +from .. import server_env +from ..models import server_env_mixin +from . import common + + +# Test need to be run post install otherwise the _register_hook is not called yet +@tagged("post_install", "-at_install") +class TestEnv(common.ServerEnvironmentCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + # Load fake models ->/ + cls.loader = FakeModelLoader(cls.env, cls.__module__) + cls.loader.backup_registry() + from .models import ExternalService + + cls.loader.update_registry((ExternalService,)) + cls.env["external_service"].create([{"name": "ftp2", "description": "another"}]) + + @classmethod + def tearDownClass(cls): + cls.loader.restore_registry() + super().tearDownClass() + + @patch.dict(odoo_config.options, {"running_env": "autocreate"}) + def test_autocreate(self): + original_serv_config = server_env_mixin.serv_config + try: + with self.set_config_dir("testfiles"): + parser = server_env._load_config() + server_env_mixin.serv_config = parser + # Needed to force _register_hook with auto creation + self.loader.update_registry(tuple()) + + # auto created record + record = self.env.ref("__server_environment__.external_service.ftp") + self.assertEqual(record.name, "ftp") + self.assertEqual(record.description, "ftp server") + self.assertEqual(record.host, "sftp.example.com") + self.assertEqual(record.user, "foo") + self.assertEqual(record.password, "bar") + + # create record in setupClass + # Test it has no xmlid + record = self.env.ref( + "__server_environment__.external_service.ftp2", False + ) + self.assertFalse(record) + # look for it + record = self.env["external_service"].search([("name", "=", "ftp2")]) + self.assertEqual(len(record), 1) + self.assertEqual(record.name, "ftp2") + # different from __autocreate dict as it is created in setUpClass + self.assertEqual(record.description, "another") + self.assertEqual(record.host, "sftp2.example.com") + self.assertEqual(record.user, "monty") + self.assertEqual(record.password, "python") + finally: + server_env_mixin.serv_config = original_serv_config diff --git a/server_environment/tests/testfiles/autocreate/base.conf b/server_environment/tests/testfiles/autocreate/base.conf new file mode 100644 index 000000000..49008fff1 --- /dev/null +++ b/server_environment/tests/testfiles/autocreate/base.conf @@ -0,0 +1,11 @@ +[external_service.ftp] +__autocreate={"description": "ftp server"} +; host=sftp.example.com +; user=foo +; password=bar + +[external_service.ftp2] +__autocreate={"description": "ftp2"} +host=sftp2.example.com +user=monty +password=python diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 000000000..4ad8e0ece --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1 @@ +odoo-test-helper