Skip to content

Commit 3c8a812

Browse files
[IMP] server_environment: add possibility of auto creating records
1 parent 40c12a6 commit 3c8a812

8 files changed

Lines changed: 169 additions & 7 deletions

File tree

server_environment/models/server_env_mixin.py

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
33

44
import logging
5+
from ast import literal_eval
56
from functools import partialmethod
67

78
from lxml import etree
@@ -10,7 +11,7 @@
1011

1112
from odoo.addons.base_sparse_field.models.fields import Serialized
1213

13-
from ..server_env import serv_config
14+
from .. import server_env
1415

1516
_logger = logging.getLogger(__name__)
1617

@@ -211,8 +212,11 @@ def _server_env_read_from_config(self, field_name, config_getter):
211212
# at this point we should have checked that we have a key with
212213
# _server_env_has_key_defined so we are sure that the value is
213214
# either in the global or the record config
214-
getter = getattr(serv_config, config_getter)
215-
if section_name in serv_config and field_name in serv_config[section_name]:
215+
getter = getattr(server_env.serv_config, config_getter)
216+
if (
217+
section_name in server_env.serv_config
218+
and field_name in server_env.serv_config[section_name]
219+
):
216220
value = getter(section_name, field_name)
217221
else:
218222
value = getter(global_section_name, field_name)
@@ -228,11 +232,12 @@ def _server_env_has_key_defined(self, field_name):
228232
global_section_name = self._server_env_global_section_name()
229233
section_name = self._server_env_section_name()
230234
has_global_config = (
231-
global_section_name in serv_config
232-
and field_name in serv_config[global_section_name]
235+
global_section_name in server_env.serv_config
236+
and field_name in server_env.serv_config[global_section_name]
233237
)
234238
has_config = (
235-
section_name in serv_config and field_name in serv_config[section_name]
239+
section_name in server_env.serv_config
240+
and field_name in server_env.serv_config[section_name]
236241
)
237242
return has_global_config or has_config
238243

@@ -424,3 +429,40 @@ def _setup_base(self):
424429
self._server_env_transform_field_to_read_from_env(field)
425430
self._server_env_add_is_editable_field(field)
426431
return
432+
433+
def _register_hook(self):
434+
super()._register_hook()
435+
for model_name in self.env:
436+
model = self.env[model_name]
437+
if hasattr(model, "_server_env_global_section_name"):
438+
global_section_name = model._server_env_global_section_name()
439+
for section in server_env.serv_config:
440+
if section.startswith(f"{global_section_name}."):
441+
if server_env.serv_config[section].get("__autocreate", None):
442+
name_value = section[len(global_section_name) + 1 :]
443+
domain = [
444+
(model._server_env_section_name_field, "=", name_value)
445+
]
446+
count = model.with_context(active_test=False).search_count(
447+
domain
448+
)
449+
if count == 0:
450+
_logger.debug("Automatic creation of %s", name_value)
451+
values = literal_eval(
452+
server_env.serv_config[section].get("__autocreate")
453+
)
454+
values[
455+
model._server_env_section_name_field
456+
] = name_value
457+
records = model.create([values])
458+
self.env["ir.model.data"].create(
459+
[
460+
{
461+
"name": section,
462+
"model": model_name,
463+
"module": "__server_environment__",
464+
"res_id": record.id,
465+
}
466+
for record in records
467+
]
468+
)

server_environment/readme/CONFIGURE.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,20 @@ Note: empty environment keys always take precedence over default fields
9292

9393
Read the documentation of the class
9494
[models/server_env_mixin.py](models/server_env_mixin.py).
95+
96+
## Auto creation of records
97+
98+
It is possible to indicate that records must be created automatically if not found in the database.
99+
100+
When specifying a section in the configuration file or environment variable, also define ``__autocreate = {}``.
101+
The value is a dictionary that will be passed when the record is created. This allows setting some non environment variables that are required.
102+
For example, when using fs_storage module, the name of the storage is required so the configuration would look like:
103+
104+
```ini
105+
[fs_storage.my_sftp]
106+
__autocreate = {"name": "My SFTP"}
107+
protocol=sftp
108+
options={"host": "10.10.10.10", "username": "foo", "password": "xxxxxxxxx"}
109+
```
110+
111+
When the module creates such a record, it will add an xml id in the form `__server_enironment__.<section name>`.

server_environment/readme/CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
- Thomas Binfeld \<<thomas.binsfeld@acsone.eu>\>
1111
- Stéphane Bidoul \<<stefane.bidoul@acsone.com>\>
1212
- Simone Orsi \<<simahawk@gmail.com>\>
13+
- Vincent Hatakeyama \<<vincent.hatakeyama@xcg-consulting.fr>\>

server_environment/readme/ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
- it is not possible to set the environment from the command line. A
2-
configuration file must be used.
2+
configuration file or environment variables must be used.
33
- the module does not allow to set low level attributes such as database
44
server, etc.
55
- server.env.techname.mixin's tech_name field could leverage the new
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
from . import test_server_environment_autocreate
12
from . import test_server_environment
23
from . import test_environment_variable

server_environment/tests/models.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright 2024 XCG Consulting
2+
# @author Vincent Hatakeyama
3+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
4+
from odoo import fields, models
5+
6+
7+
class ExternalService(models.Model):
8+
_name = "external_service"
9+
_description = "External Service"
10+
_inherit = "server.env.mixin"
11+
12+
name = fields.Char(required=True)
13+
description = fields.Char(required=True)
14+
host = fields.Char()
15+
user = fields.Char()
16+
password = fields.Char()
17+
18+
@property
19+
def _server_env_fields(self):
20+
return {
21+
"host": {},
22+
"user": {},
23+
"password": {},
24+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Copyright 2018 Camptocamp (https://www.camptocamp.com).
2+
# Copyright 2024 XCG Consulting (https://xcg-consulting.fr).
3+
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
4+
import configparser
5+
6+
from odoo_test_helper import FakeModelLoader
7+
8+
from odoo.tests import tagged
9+
10+
from .. import server_env
11+
from . import common
12+
13+
14+
# Test need to be run post install otherwise the _register_hook is not called yet
15+
@tagged("post_install", "-at_install")
16+
class TestEnv(common.ServerEnvironmentCase):
17+
@classmethod
18+
def setUpClass(cls):
19+
super().setUpClass()
20+
# Load fake models ->/
21+
cls.loader = FakeModelLoader(cls.env, cls.__module__)
22+
cls.loader.backup_registry()
23+
from .models import ExternalService
24+
25+
cls.loader.update_registry((ExternalService,))
26+
cls.env["external_service"].create([{"name": "ftp2", "description": "another"}])
27+
28+
# Add our sections
29+
cls.old_serv_config = server_env.serv_config
30+
server_env.serv_config = configparser.ConfigParser(cls.old_serv_config)
31+
# update configuration with extra sections and values
32+
server_env.serv_config.add_section("external_service.ftp")
33+
server_env.serv_config.set(
34+
"external_service.ftp", "__autocreate", "{'description': 'ftp server'}"
35+
)
36+
server_env.serv_config.set("external_service.ftp", "host", "sftp.example.com")
37+
server_env.serv_config.set("external_service.ftp", "user", "foo")
38+
server_env.serv_config.set("external_service.ftp", "password", "bar")
39+
server_env.serv_config.add_section("external_service.ftp2")
40+
server_env.serv_config.set(
41+
"external_service.ftp2", "__autocreate", "{'description': 'ftp2'}"
42+
)
43+
server_env.serv_config.set("external_service.ftp2", "host", "sftp2.example.com")
44+
server_env.serv_config.set("external_service.ftp2", "user", "monty")
45+
server_env.serv_config.set("external_service.ftp2", "password", "python")
46+
# used to force _register_hook with auto creation
47+
cls.loader.update_registry(tuple())
48+
49+
@classmethod
50+
def tearDownClass(cls):
51+
cls.loader.restore_registry()
52+
super().tearDownClass()
53+
server_env.serv_config = cls.old_serv_config
54+
55+
def test_autocreate(self):
56+
# create record in setupClass
57+
# Test it has no xmlid
58+
record = self.env.ref("__server_environment__.external_service.ftp2", False)
59+
self.assertFalse(record)
60+
# look for it
61+
record = self.env["external_service"].search([("name", "=", "ftp2")])
62+
self.assertEqual(len(record), 1)
63+
self.assertEqual(record.name, "ftp2")
64+
# different from __autocreate dict as it is created in setUpClass
65+
self.assertEqual(record.description, "another")
66+
self.assertEqual(record.host, "sftp2.example.com")
67+
self.assertEqual(record.user, "monty")
68+
self.assertEqual(record.password, "python")
69+
70+
# auto created record
71+
record = self.env.ref("__server_environment__.external_service.ftp")
72+
self.assertEqual(record.name, "ftp")
73+
self.assertEqual(record.description, "ftp server")
74+
self.assertEqual(record.host, "sftp.example.com")
75+
self.assertEqual(record.user, "foo")
76+
self.assertEqual(record.password, "bar")

test-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
odoo-test-helper

0 commit comments

Comments
 (0)